/* libs/graphics/effects/SkTransparentShader.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/

#include "SkTransparentShader.h"
#include "SkColorPriv.h"

bool SkTransparentShader::setContext(const SkBitmap& device,
                                     const SkPaint& paint,
                                     const SkMatrix& matrix)
{
    fDevice = &device;
    fAlpha = paint.getAlpha();

    return this->INHERITED::setContext(device, paint, matrix);
}

uint32_t SkTransparentShader::getFlags()
{
    uint32_t flags = this->INHERITED::getFlags();

    switch (fDevice->getConfig()) {
    case SkBitmap::kRGB_565_Config:
        flags |= kHasSpan16_Flag;
        if (fAlpha == 255)
            flags |= kOpaqueAlpha_Flag;
        break;
    case SkBitmap::kARGB_8888_Config:
    case SkBitmap::kARGB_4444_Config:
        if (fAlpha == 255 && fDevice->isOpaque())
            flags |= kOpaqueAlpha_Flag;
        break;
    default:
        break;
    }
    return flags;
}

void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count)
{
    unsigned scale = SkAlpha255To256(fAlpha);

    switch (fDevice->getConfig()) {
    case SkBitmap::kARGB_8888_Config:
        if (scale == 256)
            memcpy(span, fDevice->getAddr32(x, y), count * sizeof(SkPMColor));
        else
        {
            const SkPMColor* src = fDevice->getAddr32(x, y);
            for (int i = count - 1; i >= 0; --i)
                span[i] = SkAlphaMulQ(src[i], scale);
        }
        break;
    case SkBitmap::kRGB_565_Config:
        {
            const uint16_t* src = fDevice->getAddr16(x, y);
            if (scale == 256)
            {
                for (int i = count - 1; i >= 0; --i)
                    span[i] = SkPixel16ToPixel32(src[i]);
            }
            else
            {
                unsigned alpha = fAlpha;
                for (int i = count - 1; i >= 0; --i)
                {
                    uint16_t c = src[i];
                    unsigned r = SkPacked16ToR32(c);
                    unsigned g = SkPacked16ToG32(c);
                    unsigned b = SkPacked16ToB32(c);

                    span[i] = SkPackARGB32( alpha,
                                            SkAlphaMul(r, scale),
                                            SkAlphaMul(g, scale),
                                            SkAlphaMul(b, scale));
                }
            }
        }
        break;
    case SkBitmap::kARGB_4444_Config:
        {
            const uint16_t* src = fDevice->getAddr16(x, y);
            if (scale == 256)
            {
                for (int i = count - 1; i >= 0; --i)
                    span[i] = SkPixel4444ToPixel32(src[i]);
            }
            else
            {
                unsigned scale16 = scale >> 4;
                for (int i = count - 1; i >= 0; --i)
                {
                    uint32_t c = SkExpand_4444(src[i]) * scale16;
                    span[i] = SkCompact_8888(c);
                }
            }
        }
            break;
            case SkBitmap::kIndex8_Config:
        SkASSERT(!"index8 not supported as a destination device");
        break;
    case SkBitmap::kA8_Config:
        {
            const uint8_t* src = fDevice->getAddr8(x, y);
            if (scale == 256)
            {
                for (int i = count - 1; i >= 0; --i)
                    span[i] = SkPackARGB32(src[i], 0, 0, 0);
            }
            else
            {
                for (int i = count - 1; i >= 0; --i)
                    span[i] = SkPackARGB32(SkAlphaMul(src[i], scale), 0, 0, 0);
            }
        }
        break;
    case SkBitmap::kA1_Config:
        SkASSERT(!"kA1_Config umimplemented at this time");
        break;
    default:    // to avoid warnings
        break;
    }
}

void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count)
{
    SkASSERT(fDevice->getConfig() == SkBitmap::kRGB_565_Config);

    memcpy(span, fDevice->getAddr16(x, y), count << 1);
}