SkShader.cpp revision 91f319c5dc4493384f0a52aaeef3dcc311ef6ed0
1
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
9
10#include "SkScalar.h"
11#include "SkShader.h"
12#include "SkPaint.h"
13#include "SkMallocPixelRef.h"
14
15SK_DEFINE_INST_COUNT(SkShader)
16
17SkShader::SkShader() : fLocalMatrix(NULL) {
18    SkDEBUGCODE(fInSession = false;)
19}
20
21SkShader::SkShader(SkFlattenableReadBuffer& buffer)
22        : INHERITED(buffer), fLocalMatrix(NULL) {
23    if (buffer.readBool()) {
24        SkMatrix matrix;
25        buffer.readMatrix(&matrix);
26        setLocalMatrix(matrix);
27    }
28    SkDEBUGCODE(fInSession = false;)
29}
30
31SkShader::~SkShader() {
32    SkASSERT(!fInSession);
33    sk_free(fLocalMatrix);
34}
35
36void SkShader::beginSession() {
37    SkASSERT(!fInSession);
38    SkDEBUGCODE(fInSession = true;)
39}
40
41void SkShader::endSession() {
42    SkASSERT(fInSession);
43    SkDEBUGCODE(fInSession = false;)
44}
45
46void SkShader::flatten(SkFlattenableWriteBuffer& buffer) const {
47    this->INHERITED::flatten(buffer);
48    buffer.writeBool(fLocalMatrix != NULL);
49    if (fLocalMatrix) {
50        buffer.writeMatrix(*fLocalMatrix);
51    }
52}
53
54bool SkShader::getLocalMatrix(SkMatrix* localM) const {
55    if (fLocalMatrix) {
56        if (localM) {
57            *localM = *fLocalMatrix;
58        }
59        return true;
60    } else {
61        if (localM) {
62            localM->reset();
63        }
64        return false;
65    }
66}
67
68void SkShader::setLocalMatrix(const SkMatrix& localM) {
69    if (localM.isIdentity()) {
70        this->resetLocalMatrix();
71    } else {
72        if (fLocalMatrix == NULL) {
73            fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
74        }
75        *fLocalMatrix = localM;
76    }
77}
78
79void SkShader::resetLocalMatrix() {
80    if (fLocalMatrix) {
81        sk_free(fLocalMatrix);
82        fLocalMatrix = NULL;
83    }
84}
85
86bool SkShader::setContext(const SkBitmap& device,
87                          const SkPaint& paint,
88                          const SkMatrix& matrix) {
89    const SkMatrix* m = &matrix;
90    SkMatrix        total;
91
92    fDeviceConfig = SkToU8(device.getConfig());
93    fPaintAlpha = paint.getAlpha();
94    if (fLocalMatrix) {
95        total.setConcat(matrix, *fLocalMatrix);
96        m = &total;
97    }
98    if (m->invert(&fTotalInverse)) {
99        fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
100        return true;
101    }
102    return false;
103}
104
105#include "SkColorPriv.h"
106
107void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
108    SkASSERT(span16);
109    SkASSERT(count > 0);
110    SkASSERT(this->canCallShadeSpan16());
111
112    // basically, if we get here, the subclass screwed up
113    SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented");
114}
115
116#define kTempColorQuadCount 6   // balance between speed (larger) and saving stack-space
117#define kTempColorCount     (kTempColorQuadCount << 2)
118
119#ifdef SK_CPU_BENDIAN
120    #define SkU32BitShiftToByteOffset(shift)    (3 - ((shift) >> 3))
121#else
122    #define SkU32BitShiftToByteOffset(shift)    ((shift) >> 3)
123#endif
124
125void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
126    SkASSERT(count > 0);
127
128    SkPMColor   colors[kTempColorCount];
129
130    while ((count -= kTempColorCount) >= 0) {
131        this->shadeSpan(x, y, colors, kTempColorCount);
132        x += kTempColorCount;
133
134        const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
135        int quads = kTempColorQuadCount;
136        do {
137            U8CPU a0 = srcA[0];
138            U8CPU a1 = srcA[4];
139            U8CPU a2 = srcA[8];
140            U8CPU a3 = srcA[12];
141            srcA += 4*4;
142            *alpha++ = SkToU8(a0);
143            *alpha++ = SkToU8(a1);
144            *alpha++ = SkToU8(a2);
145            *alpha++ = SkToU8(a3);
146        } while (--quads != 0);
147    }
148    SkASSERT(count < 0);
149    SkASSERT(count + kTempColorCount >= 0);
150    if (count += kTempColorCount) {
151        this->shadeSpan(x, y, colors, count);
152
153        const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
154        do {
155            *alpha++ = *srcA;
156            srcA += 4;
157        } while (--count != 0);
158    }
159#if 0
160    do {
161        int n = count;
162        if (n > kTempColorCount)
163            n = kTempColorCount;
164        SkASSERT(n > 0);
165
166        this->shadeSpan(x, y, colors, n);
167        x += n;
168        count -= n;
169
170        const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
171        do {
172            *alpha++ = *srcA;
173            srcA += 4;
174        } while (--n != 0);
175    } while (count > 0);
176#endif
177}
178
179SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
180    MatrixClass mc = kLinear_MatrixClass;
181
182    if (mat.hasPerspective()) {
183        if (mat.fixedStepInX(0, NULL, NULL)) {
184            mc = kFixedStepInX_MatrixClass;
185        } else {
186            mc = kPerspective_MatrixClass;
187        }
188    }
189    return mc;
190}
191
192//////////////////////////////////////////////////////////////////////////////
193
194SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
195                                         TileMode*) const {
196    return kNone_BitmapType;
197}
198
199SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
200    return kNone_GradientType;
201}
202
203GrCustomStage* SkShader::asNewCustomStage(GrContext* context,
204                                          GrSamplerState* sampler) const {
205    return NULL;
206}
207
208SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
209                                       TileMode tmx, TileMode tmy) {
210    return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
211}
212
213//////////////////////////////////////////////////////////////////////////////
214
215#include "SkColorShader.h"
216#include "SkUtils.h"
217
218SkColorShader::SkColorShader() {
219    fFlags = 0;
220    fInheritColor = true;
221}
222
223SkColorShader::SkColorShader(SkColor c) {
224    fFlags = 0;
225    fColor = c;
226    fInheritColor = false;
227}
228
229SkColorShader::~SkColorShader() {}
230
231bool SkColorShader::isOpaque() const {
232    if (fInheritColor) {
233        return true; // using paint's alpha
234    }
235    return SkColorGetA(fColor) == 255;
236}
237
238SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
239    fFlags = 0; // computed in setContext
240
241    fInheritColor = b.readU8();
242    if (fInheritColor) {
243        return;
244    }
245    fColor = b.readU32();
246}
247
248void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) const {
249    this->INHERITED::flatten(buffer);
250    buffer.write8(fInheritColor);
251    if (fInheritColor) {
252        return;
253    }
254    buffer.write32(fColor);
255}
256
257uint32_t SkColorShader::getFlags() {
258    return fFlags;
259}
260
261uint8_t SkColorShader::getSpan16Alpha() const {
262    return SkGetPackedA32(fPMColor);
263}
264
265bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
266                               const SkMatrix& matrix) {
267    if (!this->INHERITED::setContext(device, paint, matrix)) {
268        return false;
269    }
270
271    unsigned a;
272
273    if (fInheritColor) {
274        fColor = paint.getColor();
275        a = SkColorGetA(fColor);
276    } else {
277        a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
278    }
279
280    unsigned r = SkColorGetR(fColor);
281    unsigned g = SkColorGetG(fColor);
282    unsigned b = SkColorGetB(fColor);
283
284    // we want this before we apply any alpha
285    fColor16 = SkPack888ToRGB16(r, g, b);
286
287    if (a != 255) {
288        r = SkMulDiv255Round(r, a);
289        g = SkMulDiv255Round(g, a);
290        b = SkMulDiv255Round(b, a);
291    }
292    fPMColor = SkPackARGB32(a, r, g, b);
293
294    fFlags = kConstInY32_Flag;
295    if (255 == a) {
296        fFlags |= kOpaqueAlpha_Flag;
297        if (paint.isDither() == false) {
298            fFlags |= kHasSpan16_Flag;
299        }
300    }
301
302    return true;
303}
304
305void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
306    sk_memset32(span, fPMColor, count);
307}
308
309void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
310    sk_memset16(span, fColor16, count);
311}
312
313void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
314    memset(alpha, SkGetPackedA32(fPMColor), count);
315}
316
317// if we had a asAColor method, that would be more efficient...
318SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
319                                              TileMode modes[]) const {
320    return kNone_BitmapType;
321}
322
323SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
324    if (info) {
325        if (info->fColors && info->fColorCount >= 1) {
326            info->fColors[0] = fColor;
327        }
328        info->fColorCount = 1;
329        info->fTileMode = SkShader::kRepeat_TileMode;
330    }
331    return kColor_GradientType;
332}
333
334SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorShader)
335
336///////////////////////////////////////////////////////////////////////////////
337
338#include "SkEmptyShader.h"
339
340uint32_t SkEmptyShader::getFlags() { return 0; }
341uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
342
343bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&,
344                               const SkMatrix&) { return false; }
345
346void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
347    SkDEBUGFAIL("should never get called, since setContext() returned false");
348}
349
350void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
351    SkDEBUGFAIL("should never get called, since setContext() returned false");
352}
353
354void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
355    SkDEBUGFAIL("should never get called, since setContext() returned false");
356}
357
358SK_DEFINE_FLATTENABLE_REGISTRAR(SkEmptyShader)
359