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