C++程序  |  823行  |  26.27 KB

/* 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.
*/

#if 0

#include "SkBitmapShader.h"
#include "SkBitmapSampler.h"

#ifdef SK_SUPPORT_MIPMAP
static SkFixed find_mip_level(SkFixed dx, SkFixed dy)
{
    dx = SkAbs32(dx);
    dy = SkAbs32(dy);
    if (dx < dy)
        dx = dy;
    
    if (dx < SK_Fixed1)
        return 0;
    
    int clz = SkCLZ(dx);
    SkASSERT(clz >= 1 && clz <= 15);
    return SkIntToFixed(15 - clz) + ((unsigned)(dx << (clz + 1)) >> 16);
}
#endif

SkBitmapShader::SkBitmapShader(const SkBitmap& src, bool doFilter,
                               TileMode tmx, TileMode tmy)
    :
#ifdef SK_SUPPORT_MIPMAP
    fMipLevel(0), fMipSrcBitmap(src),
#endif
    fOrigSrcBitmap(src)
    
{
    fFilterBitmap = doFilter;
    fTileModeX = SkToU8(tmx);
    fTileModeY = SkToU8(tmy);
}

SkBitmapShader::SkBitmapShader(SkFlattenableReadBuffer& buffer) :
    INHERITED(buffer)
{
    Bitmap src;
    buffer.readBitmap(&src); 
#ifdef SK_SUPPORT_MIPMAP
    fMipLevel = 0;
    fMipSrcBitmap = src;
#endif
    fOrigSrcBitmap = src;
    fFilterBitmap = buffer.readU8();
    fTileModeX = buffer.readU8();
    fTileModeY = buffer.readU8();
}

void SkBitmapShader::flatten(SkFlattenableWriteBuffer& buffer)
{
    this->INHERITED::flatten(buffer);
    buffer.writeBitmap(&fOrigSrcBitmap);
    buffer.write8(fFilterBitmap);
    buffer.write8(fTileModeX);
    buffer.write8(fTileModeY);
}

bool SkBitmapShader::setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
{
    // do this first, so we have a correct inverse matrix
    if (!this->INHERITED::setContext(device, paint, matrix))
        return false;

    if (fOrigSrcBitmap.getConfig() == SkBitmap::kNo_Config ||
        fOrigSrcBitmap.width() == 0 ||
        fOrigSrcBitmap.height() == 0)
        return false;

    SkBitmap& bm = fOrigSrcBitmap;

#ifdef SK_SUPPORT_MIPMAP
    if (fOrigSrcBitmap.countMipLevels())
    {
        const SkMatrix& inv = this->getTotalInverse();

        fMipLevel = SkMin32(find_mip_level( SkScalarToFixed(inv.getScaleX()),
                                            SkScalarToFixed(inv.getSkewY())),
                            SkIntToFixed(fOrigSrcBitmap.countMipLevels() - 1));

//        SkDEBUGF(("BitmapShader miplevel=%x\n", fMipLevel));

        const SkBitmap::MipLevel* mm = fOrigSrcBitmap.getMipLevel(fMipLevel >> 16);
        
        fMipSrcBitmap.setConfig(fOrigSrcBitmap.getConfig(),
                                mm->fWidth,
                                mm->fHeight,
                                mm->fRowBytes);
        fMipSrcBitmap.setPixels(mm->fPixels);
        bm = fMipSrcBitmap;
    }
    else
    {
        fMipLevel = 0;
        fMipSrcBitmap = fOrigSrcBitmap;
    }
#endif

    fFlags = 0;
    if (paint.getAlpha() == 255 && bm.isOpaque())
        fFlags |= kOpaqueAlpha_Flag;

    return true;
}

///////////////////////////////////////////////////////////////////////////

#include "SkColorPriv.h"
#include "SkBitmapSampler.h"
#include "SkPerspIter.h"

class Sampler_BitmapShader : public SkBitmapShader {
public:
    Sampler_BitmapShader(const SkBitmap& src, bool doFilter,
                         TileMode tmx, TileMode tmy)
        : SkBitmapShader(src, doFilter, tmx, tmy)
    {
        // make sure to pass our copy of the src bitmap to the sampler, and not the
        // original parameter (which might go away).
        fSampler = NULL;
    }

    virtual ~Sampler_BitmapShader()
    {
        SkDELETE(fSampler);
    }
    
    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
    {
        if (this->INHERITED::setContext(device, paint, matrix))
        {
            SkDELETE(fSampler);
            fSampler = SkBitmapSampler::Create(this->getSrcBitmap(), this->getFilterBitmap(),
                                               this->getTileModeX(), this->getTileModeY());
            fSampler->setPaint(paint);
            return true;
        }
        return false;
    }
    
    enum {
        kMaxPointStorageCount = 32
    };

    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
    {
        unsigned            scale = SkAlpha255To256(this->getPaintAlpha());
        const SkMatrix&     inv = this->getTotalInverse();
        SkMatrix::MapPtProc proc = this->getInverseMapPtProc();
        SkBitmapSampler*     sampler = fSampler;
        MatrixClass         mc = this->getInverseClass();

        SkPoint srcPt;

        if (mc != kPerspective_MatrixClass)
        {
            proc(inv, SkIntToScalar(x) + SK_ScalarHalf,
                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);

            SkFixed fx = SkScalarToFixed(srcPt.fX);
            SkFixed fy = SkScalarToFixed(srcPt.fY);
            SkFixed dx, dy;

            if (mc == kLinear_MatrixClass)
            {
                dx = SkScalarToFixed(inv.getScaleX());
                dy = SkScalarToFixed(inv.getSkewY());
            }
            else
                (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);

#if defined(SK_SUPPORT_MIPMAP)
            {   int level = this->getMipLevel() >> 16;
                fx >>= level;
                fy >>= level;
                dx >>= level;
                dy >>= level;
            }
#endif
            if (scale == 256)
            {
                for (int i = 0; i < count; i++)
                {
                    dstC[i] = sampler->sample(fx, fy);
                    fx += dx;
                    fy += dy;
                }
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    uint32_t    c = sampler->sample(fx, fy);
                    dstC[i] = SkAlphaMulQ(c, scale);
                    fx += dx;
                    fy += dy;
                }
            }
        }
        else
        {
            SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, count);
            if (scale == 256)
            {
                while ((count = iter.next()) != 0)
                {
                    const SkFixed* src = iter.getXY();
                    for (int i = 0; i < count; i++)
                    {
                        *dstC++ = sampler->sample(src[0], src[1]);
                        src += 2;
                    }
                }
            }
            else
            {
                while ((count = iter.next()) != 0)
                {
                    const SkFixed* src = iter.getXY();
                    for (int i = 0; i < count; i++)
                    {
                        uint32_t c = sampler->sample(src[0] - SK_FixedHalf, src[1] - SK_FixedHalf);
                        *dstC++ = SkAlphaMulQ(c, scale);
                        src += 2;
                    }
                }
            }
        }
    }

protected:

    const SkMatrix& getUnitInverse() const { return fUnitInverse; }
    SkMatrix::MapPtProc getUnitInverseProc() const { return fUnitInverseProc; }

    /* takes computed inverse (from setContext) and computes fUnitInverse,
        taking srcBitmap width/height into account, so that fUnitInverse
        walks 0...1, allowing the tile modes to all operate in a fast 16bit
        space (no need for mod). The resulting coords need to be scaled by
        width/height to get back into src space (coord * width >> 16).
    */
    void computeUnitInverse()
    {
        const SkBitmap& src = getSrcBitmap();
        fUnitInverse = this->getTotalInverse();
        fUnitInverse.postIDiv(src.width(), src.height());
        fUnitInverseProc = fUnitInverse.getMapPtProc();
    }

private:
    SkBitmapSampler*    fSampler;
    SkMatrix            fUnitInverse;
    SkMatrix::MapPtProc fUnitInverseProc;
    
    typedef SkBitmapShader INHERITED;
};

///////////////////////////////////////////////////////////////////////////

class HasSpan16_Sampler_BitmapShader : public Sampler_BitmapShader {
public:
    HasSpan16_Sampler_BitmapShader(const SkBitmap& src, bool doFilter,
                                   TileMode tmx, TileMode tmy)
        : Sampler_BitmapShader(src, doFilter, tmx, tmy)
    {
    }

    virtual uint32_t getFlags()
    {
        uint32_t flags = this->INHERITED::getFlags();
        
        switch (this->getSrcBitmap().getConfig()) {
        case SkBitmap::kRGB_565_Config:
            flags |= kHasSpan16_Flag;
            break;
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
            if (this->getSrcBitmap().isOpaque())
                flags |= kHasSpan16_Flag;
            break;
        default:
            break;
        }
        return flags;
    }
    
    const SkBitmap& revealSrcBitmap() const { return this->getSrcBitmap(); }
    uint8_t         revealPaintAlpha() const { return this->getPaintAlpha(); }
    const SkMatrix& revealTotalInverse() const { return this->getTotalInverse(); }

private:
    typedef Sampler_BitmapShader INHERITED;
};

///////////////////////////////////////////////////////////////////////////

static void Index8_RepeatTile_Sprite16(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, uint16_t dstC[], int count)
{
    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();

    SkColorTable* ctable = srcBitmap.getColorTable();
    const uint16_t* colors = ctable->lock16BitCache();

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);
    const uint8_t* row = srcBitmap.getAddr8(0, y);
    const uint8_t* src = row + x;

    // do the first partial run
    int n = width - x;
    if (n > count) n = count;
    count -= n;
    SkASSERT(n > 0);
    do {
        *dstC++ = colors[*src++];
    } while (--n > 0);

    // do 1 complete run
    if (count >= width)
    {
        uint16_t* baseDstC = dstC;  // remember the first complete run start
        n = width;
        count -= width;
        src = row;
        do {
            *dstC++ = colors[*src++];
        } while (--n > 0);

        // do the rest of the complete runs
        while (count >= width)
        {
            count -= width;
            memcpy(dstC, baseDstC, width << 1);
            dstC += width;
        }
        // do final partial run
        if (count > 0)
            memcpy(dstC, baseDstC, count << 1);
    }
    else // do final partial
    {
        if (count > 0)
        {
            src = row;
            do {
                *dstC++ = colors[*src++];
            } while (--count > 0);
        }
    }
    
    ctable->unlock16BitCache();
}

static void Index8_RepeatTile_Sprite32(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, SkPMColor dstC[], int count)
{
    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();

    SkColorTable* ctable = srcBitmap.getColorTable();
    const SkPMColor* colors = ctable->lockColors();

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);

    const uint8_t* row = srcBitmap.getAddr8(0, y);
    const uint8_t* src = row + x;

    // do the first partial run
    int n = width - x;
    if (n > count) n = count;
    count -= n;
    SkASSERT(n > 0);
    do {
        *dstC++ = colors[*src++];
    } while (--n > 0);

    // do 1 complete run
    if (count >= width)
    {
        SkPMColor* baseDstC = dstC;  // remember the first complete run start
        n = width;
        count -= width;
        src = row;
        do {
            *dstC++ = colors[*src++];
        } while (--n > 0);

        // do the rest of the complete runs
        while (count >= width)
        {
            count -= width;
            memcpy(dstC, baseDstC, width << 2);
            dstC += width;
        }
        // do final partial run
        if (count > 0)
            memcpy(dstC, baseDstC, count << 2);
    }
    else // do final partial
    {
        if (count > 0)
        {
            src = row;
            do {
                *dstC++ = colors[*src++];
            } while (--count > 0);
        }
    }
    
    ctable->unlockColors(false);
}

static void RGB16_RepeatTile_Sprite16(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, uint16_t dstC[], int count)
{
    SkASSERT(count > 0);

    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();
    
    SkASSERT(width > 0 && height > 0);

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);

    const uint16_t* row = srcBitmap.getAddr16(0, y);
    const uint16_t* src = row + x;

    int n = SkMin32(width - x, count);

    for (;;)
    {
        SkASSERT(n > 0 && count >= n);
        memcpy(dstC, src, n << 1);
        count -= n;
        if (count == 0)
            break;
        dstC += n;
        src = row;
        n = SkMin32(width, count);
    }
}

static void RGB16_RepeatTile_Sprite32(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, SkPMColor dstC[], int count)
{
    SkASSERT(count > 0);

    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();
    
    SkASSERT(width > 0 && height > 0);

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);

    const uint16_t* row = srcBitmap.getAddr16(0, y);
    const uint16_t* src = row + x;

    int n = SkMin32(width - x, count);

    // do the first partial run
    count -= n;
    SkASSERT(n > 0);
    do {
        *dstC++ = SkPixel16ToPixel32(*src++);
    } while (--n > 0);

    // do 1 complete run
    if (count >= width)
    {
        SkPMColor* baseDstC = dstC;  // remember the first complete run start
        n = width;
        count -= width;
        src = row;
        do {
            *dstC++ = SkPixel16ToPixel32(*src++);
        } while (--n > 0);

        // do the rest of the complete runs
        while (count >= width)
        {
            count -= width;
            memcpy(dstC, baseDstC, width << 2);
            dstC += width;
        }
        // do final partial run
        if (count > 0)
            memcpy(dstC, baseDstC, count << 2);
    }
    else // do final partial
    {
        if (count > 0)
        {
            src = row;
            do {
                *dstC++ = SkPixel16ToPixel32(*src++);;
            } while (--count > 0);
        }
    }
}

static void ARGB32_RepeatTile_Sprite16(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, uint16_t dstC[], int count)
{
    SkASSERT(count > 0);

    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();
    
    SkASSERT(width > 0 && height > 0);

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);

    const SkPMColor* row = srcBitmap.getAddr32(0, y);
    const SkPMColor* src = row + x;

    int n = SkMin32(width - x, count);

    // do the first partial run
    count -= n;
    SkASSERT(n > 0);
    do {
        *dstC++ = SkPixel32ToPixel16(*src++);
    } while (--n > 0);

    // do 1 complete run
    if (count >= width)
    {
        uint16_t* baseDstC = dstC;  // remember the first complete run start
        n = width;
        count -= width;
        src = row;
        do {
            *dstC++ = SkPixel32ToPixel16(*src++);
        } while (--n > 0);

        // do the rest of the complete runs
        while (count >= width)
        {
            count -= width;
            memcpy(dstC, baseDstC, width << 1);
            dstC += width;
        }
        // do final partial run
        if (count > 0)
            memcpy(dstC, baseDstC, count << 1);
    }
    else // do final partial
    {
        if (count > 0)
        {
            src = row;
            do {
                *dstC++ = SkPixel32ToPixel16(*src++);;
            } while (--count > 0);
        }
    }
}

static void ARGB32_RepeatTile_Sprite32(HasSpan16_Sampler_BitmapShader* shader,
                                       int x, int y, SkPMColor dstC[], int count)
{
    SkASSERT(count > 0);

    const SkMatrix& inv = shader->revealTotalInverse();
    const SkBitmap& srcBitmap = shader->revealSrcBitmap();
    int             width = srcBitmap.width();
    int             height = srcBitmap.height();
    
    SkASSERT(width > 0 && height > 0);

    x += SkScalarRound(inv[SkMatrix::kMTransX]);
    y += SkScalarRound(inv[SkMatrix::kMTransY]);
    
    x = do_repeat_mod(x, width - 1);
    y = do_repeat_mod(y, height - 1);

    const SkPMColor* row = srcBitmap.getAddr32(0, y);
    const SkPMColor* src = row + x;

    int n = SkMin32(width - x, count);

    for (;;)
    {
        SkASSERT(n > 0 && count >= n);
        memcpy(dstC, src, n << 2);
        count -= n;
        if (count == 0)
            break;
        dstC += n;
        src = row;
        n = SkMin32(width, count);
    }
}

///////////////////////////////////////////////////////////////////////////

#define NOFILTER_BITMAP_SHADER_CLASS                    Index8_NoFilter_RepeatTile_BitmapShader
#define NOFILTER_BITMAP_SHADER_TILEMODE                 SkShader::kRepeat_TileMode
#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)         (fixed_repeat(x) * (max + 1) >> 16)
#define NOFILTER_BITMAP_SHADER_TYPE                     uint8_t
#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)           colors32[p[x]]
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)   colors32[p[x + y * rb]]
#define NOFILTER_BITMAP_SHADER_PREAMBLE(bitmap, rb)     const SkPMColor* colors32 = bitmap.getColorTable()->lockColors()
#define NOFILTER_BITMAP_SHADER_POSTAMBLE(bitmap)        bitmap.getColorTable()->unlockColors(false)
#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)         colors16[p[x]]
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb) colors16[p[x + y * rb]]
#define NOFILTER_BITMAP_SHADER_PREAMBLE16(bitmap, rb)   const uint16_t* colors16 = bitmap.getColorTable()->lock16BitCache()
#define NOFILTER_BITMAP_SHADER_POSTAMBLE16(bitmap)      bitmap.getColorTable()->unlock16BitCache()
#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
#define NOFILTER_BITMAP_SHADER_SPRITEPROC16             Index8_RepeatTile_Sprite16
#define NOFILTER_BITMAP_SHADER_SPRITEPROC32             Index8_RepeatTile_Sprite32
#include "SkBitmapShaderTemplate.h"

#define NOFILTER_BITMAP_SHADER_CLASS                    U16_NoFilter_RepeatTile_BitmapShader
#define NOFILTER_BITMAP_SHADER_TILEMODE                 SkShader::kRepeat_TileMode
#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)         (fixed_repeat(x) * (max + 1) >> 16)
#define NOFILTER_BITMAP_SHADER_TYPE                     uint16_t
#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)           SkPixel16ToPixel32(p[x])
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)   SkPixel16ToPixel32(*(const uint16_t*)((const char*)p + y * rb + (x << 1)))
#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)         p[x]
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb) *(const uint16_t*)((const char*)p + y * rb + (x << 1))
#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
#define NOFILTER_BITMAP_SHADER_SPRITEPROC16             RGB16_RepeatTile_Sprite16
#define NOFILTER_BITMAP_SHADER_SPRITEPROC32             RGB16_RepeatTile_Sprite32
#include "SkBitmapShaderTemplate.h"

#define NOFILTER_BITMAP_SHADER_CLASS                    U32_NoFilter_RepeatTile_BitmapShader
#define NOFILTER_BITMAP_SHADER_TILEMODE                 SkShader::kRepeat_TileMode
#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)         (fixed_repeat(x) * (max + 1) >> 16)
#define NOFILTER_BITMAP_SHADER_TYPE                     uint32_t
#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)           p[x]
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)   *(const uint32_t*)((const char*)p + y * rb + (x << 2))
#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)         SkPixel32ToPixel16_ToU16(p[x])
#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb) SkPixel32ToPixel16_ToU16(*(const uint32_t*)((const char*)p + y * rb + (x << 2)))
#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
#define NOFILTER_BITMAP_SHADER_SPRITEPROC16             ARGB32_RepeatTile_Sprite16
#define NOFILTER_BITMAP_SHADER_SPRITEPROC32             ARGB32_RepeatTile_Sprite32
#include "SkBitmapShaderTemplate.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////

static inline SkPMColor expanded_rgb16_to_8888(uint32_t c, U8CPU alpha)
{
//    GGGG Gggg gggR RRRR rrrr r|BB BBBb bbbb
    SkASSERT(alpha <= 255);

#if 1
    int scale = SkAlpha255To256(alpha);
    int r = (c & 0xF800) * scale >> 16;
    int g = ((c >> 21) & 0x3F) * scale >> 6;
    int b = (c & 0x1F) * scale >> 5;
    return SkPackARGB32(alpha, r, g, b);
#else
    int scale = SkAlpha255To256(alpha) >> 3;
    c &= 0x07E0F81F;
    c = c * scale;
    int r = (c >> 13) & 0xFF;
    int g = (c >> 24) & 0xFF;
    int b = (c >> 2) & 0xFF;
    return SkPackARGB32(alpha, r, g, b);
#endif
}

#define BILERP_BITMAP16_SHADER_CLASS            U16_Bilerp_BitmapShader
#define BILERP_BITMAP16_SHADER_TYPE             uint16_t
#define BILERP_BITMAP16_SHADER_PREAMBLE(bm)
#define BILERP_BITMAP16_SHADER_PIXEL(c)         (c)
#define BILERP_BITMAP16_SHADER_POSTAMBLE(bm)
#include "SkBitmapShader16BilerpTemplate.h"

#define BILERP_BITMAP16_SHADER_CLASS            Index8_Bilerp_BitmapShader
#define BILERP_BITMAP16_SHADER_TYPE             uint8_t
#define BILERP_BITMAP16_SHADER_PREAMBLE(bm)     SkColorTable* ctable = (bm).getColorTable(); const uint16_t* colors16 = ctable->lock16BitCache()
#define BILERP_BITMAP16_SHADER_PIXEL(c)         colors16[c]
#define BILERP_BITMAP16_SHADER_POSTAMBLE(bm)    ctable->unlock16BitCache()
#include "SkBitmapShader16BilerpTemplate.h"

#include "ARGB32_Clamp_Bilinear_BitmapShader.h"

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

#include "SkBitmapProcShader.h"

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

#include "SkTemplatesPriv.h"

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                       bool doFilter,
                                       TileMode tmx, TileMode tmy,
                                       void* storage, size_t storageSize)
{
#if 1
    
    SkShader* shader;
    SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                          storageSize, (src, doFilter, tmx, tmy));
    return shader;
#else

    if (!doFilter)
    {
        if (kClamp_TileMode == tmx && kClamp_TileMode == tmy)
        {
            SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                                  storageSize, (src, doFilter, tmx, tmy));
        }
        else if (kRepeat_TileMode == tmx && kRepeat_TileMode == tmy)
        {
    #if 1
            SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                                  storageSize, (src, doFilter, tmx, tmy));
    #else
            switch (src.getConfig()) {
            case SkBitmap::kIndex8_Config:
                SK_PLACEMENT_NEW_ARGS(shader, Index8_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src));
                break;
            case SkBitmap::kRGB_565_Config:
                SK_PLACEMENT_NEW_ARGS(shader, U16_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src));
                break;
            case SkBitmap::kARGB_8888_Config:
                SK_PLACEMENT_NEW_ARGS(shader, U32_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src));
                break;
            default:
                break;
            }
    #endif
        }
    }
    else if (kClamp_TileMode == tmx && kClamp_TileMode == tmy)
    {
#if 1
        if (SkBitmapProcShader::CanDo(src, tmx, tmy))
        {
            SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                                  storageSize, (src, doFilter, tmx, tmy));
        }
#else
        switch (src.getConfig()) {
        case SkBitmap::kIndex8_Config:
            if (src.isOpaque())
                SK_PLACEMENT_NEW_ARGS(shader, Index8_Bilerp_BitmapShader, storage, storageSize, (src));
            break;
        case SkBitmap::kRGB_565_Config:
            SK_PLACEMENT_NEW_ARGS(shader, U16_Bilerp_BitmapShader, storage, storageSize, (src));
            break;
        case SkBitmap::kARGB_8888_Config:
            SK_PLACEMENT_NEW_ARGS(shader, ARGB32_Clamp_Bilinear_BitmapShader, storage, storageSize, (src));
            break;
        default:
            break;
        }
#endif
    }
    
    // if shader is null, then none of the special cases could handle the request
    // so fall through to our slow-general case
    if (shader == NULL)
        SK_PLACEMENT_NEW_ARGS(shader, Sampler_BitmapShader, storage, storageSize,
                              (src, doFilter, tmx, tmy));
    return shader;
#endif
}

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, bool doFilter,
                                       TileMode tmx, TileMode tmy)
{
    return SkShader::CreateBitmapShader(src, doFilter, tmx, tmy, NULL, 0);
}

#endif