gfx/skia/trunk/src/core/SkComposeShader.cpp

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

mercurial