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