blob: 7b3a024c4f0b92567c6af29d3398c0cb53fd9467 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/sgl/SkShader.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkShader.h"
19#include "SkPaint.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000020#include "SkMallocPixelRef.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
22SkShader::SkShader() : fLocalMatrix(NULL) {
23 SkDEBUGCODE(fInSession = false;)
24}
25
26SkShader::SkShader(SkFlattenableReadBuffer& buffer)
27 : INHERITED(buffer), fLocalMatrix(NULL) {
28 if (buffer.readBool()) {
29 SkMatrix matrix;
30 buffer.read(&matrix, sizeof(matrix));
31 setLocalMatrix(matrix);
32 }
33 SkDEBUGCODE(fInSession = false;)
34}
35
36SkShader::~SkShader() {
37 SkASSERT(!fInSession);
38 sk_free(fLocalMatrix);
39}
40
41void SkShader::beginSession() {
42 SkASSERT(!fInSession);
43 SkDEBUGCODE(fInSession = true;)
44}
45
46void SkShader::endSession() {
47 SkASSERT(fInSession);
48 SkDEBUGCODE(fInSession = false;)
49}
50
51void SkShader::flatten(SkFlattenableWriteBuffer& buffer) {
52 this->INHERITED::flatten(buffer);
53 buffer.writeBool(fLocalMatrix != NULL);
54 if (fLocalMatrix) {
55 buffer.writeMul4(fLocalMatrix, sizeof(SkMatrix));
56 }
57}
58
59bool SkShader::getLocalMatrix(SkMatrix* localM) const {
60 if (fLocalMatrix) {
61 if (localM) {
62 *localM = *fLocalMatrix;
63 }
64 return true;
65 } else {
66 if (localM) {
67 localM->reset();
68 }
69 return false;
70 }
71}
72
73void SkShader::setLocalMatrix(const SkMatrix& localM) {
74 if (localM.isIdentity()) {
75 this->resetLocalMatrix();
76 } else {
77 if (fLocalMatrix == NULL) {
78 fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
79 }
80 *fLocalMatrix = localM;
81 }
82}
83
84void SkShader::resetLocalMatrix() {
85 if (fLocalMatrix) {
86 sk_free(fLocalMatrix);
87 fLocalMatrix = NULL;
88 }
89}
90
91bool SkShader::setContext(const SkBitmap& device,
92 const SkPaint& paint,
93 const SkMatrix& matrix) {
94 const SkMatrix* m = &matrix;
95 SkMatrix total;
96
97 fDeviceConfig = SkToU8(device.getConfig());
98 fPaintAlpha = paint.getAlpha();
99 if (fLocalMatrix) {
100 total.setConcat(matrix, *fLocalMatrix);
101 m = &total;
102 }
103 if (m->invert(&fTotalInverse)) {
104 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
105 return true;
106 }
107 return false;
108}
109
110#include "SkColorPriv.h"
111
112void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
113 SkASSERT(span16);
114 SkASSERT(count > 0);
115 SkASSERT(this->canCallShadeSpan16());
116
117 // basically, if we get here, the subclass screwed up
118 SkASSERT(!"kHasSpan16 flag is set, but shadeSpan16() not implemented");
119}
120
121#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
122#define kTempColorCount (kTempColorQuadCount << 2)
123
124#ifdef SK_CPU_BENDIAN
125 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3))
126#else
127 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
128#endif
129
130void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
131 SkASSERT(count > 0);
132
133 SkPMColor colors[kTempColorCount];
134
135 while ((count -= kTempColorCount) >= 0) {
136 this->shadeSpan(x, y, colors, kTempColorCount);
137 x += kTempColorCount;
138
139 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
140 int quads = kTempColorQuadCount;
141 do {
142 U8CPU a0 = srcA[0];
143 U8CPU a1 = srcA[4];
144 U8CPU a2 = srcA[8];
145 U8CPU a3 = srcA[12];
146 srcA += 4*4;
147 *alpha++ = SkToU8(a0);
148 *alpha++ = SkToU8(a1);
149 *alpha++ = SkToU8(a2);
150 *alpha++ = SkToU8(a3);
151 } while (--quads != 0);
152 }
153 SkASSERT(count < 0);
154 SkASSERT(count + kTempColorCount >= 0);
155 if (count += kTempColorCount) {
156 this->shadeSpan(x, y, colors, count);
157
158 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
159 do {
160 *alpha++ = *srcA;
161 srcA += 4;
162 } while (--count != 0);
163 }
164#if 0
165 do {
166 int n = count;
167 if (n > kTempColorCount)
168 n = kTempColorCount;
169 SkASSERT(n > 0);
170
171 this->shadeSpan(x, y, colors, n);
172 x += n;
173 count -= n;
174
175 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
176 do {
177 *alpha++ = *srcA;
178 srcA += 4;
179 } while (--n != 0);
180 } while (count > 0);
181#endif
182}
183
184SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
185 MatrixClass mc = kLinear_MatrixClass;
186
187 if (mat.getType() & SkMatrix::kPerspective_Mask) {
188 if (mat.fixedStepInX(0, NULL, NULL)) {
189 mc = kFixedStepInX_MatrixClass;
190 } else {
191 mc = kPerspective_MatrixClass;
192 }
193 }
194 return mc;
195}
196
197//////////////////////////////////////////////////////////////////////////////
198
reed@android.comf2b98d62010-12-20 18:26:13 +0000199SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
200 TileMode*, SkScalar*) {
201 return kNone_BitmapType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202}
203
204SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
205 TileMode tmx, TileMode tmy) {
206 return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
207}
208
209//////////////////////////////////////////////////////////////////////////////
210
211#include "SkColorShader.h"
212#include "SkUtils.h"
213
reed@android.comf2b98d62010-12-20 18:26:13 +0000214SkColorShader::SkColorShader() {
215 fFlags = 0;
216 fInheritColor = true;
217 fAsABitmapPixelRef = NULL;
218}
219
220SkColorShader::SkColorShader(SkColor c) {
221 fFlags = 0;
222 fColor = c;
223 fInheritColor = false;
224 fAsABitmapPixelRef = NULL;
225}
226
227SkColorShader::~SkColorShader() {
228 SkSafeUnref(fAsABitmapPixelRef);
229}
230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000232 fFlags = 0; // computed in setContext
reed@android.comf2b98d62010-12-20 18:26:13 +0000233 fAsABitmapPixelRef = NULL;
234
235 fInheritColor = b.readU8();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 if (fInheritColor) {
237 return;
238 }
239 fColor = b.readU32();
240}
241
242void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) {
243 this->INHERITED::flatten(buffer);
244 buffer.write8(fInheritColor);
245 if (fInheritColor) {
246 return;
247 }
248 buffer.write32(fColor);
249}
250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251uint8_t SkColorShader::getSpan16Alpha() const {
252 return SkGetPackedA32(fPMColor);
253}
254
255bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
256 const SkMatrix& matrix) {
257 if (!this->INHERITED::setContext(device, paint, matrix)) {
258 return false;
259 }
260
261 SkColor c;
262 unsigned a;
263
264 if (fInheritColor) {
265 c = paint.getColor();
266 a = SkColorGetA(c);
267 } else {
268 c = fColor;
269 a = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
270 }
271
272 unsigned r = SkColorGetR(c);
273 unsigned g = SkColorGetG(c);
274 unsigned b = SkColorGetB(c);
275
276 // we want this before we apply any alpha
277 fColor16 = SkPack888ToRGB16(r, g, b);
278
279 if (a != 255) {
reed@android.com8f073382010-03-11 21:56:16 +0000280 r = SkMulDiv255Round(r, a);
281 g = SkMulDiv255Round(g, a);
282 b = SkMulDiv255Round(b, a);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 }
284 fPMColor = SkPackARGB32(a, r, g, b);
285
reed@android.com8f073382010-03-11 21:56:16 +0000286 fFlags = kConstInY32_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000287 if (255 == a) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000288 fFlags |= kOpaqueAlpha_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000289 if (paint.isDither() == false) {
290 fFlags |= kHasSpan16_Flag;
291 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000292 }
293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 return true;
295}
296
297void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
298 sk_memset32(span, fPMColor, count);
299}
300
301void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
302 sk_memset16(span, fColor16, count);
303}
304
305void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
306 memset(alpha, SkGetPackedA32(fPMColor), count);
307}
308
reed@android.comf2b98d62010-12-20 18:26:13 +0000309// if we had a asAColor method, that would be more efficient...
310SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
311 TileMode modes[],
312 SkScalar* twoPointRadialParams) {
313 // we cache the pixelref, since its generateID is used in the texture cache
314 if (NULL == fAsABitmapPixelRef) {
315 SkPMColor* storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor));
316 *storage = fPMColor;
317 fAsABitmapPixelRef = new SkMallocPixelRef(storage, sizeof(SkPMColor),
318 NULL);
319 }
320
321 if (bitmap) {
322 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
323 bitmap->setPixelRef(fAsABitmapPixelRef);
324 }
325 if (matrix) {
326 matrix->reset();
327 }
328 if (modes) {
329 modes[0] = modes[1] = SkShader::kRepeat_TileMode;
330 }
331 return kDefault_BitmapType;
332}
333