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