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 GrEffectRef* asNewEffect(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    SkTable_ColorFilter(SkReadBuffer& buffer);
65    virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
66
67private:
68    mutable const SkBitmap* fBitmap; // lazily allocated
69
70    uint8_t fStorage[256 * 4];
71    unsigned fFlags;
72
73    typedef SkColorFilter INHERITED;
74};
75
76static const uint8_t gIdentityTable[] = {
77    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
78    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
79    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
80    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
81    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
82    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
83    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
84    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
85    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
86    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
87    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
88    0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
89    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
90    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
91    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
92    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
93    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
94    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
95    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
96    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
97    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
98    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
99    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
100    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
101    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
102    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
103    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
104    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
105    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
106    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
107    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
108    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
109};
110
111void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
112                                     SkPMColor dst[]) const {
113    const uint8_t* table = fStorage;
114    const uint8_t* tableA = gIdentityTable;
115    const uint8_t* tableR = gIdentityTable;
116    const uint8_t* tableG = gIdentityTable;
117    const uint8_t* tableB = gIdentityTable;
118    if (fFlags & kA_Flag) {
119        tableA = table; table += 256;
120    }
121    if (fFlags & kR_Flag) {
122        tableR = table; table += 256;
123    }
124    if (fFlags & kG_Flag) {
125        tableG = table; table += 256;
126    }
127    if (fFlags & kB_Flag) {
128        tableB = table;
129    }
130
131    const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
132    for (int i = 0; i < count; ++i) {
133        SkPMColor c = src[i];
134        unsigned a, r, g, b;
135        if (0 == c) {
136            a = r = g = b = 0;
137        } else {
138            a = SkGetPackedA32(c);
139            r = SkGetPackedR32(c);
140            g = SkGetPackedG32(c);
141            b = SkGetPackedB32(c);
142
143            if (a < 255) {
144                SkUnPreMultiply::Scale scale = scaleTable[a];
145                r = SkUnPreMultiply::ApplyScale(scale, r);
146                g = SkUnPreMultiply::ApplyScale(scale, g);
147                b = SkUnPreMultiply::ApplyScale(scale, b);
148            }
149        }
150        dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
151                                         tableG[g], tableB[b]);
152    }
153}
154
155#ifndef SK_IGNORE_TO_STRING
156void SkTable_ColorFilter::toString(SkString* str) const {
157    str->append("SkTable_ColorFilter");
158}
159#endif
160
161static const uint8_t gCountNibBits[] = {
162    0, 1, 1, 2,
163    1, 2, 2, 3,
164    1, 2, 2, 3,
165    2, 3, 3, 4
166};
167
168#include "SkPackBits.h"
169
170void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
171    this->INHERITED::flatten(buffer);
172
173    uint8_t storage[5*256];
174    int count = gCountNibBits[fFlags & 0xF];
175    size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
176    SkASSERT(size <= sizeof(storage));
177
178//    SkDebugf("raw %d packed %d\n", count * 256, size);
179
180    buffer.writeInt(fFlags);
181    buffer.writeByteArray(storage, size);
182}
183
184SkTable_ColorFilter::SkTable_ColorFilter(SkReadBuffer& buffer) : INHERITED(buffer) {
185    fBitmap = NULL;
186
187    uint8_t storage[5*256];
188
189    fFlags = buffer.readInt();
190
191    size_t size = buffer.getArrayCount();
192    SkASSERT(size <= sizeof(storage));
193    buffer.validate(size <= sizeof(storage));
194    buffer.readByteArray(storage, size);
195
196    SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage);
197
198    SkASSERT(raw <= sizeof(fStorage));
199    SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]);
200    SkASSERT(raw == count * 256);
201}
202
203bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
204    if (table) {
205        if (NULL == fBitmap) {
206            SkBitmap* bmp = SkNEW(SkBitmap);
207            bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
208            uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
209            int offset = 0;
210            static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
211
212            for (int x = 0; x < 4; ++x) {
213                if (!(fFlags & kFlags[x])) {
214                    memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
215                } else {
216                    memcpy(bitmapPixels, fStorage + offset, 256);
217                    offset += 256;
218                }
219                bitmapPixels += 256;
220            }
221            fBitmap = bmp;
222        }
223        *table = *fBitmap;
224    }
225    return true;
226}
227
228#if SK_SUPPORT_GPU
229
230#include "GrEffect.h"
231#include "GrTBackendEffectFactory.h"
232#include "gl/GrGLEffect.h"
233#include "SkGr.h"
234
235class GLColorTableEffect;
236
237class ColorTableEffect : public GrEffect {
238public:
239    static GrEffectRef* Create(GrTexture* texture, unsigned flags) {
240        AutoEffectUnref effect(SkNEW_ARGS(ColorTableEffect, (texture, flags)));
241        return CreateEffectRef(effect);
242    }
243
244    virtual ~ColorTableEffect();
245
246    static const char* Name() { return "ColorTable"; }
247    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
248
249    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
250
251    typedef GLColorTableEffect GLEffect;
252
253private:
254    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
255
256    explicit ColorTableEffect(GrTexture* texture, unsigned flags);
257
258    GR_DECLARE_EFFECT_TEST;
259
260    GrTextureAccess fTextureAccess;
261    unsigned        fFlags; // currently not used in shader code, just to assist
262                            // getConstantColorComponents().
263
264    typedef GrEffect INHERITED;
265};
266
267class GLColorTableEffect : public GrGLEffect {
268public:
269    GLColorTableEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
270
271    virtual void emitCode(GrGLShaderBuilder*,
272                          const GrDrawEffect&,
273                          EffectKey,
274                          const char* outputColor,
275                          const char* inputColor,
276                          const TransformedCoordsArray&,
277                          const TextureSamplerArray&) SK_OVERRIDE;
278
279    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
280
281    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
282
283private:
284
285    typedef GrGLEffect INHERITED;
286};
287
288GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
289    : INHERITED(factory) {
290 }
291
292void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
293                                  const GrDrawEffect&,
294                                  EffectKey,
295                                  const char* outputColor,
296                                  const char* inputColor,
297                                  const TransformedCoordsArray&,
298                                  const TextureSamplerArray& samplers) {
299
300    static const float kColorScaleFactor = 255.0f / 256.0f;
301    static const float kColorOffsetFactor = 1.0f / 512.0f;
302    if (NULL == inputColor) {
303        // the input color is solid white (all ones).
304        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
305        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
306                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
307
308    } else {
309        builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
310        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
311        builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
312                              kColorScaleFactor,
313                              kColorOffsetFactor, kColorOffsetFactor,
314                              kColorOffsetFactor, kColorOffsetFactor);
315    }
316
317    builder->fsCodeAppendf("\t\t%s.a = ", outputColor);
318    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
319    builder->fsCodeAppend(";\n");
320
321    builder->fsCodeAppendf("\t\t%s.r = ", outputColor);
322    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
323    builder->fsCodeAppend(";\n");
324
325    builder->fsCodeAppendf("\t\t%s.g = ", outputColor);
326    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
327    builder->fsCodeAppend(";\n");
328
329    builder->fsCodeAppendf("\t\t%s.b = ", outputColor);
330    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
331    builder->fsCodeAppend(";\n");
332
333    builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
334}
335
336GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) {
337    return 0;
338}
339
340///////////////////////////////////////////////////////////////////////////////
341
342ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
343    : fTextureAccess(texture, "a")
344    , fFlags(flags) {
345    this->addTextureAccess(&fTextureAccess);
346}
347
348ColorTableEffect::~ColorTableEffect() {
349}
350
351const GrBackendEffectFactory&  ColorTableEffect::getFactory() const {
352    return GrTBackendEffectFactory<ColorTableEffect>::getInstance();
353}
354
355bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const {
356    return this->texture(0) == sBase.texture(0);
357}
358
359void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
360    // If we kept the table in the effect then we could actually run known inputs through the
361    // table.
362    if (fFlags & SkTable_ColorFilter::kR_Flag) {
363        *validFlags &= ~kR_GrColorComponentFlag;
364    }
365    if (fFlags & SkTable_ColorFilter::kG_Flag) {
366        *validFlags &= ~kG_GrColorComponentFlag;
367    }
368    if (fFlags & SkTable_ColorFilter::kB_Flag) {
369        *validFlags &= ~kB_GrColorComponentFlag;
370    }
371    if (fFlags & SkTable_ColorFilter::kA_Flag) {
372        *validFlags &= ~kA_GrColorComponentFlag;
373    }
374}
375
376
377///////////////////////////////////////////////////////////////////////////////
378
379GR_DEFINE_EFFECT_TEST(ColorTableEffect);
380
381GrEffectRef* ColorTableEffect::TestCreate(SkRandom* random,
382                                          GrContext* context,
383                                          const GrDrawTargetCaps&,
384                                          GrTexture* textures[]) {
385    static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
386                                SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
387    return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags);
388}
389
390GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
391    SkBitmap bitmap;
392    GrEffectRef* effect = NULL;
393    this->asComponentTable(&bitmap);
394    // passing NULL because this effect does no tiling or filtering.
395    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
396    if (NULL != texture) {
397        effect = ColorTableEffect::Create(texture, fFlags);
398
399        // Unlock immediately, this is not great, but we don't have a way of
400        // knowing when else to unlock it currently. TODO: Remove this when
401        // unref becomes the unlock replacement for all types of textures.
402        GrUnlockAndUnrefCachedBitmapTexture(texture);
403    }
404    return effect;
405}
406
407#endif // SK_SUPPORT_GPU
408
409///////////////////////////////////////////////////////////////////////////////
410
411#ifdef SK_CPU_BENDIAN
412#else
413    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
414    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
415    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
416    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
417#endif
418
419///////////////////////////////////////////////////////////////////////////////
420
421SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
422    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
423}
424
425SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
426                                              const uint8_t tableR[256],
427                                              const uint8_t tableG[256],
428                                              const uint8_t tableB[256]) {
429    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
430}
431
432SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
433    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
434SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
435