SkBitmapProcShader.cpp revision b630785db28d3dbd2ef9fa2b15eb7aea0def82e8
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
70bool SkBitmapProcShader::setContext(const SkBitmap& device,
71                                    const SkPaint& paint,
72                                    const SkMatrix& matrix) {
73    // do this first, so we have a correct inverse matrix
74    if (!this->INHERITED::setContext(device, paint, matrix)) {
75        return false;
76    }
77
78    fState.fOrigBitmap = fRawBitmap;
79    fState.fOrigBitmap.lockPixels();
80    if (fState.fOrigBitmap.getPixels() == NULL) {
81        fState.fOrigBitmap.unlockPixels();
82        return false;
83    }
84
85    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
86        return false;
87    }
88
89    bool bitmapIsOpaque = fState.fBitmap->isOpaque();
90
91    // filtering doesn't guarantee that opaque stays opaque (finite precision)
92    // so pretend we're not opaque if we're being asked to filter. If we had
93    // more blit-procs, we could specialize on opaque src, and just OR in 0xFF
94    // after the filter to be sure...
95    if (paint.isFilterBitmap()) {
96        bitmapIsOpaque = false;
97    }
98
99    // update fFlags
100    fFlags = 0;
101    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
102        fFlags |= kOpaqueAlpha_Flag;
103    }
104
105    switch (fState.fBitmap->config()) {
106        case SkBitmap::kRGB_565_Config:
107            fFlags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
108            break;
109        case SkBitmap::kIndex8_Config:
110        case SkBitmap::kARGB_8888_Config:
111            if (bitmapIsOpaque) {
112                fFlags |= kHasSpan16_Flag;
113            }
114            break;
115        case SkBitmap::kA8_Config:
116            break;  // never set kHasSpan16_Flag
117        default:
118            break;
119    }
120    return true;
121}
122
123#define BUF_MAX     128
124
125void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
126    uint32_t buffer[BUF_MAX];
127
128    const SkBitmapProcState&        state = fState;
129    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
130    SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
131    int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX;
132
133    SkASSERT(state.fBitmap->getPixels());
134    SkASSERT(state.fBitmap->pixelRef() == NULL ||
135             state.fBitmap->pixelRef()->getLockCount());
136
137    for (;;) {
138        int n = count;
139        if (n > max) {
140            n = max;
141        }
142        mproc(state, buffer, n, x, y);
143        sproc(state, buffer, n, dstC);
144
145        if ((count -= n) == 0) {
146            break;
147        }
148        x += n;
149        dstC += n;
150    }
151}
152
153void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
154    uint32_t buffer[BUF_MAX];
155
156    const SkBitmapProcState&        state = fState;
157    SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
158    SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
159    int max = fState.fDoFilter ? (BUF_MAX >> 1) : 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        mproc(state, buffer, n, x, y);
171        sproc(state, buffer, n, dstC);
172
173        if ((count -= n) == 0) {
174            break;
175        }
176        x += n;
177        dstC += n;
178    }
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
183#include "SkTemplatesPriv.h"
184
185SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
186                                       TileMode tmx, TileMode tmy,
187                                       void* storage, size_t storageSize) {
188    SkShader* shader;
189    SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
190                          storageSize, (src, tmx, tmy));
191    return shader;
192}
193
194static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader",
195                                               SkBitmapProcShader::CreateProc);
196
197///////////////////////////////////////////////////////////////////////////////
198
199static const char* gTileModeName[] = {
200    "clamp", "repeat", "mirror"
201};
202
203bool SkBitmapProcShader::toDumpString(SkString* str) const {
204    str->printf("BitmapShader: [%d %d %d",
205                fRawBitmap.width(), fRawBitmap.height(),
206                fRawBitmap.bytesPerPixel());
207
208    // add the pixelref
209    SkPixelRef* pr = fRawBitmap.pixelRef();
210    if (pr) {
211        const char* uri = pr->getURI();
212        if (uri) {
213            str->appendf(" \"%s\"", uri);
214        }
215    }
216
217    // add the (optional) matrix
218    {
219        SkMatrix m;
220        if (this->getLocalMatrix(&m)) {
221            SkString info;
222            m.toDumpString(&info);
223            str->appendf(" %s", info.c_str());
224        }
225    }
226
227    str->appendf(" [%s %s]]",
228                 gTileModeName[fState.fTileModeX],
229                 gTileModeName[fState.fTileModeY]);
230    return true;
231}
232
233