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