• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkBitmapProcShader.h"
9 #include "SkColorPriv.h"
10 #include "SkFlattenableBuffers.h"
11 #include "SkPixelRef.h"
12 
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)13 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
14     switch (bm.config()) {
15         case SkBitmap::kA8_Config:
16         case SkBitmap::kRGB_565_Config:
17         case SkBitmap::kIndex8_Config:
18         case SkBitmap::kARGB_8888_Config:
19     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
20                 return true;
21         default:
22             break;
23     }
24     return false;
25 }
26 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy)27 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
28                                        TileMode tmx, TileMode tmy) {
29     fRawBitmap = src;
30     fState.fTileModeX = (uint8_t)tmx;
31     fState.fTileModeY = (uint8_t)tmy;
32     fFlags = 0; // computed in setContext
33 }
34 
SkBitmapProcShader(SkFlattenableReadBuffer & buffer)35 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
36         : INHERITED(buffer) {
37     buffer.readBitmap(&fRawBitmap);
38     fRawBitmap.setImmutable();
39     fState.fTileModeX = buffer.readUInt();
40     fState.fTileModeY = buffer.readUInt();
41     fFlags = 0; // computed in setContext
42 }
43 
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const44 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
45                                                    SkMatrix* texM,
46                                                    TileMode xy[]) const {
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 kDefault_BitmapType;
58 }
59 
flatten(SkFlattenableWriteBuffer & buffer) const60 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
61     this->INHERITED::flatten(buffer);
62 
63     buffer.writeBitmap(fRawBitmap);
64     buffer.writeUInt(fState.fTileModeX);
65     buffer.writeUInt(fState.fTileModeY);
66 }
67 
only_scale_and_translate(const SkMatrix & matrix)68 static bool only_scale_and_translate(const SkMatrix& matrix) {
69     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
70     return (matrix.getType() & ~mask) == 0;
71 }
72 
isOpaque() const73 bool SkBitmapProcShader::isOpaque() const {
74     return fRawBitmap.isOpaque();
75 }
76 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)77 bool SkBitmapProcShader::setContext(const SkBitmap& device,
78                                     const SkPaint& paint,
79                                     const SkMatrix& matrix) {
80     // do this first, so we have a correct inverse matrix
81     if (!this->INHERITED::setContext(device, paint, matrix)) {
82         return false;
83     }
84 
85     fState.fOrigBitmap = fRawBitmap;
86     fState.fOrigBitmap.lockPixels();
87     if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
88         fState.fOrigBitmap.unlockPixels();
89         this->INHERITED::endContext();
90         return false;
91     }
92 
93     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
94         fState.fOrigBitmap.unlockPixels();
95         this->INHERITED::endContext();
96         return false;
97     }
98 
99     const SkBitmap& bitmap = *fState.fBitmap;
100     bool bitmapIsOpaque = bitmap.isOpaque();
101 
102     // update fFlags
103     uint32_t flags = 0;
104     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
105         flags |= kOpaqueAlpha_Flag;
106     }
107 
108     switch (bitmap.config()) {
109         case SkBitmap::kRGB_565_Config:
110             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
111             break;
112         case SkBitmap::kIndex8_Config:
113         case SkBitmap::kARGB_8888_Config:
114             if (bitmapIsOpaque) {
115                 flags |= kHasSpan16_Flag;
116             }
117             break;
118         case SkBitmap::kA8_Config:
119             break;  // never set kHasSpan16_Flag
120         default:
121             break;
122     }
123 
124     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
125         // gradients can auto-dither in their 16bit sampler, but we don't so
126         // we clear the flag here.
127         flags &= ~kHasSpan16_Flag;
128     }
129 
130     // if we're only 1-pixel high, and we don't rotate, then we can claim this
131     if (1 == bitmap.height() &&
132             only_scale_and_translate(this->getTotalInverse())) {
133         flags |= kConstInY32_Flag;
134         if (flags & kHasSpan16_Flag) {
135             flags |= kConstInY16_Flag;
136         }
137     }
138 
139     fFlags = flags;
140     return true;
141 }
142 
endContext()143 void SkBitmapProcShader::endContext() {
144     fState.fOrigBitmap.unlockPixels();
145     this->INHERITED::endContext();
146 }
147 
148 #define BUF_MAX     128
149 
150 #define TEST_BUFFER_OVERRITEx
151 
152 #ifdef TEST_BUFFER_OVERRITE
153     #define TEST_BUFFER_EXTRA   32
154     #define TEST_PATTERN    0x88888888
155 #else
156     #define TEST_BUFFER_EXTRA   0
157 #endif
158 
shadeSpan(int x,int y,SkPMColor dstC[],int count)159 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
160     const SkBitmapProcState& state = fState;
161     if (state.getShaderProc32()) {
162         state.getShaderProc32()(state, x, y, dstC, count);
163         return;
164     }
165 
166     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
167     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
168     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
169     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
170 
171     SkASSERT(state.fBitmap->getPixels());
172     SkASSERT(state.fBitmap->pixelRef() == NULL ||
173              state.fBitmap->pixelRef()->isLocked());
174 
175     for (;;) {
176         int n = count;
177         if (n > max) {
178             n = max;
179         }
180         SkASSERT(n > 0 && n < BUF_MAX*2);
181 #ifdef TEST_BUFFER_OVERRITE
182         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
183             buffer[BUF_MAX + i] = TEST_PATTERN;
184         }
185 #endif
186         mproc(state, buffer, n, x, y);
187 #ifdef TEST_BUFFER_OVERRITE
188         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
189             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
190         }
191 #endif
192         sproc(state, buffer, n, dstC);
193 
194         if ((count -= n) == 0) {
195             break;
196         }
197         SkASSERT(count > 0);
198         x += n;
199         dstC += n;
200     }
201 }
202 
asAShadeProc(void ** ctx)203 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
204     if (fState.getShaderProc32()) {
205         *ctx = &fState;
206         return (ShadeProc)fState.getShaderProc32();
207     }
208     return NULL;
209 }
210 
shadeSpan16(int x,int y,uint16_t dstC[],int count)211 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
212     const SkBitmapProcState& state = fState;
213     if (state.getShaderProc16()) {
214         state.getShaderProc16()(state, x, y, dstC, count);
215         return;
216     }
217 
218     uint32_t buffer[BUF_MAX];
219     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
220     SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
221     int max = fState.maxCountForBufferSize(sizeof(buffer));
222 
223     SkASSERT(state.fBitmap->getPixels());
224     SkASSERT(state.fBitmap->pixelRef() == NULL ||
225              state.fBitmap->pixelRef()->isLocked());
226 
227     for (;;) {
228         int n = count;
229         if (n > max) {
230             n = max;
231         }
232         mproc(state, buffer, n, x, y);
233         sproc(state, buffer, n, dstC);
234 
235         if ((count -= n) == 0) {
236             break;
237         }
238         x += n;
239         dstC += n;
240     }
241 }
242 
243 ///////////////////////////////////////////////////////////////////////////////
244 
245 #include "SkUnPreMultiply.h"
246 #include "SkColorShader.h"
247 #include "SkEmptyShader.h"
248 
249 // returns true and set color if the bitmap can be drawn as a single color
250 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)251 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
252     if (1 != bm.width() || 1 != bm.height()) {
253         return false;
254     }
255 
256     SkAutoLockPixels alp(bm);
257     if (!bm.readyToDraw()) {
258         return false;
259     }
260 
261     switch (bm.config()) {
262         case SkBitmap::kARGB_8888_Config:
263             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
264             return true;
265         case SkBitmap::kRGB_565_Config:
266             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
267             return true;
268         case SkBitmap::kIndex8_Config:
269             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
270             return true;
271         default: // just skip the other configs for now
272             break;
273     }
274     return false;
275 }
276 
277 #include "SkTemplatesPriv.h"
278 
bitmapIsTooBig(const SkBitmap & bm)279 static bool bitmapIsTooBig(const SkBitmap& bm) {
280     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
281     // communicates between its matrix-proc and its sampler-proc. Until we can
282     // widen that, we have to reject bitmaps that are larger.
283     //
284     const int maxSize = 65535;
285 
286     return bm.width() > maxSize || bm.height() > maxSize;
287 }
288 
CreateBitmapShader(const SkBitmap & src,TileMode tmx,TileMode tmy,void * storage,size_t storageSize)289 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
290                                        TileMode tmx, TileMode tmy,
291                                        void* storage, size_t storageSize) {
292     SkShader* shader;
293     SkColor color;
294     if (src.isNull() || bitmapIsTooBig(src)) {
295         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
296     }
297     else if (canUseColorShader(src, &color)) {
298         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
299                               (color));
300     } else {
301         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
302                               storageSize, (src, tmx, tmy));
303     }
304     return shader;
305 }
306 
307 ///////////////////////////////////////////////////////////////////////////////
308 
309 #ifdef SK_DEVELOPER
toString(SkString * str) const310 void SkBitmapProcShader::toString(SkString* str) const {
311     static const char* gTileModeName[SkShader::kTileModeCount] = {
312         "clamp", "repeat", "mirror"
313     };
314 
315     str->append("BitmapShader: (");
316 
317     str->appendf("(%s, %s)",
318                  gTileModeName[fState.fTileModeX],
319                  gTileModeName[fState.fTileModeY]);
320 
321     str->append(" ");
322     fRawBitmap.toString(str);
323 
324     this->INHERITED::toString(str);
325 
326     str->append(")");
327 }
328 #endif
329 
330 ///////////////////////////////////////////////////////////////////////////////
331 
332 #if SK_SUPPORT_GPU
333 
334 #include "GrTextureAccess.h"
335 #include "effects/GrSimpleTextureEffect.h"
336 #include "SkGr.h"
337 
asNewEffect(GrContext * context,const SkPaint & paint) const338 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
339     SkMatrix matrix;
340     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
341 
342     if (this->hasLocalMatrix()) {
343         SkMatrix inverse;
344         if (!this->getLocalMatrix().invert(&inverse)) {
345             return NULL;
346         }
347         matrix.preConcat(inverse);
348     }
349     SkShader::TileMode tm[] = {
350         (TileMode)fState.fTileModeX,
351         (TileMode)fState.fTileModeY,
352     };
353 
354     // Must set wrap and filter on the sampler before requesting a texture.
355     GrTextureParams params(tm, paint.isFilterBitmap());
356     GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
357 
358     if (NULL == texture) {
359         SkDebugf("Couldn't convert bitmap to texture.\n");
360         return NULL;
361     }
362 
363     GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
364     GrUnlockAndUnrefCachedBitmapTexture(texture);
365     return effect;
366 }
367 #endif
368