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