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