OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkComposeShader.h" | 10 #include "SkComposeShader.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 } | 38 } |
39 fMode = buffer.readXfermode(); | 39 fMode = buffer.readXfermode(); |
40 } | 40 } |
41 | 41 |
42 SkComposeShader::~SkComposeShader() { | 42 SkComposeShader::~SkComposeShader() { |
43 SkSafeUnref(fMode); | 43 SkSafeUnref(fMode); |
44 fShaderB->unref(); | 44 fShaderB->unref(); |
45 fShaderA->unref(); | 45 fShaderA->unref(); |
46 } | 46 } |
47 | 47 |
48 size_t SkComposeShader::contextSize() const { | |
49 return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->co
ntextSize(); | |
50 } | |
51 | |
52 class SkAutoAlphaRestore { | 48 class SkAutoAlphaRestore { |
53 public: | 49 public: |
54 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { | 50 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { |
55 fAlpha = paint->getAlpha(); | 51 fAlpha = paint->getAlpha(); |
56 fPaint = paint; | 52 fPaint = paint; |
57 paint->setAlpha(newAlpha); | 53 paint->setAlpha(newAlpha); |
58 } | 54 } |
59 | 55 |
60 ~SkAutoAlphaRestore() { | 56 ~SkAutoAlphaRestore() { |
61 fPaint->setAlpha(fAlpha); | 57 fPaint->setAlpha(fAlpha); |
62 } | 58 } |
63 private: | 59 private: |
64 SkPaint* fPaint; | 60 SkPaint* fPaint; |
65 uint8_t fAlpha; | 61 uint8_t fAlpha; |
66 }; | 62 }; |
67 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) | 63 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) |
68 | 64 |
69 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { | 65 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { |
70 this->INHERITED::flatten(buffer); | 66 this->INHERITED::flatten(buffer); |
71 buffer.writeFlattenable(fShaderA); | 67 buffer.writeFlattenable(fShaderA); |
72 buffer.writeFlattenable(fShaderB); | 68 buffer.writeFlattenable(fShaderB); |
73 buffer.writeFlattenable(fMode); | 69 buffer.writeFlattenable(fMode); |
74 } | 70 } |
75 | 71 |
76 /* We call validContext/createContext on our two worker shaders. | 72 /* We call setContext on our two worker shaders. However, we |
77 However, we always let them see opaque alpha, and if the paint | 73 always let them see opaque alpha, and if the paint really |
78 really is translucent, then we apply that after the fact. | 74 is translucent, then we apply that after the fact. |
79 | 75 |
| 76 We need to keep the calls to setContext/endContext balanced, since if we |
| 77 return false, our endContext() will not be called. |
80 */ | 78 */ |
81 bool SkComposeShader::validContext(const SkBitmap& device, | 79 bool SkComposeShader::setContext(const SkBitmap& device, |
82 const SkPaint& paint, | 80 const SkPaint& paint, |
83 const SkMatrix& matrix, | 81 const SkMatrix& matrix) { |
84 SkMatrix* totalInverse) const { | 82 if (!this->INHERITED::setContext(device, paint, matrix)) { |
85 if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { | |
86 return false; | 83 return false; |
87 } | 84 } |
88 | 85 |
89 // we preconcat our localMatrix (if any) with the device matrix | 86 // we preconcat our localMatrix (if any) with the device matrix |
90 // before calling our sub-shaders | |
91 | |
92 SkMatrix tmpM; | |
93 | |
94 tmpM.setConcat(matrix, this->getLocalMatrix()); | |
95 | |
96 return fShaderA->validContext(device, paint, tmpM) && | |
97 fShaderB->validContext(device, paint, tmpM); | |
98 } | |
99 | |
100 SkShader::Context* SkComposeShader::createContext(const SkBitmap& device, const
SkPaint& paint, | |
101 const SkMatrix& matrix, void*
storage) const { | |
102 if (!this->validContext(device, paint, matrix)) { | |
103 return NULL; | |
104 } | |
105 | |
106 // we preconcat our localMatrix (if any) with the device matrix | |
107 // before calling our sub-shaders | 87 // before calling our sub-shaders |
108 | 88 |
109 SkMatrix tmpM; | 89 SkMatrix tmpM; |
110 | 90 |
111 tmpM.setConcat(matrix, this->getLocalMatrix()); | 91 tmpM.setConcat(matrix, this->getLocalMatrix()); |
112 | 92 |
113 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); | 93 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); |
114 | 94 |
115 char* aStorage = (char*) storage + sizeof(ComposeShaderContext); | 95 bool setContextA = fShaderA->setContext(device, paint, tmpM); |
116 char* bStorage = aStorage + fShaderA->contextSize(); | 96 bool setContextB = fShaderB->setContext(device, paint, tmpM); |
117 | 97 if (!setContextA || !setContextB) { |
118 SkShader::Context* contextA = fShaderA->createContext(device, paint, tmpM, a
Storage); | 98 if (setContextB) { |
119 SkShader::Context* contextB = fShaderB->createContext(device, paint, tmpM, b
Storage); | 99 fShaderB->endContext(); |
120 | 100 } |
121 // Both functions must succeed; otherwise validContext should have returned | 101 else if (setContextA) { |
122 // false. | 102 fShaderA->endContext(); |
123 SkASSERT(contextA); | 103 } |
124 SkASSERT(contextB); | 104 this->INHERITED::endContext(); |
125 | 105 return false; |
126 return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext, | 106 } |
127 (*this, device, paint, matrix, contextA, context
B)); | 107 return true; |
128 } | 108 } |
129 | 109 |
130 SkComposeShader::ComposeShaderContext::ComposeShaderContext( | 110 void SkComposeShader::endContext() { |
131 const SkComposeShader& shader, const SkBitmap& device, | 111 fShaderB->endContext(); |
132 const SkPaint& paint, const SkMatrix& matrix, | 112 fShaderA->endContext(); |
133 SkShader::Context* contextA, SkShader::Context* contextB) | 113 this->INHERITED::endContext(); |
134 : INHERITED(shader, device, paint, matrix) | |
135 , fShaderContextA(contextA) | |
136 , fShaderContextB(contextB) {} | |
137 | |
138 SkComposeShader::ComposeShaderContext::~ComposeShaderContext() { | |
139 fShaderContextA->SkShader::Context::~Context(); | |
140 fShaderContextB->SkShader::Context::~Context(); | |
141 } | 114 } |
142 | 115 |
143 // larger is better (fewer times we have to loop), but we shouldn't | 116 // larger is better (fewer times we have to loop), but we shouldn't |
144 // take up too much stack-space (each element is 4 bytes) | 117 // take up too much stack-space (each element is 4 bytes) |
145 #define TMP_COLOR_COUNT 64 | 118 #define TMP_COLOR_COUNT 64 |
146 | 119 |
147 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re
sult[], int count) { | 120 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { |
148 SkShader::Context* shaderContextA = fShaderContextA; | 121 SkShader* shaderA = fShaderA; |
149 SkShader::Context* shaderContextB = fShaderContextB; | 122 SkShader* shaderB = fShaderB; |
150 SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode
; | 123 SkXfermode* mode = fMode; |
151 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); | 124 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); |
152 | 125 |
153 SkPMColor tmp[TMP_COLOR_COUNT]; | 126 SkPMColor tmp[TMP_COLOR_COUNT]; |
154 | 127 |
155 if (NULL == mode) { // implied SRC_OVER | 128 if (NULL == mode) { // implied SRC_OVER |
156 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 | 129 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 |
157 // for these loops | 130 // for these loops |
158 do { | 131 do { |
159 int n = count; | 132 int n = count; |
160 if (n > TMP_COLOR_COUNT) { | 133 if (n > TMP_COLOR_COUNT) { |
161 n = TMP_COLOR_COUNT; | 134 n = TMP_COLOR_COUNT; |
162 } | 135 } |
163 | 136 |
164 shaderContextA->shadeSpan(x, y, result, n); | 137 shaderA->shadeSpan(x, y, result, n); |
165 shaderContextB->shadeSpan(x, y, tmp, n); | 138 shaderB->shadeSpan(x, y, tmp, n); |
166 | 139 |
167 if (256 == scale) { | 140 if (256 == scale) { |
168 for (int i = 0; i < n; i++) { | 141 for (int i = 0; i < n; i++) { |
169 result[i] = SkPMSrcOver(tmp[i], result[i]); | 142 result[i] = SkPMSrcOver(tmp[i], result[i]); |
170 } | 143 } |
171 } else { | 144 } else { |
172 for (int i = 0; i < n; i++) { | 145 for (int i = 0; i < n; i++) { |
173 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), | 146 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), |
174 scale); | 147 scale); |
175 } | 148 } |
176 } | 149 } |
177 | 150 |
178 result += n; | 151 result += n; |
179 x += n; | 152 x += n; |
180 count -= n; | 153 count -= n; |
181 } while (count > 0); | 154 } while (count > 0); |
182 } else { // use mode for the composition | 155 } else { // use mode for the composition |
183 do { | 156 do { |
184 int n = count; | 157 int n = count; |
185 if (n > TMP_COLOR_COUNT) { | 158 if (n > TMP_COLOR_COUNT) { |
186 n = TMP_COLOR_COUNT; | 159 n = TMP_COLOR_COUNT; |
187 } | 160 } |
188 | 161 |
189 shaderContextA->shadeSpan(x, y, result, n); | 162 shaderA->shadeSpan(x, y, result, n); |
190 shaderContextB->shadeSpan(x, y, tmp, n); | 163 shaderB->shadeSpan(x, y, tmp, n); |
191 mode->xfer32(result, tmp, n, NULL); | 164 mode->xfer32(result, tmp, n, NULL); |
192 | 165 |
193 if (256 == scale) { | 166 if (256 == scale) { |
194 for (int i = 0; i < n; i++) { | 167 for (int i = 0; i < n; i++) { |
195 result[i] = SkAlphaMulQ(result[i], scale); | 168 result[i] = SkAlphaMulQ(result[i], scale); |
196 } | 169 } |
197 } | 170 } |
198 | 171 |
199 result += n; | 172 result += n; |
200 x += n; | 173 x += n; |
(...skipping 11 matching lines...) Expand all Loading... |
212 str->append(" ShaderB: "); | 185 str->append(" ShaderB: "); |
213 fShaderB->toString(str); | 186 fShaderB->toString(str); |
214 str->append(" Xfermode: "); | 187 str->append(" Xfermode: "); |
215 fMode->toString(str); | 188 fMode->toString(str); |
216 | 189 |
217 this->INHERITED::toString(str); | 190 this->INHERITED::toString(str); |
218 | 191 |
219 str->append(")"); | 192 str->append(")"); |
220 } | 193 } |
221 #endif | 194 #endif |
OLD | NEW |