• 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 "SkPixelRef.h"
11 
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)12 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
13     switch (bm.config()) {
14         case SkBitmap::kA8_Config:
15         case SkBitmap::kRGB_565_Config:
16         case SkBitmap::kIndex8_Config:
17         case SkBitmap::kARGB_8888_Config:
18     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
19                 return true;
20         default:
21             break;
22     }
23     return false;
24 }
25 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy)26 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
27                                        TileMode tmx, TileMode tmy) {
28     fRawBitmap = src;
29     fState.fTileModeX = (uint8_t)tmx;
30     fState.fTileModeY = (uint8_t)tmy;
31     fFlags = 0; // computed in setContext
32 }
33 
SkBitmapProcShader(SkFlattenableReadBuffer & buffer)34 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
35         : INHERITED(buffer) {
36     fRawBitmap.unflatten(buffer);
37     fState.fTileModeX = buffer.readU8();
38     fState.fTileModeY = buffer.readU8();
39     fFlags = 0; // computed in setContext
40 }
41 
beginSession()42 void SkBitmapProcShader::beginSession() {
43     this->INHERITED::beginSession();
44 
45     fRawBitmap.lockPixels();
46 }
47 
endSession()48 void SkBitmapProcShader::endSession() {
49     fRawBitmap.unlockPixels();
50 
51     this->INHERITED::endSession();
52 }
53 
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[],SkScalar * twoPointRadialParams) const54 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
55                                                    SkMatrix* texM,
56                                                    TileMode xy[],
57                                        SkScalar* twoPointRadialParams) const {
58     if (texture) {
59         *texture = fRawBitmap;
60     }
61     if (texM) {
62         texM->reset();
63     }
64     if (xy) {
65         xy[0] = (TileMode)fState.fTileModeX;
66         xy[1] = (TileMode)fState.fTileModeY;
67     }
68     return kDefault_BitmapType;
69 }
70 
flatten(SkFlattenableWriteBuffer & buffer)71 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) {
72     this->INHERITED::flatten(buffer);
73 
74     fRawBitmap.flatten(buffer);
75     buffer.write8(fState.fTileModeX);
76     buffer.write8(fState.fTileModeY);
77 }
78 
only_scale_and_translate(const SkMatrix & matrix)79 static bool only_scale_and_translate(const SkMatrix& matrix) {
80     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
81     return (matrix.getType() & ~mask) == 0;
82 }
83 
isOpaque() const84 bool SkBitmapProcShader::isOpaque() const {
85     return fRawBitmap.isOpaque();
86 }
87 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)88 bool SkBitmapProcShader::setContext(const SkBitmap& device,
89                                     const SkPaint& paint,
90                                     const SkMatrix& matrix) {
91     // do this first, so we have a correct inverse matrix
92     if (!this->INHERITED::setContext(device, paint, matrix)) {
93         return false;
94     }
95 
96     fState.fOrigBitmap = fRawBitmap;
97     fState.fOrigBitmap.lockPixels();
98     if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
99         fState.fOrigBitmap.unlockPixels();
100         return false;
101     }
102 
103     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
104         return false;
105     }
106 
107     const SkBitmap& bitmap = *fState.fBitmap;
108     bool bitmapIsOpaque = bitmap.isOpaque();
109 
110     // update fFlags
111     uint32_t flags = 0;
112     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
113         flags |= kOpaqueAlpha_Flag;
114     }
115 
116     switch (bitmap.config()) {
117         case SkBitmap::kRGB_565_Config:
118             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
119             break;
120         case SkBitmap::kIndex8_Config:
121         case SkBitmap::kARGB_8888_Config:
122             if (bitmapIsOpaque) {
123                 flags |= kHasSpan16_Flag;
124             }
125             break;
126         case SkBitmap::kA8_Config:
127             break;  // never set kHasSpan16_Flag
128         default:
129             break;
130     }
131 
132     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
133         // gradients can auto-dither in their 16bit sampler, but we don't so
134         // we clear the flag here.
135         flags &= ~kHasSpan16_Flag;
136     }
137 
138     // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
139     if (1 == bitmap.height() &&
140             only_scale_and_translate(this->getTotalInverse())) {
141         flags |= kConstInY32_Flag;
142         if (flags & kHasSpan16_Flag) {
143             flags |= kConstInY16_Flag;
144         }
145     }
146 
147     fFlags = flags;
148     return true;
149 }
150 
151 #define BUF_MAX     128
152 
153 #define TEST_BUFFER_OVERRITEx
154 
155 #ifdef TEST_BUFFER_OVERRITE
156     #define TEST_BUFFER_EXTRA   32
157     #define TEST_PATTERN    0x88888888
158 #else
159     #define TEST_BUFFER_EXTRA   0
160 #endif
161 
shadeSpan(int x,int y,SkPMColor dstC[],int count)162 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
163     const SkBitmapProcState& state = fState;
164     if (state.fShaderProc32) {
165         state.fShaderProc32(state, x, y, dstC, count);
166         return;
167     }
168 
169     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
170     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
171     SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
172     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
173 
174     SkASSERT(state.fBitmap->getPixels());
175     SkASSERT(state.fBitmap->pixelRef() == NULL ||
176              state.fBitmap->pixelRef()->isLocked());
177 
178     for (;;) {
179         int n = count;
180         if (n > max) {
181             n = max;
182         }
183         SkASSERT(n > 0 && n < BUF_MAX*2);
184 #ifdef TEST_BUFFER_OVERRITE
185         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
186             buffer[BUF_MAX + i] = TEST_PATTERN;
187         }
188 #endif
189         mproc(state, buffer, n, x, y);
190 #ifdef TEST_BUFFER_OVERRITE
191         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
192             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
193         }
194 #endif
195         sproc(state, buffer, n, dstC);
196 
197         if ((count -= n) == 0) {
198             break;
199         }
200         SkASSERT(count > 0);
201         x += n;
202         dstC += n;
203     }
204 }
205 
shadeSpan16(int x,int y,uint16_t dstC[],int count)206 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
207     const SkBitmapProcState& state = fState;
208     if (state.fShaderProc16) {
209         state.fShaderProc16(state, x, y, dstC, count);
210         return;
211     }
212 
213     uint32_t buffer[BUF_MAX];
214     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
215     SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
216     int max = fState.maxCountForBufferSize(sizeof(buffer));
217 
218     SkASSERT(state.fBitmap->getPixels());
219     SkASSERT(state.fBitmap->pixelRef() == NULL ||
220              state.fBitmap->pixelRef()->isLocked());
221 
222     for (;;) {
223         int n = count;
224         if (n > max) {
225             n = max;
226         }
227         mproc(state, buffer, n, x, y);
228         sproc(state, buffer, n, dstC);
229 
230         if ((count -= n) == 0) {
231             break;
232         }
233         x += n;
234         dstC += n;
235     }
236 }
237 
238 ///////////////////////////////////////////////////////////////////////////////
239 
240 #include "SkUnPreMultiply.h"
241 #include "SkColorShader.h"
242 #include "SkEmptyShader.h"
243 
244 // returns true and set color if the bitmap can be drawn as a single color
245 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)246 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
247     if (1 != bm.width() || 1 != bm.height()) {
248         return false;
249     }
250 
251     SkAutoLockPixels alp(bm);
252     if (!bm.readyToDraw()) {
253         return false;
254     }
255 
256     switch (bm.config()) {
257         case SkBitmap::kARGB_8888_Config:
258             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
259             return true;
260         case SkBitmap::kRGB_565_Config:
261             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
262             return true;
263         case SkBitmap::kIndex8_Config:
264             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
265             return true;
266         default: // just skip the other configs for now
267             break;
268     }
269     return false;
270 }
271 
272 #include "SkTemplatesPriv.h"
273 
CreateBitmapShader(const SkBitmap & src,TileMode tmx,TileMode tmy,void * storage,size_t storageSize)274 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
275                                        TileMode tmx, TileMode tmy,
276                                        void* storage, size_t storageSize) {
277     SkShader* shader;
278     SkColor color;
279     if (src.isNull()) {
280         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
281     }
282     else if (canUseColorShader(src, &color)) {
283         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
284                               (color));
285     } else {
286         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
287                               storageSize, (src, tmx, tmy));
288     }
289     return shader;
290 }
291 
292 SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapProcShader)
293 
294 ///////////////////////////////////////////////////////////////////////////////
295 
296 static const char* gTileModeName[] = {
297     "clamp", "repeat", "mirror"
298 };
299 
toDumpString(SkString * str) const300 bool SkBitmapProcShader::toDumpString(SkString* str) const {
301     str->printf("BitmapShader: [%d %d %d",
302                 fRawBitmap.width(), fRawBitmap.height(),
303                 fRawBitmap.bytesPerPixel());
304 
305     // add the pixelref
306     SkPixelRef* pr = fRawBitmap.pixelRef();
307     if (pr) {
308         const char* uri = pr->getURI();
309         if (uri) {
310             str->appendf(" \"%s\"", uri);
311         }
312     }
313 
314     // add the (optional) matrix
315     {
316         SkMatrix m;
317         if (this->getLocalMatrix(&m)) {
318             SkString info;
319             m.toDumpString(&info);
320             str->appendf(" %s", info.c_str());
321         }
322     }
323 
324     str->appendf(" [%s %s]]",
325                  gTileModeName[fState.fTileModeX],
326                  gTileModeName[fState.fTileModeY]);
327     return true;
328 }
329 
330