SkBitmapProcShader.cpp revision 7f6e1e9caa4ced154c23701768e6c618dfe6ad48
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
75// return true if the config can possibly have per-pixel alpha, ignoring the
76// current setting of isOpaque.
77static bool canSupportPerPixelAlpha(const SkBitmap& bm) {
78    // return true unless we're guaranteed to be opaque
79    return bm.config() != SkBitmap::kRGB_565_Config;
80}
81
82bool SkBitmapProcShader::setContext(const SkBitmap& device,
83                                    const SkPaint& paint,
84                                    const SkMatrix& matrix) {
85    // do this first, so we have a correct inverse matrix
86    if (!this->INHERITED::setContext(device, paint, matrix)) {
87        return false;
88    }
89
90    fState.fOrigBitmap = fRawBitmap;
91    fState.fOrigBitmap.lockPixels();
92    if (fState.fOrigBitmap.getPixels() == NULL) {
93        fState.fOrigBitmap.unlockPixels();
94        return false;
95    }
96
97    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
98        return false;
99    }
100
101    const SkBitmap& bitmap = *fState.fBitmap;
102    bool bitmapIsOpaque = bitmap.isOpaque();
103
104    // filtering doesn't guarantee that opaque stays opaque (finite precision)
105    // so pretend we're not opaque if we're being asked to filter. If we had
106    // more blit-procs, we could specialize on opaque src, and just OR in 0xFF
107    // after the filter to be sure...
108    /*
109        (some time later)
110        Adding check for canSupportPerPixelAlpha, since bitmaps that are 565
111        (for example) will *always* be opaque, even after filtering.
112
113        Would be really nice to never do this, if we could ensure that
114        filtering didn't introduct non-opaqueness accidentally.
115     */
116    if (paint.isFilterBitmap() && canSupportPerPixelAlpha(bitmap)) {
117        bitmapIsOpaque = false;
118    }
119
120    // update fFlags
121    uint32_t flags = 0;
122    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
123        flags |= kOpaqueAlpha_Flag;
124    }
125
126    switch (bitmap.config()) {
127        case SkBitmap::kRGB_565_Config:
128            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
129            break;
130        case SkBitmap::kIndex8_Config:
131        case SkBitmap::kARGB_8888_Config:
132            if (bitmapIsOpaque) {
133                flags |= kHasSpan16_Flag;
134            }
135            break;
136        case SkBitmap::kA8_Config:
137            break;  // never set kHasSpan16_Flag
138        default:
139            break;
140    }
141
142    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
143        // gradients can auto-dither in their 16bit sampler, but we don't so
144        // we clear the flag here.
145        flags &= ~kHasSpan16_Flag;
146    }
147
148    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
149    if (1 == bitmap.height() &&
150            only_scale_and_translate(this->getTotalInverse())) {
151        flags |= kConstInY32_Flag;
152        if (flags & kHasSpan16_Flag) {
153            flags |= kConstInY16_Flag;
154        }
155    }
156
157    fFlags = flags;
158    return true;
159}
160
161#define BUF_MAX     128
162
163void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
164    const SkBitmapProcState& state = fState;
165    if (state.fShaderProc32) {
166        state.fShaderProc32(state, x, y, dstC, count);
167        return;
168    }
169
170    uint32_t buffer[BUF_MAX];
171    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
172    SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
173    int max = fState.maxCountForBufferSize(sizeof(buffer));
174
175    SkASSERT(state.fBitmap->getPixels());
176    SkASSERT(state.fBitmap->pixelRef() == NULL ||
177             state.fBitmap->pixelRef()->getLockCount());
178
179    for (;;) {
180        int n = count;
181        if (n > max) {
182            n = max;
183        }
184        mproc(state, buffer, n, x, y);
185        sproc(state, buffer, n, dstC);
186
187        if ((count -= n) == 0) {
188            break;
189        }
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