SkTableColorFilter.cpp revision cfc18867d982119d9dc2888bf09f1093012daadd
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
16class SkTable_ColorFilter : public SkColorFilter {
17public:
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
69protected:
70    void flatten(SkWriteBuffer&) const override;
71
72private:
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
83static 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
118void 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
162void 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
192static 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
201void 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
211SkFlattenable* 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
257bool 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[].
284static 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
290SkColorFilter* 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
341class ColorTableEffect : public GrFragmentProcessor {
342public:
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
356private:
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
376class GLColorTableEffect : public GrGLFragmentProcessor {
377public:
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
391private:
392    UniformHandle fRGBAYValuesUni;
393    typedef GrGLFragmentProcessor INHERITED;
394};
395
396GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
397}
398
399void 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
418void 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    GrGLFPFragmentBuilder* 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///////////////////////////////////////////////////////////////////////////////
472GrFragmentProcessor* 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
494ColorTableEffect::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
504ColorTableEffect::~ColorTableEffect() {
505    if (fAtlas) {
506        fAtlas->unlockRow(fRow);
507    }
508}
509
510void ColorTableEffect::getGLProcessorKey(const GrGLSLCaps& caps,
511                                         GrProcessorKeyBuilder* b) const {
512    GLColorTableEffect::GenKey(*this, caps, b);
513}
514
515GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
516    return SkNEW_ARGS(GLColorTableEffect, (*this));
517}
518
519bool 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
529void 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
550GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
551
552GrFragmentProcessor* 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
585bool 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
614SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
615    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
616}
617
618SkColorFilter* 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
625SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
626    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
627SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
628