SkBitmapProcShader.cpp revision 3bafe74a29c37761082980ed4ee9b831256bd27e
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 "SkFlattenableBuffers.h"
11#include "SkPixelRef.h"
12
13bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
14    switch (bm.config()) {
15        case SkBitmap::kA8_Config:
16        case SkBitmap::kRGB_565_Config:
17        case SkBitmap::kIndex8_Config:
18        case SkBitmap::kARGB_8888_Config:
19    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
20                return true;
21        default:
22            break;
23    }
24    return false;
25}
26
27SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
28                                       TileMode tmx, TileMode tmy) {
29    fRawBitmap = src;
30    fState.fTileModeX = (uint8_t)tmx;
31    fState.fTileModeY = (uint8_t)tmy;
32    fFlags = 0; // computed in setContext
33}
34
35SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
36        : INHERITED(buffer) {
37    buffer.readBitmap(&fRawBitmap);
38    fState.fTileModeX = buffer.readUInt();
39    fState.fTileModeY = buffer.readUInt();
40    fFlags = 0; // computed in setContext
41}
42
43void SkBitmapProcShader::beginSession() {
44    this->INHERITED::beginSession();
45
46    fRawBitmap.lockPixels();
47}
48
49void SkBitmapProcShader::endSession() {
50    fRawBitmap.unlockPixels();
51
52    this->INHERITED::endSession();
53}
54
55SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
56                                                   SkMatrix* texM,
57                                                   TileMode xy[]) 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) const {
72    this->INHERITED::flatten(buffer);
73
74    buffer.writeBitmap(fRawBitmap);
75    buffer.writeUInt(fState.fTileModeX);
76    buffer.writeUInt(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.getShaderProc32()) {
165        state.getShaderProc32()(state, x, y, dstC, count);
166        return;
167    }
168
169    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
170    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
171    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
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
206SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
207    if (fState.getShaderProc32()) {
208        *ctx = &fState;
209        return (ShadeProc)fState.getShaderProc32();
210    }
211    return NULL;
212}
213
214void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
215    const SkBitmapProcState& state = fState;
216    if (state.getShaderProc16()) {
217        state.getShaderProc16()(state, x, y, dstC, count);
218        return;
219    }
220
221    uint32_t buffer[BUF_MAX];
222    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
223    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
224    int max = fState.maxCountForBufferSize(sizeof(buffer));
225
226    SkASSERT(state.fBitmap->getPixels());
227    SkASSERT(state.fBitmap->pixelRef() == NULL ||
228             state.fBitmap->pixelRef()->isLocked());
229
230    for (;;) {
231        int n = count;
232        if (n > max) {
233            n = max;
234        }
235        mproc(state, buffer, n, x, y);
236        sproc(state, buffer, n, dstC);
237
238        if ((count -= n) == 0) {
239            break;
240        }
241        x += n;
242        dstC += n;
243    }
244}
245
246///////////////////////////////////////////////////////////////////////////////
247
248#include "SkUnPreMultiply.h"
249#include "SkColorShader.h"
250#include "SkEmptyShader.h"
251
252// returns true and set color if the bitmap can be drawn as a single color
253// (for efficiency)
254static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
255    if (1 != bm.width() || 1 != bm.height()) {
256        return false;
257    }
258
259    SkAutoLockPixels alp(bm);
260    if (!bm.readyToDraw()) {
261        return false;
262    }
263
264    switch (bm.config()) {
265        case SkBitmap::kARGB_8888_Config:
266            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
267            return true;
268        case SkBitmap::kRGB_565_Config:
269            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
270            return true;
271        case SkBitmap::kIndex8_Config:
272            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
273            return true;
274        default: // just skip the other configs for now
275            break;
276    }
277    return false;
278}
279
280#include "SkTemplatesPriv.h"
281
282static bool bitmapIsTooBig(const SkBitmap& bm) {
283    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
284    // communicates between its matrix-proc and its sampler-proc. Until we can
285    // widen that, we have to reject bitmaps that are larger.
286    //
287    const int maxSize = 65535;
288
289    return bm.width() > maxSize || bm.height() > maxSize;
290}
291
292SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
293                                       TileMode tmx, TileMode tmy,
294                                       void* storage, size_t storageSize) {
295    SkShader* shader;
296    SkColor color;
297    if (src.isNull() || bitmapIsTooBig(src)) {
298        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
299    }
300    else if (canUseColorShader(src, &color)) {
301        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
302                              (color));
303    } else {
304        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
305                              storageSize, (src, tmx, tmy));
306    }
307    return shader;
308}
309
310///////////////////////////////////////////////////////////////////////////////
311
312static const char* gTileModeName[] = {
313    "clamp", "repeat", "mirror"
314};
315
316bool SkBitmapProcShader::toDumpString(SkString* str) const {
317    str->printf("BitmapShader: [%d %d %d",
318                fRawBitmap.width(), fRawBitmap.height(),
319                fRawBitmap.bytesPerPixel());
320
321    // add the pixelref
322    SkPixelRef* pr = fRawBitmap.pixelRef();
323    if (pr) {
324        const char* uri = pr->getURI();
325        if (uri) {
326            str->appendf(" \"%s\"", uri);
327        }
328    }
329
330    // add the (optional) matrix
331    {
332        SkMatrix m;
333        if (this->getLocalMatrix(&m)) {
334            SkString info;
335            m.toDumpString(&info);
336            str->appendf(" %s", info.c_str());
337        }
338    }
339
340    str->appendf(" [%s %s]]",
341                 gTileModeName[fState.fTileModeX],
342                 gTileModeName[fState.fTileModeY]);
343    return true;
344}
345
346