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