1
2/*
3 * Copyright 2011 Google Inc.
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#include "SkBitmapProcShader.h"
9#include "SkColorPriv.h"
10#include "SkPixelRef.h"
11
12bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
13    switch (bm.config()) {
14        case SkBitmap::kA8_Config:
15        case SkBitmap::kRGB_565_Config:
16        case SkBitmap::kIndex8_Config:
17        case SkBitmap::kARGB_8888_Config:
18    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
19                return true;
20        default:
21            break;
22    }
23    return false;
24}
25
26SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
27                                       TileMode tmx, TileMode tmy) {
28    fRawBitmap = src;
29    fState.fTileModeX = (uint8_t)tmx;
30    fState.fTileModeY = (uint8_t)tmy;
31    fFlags = 0; // computed in setContext
32}
33
34SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
35        : INHERITED(buffer) {
36    fRawBitmap.unflatten(buffer);
37    fState.fTileModeX = buffer.readU8();
38    fState.fTileModeY = buffer.readU8();
39    fFlags = 0; // computed in setContext
40}
41
42void SkBitmapProcShader::beginSession() {
43    this->INHERITED::beginSession();
44
45    fRawBitmap.lockPixels();
46}
47
48void SkBitmapProcShader::endSession() {
49    fRawBitmap.unlockPixels();
50
51    this->INHERITED::endSession();
52}
53
54SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
55                                                   SkMatrix* texM,
56                                                   TileMode xy[],
57                                       SkScalar* twoPointRadialParams) const {
58    if (texture) {
59        *texture = fRawBitmap;
60    }
61    if (texM) {
62        texM->reset();
63    }
64    if (xy) {
65        xy[0] = (TileMode)fState.fTileModeX;
66        xy[1] = (TileMode)fState.fTileModeY;
67    }
68    return kDefault_BitmapType;
69}
70
71void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) {
72    this->INHERITED::flatten(buffer);
73
74    fRawBitmap.flatten(buffer);
75    buffer.write8(fState.fTileModeX);
76    buffer.write8(fState.fTileModeY);
77}
78
79static bool only_scale_and_translate(const SkMatrix& matrix) {
80    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
81    return (matrix.getType() & ~mask) == 0;
82}
83
84bool SkBitmapProcShader::isOpaque() const {
85    return fRawBitmap.isOpaque();
86}
87
88bool SkBitmapProcShader::setContext(const SkBitmap& device,
89                                    const SkPaint& paint,
90                                    const SkMatrix& matrix) {
91    // do this first, so we have a correct inverse matrix
92    if (!this->INHERITED::setContext(device, paint, matrix)) {
93        return false;
94    }
95
96    fState.fOrigBitmap = fRawBitmap;
97    fState.fOrigBitmap.lockPixels();
98    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
99        fState.fOrigBitmap.unlockPixels();
100        return false;
101    }
102
103    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
104        return false;
105    }
106
107    const SkBitmap& bitmap = *fState.fBitmap;
108    bool bitmapIsOpaque = bitmap.isOpaque();
109
110    // update fFlags
111    uint32_t flags = 0;
112    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
113        flags |= kOpaqueAlpha_Flag;
114    }
115
116    switch (bitmap.config()) {
117        case SkBitmap::kRGB_565_Config:
118            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
119            break;
120        case SkBitmap::kIndex8_Config:
121        case SkBitmap::kARGB_8888_Config:
122            if (bitmapIsOpaque) {
123                flags |= kHasSpan16_Flag;
124            }
125            break;
126        case SkBitmap::kA8_Config:
127            break;  // never set kHasSpan16_Flag
128        default:
129            break;
130    }
131
132    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
133        // gradients can auto-dither in their 16bit sampler, but we don't so
134        // we clear the flag here.
135        flags &= ~kHasSpan16_Flag;
136    }
137
138    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
139    if (1 == bitmap.height() &&
140            only_scale_and_translate(this->getTotalInverse())) {
141        flags |= kConstInY32_Flag;
142        if (flags & kHasSpan16_Flag) {
143            flags |= kConstInY16_Flag;
144        }
145    }
146
147    fFlags = flags;
148    return true;
149}
150
151#define BUF_MAX     128
152
153#define TEST_BUFFER_OVERRITEx
154
155#ifdef TEST_BUFFER_OVERRITE
156    #define TEST_BUFFER_EXTRA   32
157    #define TEST_PATTERN    0x88888888
158#else
159    #define TEST_BUFFER_EXTRA   0
160#endif
161
162void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
163    const SkBitmapProcState& state = fState;
164    if (state.fShaderProc32) {
165        state.fShaderProc32(state, x, y, dstC, count);
166        return;
167    }
168
169    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
170    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
171    SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
172    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
173
174    SkASSERT(state.fBitmap->getPixels());
175    SkASSERT(state.fBitmap->pixelRef() == NULL ||
176             state.fBitmap->pixelRef()->isLocked());
177
178    for (;;) {
179        int n = count;
180        if (n > max) {
181            n = max;
182        }
183        SkASSERT(n > 0 && n < BUF_MAX*2);
184#ifdef TEST_BUFFER_OVERRITE
185        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
186            buffer[BUF_MAX + i] = TEST_PATTERN;
187        }
188#endif
189        mproc(state, buffer, n, x, y);
190#ifdef TEST_BUFFER_OVERRITE
191        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
192            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
193        }
194#endif
195        sproc(state, buffer, n, dstC);
196
197        if ((count -= n) == 0) {
198            break;
199        }
200        SkASSERT(count > 0);
201        x += n;
202        dstC += n;
203    }
204}
205
206void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
207    const SkBitmapProcState& state = fState;
208    if (state.fShaderProc16) {
209        state.fShaderProc16(state, x, y, dstC, count);
210        return;
211    }
212
213    uint32_t buffer[BUF_MAX];
214    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
215    SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
216    int max = fState.maxCountForBufferSize(sizeof(buffer));
217
218    SkASSERT(state.fBitmap->getPixels());
219    SkASSERT(state.fBitmap->pixelRef() == NULL ||
220             state.fBitmap->pixelRef()->isLocked());
221
222    for (;;) {
223        int n = count;
224        if (n > max) {
225            n = max;
226        }
227        mproc(state, buffer, n, x, y);
228        sproc(state, buffer, n, dstC);
229
230        if ((count -= n) == 0) {
231            break;
232        }
233        x += n;
234        dstC += n;
235    }
236}
237
238///////////////////////////////////////////////////////////////////////////////
239
240#include "SkUnPreMultiply.h"
241#include "SkColorShader.h"
242#include "SkEmptyShader.h"
243
244// returns true and set color if the bitmap can be drawn as a single color
245// (for efficiency)
246static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
247    if (1 != bm.width() || 1 != bm.height()) {
248        return false;
249    }
250
251    SkAutoLockPixels alp(bm);
252    if (!bm.readyToDraw()) {
253        return false;
254    }
255
256    switch (bm.config()) {
257        case SkBitmap::kARGB_8888_Config:
258            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
259            return true;
260        case SkBitmap::kRGB_565_Config:
261            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
262            return true;
263        case SkBitmap::kIndex8_Config:
264            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
265            return true;
266        default: // just skip the other configs for now
267            break;
268    }
269    return false;
270}
271
272#include "SkTemplatesPriv.h"
273
274SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
275                                       TileMode tmx, TileMode tmy,
276                                       void* storage, size_t storageSize) {
277    SkShader* shader;
278    SkColor color;
279    if (src.isNull()) {
280        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
281    }
282    else if (canUseColorShader(src, &color)) {
283        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
284                              (color));
285    } else {
286        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
287                              storageSize, (src, tmx, tmy));
288    }
289    return shader;
290}
291
292SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapProcShader)
293
294///////////////////////////////////////////////////////////////////////////////
295
296static const char* gTileModeName[] = {
297    "clamp", "repeat", "mirror"
298};
299
300bool SkBitmapProcShader::toDumpString(SkString* str) const {
301    str->printf("BitmapShader: [%d %d %d",
302                fRawBitmap.width(), fRawBitmap.height(),
303                fRawBitmap.bytesPerPixel());
304
305    // add the pixelref
306    SkPixelRef* pr = fRawBitmap.pixelRef();
307    if (pr) {
308        const char* uri = pr->getURI();
309        if (uri) {
310            str->appendf(" \"%s\"", uri);
311        }
312    }
313
314    // add the (optional) matrix
315    {
316        SkMatrix m;
317        if (this->getLocalMatrix(&m)) {
318            SkString info;
319            m.toDumpString(&info);
320            str->appendf(" %s", info.c_str());
321        }
322    }
323
324    str->appendf(" [%s %s]]",
325                 gTileModeName[fState.fTileModeX],
326                 gTileModeName[fState.fTileModeY]);
327    return true;
328}
329
330