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