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
10class SkTable_ColorFilter : public SkColorFilter {
11public:
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
63protected:
64#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
65    SkTable_ColorFilter(SkReadBuffer& buffer);
66#endif
67    virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
68
69private:
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
80static 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
115void 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
160void SkTable_ColorFilter::toString(SkString* str) const {
161    str->append("SkTable_ColorFilter");
162}
163#endif
164
165static 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
174void 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
184SkFlattenable* 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
231SkTable_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
251bool 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 "GrProcessor.h"
279#include "GrTBackendProcessorFactory.h"
280#include "gl/GrGLProcessor.h"
281#include "gl/builders/GrGLProgramBuilder.h"
282#include "SkGr.h"
283
284class GLColorTableEffect;
285
286class ColorTableEffect : public GrFragmentProcessor {
287public:
288    static GrFragmentProcessor* Create(GrTexture* texture, unsigned flags) {
289        return SkNEW_ARGS(ColorTableEffect, (texture, flags));
290    }
291
292    virtual ~ColorTableEffect();
293
294    static const char* Name() { return "ColorTable"; }
295    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
296
297    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
298
299    typedef GLColorTableEffect GLProcessor;
300
301private:
302    virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
303
304    explicit ColorTableEffect(GrTexture* texture, unsigned flags);
305
306    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
307
308    GrTextureAccess fTextureAccess;
309    unsigned        fFlags; // currently not used in shader code, just to assist
310                            // getConstantColorComponents().
311
312    typedef GrFragmentProcessor INHERITED;
313};
314
315class GLColorTableEffect : public GrGLFragmentProcessor {
316public:
317    GLColorTableEffect(const GrBackendProcessorFactory&, const GrProcessor&);
318
319    virtual void emitCode(GrGLProgramBuilder*,
320                          const GrFragmentProcessor&,
321                          const GrProcessorKey&,
322                          const char* outputColor,
323                          const char* inputColor,
324                          const TransformedCoordsArray&,
325                          const TextureSamplerArray&) SK_OVERRIDE;
326
327    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
328
329    static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
330
331private:
332
333    typedef GrGLFragmentProcessor INHERITED;
334};
335
336GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, const GrProcessor&)
337    : INHERITED(factory) {
338 }
339
340void GLColorTableEffect::emitCode(GrGLProgramBuilder* builder,
341                                  const GrFragmentProcessor&,
342                                  const GrProcessorKey&,
343                                  const char* outputColor,
344                                  const char* inputColor,
345                                  const TransformedCoordsArray&,
346                                  const TextureSamplerArray& samplers) {
347
348    static const float kColorScaleFactor = 255.0f / 256.0f;
349    static const float kColorOffsetFactor = 1.0f / 512.0f;
350    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
351    if (NULL == inputColor) {
352        // the input color is solid white (all ones).
353        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
354        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
355                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
356
357    } else {
358        fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
359        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
360        fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
361                              kColorScaleFactor,
362                              kColorOffsetFactor, kColorOffsetFactor,
363                              kColorOffsetFactor, kColorOffsetFactor);
364    }
365
366    fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
367    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
368    fsBuilder->codeAppend(";\n");
369
370    fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
371    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
372    fsBuilder->codeAppend(";\n");
373
374    fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
375    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
376    fsBuilder->codeAppend(";\n");
377
378    fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
379    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
380    fsBuilder->codeAppend(";\n");
381
382    fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
383}
384
385///////////////////////////////////////////////////////////////////////////////
386
387ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
388    : fTextureAccess(texture, "a")
389    , fFlags(flags) {
390    this->addTextureAccess(&fTextureAccess);
391}
392
393ColorTableEffect::~ColorTableEffect() {
394}
395
396const GrBackendFragmentProcessorFactory&  ColorTableEffect::getFactory() const {
397    return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance();
398}
399
400bool ColorTableEffect::onIsEqual(const GrProcessor& sBase) const {
401    return this->texture(0) == sBase.texture(0);
402}
403
404void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
405    // If we kept the table in the effect then we could actually run known inputs through the
406    // table.
407    if (fFlags & SkTable_ColorFilter::kR_Flag) {
408        *validFlags &= ~kR_GrColorComponentFlag;
409    }
410    if (fFlags & SkTable_ColorFilter::kG_Flag) {
411        *validFlags &= ~kG_GrColorComponentFlag;
412    }
413    if (fFlags & SkTable_ColorFilter::kB_Flag) {
414        *validFlags &= ~kB_GrColorComponentFlag;
415    }
416    if (fFlags & SkTable_ColorFilter::kA_Flag) {
417        *validFlags &= ~kA_GrColorComponentFlag;
418    }
419}
420
421
422///////////////////////////////////////////////////////////////////////////////
423
424GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
425
426GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
427                                                  GrContext* context,
428                                                  const GrDrawTargetCaps&,
429                                                  GrTexture* textures[]) {
430    static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
431                                SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
432    return ColorTableEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx], kAllFlags);
433}
434
435GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
436    SkBitmap bitmap;
437    GrFragmentProcessor* fp = NULL;
438    this->asComponentTable(&bitmap);
439    // passing NULL because this effect does no tiling or filtering.
440    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
441    if (texture) {
442        fp = ColorTableEffect::Create(texture, fFlags);
443
444        // Unlock immediately, this is not great, but we don't have a way of
445        // knowing when else to unlock it currently. TODO: Remove this when
446        // unref becomes the unlock replacement for all types of textures.
447        GrUnlockAndUnrefCachedBitmapTexture(texture);
448    }
449    return fp;
450}
451
452#endif // SK_SUPPORT_GPU
453
454///////////////////////////////////////////////////////////////////////////////
455
456#ifdef SK_CPU_BENDIAN
457#else
458    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
459    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
460    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
461    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
462#endif
463
464///////////////////////////////////////////////////////////////////////////////
465
466SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
467    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
468}
469
470SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
471                                              const uint8_t tableR[256],
472                                              const uint8_t tableG[256],
473                                              const uint8_t tableB[256]) {
474    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
475}
476
477SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
478    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
479SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
480