b60fa84b68d454de73e0ab17330e6d0bfebe7724
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / SkColorMatrixFilter.cpp
1
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkColorMatrixFilter.h"
9 #include "SkColorMatrix.h"
10 #include "SkColorPriv.h"
11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
13 #include "SkUnPreMultiply.h"
14 #include "SkString.h"
15
16 static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g,
17                           unsigned b, unsigned a) {
18     return array[0] * r + array[1] * g  + array[2] * b + array[3] * a + array[4];
19 }
20
21 static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g,
22                        unsigned b) {
23     return array[0] * r + array[1] * g  + array[2] * b + array[4];
24 }
25
26 static void General(const SkColorMatrixFilter::State& state,
27                     unsigned r, unsigned g, unsigned b, unsigned a,
28                     int32_t* SK_RESTRICT result) {
29     const int32_t* SK_RESTRICT array = state.fArray;
30     const int shift = state.fShift;
31
32     result[0] = rowmul4(&array[0], r, g, b, a) >> shift;
33     result[1] = rowmul4(&array[5], r, g, b, a) >> shift;
34     result[2] = rowmul4(&array[10], r, g, b, a) >> shift;
35     result[3] = rowmul4(&array[15], r, g, b, a) >> shift;
36 }
37
38 static void General16(const SkColorMatrixFilter::State& state,
39                       unsigned r, unsigned g, unsigned b, unsigned a,
40                       int32_t* SK_RESTRICT result) {
41     const int32_t* SK_RESTRICT array = state.fArray;
42
43     result[0] = rowmul4(&array[0], r, g, b, a) >> 16;
44     result[1] = rowmul4(&array[5], r, g, b, a) >> 16;
45     result[2] = rowmul4(&array[10], r, g, b, a) >> 16;
46     result[3] = rowmul4(&array[15], r, g, b, a) >> 16;
47 }
48
49 static void AffineAdd(const SkColorMatrixFilter::State& state,
50                       unsigned r, unsigned g, unsigned b, unsigned a,
51                       int32_t* SK_RESTRICT result) {
52     const int32_t* SK_RESTRICT array = state.fArray;
53     const int shift = state.fShift;
54
55     result[0] = rowmul3(&array[0], r, g, b) >> shift;
56     result[1] = rowmul3(&array[5], r, g, b) >> shift;
57     result[2] = rowmul3(&array[10], r, g, b) >> shift;
58     result[3] = a;
59 }
60
61 static void AffineAdd16(const SkColorMatrixFilter::State& state,
62                         unsigned r, unsigned g, unsigned b, unsigned a,
63                         int32_t* SK_RESTRICT result) {
64     const int32_t* SK_RESTRICT array = state.fArray;
65
66     result[0] = rowmul3(&array[0], r, g, b) >> 16;
67     result[1] = rowmul3(&array[5], r, g, b) >> 16;
68     result[2] = rowmul3(&array[10], r, g, b) >> 16;
69     result[3] = a;
70 }
71
72 static void ScaleAdd(const SkColorMatrixFilter::State& state,
73                      unsigned r, unsigned g, unsigned b, unsigned a,
74                      int32_t* SK_RESTRICT result) {
75     const int32_t* SK_RESTRICT array = state.fArray;
76     const int shift = state.fShift;
77
78     // cast to (int) to keep the expression signed for the shift
79     result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> shift;
80     result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> shift;
81     result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> shift;
82     result[3] = a;
83 }
84
85 static void ScaleAdd16(const SkColorMatrixFilter::State& state,
86                        unsigned r, unsigned g, unsigned b, unsigned a,
87                        int32_t* SK_RESTRICT result) {
88     const int32_t* SK_RESTRICT array = state.fArray;
89
90     // cast to (int) to keep the expression signed for the shift
91     result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> 16;
92     result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> 16;
93     result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> 16;
94     result[3] = a;
95 }
96
97 static void Add(const SkColorMatrixFilter::State& state,
98                 unsigned r, unsigned g, unsigned b, unsigned a,
99                 int32_t* SK_RESTRICT result) {
100     const int32_t* SK_RESTRICT array = state.fArray;
101     const int shift = state.fShift;
102
103     result[0] = r + (array[SkColorMatrix::kR_Trans] >> shift);
104     result[1] = g + (array[SkColorMatrix::kG_Trans] >> shift);
105     result[2] = b + (array[SkColorMatrix::kB_Trans] >> shift);
106     result[3] = a;
107 }
108
109 static void Add16(const SkColorMatrixFilter::State& state,
110                   unsigned r, unsigned g, unsigned b, unsigned a,
111                   int32_t* SK_RESTRICT result) {
112     const int32_t* SK_RESTRICT array = state.fArray;
113
114     result[0] = r + (array[SkColorMatrix::kR_Trans] >> 16);
115     result[1] = g + (array[SkColorMatrix::kG_Trans] >> 16);
116     result[2] = b + (array[SkColorMatrix::kB_Trans] >> 16);
117     result[3] = a;
118 }
119
120 #define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag |  \
121                          SkColorFilter::kHasFilter16_Flag)
122
123 // src is [20] but some compilers won't accept __restrict__ on anything
124 // but an raw pointer or reference
125 void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
126     int32_t* array = fState.fArray;
127     SkFixed max = 0;
128     for (int i = 0; i < 20; i++) {
129         SkFixed value = SkScalarToFixed(src[i]);
130         array[i] = value;
131         value = SkAbs32(value);
132         max = SkMax32(max, value);
133     }
134
135     /*  All of fArray[] values must fit in 23 bits, to safely allow me to
136         multiply them by 8bit unsigned values, and get a signed answer without
137         overflow. This means clz needs to be 9 or bigger
138     */
139     int bits = SkCLZ(max);
140     int32_t one = SK_Fixed1;
141
142     fState.fShift = 16; // we are starting out as fixed 16.16
143     if (bits < 9) {
144         bits = 9 - bits;
145         fState.fShift -= bits;
146         for (int i = 0; i < 20; i++) {
147             array[i] >>= bits;
148         }
149         one >>= bits;
150     }
151
152     // check if we have to munge Alpha
153     int32_t changesAlpha = (array[15] | array[16] | array[17] |
154                             (array[18] - one) | array[19]);
155     int32_t usesAlpha = (array[3] | array[8] | array[13]);
156     bool shiftIs16 = (16 == fState.fShift);
157
158     if (changesAlpha | usesAlpha) {
159         fProc = shiftIs16 ? General16 : General;
160         fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag;
161     } else {
162         fFlags = kNO_ALPHA_FLAGS;
163
164         int32_t needsScale = (array[SkColorMatrix::kR_Scale] - one) |
165                              (array[SkColorMatrix::kG_Scale] - one) |
166                              (array[SkColorMatrix::kB_Scale] - one);
167
168         int32_t needs3x3 =  array[1] | array[2] |     // red off-axis
169                             array[5] | array[7] |     // green off-axis
170                             array[10] | array[11];    // blue off-axis
171
172         if (needs3x3) {
173             fProc = shiftIs16 ? AffineAdd16 : AffineAdd;
174         } else if (needsScale) {
175             fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd;
176         } else if (array[SkColorMatrix::kR_Trans] |
177                    array[SkColorMatrix::kG_Trans] |
178                    array[SkColorMatrix::kB_Trans]) {
179             fProc = shiftIs16 ? Add16 : Add;
180         } else {
181             fProc = NULL;   // identity
182         }
183     }
184
185     /*  preround our add values so we get a rounded shift. We do this after we
186         analyze the array, so we don't miss the case where the caller has zeros
187         which could make us accidentally take the General or Add case.
188     */
189     if (NULL != fProc) {
190         int32_t add = 1 << (fState.fShift - 1);
191         array[4] += add;
192         array[9] += add;
193         array[14] += add;
194         array[19] += add;
195     }
196 }
197
198 ///////////////////////////////////////////////////////////////////////////////
199
200 static int32_t pin(int32_t value, int32_t max) {
201     if (value < 0) {
202         value = 0;
203     }
204     if (value > max) {
205         value = max;
206     }
207     return value;
208 }
209
210 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) {
211     this->initState(cm.fMat);
212 }
213
214 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
215     memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar));
216     this->initState(array);
217 }
218
219 uint32_t SkColorMatrixFilter::getFlags() const {
220     return this->INHERITED::getFlags() | fFlags;
221 }
222
223 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count,
224                                      SkPMColor dst[]) const {
225     Proc proc = fProc;
226     const State& state = fState;
227     int32_t result[4];
228
229     if (NULL == proc) {
230         if (src != dst) {
231             memcpy(dst, src, count * sizeof(SkPMColor));
232         }
233         return;
234     }
235
236     const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
237
238     for (int i = 0; i < count; i++) {
239         SkPMColor c = src[i];
240
241         unsigned r = SkGetPackedR32(c);
242         unsigned g = SkGetPackedG32(c);
243         unsigned b = SkGetPackedB32(c);
244         unsigned a = SkGetPackedA32(c);
245
246         // need our components to be un-premultiplied
247         if (255 != a) {
248             SkUnPreMultiply::Scale scale = table[a];
249             r = SkUnPreMultiply::ApplyScale(scale, r);
250             g = SkUnPreMultiply::ApplyScale(scale, g);
251             b = SkUnPreMultiply::ApplyScale(scale, b);
252
253             SkASSERT(r <= 255);
254             SkASSERT(g <= 255);
255             SkASSERT(b <= 255);
256         }
257
258         proc(state, r, g, b, a, result);
259
260         r = pin(result[0], SK_R32_MASK);
261         g = pin(result[1], SK_G32_MASK);
262         b = pin(result[2], SK_B32_MASK);
263         a = pin(result[3], SK_A32_MASK);
264         // re-prepremultiply if needed
265         dst[i] = SkPremultiplyARGBInline(a, r, g, b);
266     }
267 }
268
269 void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count,
270                                        uint16_t dst[]) const {
271     SkASSERT(fFlags & SkColorFilter::kHasFilter16_Flag);
272
273     Proc   proc = fProc;
274     const State& state = fState;
275     int32_t result[4];
276
277     if (NULL == proc) {
278         if (src != dst) {
279             memcpy(dst, src, count * sizeof(uint16_t));
280         }
281         return;
282     }
283
284     for (int i = 0; i < count; i++) {
285         uint16_t c = src[i];
286
287         // expand to 8bit components (since our matrix translate is 8bit biased
288         unsigned r = SkPacked16ToR32(c);
289         unsigned g = SkPacked16ToG32(c);
290         unsigned b = SkPacked16ToB32(c);
291
292         proc(state, r, g, b, 0, result);
293
294         r = pin(result[0], SK_R32_MASK);
295         g = pin(result[1], SK_G32_MASK);
296         b = pin(result[2], SK_B32_MASK);
297
298         // now packed it back down to 16bits (hmmm, could dither...)
299         dst[i] = SkPack888ToRGB16(r, g, b);
300     }
301 }
302
303 ///////////////////////////////////////////////////////////////////////////////
304
305 void SkColorMatrixFilter::flatten(SkWriteBuffer& buffer) const {
306     this->INHERITED::flatten(buffer);
307     SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
308     buffer.writeScalarArray(fMatrix.fMat, 20);
309 }
310
311 SkColorMatrixFilter::SkColorMatrixFilter(SkReadBuffer& buffer)
312         : INHERITED(buffer) {
313     SkASSERT(buffer.getArrayCount() == 20);
314     if (buffer.readScalarArray(fMatrix.fMat, 20)) {
315         this->initState(fMatrix.fMat);
316     }
317 }
318
319 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
320     if (matrix) {
321         memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
322     }
323     return true;
324 }
325
326 #if SK_SUPPORT_GPU
327 #include "GrEffect.h"
328 #include "GrTBackendEffectFactory.h"
329 #include "gl/GrGLEffect.h"
330
331 class ColorMatrixEffect : public GrEffect {
332 public:
333     static GrEffectRef* Create(const SkColorMatrix& matrix) {
334         AutoEffectUnref effect(SkNEW_ARGS(ColorMatrixEffect, (matrix)));
335         return CreateEffectRef(effect);
336     }
337
338     static const char* Name() { return "Color Matrix"; }
339
340     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
341         return GrTBackendEffectFactory<ColorMatrixEffect>::getInstance();
342     }
343
344     virtual void getConstantColorComponents(GrColor* color,
345                                             uint32_t* validFlags) const SK_OVERRIDE {
346         // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
347         // type flags it might be worth checking the other components.
348
349         // The matrix is defined such the 4th row determines the output alpha. The first four
350         // columns of that row multiply the input r, g, b, and a, respectively, and the last column
351         // is the "translation".
352         static const uint32_t kRGBAFlags[] = {
353             kR_GrColorComponentFlag,
354             kG_GrColorComponentFlag,
355             kB_GrColorComponentFlag,
356             kA_GrColorComponentFlag
357         };
358         static const int kShifts[] = {
359             GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
360         };
361         enum {
362             kAlphaRowStartIdx = 15,
363             kAlphaRowTranslateIdx = 19,
364         };
365
366         SkScalar outputA = 0;
367         for (int i = 0; i < 4; ++i) {
368             // If any relevant component of the color to be passed through the matrix is non-const
369             // then we can't know the final result.
370             if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
371                 if (!(*validFlags & kRGBAFlags[i])) {
372                     *validFlags = 0;
373                     return;
374                 } else {
375                     uint32_t component = (*color >> kShifts[i]) & 0xFF;
376                     outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
377                 }
378             }
379         }
380         outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
381         *validFlags = kA_GrColorComponentFlag;
382         // We pin the color to [0,1]. This would happen to the *final* color output from the frag
383         // shader but currently the effect does not pin its own output. So in the case of over/
384         // underflow this may deviate from the actual result. Maybe the effect should pin its
385         // result if the matrix could over/underflow for any component?
386         *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
387     }
388
389     GR_DECLARE_EFFECT_TEST;
390
391     class GLEffect : public GrGLEffect {
392     public:
393         // this class always generates the same code.
394         static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
395
396         GLEffect(const GrBackendEffectFactory& factory,
397                  const GrDrawEffect&)
398         : INHERITED(factory) {
399         }
400
401         virtual void emitCode(GrGLShaderBuilder* builder,
402                               const GrDrawEffect&,
403                               EffectKey,
404                               const char* outputColor,
405                               const char* inputColor,
406                               const TransformedCoordsArray&,
407                               const TextureSamplerArray&) SK_OVERRIDE {
408             fMatrixHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
409                                                 kMat44f_GrSLType,
410                                                 "ColorMatrix");
411             fVectorHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
412                                                 kVec4f_GrSLType,
413                                                 "ColorMatrixVector");
414
415             if (NULL == inputColor) {
416                 // could optimize this case, but we aren't for now.
417                 inputColor = "vec4(1)";
418             }
419             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
420             // transparent black.
421             builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
422             builder->fsCodeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
423                                    outputColor,
424                                    builder->getUniformCStr(fMatrixHandle),
425                                    inputColor,
426                                    builder->getUniformCStr(fVectorHandle));
427             builder->fsCodeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
428             builder->fsCodeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
429         }
430
431         virtual void setData(const GrGLUniformManager& uniManager,
432                              const GrDrawEffect& drawEffect) SK_OVERRIDE {
433             const ColorMatrixEffect& cme = drawEffect.castEffect<ColorMatrixEffect>();
434             const float* m = cme.fMatrix.fMat;
435             // The GL matrix is transposed from SkColorMatrix.
436             GrGLfloat mt[]  = {
437                 m[0], m[5], m[10], m[15],
438                 m[1], m[6], m[11], m[16],
439                 m[2], m[7], m[12], m[17],
440                 m[3], m[8], m[13], m[18],
441             };
442             static const float kScale = 1.0f / 255.0f;
443             GrGLfloat vec[] = {
444                 m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale,
445             };
446             uniManager.setMatrix4fv(fMatrixHandle, 1, mt);
447             uniManager.set4fv(fVectorHandle, 1, vec);
448         }
449
450     private:
451         GrGLUniformManager::UniformHandle fMatrixHandle;
452         GrGLUniformManager::UniformHandle fVectorHandle;
453     };
454
455 private:
456     ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {}
457
458     virtual bool onIsEqual(const GrEffect& s) const {
459         const ColorMatrixEffect& cme = CastEffect<ColorMatrixEffect>(s);
460         return cme.fMatrix == fMatrix;
461     }
462
463     SkColorMatrix fMatrix;
464
465     typedef GrGLEffect INHERITED;
466 };
467
468 GR_DEFINE_EFFECT_TEST(ColorMatrixEffect);
469
470 GrEffectRef* ColorMatrixEffect::TestCreate(SkRandom* random,
471                                            GrContext*,
472                                            const GrDrawTargetCaps&,
473                                            GrTexture* dummyTextures[2]) {
474     SkColorMatrix colorMatrix;
475     for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
476         colorMatrix.fMat[i] = random->nextSScalar1();
477     }
478     return ColorMatrixEffect::Create(colorMatrix);
479 }
480
481 GrEffectRef* SkColorMatrixFilter::asNewEffect(GrContext*) const {
482     return ColorMatrixEffect::Create(fMatrix);
483 }
484
485 #endif
486
487 #ifndef SK_IGNORE_TO_STRING
488 void SkColorMatrixFilter::toString(SkString* str) const {
489     str->append("SkColorMatrixFilter: ");
490
491     str->append("matrix: (");
492     for (int i = 0; i < 20; ++i) {
493         str->appendScalar(fMatrix.fMat[i]);
494         if (i < 19) {
495             str->append(", ");
496         }
497     }
498     str->append(")");
499 }
500 #endif