Home | History | Annotate | Download | only in effects
      1 /*
      2 * Copyright 2015 Google Inc.
      3 *
      4 * Use of this source code is governed by a BSD-style license that can be
      5 * found in the LICENSE file.
      6 */
      7 
      8 #include "SkBitmap.h"
      9 #include "SkTableColorFilter.h"
     10 #include "SkColorPriv.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkWriteBuffer.h"
     13 #include "SkUnPreMultiply.h"
     14 #include "SkString.h"
     15 
     16 class SkTable_ColorFilter : public SkColorFilter {
     17 public:
     18     SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
     19                         const uint8_t tableG[], const uint8_t tableB[]) {
     20         fBitmap = NULL;
     21         fFlags = 0;
     22 
     23         uint8_t* dst = fStorage;
     24         if (tableA) {
     25             memcpy(dst, tableA, 256);
     26             dst += 256;
     27             fFlags |= kA_Flag;
     28         }
     29         if (tableR) {
     30             memcpy(dst, tableR, 256);
     31             dst += 256;
     32             fFlags |= kR_Flag;
     33         }
     34         if (tableG) {
     35             memcpy(dst, tableG, 256);
     36             dst += 256;
     37             fFlags |= kG_Flag;
     38         }
     39         if (tableB) {
     40             memcpy(dst, tableB, 256);
     41             fFlags |= kB_Flag;
     42         }
     43     }
     44 
     45     virtual ~SkTable_ColorFilter() {
     46         SkDELETE(fBitmap);
     47     }
     48 
     49     bool asComponentTable(SkBitmap* table) const override;
     50     SkColorFilter* newComposed(const SkColorFilter* inner) const override;
     51 
     52 #if SK_SUPPORT_GPU
     53     bool asFragmentProcessors(GrContext*, SkTDArray<GrFragmentProcessor*>*) const override;
     54 #endif
     55 
     56     void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
     57 
     58     SK_TO_STRING_OVERRIDE()
     59 
     60     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
     61 
     62     enum {
     63         kA_Flag = 1 << 0,
     64         kR_Flag = 1 << 1,
     65         kG_Flag = 1 << 2,
     66         kB_Flag = 1 << 3,
     67     };
     68 
     69 protected:
     70     void flatten(SkWriteBuffer&) const override;
     71 
     72 private:
     73     mutable const SkBitmap* fBitmap; // lazily allocated
     74 
     75     uint8_t fStorage[256 * 4];
     76     unsigned fFlags;
     77 
     78     friend class SkTableColorFilter;
     79 
     80     typedef SkColorFilter INHERITED;
     81 };
     82 
     83 static const uint8_t gIdentityTable[] = {
     84     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     85     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
     86     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     87     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
     88     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
     89     0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
     90     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
     91     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
     92     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
     93     0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
     94     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
     95     0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
     96     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
     97     0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
     98     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
     99     0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
    100     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    101     0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
    102     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    103     0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
    104     0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    105     0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
    106     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
    107     0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
    108     0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
    109     0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
    110     0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
    111     0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
    112     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
    113     0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
    114     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
    115     0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
    116 };
    117 
    118 void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
    119     const uint8_t* table = fStorage;
    120     const uint8_t* tableA = gIdentityTable;
    121     const uint8_t* tableR = gIdentityTable;
    122     const uint8_t* tableG = gIdentityTable;
    123     const uint8_t* tableB = gIdentityTable;
    124     if (fFlags & kA_Flag) {
    125         tableA = table; table += 256;
    126     }
    127     if (fFlags & kR_Flag) {
    128         tableR = table; table += 256;
    129     }
    130     if (fFlags & kG_Flag) {
    131         tableG = table; table += 256;
    132     }
    133     if (fFlags & kB_Flag) {
    134         tableB = table;
    135     }
    136 
    137     const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
    138     for (int i = 0; i < count; ++i) {
    139         SkPMColor c = src[i];
    140         unsigned a, r, g, b;
    141         if (0 == c) {
    142             a = r = g = b = 0;
    143         } else {
    144             a = SkGetPackedA32(c);
    145             r = SkGetPackedR32(c);
    146             g = SkGetPackedG32(c);
    147             b = SkGetPackedB32(c);
    148 
    149             if (a < 255) {
    150                 SkUnPreMultiply::Scale scale = scaleTable[a];
    151                 r = SkUnPreMultiply::ApplyScale(scale, r);
    152                 g = SkUnPreMultiply::ApplyScale(scale, g);
    153                 b = SkUnPreMultiply::ApplyScale(scale, b);
    154             }
    155         }
    156         dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
    157                                          tableG[g], tableB[b]);
    158     }
    159 }
    160 
    161 #ifndef SK_IGNORE_TO_STRING
    162 void SkTable_ColorFilter::toString(SkString* str) const {
    163     const uint8_t* table = fStorage;
    164     const uint8_t* tableA = gIdentityTable;
    165     const uint8_t* tableR = gIdentityTable;
    166     const uint8_t* tableG = gIdentityTable;
    167     const uint8_t* tableB = gIdentityTable;
    168     if (fFlags & kA_Flag) {
    169         tableA = table; table += 256;
    170     }
    171     if (fFlags & kR_Flag) {
    172         tableR = table; table += 256;
    173     }
    174     if (fFlags & kG_Flag) {
    175         tableG = table; table += 256;
    176     }
    177     if (fFlags & kB_Flag) {
    178         tableB = table;
    179     }
    180 
    181     str->append("SkTable_ColorFilter (");
    182 
    183     for (int i = 0; i < 256; ++i) {
    184         str->appendf("%d: %d,%d,%d,%d\n",
    185                      i, tableR[i], tableG[i], tableB[i], tableA[i]);
    186     }
    187 
    188     str->append(")");
    189 }
    190 #endif
    191 
    192 static const uint8_t gCountNibBits[] = {
    193     0, 1, 1, 2,
    194     1, 2, 2, 3,
    195     1, 2, 2, 3,
    196     2, 3, 3, 4
    197 };
    198 
    199 #include "SkPackBits.h"
    200 
    201 void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
    202     uint8_t storage[5*256];
    203     int count = gCountNibBits[fFlags & 0xF];
    204     size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
    205     SkASSERT(size <= sizeof(storage));
    206 
    207     buffer.write32(fFlags);
    208     buffer.writeByteArray(storage, size);
    209 }
    210 
    211 SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
    212     const int flags = buffer.read32();
    213     const size_t count = gCountNibBits[flags & 0xF];
    214     SkASSERT(count <= 4);
    215 
    216     uint8_t packedStorage[5*256];
    217     size_t packedSize = buffer.getArrayCount();
    218     if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
    219         return NULL;
    220     }
    221     if (!buffer.readByteArray(packedStorage, packedSize)) {
    222         return NULL;
    223     }
    224 
    225     uint8_t unpackedStorage[4*256];
    226     size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
    227     // now check that we got the size we expected
    228     if (!buffer.validate(unpackedSize == count*256)) {
    229         return NULL;
    230     }
    231 
    232     const uint8_t* a = NULL;
    233     const uint8_t* r = NULL;
    234     const uint8_t* g = NULL;
    235     const uint8_t* b = NULL;
    236     const uint8_t* ptr = unpackedStorage;
    237 
    238     if (flags & kA_Flag) {
    239         a = ptr;
    240         ptr += 256;
    241     }
    242     if (flags & kR_Flag) {
    243         r = ptr;
    244         ptr += 256;
    245     }
    246     if (flags & kG_Flag) {
    247         g = ptr;
    248         ptr += 256;
    249     }
    250     if (flags & kB_Flag) {
    251         b = ptr;
    252         ptr += 256;
    253     }
    254     return SkTableColorFilter::CreateARGB(a, r, g, b);
    255 }
    256 
    257 bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
    258     if (table) {
    259         if (NULL == fBitmap) {
    260             SkBitmap* bmp = SkNEW(SkBitmap);
    261             bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
    262             uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
    263             int offset = 0;
    264             static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
    265 
    266             for (int x = 0; x < 4; ++x) {
    267                 if (!(fFlags & kFlags[x])) {
    268                     memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
    269                 } else {
    270                     memcpy(bitmapPixels, fStorage + offset, 256);
    271                     offset += 256;
    272                 }
    273                 bitmapPixels += 256;
    274             }
    275             fBitmap = bmp;
    276         }
    277         *table = *fBitmap;
    278     }
    279     return true;
    280 }
    281 
    282 // Combines the two lookup tables so that making a lookup using res[] has
    283 // the same effect as making a lookup through inner[] then outer[].
    284 static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
    285     for (int i = 0; i < 256; i++) {
    286         res[i] = outer[inner[i]];
    287     }
    288 }
    289 
    290 SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
    291     SkBitmap innerBM;
    292     if (!innerFilter->asComponentTable(&innerBM)) {
    293         return NULL;
    294     }
    295 
    296     innerBM.lockPixels();
    297     if (NULL == innerBM.getPixels()) {
    298         return NULL;
    299     }
    300 
    301     const uint8_t* table = fStorage;
    302     const uint8_t* tableA = gIdentityTable;
    303     const uint8_t* tableR = gIdentityTable;
    304     const uint8_t* tableG = gIdentityTable;
    305     const uint8_t* tableB = gIdentityTable;
    306     if (fFlags & kA_Flag) {
    307         tableA = table; table += 256;
    308     }
    309     if (fFlags & kR_Flag) {
    310         tableR = table; table += 256;
    311     }
    312     if (fFlags & kG_Flag) {
    313         tableG = table; table += 256;
    314     }
    315     if (fFlags & kB_Flag) {
    316         tableB = table;
    317     }
    318 
    319     uint8_t concatA[256];
    320     uint8_t concatR[256];
    321     uint8_t concatG[256];
    322     uint8_t concatB[256];
    323 
    324     combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
    325     combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
    326     combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
    327     combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
    328 
    329     return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
    330 }
    331 
    332 #if SK_SUPPORT_GPU
    333 
    334 #include "GrFragmentProcessor.h"
    335 #include "GrInvariantOutput.h"
    336 #include "SkGr.h"
    337 #include "effects/GrTextureStripAtlas.h"
    338 #include "gl/GrGLProcessor.h"
    339 #include "gl/builders/GrGLProgramBuilder.h"
    340 
    341 class ColorTableEffect : public GrFragmentProcessor {
    342 public:
    343     static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
    344 
    345     virtual ~ColorTableEffect();
    346 
    347     const char* name() const override { return "ColorTable"; }
    348 
    349     void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
    350 
    351     GrGLFragmentProcessor* createGLInstance() const override;
    352 
    353     const GrTextureStripAtlas* atlas() const { return fAtlas; }
    354     int atlasRow() const { return fRow; }
    355 
    356 private:
    357     bool onIsEqual(const GrFragmentProcessor&) const override;
    358 
    359     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
    360 
    361     ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
    362 
    363     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
    364 
    365     GrTextureAccess         fTextureAccess;
    366 
    367     // currently not used in shader code, just to assist onComputeInvariantOutput().
    368     unsigned                fFlags;
    369 
    370     GrTextureStripAtlas*    fAtlas;
    371     int                     fRow;
    372 
    373     typedef GrFragmentProcessor INHERITED;
    374 };
    375 
    376 class GLColorTableEffect : public GrGLFragmentProcessor {
    377 public:
    378     GLColorTableEffect(const GrProcessor&);
    379 
    380     virtual void emitCode(GrGLFPBuilder*,
    381                           const GrFragmentProcessor&,
    382                           const char* outputColor,
    383                           const char* inputColor,
    384                           const TransformedCoordsArray&,
    385                           const TextureSamplerArray&) override;
    386 
    387     void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
    388 
    389     static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
    390 
    391 private:
    392     UniformHandle fRGBAYValuesUni;
    393     typedef GrGLFragmentProcessor INHERITED;
    394 };
    395 
    396 GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
    397 }
    398 
    399 void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
    400     // The textures are organized in a strip where the rows are ordered a, r, g, b.
    401     float rgbaYValues[4];
    402     const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
    403     if (cte.atlas()) {
    404         SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
    405         rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
    406         rgbaYValues[0] = rgbaYValues[3] + yDelta;
    407         rgbaYValues[1] = rgbaYValues[0] + yDelta;
    408         rgbaYValues[2] = rgbaYValues[1] + yDelta;
    409     } else {
    410         rgbaYValues[3] = 0.125;
    411         rgbaYValues[0] = 0.375;
    412         rgbaYValues[1] = 0.625;
    413         rgbaYValues[2] = 0.875;
    414     }
    415     pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
    416 }
    417 
    418 void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
    419                                   const GrFragmentProcessor&,
    420                                   const char* outputColor,
    421                                   const char* inputColor,
    422                                   const TransformedCoordsArray&,
    423                                   const TextureSamplerArray& samplers) {
    424     const char* yoffsets;
    425     fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
    426                                           kVec4f_GrSLType, kDefault_GrSLPrecision,
    427                                           "yoffsets", &yoffsets);
    428     static const float kColorScaleFactor = 255.0f / 256.0f;
    429     static const float kColorOffsetFactor = 1.0f / 512.0f;
    430     GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
    431     if (NULL == inputColor) {
    432         // the input color is solid white (all ones).
    433         static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
    434         fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
    435                                kMaxValue, kMaxValue, kMaxValue, kMaxValue);
    436 
    437     } else {
    438         fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
    439         fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
    440         fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
    441                               kColorScaleFactor,
    442                               kColorOffsetFactor, kColorOffsetFactor,
    443                               kColorOffsetFactor, kColorOffsetFactor);
    444     }
    445 
    446     SkString coord;
    447 
    448     fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
    449     coord.printf("vec2(coord.a, %s.a)", yoffsets);
    450     fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
    451     fsBuilder->codeAppend(";\n");
    452 
    453     fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
    454     coord.printf("vec2(coord.r, %s.r)", yoffsets);
    455     fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
    456     fsBuilder->codeAppend(";\n");
    457 
    458     fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
    459     coord.printf("vec2(coord.g, %s.g)", yoffsets);
    460     fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
    461     fsBuilder->codeAppend(";\n");
    462 
    463     fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
    464     coord.printf("vec2(coord.b, %s.b)", yoffsets);
    465     fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
    466     fsBuilder->codeAppend(";\n");
    467 
    468     fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
    469 }
    470 
    471 ///////////////////////////////////////////////////////////////////////////////
    472 GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
    473 
    474     GrTextureStripAtlas::Desc desc;
    475     desc.fWidth  = bitmap.width();
    476     desc.fHeight = 128;
    477     desc.fRowHeight = bitmap.height();
    478     desc.fContext = context;
    479     desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
    480     GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
    481     int row = atlas->lockRow(bitmap);
    482     SkAutoTUnref<GrTexture> texture;
    483     if (-1 == row) {
    484         atlas = NULL;
    485         // Passing params=NULL because this effect does no tiling or filtering.
    486         texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
    487     } else {
    488         texture.reset(SkRef(atlas->getTexture()));
    489     }
    490 
    491     return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
    492 }
    493 
    494 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
    495                                    unsigned flags)
    496     : fTextureAccess(texture, "a")
    497     , fFlags(flags)
    498     , fAtlas(atlas)
    499     , fRow(row) {
    500     this->initClassID<ColorTableEffect>();
    501     this->addTextureAccess(&fTextureAccess);
    502 }
    503 
    504 ColorTableEffect::~ColorTableEffect() {
    505     if (fAtlas) {
    506         fAtlas->unlockRow(fRow);
    507     }
    508 }
    509 
    510 void ColorTableEffect::getGLProcessorKey(const GrGLSLCaps& caps,
    511                                          GrProcessorKeyBuilder* b) const {
    512     GLColorTableEffect::GenKey(*this, caps, b);
    513 }
    514 
    515 GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
    516     return SkNEW_ARGS(GLColorTableEffect, (*this));
    517 }
    518 
    519 bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
    520     // For non-atlased instances, the texture (compared by base class) is sufficient to
    521     // differentiate different tables. For atlased instances we ensure they are using the
    522     // same row.
    523     const ColorTableEffect& that = other.cast<ColorTableEffect>();
    524     SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
    525     // Ok to always do this comparison since both would be -1 if non-atlased.
    526     return fRow == that.fRow;
    527 }
    528 
    529 void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    530     // If we kept the table in the effect then we could actually run known inputs through the
    531     // table.
    532     uint8_t invalidateFlags = 0;
    533     if (fFlags & SkTable_ColorFilter::kR_Flag) {
    534         invalidateFlags |= kR_GrColorComponentFlag;
    535     }
    536     if (fFlags & SkTable_ColorFilter::kG_Flag) {
    537         invalidateFlags |= kG_GrColorComponentFlag;
    538     }
    539     if (fFlags & SkTable_ColorFilter::kB_Flag) {
    540         invalidateFlags |= kB_GrColorComponentFlag;
    541     }
    542     if (fFlags & SkTable_ColorFilter::kA_Flag) {
    543         invalidateFlags |= kA_GrColorComponentFlag;
    544     }
    545     inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
    546 }
    547 
    548 ///////////////////////////////////////////////////////////////////////////////
    549 
    550 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
    551 
    552 GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
    553                                                   GrContext* context,
    554                                                   const GrDrawTargetCaps&,
    555                                                   GrTexture* textures[]) {
    556     int flags = 0;
    557     uint8_t luts[256][4];
    558     do {
    559         for (int i = 0; i < 4; ++i) {
    560             flags |= random->nextBool() ? (1  << i): 0;
    561         }
    562     } while (!flags);
    563     for (int i = 0; i < 4; ++i) {
    564         if (flags & (1 << i)) {
    565             for (int j = 0; j < 256; ++j) {
    566                 luts[j][i] = SkToU8(random->nextBits(8));
    567             }
    568         }
    569     }
    570     SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
    571         (flags & (1 << 0)) ? luts[0] : NULL,
    572         (flags & (1 << 1)) ? luts[1] : NULL,
    573         (flags & (1 << 2)) ? luts[2] : NULL,
    574         (flags & (1 << 3)) ? luts[3] : NULL
    575     ));
    576 
    577     SkTDArray<GrFragmentProcessor*> array;
    578     if (filter->asFragmentProcessors(context, &array)) {
    579         SkASSERT(1 == array.count());   // TableColorFilter only returns 1
    580         return array[0];
    581     }
    582     return NULL;
    583 }
    584 
    585 bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
    586                                                SkTDArray<GrFragmentProcessor*>* array) const {
    587     SkBitmap bitmap;
    588     this->asComponentTable(&bitmap);
    589 
    590     GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
    591     if (frag) {
    592         if (array) {
    593             *array->append() = frag;
    594         }
    595         return true;
    596     }
    597     return false;
    598 }
    599 
    600 #endif // SK_SUPPORT_GPU
    601 
    602 ///////////////////////////////////////////////////////////////////////////////
    603 
    604 #ifdef SK_CPU_BENDIAN
    605 #else
    606     #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
    607     #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
    608     #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
    609     #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
    610 #endif
    611 
    612 ///////////////////////////////////////////////////////////////////////////////
    613 
    614 SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
    615     return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
    616 }
    617 
    618 SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
    619                                               const uint8_t tableR[256],
    620                                               const uint8_t tableG[256],
    621                                               const uint8_t tableB[256]) {
    622     return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
    623 }
    624 
    625 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
    626     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
    627 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    628