0d2d68717f2c7ccd8647ff5187e221b4c00a691a
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkComposeShader.cpp
1
2 /*
3  * Copyright 2006 The Android Open Source Project
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
9
10 #include "SkComposeShader.h"
11 #include "SkColorFilter.h"
12 #include "SkColorPriv.h"
13 #include "SkColorShader.h"
14 #include "SkFlattenableBuffers.h"
15 #include "SkXfermode.h"
16 #include "SkString.h"
17
18 ///////////////////////////////////////////////////////////////////////////////
19
20 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
21     fShaderA = sA;  sA->ref();
22     fShaderB = sB;  sB->ref();
23     // mode may be null
24     fMode = mode;
25     SkSafeRef(mode);
26 }
27
28 SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
29     INHERITED(buffer) {
30     fShaderA = buffer.readShader();
31     if (NULL == fShaderA) {
32         fShaderA = SkNEW_ARGS(SkColorShader, (0));
33     }
34     fShaderB = buffer.readShader();
35     if (NULL == fShaderB) {
36         fShaderB = SkNEW_ARGS(SkColorShader, (0));
37     }
38     fMode = buffer.readXfermode();
39 }
40
41 SkComposeShader::~SkComposeShader() {
42     SkSafeUnref(fMode);
43     fShaderB->unref();
44     fShaderA->unref();
45 }
46
47 class SkAutoAlphaRestore {
48 public:
49     SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
50         fAlpha = paint->getAlpha();
51         fPaint = paint;
52         paint->setAlpha(newAlpha);
53     }
54
55     ~SkAutoAlphaRestore() {
56         fPaint->setAlpha(fAlpha);
57     }
58 private:
59     SkPaint*    fPaint;
60     uint8_t     fAlpha;
61 };
62 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
63
64 void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) const {
65     this->INHERITED::flatten(buffer);
66     buffer.writeFlattenable(fShaderA);
67     buffer.writeFlattenable(fShaderB);
68     buffer.writeFlattenable(fMode);
69 }
70
71 /*  We call setContext on our two worker shaders. However, we
72     always let them see opaque alpha, and if the paint really
73     is translucent, then we apply that after the fact.
74
75     We need to keep the calls to setContext/endContext balanced, since if we
76     return false, our endContext() will not be called.
77  */
78 bool SkComposeShader::setContext(const SkBitmap& device,
79                                  const SkPaint& paint,
80                                  const SkMatrix& matrix) {
81     if (!this->INHERITED::setContext(device, paint, matrix)) {
82         return false;
83     }
84
85     // we preconcat our localMatrix (if any) with the device matrix
86     // before calling our sub-shaders
87
88     SkMatrix tmpM;
89
90     tmpM.setConcat(matrix, this->getLocalMatrix());
91
92     SkAutoAlphaRestore  restore(const_cast<SkPaint*>(&paint), 0xFF);
93
94     bool setContextA = fShaderA->setContext(device, paint, tmpM);
95     bool setContextB = fShaderB->setContext(device, paint, tmpM);
96     if (!setContextA || !setContextB) {
97         if (setContextB) {
98             fShaderB->endContext();
99         }
100         else if (setContextA) {
101             fShaderA->endContext();
102         }
103         this->INHERITED::endContext();
104         return false;
105     }
106     return true;
107 }
108
109 void SkComposeShader::endContext() {
110     fShaderB->endContext();
111     fShaderA->endContext();
112     this->INHERITED::endContext();
113 }
114
115 // larger is better (fewer times we have to loop), but we shouldn't
116 // take up too much stack-space (each element is 4 bytes)
117 #define TMP_COLOR_COUNT     64
118
119 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
120     SkShader*   shaderA = fShaderA;
121     SkShader*   shaderB = fShaderB;
122     SkXfermode* mode = fMode;
123     unsigned    scale = SkAlpha255To256(this->getPaintAlpha());
124
125     SkPMColor   tmp[TMP_COLOR_COUNT];
126
127     if (NULL == mode) {   // implied SRC_OVER
128         // TODO: when we have a good test-case, should use SkBlitRow::Proc32
129         // for these loops
130         do {
131             int n = count;
132             if (n > TMP_COLOR_COUNT) {
133                 n = TMP_COLOR_COUNT;
134             }
135
136             shaderA->shadeSpan(x, y, result, n);
137             shaderB->shadeSpan(x, y, tmp, n);
138
139             if (256 == scale) {
140                 for (int i = 0; i < n; i++) {
141                     result[i] = SkPMSrcOver(tmp[i], result[i]);
142                 }
143             } else {
144                 for (int i = 0; i < n; i++) {
145                     result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
146                                             scale);
147                 }
148             }
149
150             result += n;
151             x += n;
152             count -= n;
153         } while (count > 0);
154     } else {    // use mode for the composition
155         do {
156             int n = count;
157             if (n > TMP_COLOR_COUNT) {
158                 n = TMP_COLOR_COUNT;
159             }
160
161             shaderA->shadeSpan(x, y, result, n);
162             shaderB->shadeSpan(x, y, tmp, n);
163             mode->xfer32(result, tmp, n, NULL);
164
165             if (256 == scale) {
166                 for (int i = 0; i < n; i++) {
167                     result[i] = SkAlphaMulQ(result[i], scale);
168                 }
169             }
170
171             result += n;
172             x += n;
173             count -= n;
174         } while (count > 0);
175     }
176 }
177
178 #ifdef SK_DEVELOPER
179 void SkComposeShader::toString(SkString* str) const {
180     str->append("SkComposeShader: (");
181
182     str->append("ShaderA: ");
183     fShaderA->toString(str);
184     str->append(" ShaderB: ");
185     fShaderB->toString(str);
186     str->append(" Xfermode: ");
187     fMode->toString(str);
188
189     this->INHERITED::toString(str);
190
191     str->append(")");
192 }
193 #endif