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