blob: 8e6112ae7d988add767dd95298a1fe80d05572d3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +00008#include "SkBitmapProcShader.h"
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +00009#include "SkEmptyShader.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +000010#include "SkReadBuffer.h"
11#include "SkMallocPixelRef.h"
12#include "SkPaint.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000013#include "SkPicture.h"
14#include "SkPictureShader.h"
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +000015#include "SkScalar.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkShader.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000017#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +000019SkShader::SkShader(const SkMatrix* localMatrix) {
20 if (localMatrix) {
21 fLocalMatrix = *localMatrix;
22 } else {
23 fLocalMatrix.reset();
24 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000025}
26
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000027SkShader::SkShader(SkReadBuffer& buffer)
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000028 : INHERITED(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 if (buffer.readBool()) {
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000030 buffer.readMatrix(&fLocalMatrix);
31 } else {
32 fLocalMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000033 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000034}
35
36SkShader::~SkShader() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037}
38
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000039void SkShader::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 this->INHERITED::flatten(buffer);
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000041 bool hasLocalM = this->hasLocalMatrix();
42 buffer.writeBool(hasLocalM);
43 if (hasLocalM) {
44 buffer.writeMatrix(fLocalMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 }
46}
47
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000048bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const {
49 const SkMatrix* m = rec.fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 SkMatrix total;
51
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000052 if (this->hasLocalMatrix()) {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000053 total.setConcat(*m, this->getLocalMatrix());
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 m = &total;
55 }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000056 return m->invert(totalInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +000057}
58
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000059SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const {
60 if (!this->computeTotalInverse(rec, NULL)) {
61 return NULL;
62 }
63 return this->onCreateContext(rec, storage);
reed@google.coma641f3f2012-12-13 22:16:30 +000064}
65
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000066SkShader::Context* SkShader::onCreateContext(const ContextRec&, void*) const {
commit-bot@chromium.orgf3e50592014-04-30 23:29:02 +000067 return NULL;
68}
69
70size_t SkShader::contextSize() const {
71 return 0;
72}
73
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +000074SkShader::Context::Context(const SkShader& shader, const ContextRec& rec)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000075 : fShader(shader)
76{
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000077 // Because the context parameters must be valid at this point, we know that the matrix is
78 // invertible.
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000079 SkAssertResult(fShader.computeTotalInverse(rec, &fTotalInverse));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000080 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
81
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +000082 fPaintAlpha = rec.fPaint->getAlpha();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000083}
84
85SkShader::Context::~Context() {}
86
87SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) {
reed@google.com3bafe742012-10-12 18:56:18 +000088 return NULL;
89}
90
reed@android.com8a1c16f2008-12-17 15:59:43 +000091#include "SkColorPriv.h"
92
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000093void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 SkASSERT(span16);
95 SkASSERT(count > 0);
96 SkASSERT(this->canCallShadeSpan16());
97
98 // basically, if we get here, the subclass screwed up
tomhudson@google.com0c00f212011-12-28 14:59:50 +000099 SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100}
101
102#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
reed@google.com7c2f27d2011-03-07 19:29:00 +0000103#define kTempColorCount (kTempColorQuadCount << 2)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104
105#ifdef SK_CPU_BENDIAN
106 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3))
107#else
108 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
109#endif
110
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000111void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 SkASSERT(count > 0);
113
114 SkPMColor colors[kTempColorCount];
115
116 while ((count -= kTempColorCount) >= 0) {
117 this->shadeSpan(x, y, colors, kTempColorCount);
118 x += kTempColorCount;
119
120 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
121 int quads = kTempColorQuadCount;
122 do {
123 U8CPU a0 = srcA[0];
124 U8CPU a1 = srcA[4];
125 U8CPU a2 = srcA[8];
126 U8CPU a3 = srcA[12];
127 srcA += 4*4;
128 *alpha++ = SkToU8(a0);
129 *alpha++ = SkToU8(a1);
130 *alpha++ = SkToU8(a2);
131 *alpha++ = SkToU8(a3);
132 } while (--quads != 0);
133 }
134 SkASSERT(count < 0);
135 SkASSERT(count + kTempColorCount >= 0);
136 if (count += kTempColorCount) {
137 this->shadeSpan(x, y, colors, count);
138
139 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
140 do {
141 *alpha++ = *srcA;
142 srcA += 4;
143 } while (--count != 0);
144 }
145#if 0
146 do {
147 int n = count;
148 if (n > kTempColorCount)
149 n = kTempColorCount;
150 SkASSERT(n > 0);
151
152 this->shadeSpan(x, y, colors, n);
153 x += n;
154 count -= n;
155
156 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
157 do {
158 *alpha++ = *srcA;
159 srcA += 4;
160 } while (--n != 0);
161 } while (count > 0);
162#endif
163}
164
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000165SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 MatrixClass mc = kLinear_MatrixClass;
167
tomhudson@google.com8d430182011-06-06 19:11:19 +0000168 if (mat.hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 if (mat.fixedStepInX(0, NULL, NULL)) {
170 mc = kFixedStepInX_MatrixClass;
171 } else {
172 mc = kPerspective_MatrixClass;
173 }
174 }
175 return mc;
176}
177
178//////////////////////////////////////////////////////////////////////////////
179
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000180SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const {
reed@android.comf2b98d62010-12-20 18:26:13 +0000181 return kNone_BitmapType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182}
183
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000184SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
185 return kNone_GradientType;
186}
187
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000188GrEffectRef* SkShader::asNewEffect(GrContext*, const SkPaint&) const {
humper@google.coma3bdc1a2013-01-14 21:01:28 +0000189 return NULL;
rileya@google.com03c1c352012-07-20 20:02:43 +0000190}
191
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000192SkShader* SkShader::CreateEmptyShader() {
193 return SkNEW(SkEmptyShader);
194}
195
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000196SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
197 const SkMatrix* localMatrix) {
198 return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199}
200
commit-bot@chromium.org5aacfe92014-05-02 21:23:52 +0000201SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy,
202 const SkMatrix* localMatrix) {
203 return SkPictureShader::Create(src, tmx, tmy, localMatrix);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000204}
205
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000206#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000207void SkShader::toString(SkString* str) const {
208 if (this->hasLocalMatrix()) {
209 str->append(" ");
210 this->getLocalMatrix().toString(str);
211 }
212}
213#endif
214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215//////////////////////////////////////////////////////////////////////////////
216
217#include "SkColorShader.h"
218#include "SkUtils.h"
219
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000220SkColorShader::SkColorShader(SkColor c)
commit-bot@chromium.org76a3b2a2014-04-24 16:54:46 +0000221 : fColor(c) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000222}
223
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000224bool SkColorShader::isOpaque() const {
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000225 return SkColorGetA(fColor) == 255;
226}
227
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000228SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) {
commit-bot@chromium.org76a3b2a2014-04-24 16:54:46 +0000229 // V25_COMPATIBILITY_CODE We had a boolean to make the color shader inherit the paint's
230 // color. We don't support that any more.
231 if (b.pictureVersion() < 26 && 0 != b.pictureVersion()) {
232 if (b.readBool()) {
233 SkDEBUGFAIL("We shouldn't have pictures that recorded the inherited case.");
234 fColor = SK_ColorWHITE;
235 return;
236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000238 fColor = b.readColor();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239}
240
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000241void SkColorShader::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 this->INHERITED::flatten(buffer);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000243 buffer.writeColor(fColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244}
245
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000246uint32_t SkColorShader::ColorShaderContext::getFlags() const {
reed@google.com59ccef62011-12-07 14:59:50 +0000247 return fFlags;
248}
249
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000250uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 return SkGetPackedA32(fPMColor);
252}
253
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000254SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const {
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000255 return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, rec));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000256}
257
258SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000259 const ContextRec& rec)
260 : INHERITED(shader, rec)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000261{
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000262 SkColor color = shader.fColor;
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000263 unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000265 unsigned r = SkColorGetR(color);
266 unsigned g = SkColorGetG(color);
267 unsigned b = SkColorGetB(color);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
269 // we want this before we apply any alpha
270 fColor16 = SkPack888ToRGB16(r, g, b);
271
272 if (a != 255) {
reed@android.com8f073382010-03-11 21:56:16 +0000273 r = SkMulDiv255Round(r, a);
274 g = SkMulDiv255Round(g, a);
275 b = SkMulDiv255Round(b, a);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 }
277 fPMColor = SkPackARGB32(a, r, g, b);
278
reed@android.com8f073382010-03-11 21:56:16 +0000279 fFlags = kConstInY32_Flag;
reed@android.com5b815352010-03-11 22:20:43 +0000280 if (255 == a) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000281 fFlags |= kOpaqueAlpha_Flag;
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000282 if (rec.fPaint->isDither() == false) {
reed@android.com5b815352010-03-11 22:20:43 +0000283 fFlags |= kHasSpan16_Flag;
284 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286}
287
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000288void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 sk_memset32(span, fPMColor, count);
290}
291
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000292void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 sk_memset16(span, fColor16, count);
294}
295
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000296void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 memset(alpha, SkGetPackedA32(fPMColor), count);
298}
299
reed@android.comf2b98d62010-12-20 18:26:13 +0000300// if we had a asAColor method, that would be more efficient...
301SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
rileya@google.com91f319c2012-07-25 17:18:31 +0000302 TileMode modes[]) const {
reed@google.com2be9e8b2011-07-06 21:18:09 +0000303 return kNone_BitmapType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000304}
305
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000306SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
307 if (info) {
308 if (info->fColors && info->fColorCount >= 1) {
309 info->fColors[0] = fColor;
310 }
311 info->fColorCount = 1;
312 info->fTileMode = SkShader::kRepeat_TileMode;
313 }
314 return kColor_GradientType;
315}
reed@google.com37a20122011-07-05 18:54:12 +0000316
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000317#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000318void SkColorShader::toString(SkString* str) const {
319 str->append("SkColorShader: (");
320
commit-bot@chromium.org76a3b2a2014-04-24 16:54:46 +0000321 str->append("Color: ");
322 str->appendHex(fColor);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000323
324 this->INHERITED::toString(str);
325
326 str->append(")");
327}
328#endif
329
reed@google.com37a20122011-07-05 18:54:12 +0000330///////////////////////////////////////////////////////////////////////////////
331
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000332#ifndef SK_IGNORE_TO_STRING
reed@google.com37a20122011-07-05 18:54:12 +0000333#include "SkEmptyShader.h"
334
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000335void SkEmptyShader::toString(SkString* str) const {
336 str->append("SkEmptyShader: (");
337
338 this->INHERITED::toString(str);
339
340 str->append(")");
341}
342#endif