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
140void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
141    const SkBitmapProcState& state = fState;
142    if (state.fShaderProc32) {
143        state.fShaderProc32(state, x, y, dstC, count);
144        return;
145    }
146
147    uint32_t buffer[BUF_MAX];
148    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
149    SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
150    int max = fState.maxCountForBufferSize(sizeof(buffer));
151
152    SkASSERT(state.fBitmap->getPixels());
153    SkASSERT(state.fBitmap->pixelRef() == NULL ||
154             state.fBitmap->pixelRef()->getLockCount());
155
156    for (;;) {
157        int n = count;
158        if (n > max) {
159            n = max;
160        }
161        mproc(state, buffer, n, x, y);
162        sproc(state, buffer, n, dstC);
163
164        if ((count -= n) == 0) {
165            break;
166        }
167        x += n;
168        dstC += n;
169    }
170}
171
172void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
173    const SkBitmapProcState& state = fState;
174    if (state.fShaderProc16) {
175        state.fShaderProc16(state, x, y, dstC, count);
176        return;
177    }
178
179    uint32_t buffer[BUF_MAX];
180    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
181    SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
182    int max = fState.maxCountForBufferSize(sizeof(buffer));
183
184    SkASSERT(state.fBitmap->getPixels());
185    SkASSERT(state.fBitmap->pixelRef() == NULL ||
186             state.fBitmap->pixelRef()->getLockCount());
187
188    for (;;) {
189        int n = count;
190        if (n > max) {
191            n = max;
192        }
193        mproc(state, buffer, n, x, y);
194        sproc(state, buffer, n, dstC);
195
196        if ((count -= n) == 0) {
197            break;
198        }
199        x += n;
200        dstC += n;
201    }
202}
203
204///////////////////////////////////////////////////////////////////////////////
205
206#include "SkUnPreMultiply.h"
207#include "SkColorShader.h"
208
209// returns true and set color if the bitmap can be drawn as a single color
210// (for efficiency)
211static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
212    if (1 != bm.width() || 1 != bm.height()) {
213        return false;
214    }
215
216    SkAutoLockPixels alp(bm);
217    if (!bm.readyToDraw()) {
218        return false;
219    }
220
221    switch (bm.config()) {
222        case SkBitmap::kARGB_8888_Config:
223            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
224            return true;
225        case SkBitmap::kRGB_565_Config:
226            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
227            return true;
228        case SkBitmap::kIndex8_Config:
229            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
230            return true;
231        default: // just skip the other configs for now
232            break;
233    }
234    return false;
235}
236
237#include "SkTemplatesPriv.h"
238
239SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
240                                       TileMode tmx, TileMode tmy,
241                                       void* storage, size_t storageSize) {
242    SkShader* shader;
243    SkColor color;
244    if (canUseColorShader(src, &color)) {
245        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
246                              (color));
247    } else {
248        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
249                              storageSize, (src, tmx, tmy));
250    }
251    return shader;
252}
253
254static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader",
255                                               SkBitmapProcShader::CreateProc);
256
257///////////////////////////////////////////////////////////////////////////////
258
259static const char* gTileModeName[] = {
260    "clamp", "repeat", "mirror"
261};
262
263bool SkBitmapProcShader::toDumpString(SkString* str) const {
264    str->printf("BitmapShader: [%d %d %d",
265                fRawBitmap.width(), fRawBitmap.height(),
266                fRawBitmap.bytesPerPixel());
267
268    // add the pixelref
269    SkPixelRef* pr = fRawBitmap.pixelRef();
270    if (pr) {
271        const char* uri = pr->getURI();
272        if (uri) {
273            str->appendf(" \"%s\"", uri);
274        }
275    }
276
277    // add the (optional) matrix
278    {
279        SkMatrix m;
280        if (this->getLocalMatrix(&m)) {
281            SkString info;
282            m.toDumpString(&info);
283            str->appendf(" %s", info.c_str());
284        }
285    }
286
287    str->appendf(" [%s %s]]",
288                 gTileModeName[fState.fTileModeX],
289                 gTileModeName[fState.fTileModeY]);
290    return true;
291}
292
293