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