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
SkComposeShader(SkShader * sA,SkShader * sB,SkXfermode * mode)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
SkComposeShader(SkReadBuffer & buffer)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
~SkComposeShader()42 SkComposeShader::~SkComposeShader() {
43 SkSafeUnref(fMode);
44 fShaderB->unref();
45 fShaderA->unref();
46 }
47
contextSize() const48 size_t SkComposeShader::contextSize() const {
49 return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
50 }
51
52 class SkAutoAlphaRestore {
53 public:
SkAutoAlphaRestore(SkPaint * paint,uint8_t newAlpha)54 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
55 fAlpha = paint->getAlpha();
56 fPaint = paint;
57 paint->setAlpha(newAlpha);
58 }
59
~SkAutoAlphaRestore()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
flatten(SkWriteBuffer & buffer) const69 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
safe_call_destructor(T * obj)76 template <typename T> void safe_call_destructor(T* obj) {
77 if (obj) {
78 obj->~T();
79 }
80 }
81
onCreateContext(const ContextRec & rec,void * storage) const82 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
ComposeShaderContext(const SkComposeShader & shader,const ContextRec & rec,SkShader::Context * contextA,SkShader::Context * contextB)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
~ComposeShaderContext()119 SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
120 fShaderContextA->~Context();
121 fShaderContextB->~Context();
122 }
123
asACompose(ComposeRec * rec) const124 bool SkComposeShader::asACompose(ComposeRec* rec) const {
125 if (rec) {
126 rec->fShaderA = fShaderA;
127 rec->fShaderB = fShaderB;
128 rec->fMode = fMode;
129 }
130 return true;
131 }
132
133
134 // larger is better (fewer times we have to loop), but we shouldn't
135 // take up too much stack-space (each element is 4 bytes)
136 #define TMP_COLOR_COUNT 64
137
shadeSpan(int x,int y,SkPMColor result[],int count)138 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
139 SkShader::Context* shaderContextA = fShaderContextA;
140 SkShader::Context* shaderContextB = fShaderContextB;
141 SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode;
142 unsigned scale = SkAlpha255To256(this->getPaintAlpha());
143
144 #ifdef SK_BUILD_FOR_ANDROID
145 scale = 256; // ugh -- maintain old bug/behavior for now
146 #endif
147
148 SkPMColor tmp[TMP_COLOR_COUNT];
149
150 if (NULL == mode) { // implied SRC_OVER
151 // TODO: when we have a good test-case, should use SkBlitRow::Proc32
152 // for these loops
153 do {
154 int n = count;
155 if (n > TMP_COLOR_COUNT) {
156 n = TMP_COLOR_COUNT;
157 }
158
159 shaderContextA->shadeSpan(x, y, result, n);
160 shaderContextB->shadeSpan(x, y, tmp, n);
161
162 if (256 == scale) {
163 for (int i = 0; i < n; i++) {
164 result[i] = SkPMSrcOver(tmp[i], result[i]);
165 }
166 } else {
167 for (int i = 0; i < n; i++) {
168 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
169 scale);
170 }
171 }
172
173 result += n;
174 x += n;
175 count -= n;
176 } while (count > 0);
177 } else { // use mode for the composition
178 do {
179 int n = count;
180 if (n > TMP_COLOR_COUNT) {
181 n = TMP_COLOR_COUNT;
182 }
183
184 shaderContextA->shadeSpan(x, y, result, n);
185 shaderContextB->shadeSpan(x, y, tmp, n);
186 mode->xfer32(result, tmp, n, NULL);
187
188 if (256 != scale) {
189 for (int i = 0; i < n; i++) {
190 result[i] = SkAlphaMulQ(result[i], scale);
191 }
192 }
193
194 result += n;
195 x += n;
196 count -= n;
197 } while (count > 0);
198 }
199 }
200
201 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const202 void SkComposeShader::toString(SkString* str) const {
203 str->append("SkComposeShader: (");
204
205 str->append("ShaderA: ");
206 fShaderA->toString(str);
207 str->append(" ShaderB: ");
208 fShaderB->toString(str);
209 str->append(" Xfermode: ");
210 fMode->toString(str);
211
212 this->INHERITED::toString(str);
213
214 str->append(")");
215 }
216 #endif
217