blob: 6865fb7c193d5d091ffad3559e85c6f93c392724 [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**
reed@google.com7c2f27d2011-03-07 19:29:00 +00005** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008**
reed@google.com7c2f27d2011-03-07 19:29:00 +00009** http://www.apache.org/licenses/LICENSE-2.0
reed@android.com8a1c16f2008-12-17 15:59:43 +000010**
reed@google.com7c2f27d2011-03-07 19:29:00 +000011** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000015** limitations under the License.
16*/
17
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +000018#include "SkScalar.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019#include "SkShader.h"
20#include "SkPaint.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000021#include "SkMallocPixelRef.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
23SkShader::SkShader() : fLocalMatrix(NULL) {
24 SkDEBUGCODE(fInSession = false;)
25}
26
27SkShader::SkShader(SkFlattenableReadBuffer& buffer)
28 : INHERITED(buffer), fLocalMatrix(NULL) {
29 if (buffer.readBool()) {
30 SkMatrix matrix;
reed@google.comf2eb5ab2011-05-10 22:56:42 +000031 SkReadMatrix(&buffer, &matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 setLocalMatrix(matrix);
33 }
34 SkDEBUGCODE(fInSession = false;)
35}
36
37SkShader::~SkShader() {
38 SkASSERT(!fInSession);
39 sk_free(fLocalMatrix);
40}
41
42void SkShader::beginSession() {
43 SkASSERT(!fInSession);
44 SkDEBUGCODE(fInSession = true;)
45}
46
47void SkShader::endSession() {
48 SkASSERT(fInSession);
49 SkDEBUGCODE(fInSession = false;)
50}
51
52void SkShader::flatten(SkFlattenableWriteBuffer& buffer) {
53 this->INHERITED::flatten(buffer);
54 buffer.writeBool(fLocalMatrix != NULL);
55 if (fLocalMatrix) {
reed@google.comf2eb5ab2011-05-10 22:56:42 +000056 SkWriteMatrix(&buffer, *fLocalMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 }
58}
59
60bool SkShader::getLocalMatrix(SkMatrix* localM) const {
61 if (fLocalMatrix) {
62 if (localM) {
63 *localM = *fLocalMatrix;
64 }
65 return true;
66 } else {
67 if (localM) {
68 localM->reset();
69 }
70 return false;
71 }
72}
73
74void SkShader::setLocalMatrix(const SkMatrix& localM) {
75 if (localM.isIdentity()) {
76 this->resetLocalMatrix();
77 } else {
78 if (fLocalMatrix == NULL) {
79 fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
80 }
81 *fLocalMatrix = localM;
82 }
83}
84
85void SkShader::resetLocalMatrix() {
86 if (fLocalMatrix) {
87 sk_free(fLocalMatrix);
88 fLocalMatrix = NULL;
89 }
90}
91
92bool SkShader::setContext(const SkBitmap& device,
93 const SkPaint& paint,
94 const SkMatrix& matrix) {
95 const SkMatrix* m = &matrix;
96 SkMatrix total;
97
98 fDeviceConfig = SkToU8(device.getConfig());
99 fPaintAlpha = paint.getAlpha();
100 if (fLocalMatrix) {
101 total.setConcat(matrix, *fLocalMatrix);
102 m = &total;
103 }
104 if (m->invert(&fTotalInverse)) {
105 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
106 return true;
107 }
108 return false;
109}
110
111#include "SkColorPriv.h"
112
113void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
114 SkASSERT(span16);
115 SkASSERT(count > 0);
116 SkASSERT(this->canCallShadeSpan16());
117
118 // basically, if we get here, the subclass screwed up
119 SkASSERT(!"kHasSpan16 flag is set, but shadeSpan16() not implemented");
120}
121
122#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
reed@google.com7c2f27d2011-03-07 19:29:00 +0000123#define kTempColorCount (kTempColorQuadCount << 2)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124
125#ifdef SK_CPU_BENDIAN
126 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3))
127#else
128 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
129#endif
130
131void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
132 SkASSERT(count > 0);
133
134 SkPMColor colors[kTempColorCount];
135
136 while ((count -= kTempColorCount) >= 0) {
137 this->shadeSpan(x, y, colors, kTempColorCount);
138 x += kTempColorCount;
139
140 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
141 int quads = kTempColorQuadCount;
142 do {
143 U8CPU a0 = srcA[0];
144 U8CPU a1 = srcA[4];
145 U8CPU a2 = srcA[8];
146 U8CPU a3 = srcA[12];
147 srcA += 4*4;
148 *alpha++ = SkToU8(a0);
149 *alpha++ = SkToU8(a1);
150 *alpha++ = SkToU8(a2);
151 *alpha++ = SkToU8(a3);
152 } while (--quads != 0);
153 }
154 SkASSERT(count < 0);
155 SkASSERT(count + kTempColorCount >= 0);
156 if (count += kTempColorCount) {
157 this->shadeSpan(x, y, colors, count);
158
159 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
160 do {
161 *alpha++ = *srcA;
162 srcA += 4;
163 } while (--count != 0);
164 }
165#if 0
166 do {
167 int n = count;
168 if (n > kTempColorCount)
169 n = kTempColorCount;
170 SkASSERT(n > 0);
171
172 this->shadeSpan(x, y, colors, n);
173 x += n;
174 count -= n;
175
176 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
177 do {
178 *alpha++ = *srcA;
179 srcA += 4;
180 } while (--n != 0);
181 } while (count > 0);
182#endif
183}
184
185SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
186 MatrixClass mc = kLinear_MatrixClass;
187
tomhudson@google.com8d430182011-06-06 19:11:19 +0000188 if (mat.hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 if (mat.fixedStepInX(0, NULL, NULL)) {
190 mc = kFixedStepInX_MatrixClass;
191 } else {
192 mc = kPerspective_MatrixClass;
193 }
194 }
195 return mc;
196}
197
198//////////////////////////////////////////////////////////////////////////////
199
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000200SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
reed@google.com7c2f27d2011-03-07 19:29:00 +0000201 TileMode*, SkScalar*) const {
reed@android.comf2b98d62010-12-20 18:26:13 +0000202 return kNone_BitmapType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203}
204
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000205SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
206 return kNone_GradientType;
207}
208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
210 TileMode tmx, TileMode tmy) {
211 return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
212}
213
214//////////////////////////////////////////////////////////////////////////////
215
216#include "SkColorShader.h"
217#include "SkUtils.h"
218
reed@android.comf2b98d62010-12-20 18:26:13 +0000219SkColorShader::SkColorShader() {
220 fFlags = 0;
221 fInheritColor = true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000222}
223
224SkColorShader::SkColorShader(SkColor c) {
225 fFlags = 0;
226 fColor = c;
227 fInheritColor = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000228}
229
reed@google.com2be9e8b2011-07-06 21:18:09 +0000230SkColorShader::~SkColorShader() {}
reed@android.comf2b98d62010-12-20 18:26:13 +0000231
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000233 fFlags = 0; // computed in setContext
reed@android.comf2b98d62010-12-20 18:26:13 +0000234
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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 unsigned a;
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 if (fInheritColor) {
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000264 fColor = paint.getColor();
265 a = SkColorGetA(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 } else {
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000267 a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 }
269
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000270 unsigned r = SkColorGetR(fColor);
271 unsigned g = SkColorGetG(fColor);
272 unsigned b = SkColorGetB(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273
274 // we want this before we apply any alpha
275 fColor16 = SkPack888ToRGB16(r, g, b);
276
277 if (a != 255) {
reed@android.com8f073382010-03-11 21:56:16 +0000278 r = SkMulDiv255Round(r, a);
279 g = SkMulDiv255Round(g, a);
280 b = SkMulDiv255Round(b, a);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 }
282 fPMColor = SkPackARGB32(a, r, g, b);
283
reed@android.com8f073382010-03-11 21:56:16 +0000284 fFlags = kConstInY32_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000285 if (255 == a) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000286 fFlags |= kOpaqueAlpha_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000287 if (paint.isDither() == false) {
288 fFlags |= kHasSpan16_Flag;
289 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000290 }
291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 return true;
293}
294
295void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
296 sk_memset32(span, fPMColor, count);
297}
298
299void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
300 sk_memset16(span, fColor16, count);
301}
302
303void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
304 memset(alpha, SkGetPackedA32(fPMColor), count);
305}
306
reed@android.comf2b98d62010-12-20 18:26:13 +0000307// if we had a asAColor method, that would be more efficient...
308SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
reed@google.com7c2f27d2011-03-07 19:29:00 +0000309 TileMode modes[],
reed@google.com8cad5862011-03-08 14:51:44 +0000310 SkScalar* twoPointRadialParams) const {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000311 return kNone_BitmapType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000312}
313
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000314SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
315 if (info) {
316 if (info->fColors && info->fColorCount >= 1) {
317 info->fColors[0] = fColor;
318 }
319 info->fColorCount = 1;
320 info->fTileMode = SkShader::kRepeat_TileMode;
321 }
322 return kColor_GradientType;
323}
reed@google.com37a20122011-07-05 18:54:12 +0000324
325///////////////////////////////////////////////////////////////////////////////
326
327#include "SkEmptyShader.h"
328
329SkEmptyShader::SkEmptyShader() {}
330SkEmptyShader::SkEmptyShader(SkFlattenableReadBuffer& b) : INHERITED(b) {}
331
332uint32_t SkEmptyShader::getFlags() { return 0; }
333uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
334bool SkEmptyShader::setContext(const SkBitmap& device, const SkPaint& paint,
335 const SkMatrix& matrix) {
336 return false;
337}
338void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {}
339void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {}
340void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {}
341
342SkFlattenable::Factory SkEmptyShader::getFactory() { return NULL; }
343void SkEmptyShader::flatten(SkFlattenableWriteBuffer& buffer) {
344 this->INHERITED::flatten(buffer);
345}
346