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