blob: 2b20e3d31f04f533d0ed1955328d7b117ea7c375 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +000010#include "SkScalar.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkShader.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkPaint.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000014#include "SkMallocPixelRef.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000016SK_DEFINE_INST_COUNT(SkShader)
17
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000018SkShader::SkShader() {
19 fLocalMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 SkDEBUGCODE(fInSession = false;)
21}
22
23SkShader::SkShader(SkFlattenableReadBuffer& buffer)
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000024 : INHERITED(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 if (buffer.readBool()) {
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000026 buffer.readMatrix(&fLocalMatrix);
27 } else {
28 fLocalMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 }
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000030
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 SkDEBUGCODE(fInSession = false;)
32}
33
34SkShader::~SkShader() {
35 SkASSERT(!fInSession);
reed@android.com8a1c16f2008-12-17 15:59:43 +000036}
37
38void SkShader::beginSession() {
39 SkASSERT(!fInSession);
40 SkDEBUGCODE(fInSession = true;)
41}
42
43void SkShader::endSession() {
44 SkASSERT(fInSession);
45 SkDEBUGCODE(fInSession = false;)
46}
47
djsollen@google.com54924242012-03-29 15:18:04 +000048void SkShader::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 this->INHERITED::flatten(buffer);
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000050 bool hasLocalM = this->hasLocalMatrix();
51 buffer.writeBool(hasLocalM);
52 if (hasLocalM) {
53 buffer.writeMatrix(fLocalMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 }
55}
56
57bool SkShader::setContext(const SkBitmap& device,
58 const SkPaint& paint,
59 const SkMatrix& matrix) {
60 const SkMatrix* m = &matrix;
61 SkMatrix total;
62
63 fDeviceConfig = SkToU8(device.getConfig());
64 fPaintAlpha = paint.getAlpha();
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000065 if (this->hasLocalMatrix()) {
66 total.setConcat(matrix, this->getLocalMatrix());
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 m = &total;
68 }
69 if (m->invert(&fTotalInverse)) {
70 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
71 return true;
72 }
73 return false;
74}
75
reed@google.com3bafe742012-10-12 18:56:18 +000076SkShader::ShadeProc SkShader::asAShadeProc(void** ctx) {
77 return NULL;
78}
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080#include "SkColorPriv.h"
81
82void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
83 SkASSERT(span16);
84 SkASSERT(count > 0);
85 SkASSERT(this->canCallShadeSpan16());
86
87 // basically, if we get here, the subclass screwed up
tomhudson@google.com0c00f212011-12-28 14:59:50 +000088 SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000089}
90
91#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
reed@google.com7c2f27d2011-03-07 19:29:00 +000092#define kTempColorCount (kTempColorQuadCount << 2)
reed@android.com8a1c16f2008-12-17 15:59:43 +000093
94#ifdef SK_CPU_BENDIAN
95 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3))
96#else
97 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
98#endif
99
100void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
101 SkASSERT(count > 0);
102
103 SkPMColor colors[kTempColorCount];
104
105 while ((count -= kTempColorCount) >= 0) {
106 this->shadeSpan(x, y, colors, kTempColorCount);
107 x += kTempColorCount;
108
109 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
110 int quads = kTempColorQuadCount;
111 do {
112 U8CPU a0 = srcA[0];
113 U8CPU a1 = srcA[4];
114 U8CPU a2 = srcA[8];
115 U8CPU a3 = srcA[12];
116 srcA += 4*4;
117 *alpha++ = SkToU8(a0);
118 *alpha++ = SkToU8(a1);
119 *alpha++ = SkToU8(a2);
120 *alpha++ = SkToU8(a3);
121 } while (--quads != 0);
122 }
123 SkASSERT(count < 0);
124 SkASSERT(count + kTempColorCount >= 0);
125 if (count += kTempColorCount) {
126 this->shadeSpan(x, y, colors, count);
127
128 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
129 do {
130 *alpha++ = *srcA;
131 srcA += 4;
132 } while (--count != 0);
133 }
134#if 0
135 do {
136 int n = count;
137 if (n > kTempColorCount)
138 n = kTempColorCount;
139 SkASSERT(n > 0);
140
141 this->shadeSpan(x, y, colors, n);
142 x += n;
143 count -= n;
144
145 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
146 do {
147 *alpha++ = *srcA;
148 srcA += 4;
149 } while (--n != 0);
150 } while (count > 0);
151#endif
152}
153
154SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
155 MatrixClass mc = kLinear_MatrixClass;
156
tomhudson@google.com8d430182011-06-06 19:11:19 +0000157 if (mat.hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 if (mat.fixedStepInX(0, NULL, NULL)) {
159 mc = kFixedStepInX_MatrixClass;
160 } else {
161 mc = kPerspective_MatrixClass;
162 }
163 }
164 return mc;
165}
166
167//////////////////////////////////////////////////////////////////////////////
168
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000169SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
rileya@google.com91f319c2012-07-25 17:18:31 +0000170 TileMode*) const {
reed@android.comf2b98d62010-12-20 18:26:13 +0000171 return kNone_BitmapType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172}
173
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000174SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
175 return kNone_GradientType;
176}
177
bsalomon@google.com08283af2012-10-26 13:01:20 +0000178bool SkShader::asNewEffect(GrContext*, GrEffectStage*) const {
bsalomon@google.comdfdb7e52012-10-16 15:19:45 +0000179 return false;
rileya@google.com03c1c352012-07-20 20:02:43 +0000180}
181
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
183 TileMode tmx, TileMode tmy) {
184 return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
185}
186
187//////////////////////////////////////////////////////////////////////////////
188
189#include "SkColorShader.h"
190#include "SkUtils.h"
191
reed@android.comf2b98d62010-12-20 18:26:13 +0000192SkColorShader::SkColorShader() {
193 fFlags = 0;
194 fInheritColor = true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000195}
196
197SkColorShader::SkColorShader(SkColor c) {
198 fFlags = 0;
199 fColor = c;
200 fInheritColor = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000201}
202
reed@google.com2be9e8b2011-07-06 21:18:09 +0000203SkColorShader::~SkColorShader() {}
reed@android.comf2b98d62010-12-20 18:26:13 +0000204
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000205bool SkColorShader::isOpaque() const {
206 if (fInheritColor) {
207 return true; // using paint's alpha
208 }
209 return SkColorGetA(fColor) == 255;
210}
211
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000213 fFlags = 0; // computed in setContext
reed@android.comf2b98d62010-12-20 18:26:13 +0000214
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000215 fInheritColor = b.readBool();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 if (fInheritColor) {
217 return;
218 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000219 fColor = b.readColor();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220}
221
djsollen@google.com54924242012-03-29 15:18:04 +0000222void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 this->INHERITED::flatten(buffer);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000224 buffer.writeBool(fInheritColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if (fInheritColor) {
226 return;
227 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000228 buffer.writeColor(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229}
230
reed@google.com59ccef62011-12-07 14:59:50 +0000231uint32_t SkColorShader::getFlags() {
232 return fFlags;
233}
234
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235uint8_t SkColorShader::getSpan16Alpha() const {
236 return SkGetPackedA32(fPMColor);
237}
238
239bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
240 const SkMatrix& matrix) {
241 if (!this->INHERITED::setContext(device, paint, matrix)) {
242 return false;
243 }
244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 unsigned a;
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 if (fInheritColor) {
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000248 fColor = paint.getColor();
249 a = SkColorGetA(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 } else {
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000251 a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 }
253
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000254 unsigned r = SkColorGetR(fColor);
255 unsigned g = SkColorGetG(fColor);
256 unsigned b = SkColorGetB(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
258 // we want this before we apply any alpha
259 fColor16 = SkPack888ToRGB16(r, g, b);
260
261 if (a != 255) {
reed@android.com8f073382010-03-11 21:56:16 +0000262 r = SkMulDiv255Round(r, a);
263 g = SkMulDiv255Round(g, a);
264 b = SkMulDiv255Round(b, a);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 }
266 fPMColor = SkPackARGB32(a, r, g, b);
267
reed@android.com8f073382010-03-11 21:56:16 +0000268 fFlags = kConstInY32_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000269 if (255 == a) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000270 fFlags |= kOpaqueAlpha_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000271 if (paint.isDither() == false) {
272 fFlags |= kHasSpan16_Flag;
273 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000274 }
275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 return true;
277}
278
279void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
280 sk_memset32(span, fPMColor, count);
281}
282
283void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
284 sk_memset16(span, fColor16, count);
285}
286
287void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
288 memset(alpha, SkGetPackedA32(fPMColor), count);
289}
290
reed@android.comf2b98d62010-12-20 18:26:13 +0000291// if we had a asAColor method, that would be more efficient...
292SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
rileya@google.com91f319c2012-07-25 17:18:31 +0000293 TileMode modes[]) const {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000294 return kNone_BitmapType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000295}
296
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000297SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
298 if (info) {
299 if (info->fColors && info->fColorCount >= 1) {
300 info->fColors[0] = fColor;
301 }
302 info->fColorCount = 1;
303 info->fTileMode = SkShader::kRepeat_TileMode;
304 }
305 return kColor_GradientType;
306}
reed@google.com37a20122011-07-05 18:54:12 +0000307
308///////////////////////////////////////////////////////////////////////////////
309
310#include "SkEmptyShader.h"
311
reed@google.com37a20122011-07-05 18:54:12 +0000312uint32_t SkEmptyShader::getFlags() { return 0; }
313uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
reed@google.com59ccef62011-12-07 14:59:50 +0000314
315bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&,
316 const SkMatrix&) { return false; }
317
318void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000319 SkDEBUGFAIL("should never get called, since setContext() returned false");
reed@google.com37a20122011-07-05 18:54:12 +0000320}
reed@google.com59ccef62011-12-07 14:59:50 +0000321
322void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000323 SkDEBUGFAIL("should never get called, since setContext() returned false");
reed@google.com59ccef62011-12-07 14:59:50 +0000324}
325
326void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000327 SkDEBUGFAIL("should never get called, since setContext() returned false");
reed@google.com59ccef62011-12-07 14:59:50 +0000328}