Upstream version 10.39.225.0
[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 "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkXfermode.h"
17 #include "SkString.h"
18
19 ///////////////////////////////////////////////////////////////////////////////
20
21 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
22     fShaderA = sA;  sA->ref();
23     fShaderB = sB;  sB->ref();
24     // mode may be null
25     fMode = mode;
26     SkSafeRef(mode);
27 }
28
29 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
30 SkComposeShader::SkComposeShader(SkReadBuffer& buffer) : INHERITED(buffer) {
31     fShaderA = buffer.readShader();
32     if (NULL == fShaderA) {
33         fShaderA = SkNEW_ARGS(SkColorShader, ((SkColor)0));
34     }
35     fShaderB = buffer.readShader();
36     if (NULL == fShaderB) {
37         fShaderB = SkNEW_ARGS(SkColorShader, ((SkColor)0));
38     }
39     fMode = buffer.readXfermode();
40 }
41 #endif
42
43 SkComposeShader::~SkComposeShader() {
44     SkSafeUnref(fMode);
45     fShaderB->unref();
46     fShaderA->unref();
47 }
48
49 size_t SkComposeShader::contextSize() const {
50     return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
51 }
52
53 class SkAutoAlphaRestore {
54 public:
55     SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
56         fAlpha = paint->getAlpha();
57         fPaint = paint;
58         paint->setAlpha(newAlpha);
59     }
60
61     ~SkAutoAlphaRestore() {
62         fPaint->setAlpha(fAlpha);
63     }
64 private:
65     SkPaint*    fPaint;
66     uint8_t     fAlpha;
67 };
68 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
69
70 SkFlattenable* SkComposeShader::CreateProc(SkReadBuffer& buffer) {
71     SkAutoTUnref<SkShader> shaderA(buffer.readShader());
72     SkAutoTUnref<SkShader> shaderB(buffer.readShader());
73     SkAutoTUnref<SkXfermode> mode(buffer.readXfermode());
74     if (!shaderA.get() || !shaderB.get()) {
75         return NULL;
76     }
77     return SkNEW_ARGS(SkComposeShader, (shaderA, shaderB, mode));
78 }
79
80 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
81     buffer.writeFlattenable(fShaderA);
82     buffer.writeFlattenable(fShaderB);
83     buffer.writeFlattenable(fMode);
84 }
85
86 template <typename T> void safe_call_destructor(T* obj) {
87     if (obj) {
88         obj->~T();
89     }
90 }
91
92 SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const {
93     char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
94     char* bStorage = aStorage + fShaderA->contextSize();
95
96     // we preconcat our localMatrix (if any) with the device matrix
97     // before calling our sub-shaders
98     SkMatrix tmpM;
99     tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());
100
101     // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
102     // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
103     // sub-shaders.
104     SkPaint opaquePaint(*rec.fPaint);
105     opaquePaint.setAlpha(0xFF);
106
107     ContextRec newRec(rec);
108     newRec.fMatrix = &tmpM;
109     newRec.fPaint = &opaquePaint;
110
111     SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage);
112     SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage);
113     if (!contextA || !contextB) {
114         safe_call_destructor(contextA);
115         safe_call_destructor(contextB);
116         return NULL;
117     }
118
119     return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext, (*this, rec, contextA, contextB));
120 }
121
122 SkComposeShader::ComposeShaderContext::ComposeShaderContext(
123         const SkComposeShader& shader, const ContextRec& rec,
124         SkShader::Context* contextA, SkShader::Context* contextB)
125     : INHERITED(shader, rec)
126     , fShaderContextA(contextA)
127     , fShaderContextB(contextB) {}
128
129 SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
130     fShaderContextA->~Context();
131     fShaderContextB->~Context();
132 }
133
134 bool SkComposeShader::asACompose(ComposeRec* rec) const {
135     if (rec) {
136         rec->fShaderA = fShaderA;
137         rec->fShaderB = fShaderB;
138         rec->fMode = fMode;
139     }
140     return true;
141 }
142
143
144 // larger is better (fewer times we have to loop), but we shouldn't
145 // take up too much stack-space (each element is 4 bytes)
146 #define TMP_COLOR_COUNT     64
147
148 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
149     SkShader::Context* shaderContextA = fShaderContextA;
150     SkShader::Context* shaderContextB = fShaderContextB;
151     SkXfermode*        mode = static_cast<const SkComposeShader&>(fShader).fMode;
152     unsigned           scale = SkAlpha255To256(this->getPaintAlpha());
153
154 #ifdef SK_BUILD_FOR_ANDROID
155     scale = 256;    // ugh -- maintain old bug/behavior for now
156 #endif
157
158     SkPMColor   tmp[TMP_COLOR_COUNT];
159
160     if (NULL == mode) {   // implied SRC_OVER
161         // TODO: when we have a good test-case, should use SkBlitRow::Proc32
162         // for these loops
163         do {
164             int n = count;
165             if (n > TMP_COLOR_COUNT) {
166                 n = TMP_COLOR_COUNT;
167             }
168
169             shaderContextA->shadeSpan(x, y, result, n);
170             shaderContextB->shadeSpan(x, y, tmp, n);
171
172             if (256 == scale) {
173                 for (int i = 0; i < n; i++) {
174                     result[i] = SkPMSrcOver(tmp[i], result[i]);
175                 }
176             } else {
177                 for (int i = 0; i < n; i++) {
178                     result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
179                                             scale);
180                 }
181             }
182
183             result += n;
184             x += n;
185             count -= n;
186         } while (count > 0);
187     } else {    // use mode for the composition
188         do {
189             int n = count;
190             if (n > TMP_COLOR_COUNT) {
191                 n = TMP_COLOR_COUNT;
192             }
193
194             shaderContextA->shadeSpan(x, y, result, n);
195             shaderContextB->shadeSpan(x, y, tmp, n);
196             mode->xfer32(result, tmp, n, NULL);
197
198             if (256 != scale) {
199                 for (int i = 0; i < n; i++) {
200                     result[i] = SkAlphaMulQ(result[i], scale);
201                 }
202             }
203
204             result += n;
205             x += n;
206             count -= n;
207         } while (count > 0);
208     }
209 }
210
211 #ifndef SK_IGNORE_TO_STRING
212 void SkComposeShader::toString(SkString* str) const {
213     str->append("SkComposeShader: (");
214
215     str->append("ShaderA: ");
216     fShaderA->toString(str);
217     str->append(" ShaderB: ");
218     fShaderB->toString(str);
219     str->append(" Xfermode: ");
220     fMode->toString(str);
221
222     this->INHERITED::toString(str);
223
224     str->append(")");
225 }
226 #endif