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