• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "SkBitmapProcShader.h"
2 #include "SkColorPriv.h"
3 #include "SkPixelRef.h"
4 
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)5 bool 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 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy)19 SkBitmapProcShader::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 
SkBitmapProcShader(SkFlattenableReadBuffer & buffer)27 SkBitmapProcShader::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 
beginSession()35 void SkBitmapProcShader::beginSession() {
36     this->INHERITED::beginSession();
37 
38     fRawBitmap.lockPixels();
39 }
40 
endSession()41 void SkBitmapProcShader::endSession() {
42     fRawBitmap.unlockPixels();
43 
44     this->INHERITED::endSession();
45 }
46 
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[])47 bool 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 
flatten(SkFlattenableWriteBuffer & buffer)62 void 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 
only_scale_and_translate(const SkMatrix & matrix)70 static 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 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)75 bool 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     bool bitmapIsOpaque = fState.fBitmap->isOpaque();
95 
96     // filtering doesn't guarantee that opaque stays opaque (finite precision)
97     // so pretend we're not opaque if we're being asked to filter. If we had
98     // more blit-procs, we could specialize on opaque src, and just OR in 0xFF
99     // after the filter to be sure...
100     if (paint.isFilterBitmap()) {
101         bitmapIsOpaque = false;
102     }
103 
104     // update fFlags
105     uint32_t flags = 0;
106     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
107         flags |= kOpaqueAlpha_Flag;
108     }
109 
110     switch (fState.fBitmap->config()) {
111         case SkBitmap::kRGB_565_Config:
112             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
113             break;
114         case SkBitmap::kIndex8_Config:
115         case SkBitmap::kARGB_8888_Config:
116             if (bitmapIsOpaque) {
117                 flags |= kHasSpan16_Flag;
118             }
119             break;
120         case SkBitmap::kA8_Config:
121             break;  // never set kHasSpan16_Flag
122         default:
123             break;
124     }
125 
126     if (paint.isDither()) {
127         // gradients can auto-dither in their 16bit sampler, but we don't so
128         // we clear the flag here
129         flags &= ~kHasSpan16_Flag;
130     }
131 
132     // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
133     if (1 == fState.fBitmap->height() &&
134             only_scale_and_translate(this->getTotalInverse())) {
135         flags |= kConstInY32_Flag;
136         if (flags & kHasSpan16_Flag) {
137             flags |= kConstInY16_Flag;
138         }
139     }
140 
141     fFlags = flags;
142     return true;
143 }
144 
145 #define BUF_MAX     128
146 
shadeSpan(int x,int y,SkPMColor dstC[],int count)147 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
148     const SkBitmapProcState& state = fState;
149     if (state.fShaderProc32) {
150         state.fShaderProc32(state, x, y, dstC, count);
151         return;
152     }
153 
154     uint32_t buffer[BUF_MAX];
155     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
156     SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
157     int max = fState.maxCountForBufferSize(sizeof(buffer));
158 
159     SkASSERT(state.fBitmap->getPixels());
160     SkASSERT(state.fBitmap->pixelRef() == NULL ||
161              state.fBitmap->pixelRef()->getLockCount());
162 
163     for (;;) {
164         int n = count;
165         if (n > max) {
166             n = max;
167         }
168         mproc(state, buffer, n, x, y);
169         sproc(state, buffer, n, dstC);
170 
171         if ((count -= n) == 0) {
172             break;
173         }
174         x += n;
175         dstC += n;
176     }
177 }
178 
shadeSpan16(int x,int y,uint16_t dstC[],int count)179 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
180     const SkBitmapProcState& state = fState;
181     if (state.fShaderProc16) {
182         state.fShaderProc16(state, x, y, dstC, count);
183         return;
184     }
185 
186     uint32_t buffer[BUF_MAX];
187     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
188     SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
189     int max = fState.maxCountForBufferSize(sizeof(buffer));
190 
191     SkASSERT(state.fBitmap->getPixels());
192     SkASSERT(state.fBitmap->pixelRef() == NULL ||
193              state.fBitmap->pixelRef()->getLockCount());
194 
195     for (;;) {
196         int n = count;
197         if (n > max) {
198             n = max;
199         }
200         mproc(state, buffer, n, x, y);
201         sproc(state, buffer, n, dstC);
202 
203         if ((count -= n) == 0) {
204             break;
205         }
206         x += n;
207         dstC += n;
208     }
209 }
210 
211 ///////////////////////////////////////////////////////////////////////////////
212 
213 #include "SkUnPreMultiply.h"
214 #include "SkColorShader.h"
215 
216 // returns true and set color if the bitmap can be drawn as a single color
217 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)218 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
219     if (1 != bm.width() || 1 != bm.height()) {
220         return false;
221     }
222 
223     SkAutoLockPixels alp(bm);
224     if (!bm.readyToDraw()) {
225         return false;
226     }
227 
228     switch (bm.config()) {
229         case SkBitmap::kARGB_8888_Config:
230             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
231             return true;
232         case SkBitmap::kRGB_565_Config:
233             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
234             return true;
235         case SkBitmap::kIndex8_Config:
236             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
237             return true;
238         default: // just skip the other configs for now
239             break;
240     }
241     return false;
242 }
243 
244 #include "SkTemplatesPriv.h"
245 
CreateBitmapShader(const SkBitmap & src,TileMode tmx,TileMode tmy,void * storage,size_t storageSize)246 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
247                                        TileMode tmx, TileMode tmy,
248                                        void* storage, size_t storageSize) {
249     SkShader* shader;
250     SkColor color;
251     if (canUseColorShader(src, &color)) {
252         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
253                               (color));
254     } else {
255         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
256                               storageSize, (src, tmx, tmy));
257     }
258     return shader;
259 }
260 
261 static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader",
262                                                SkBitmapProcShader::CreateProc);
263 
264 ///////////////////////////////////////////////////////////////////////////////
265 
266 static const char* gTileModeName[] = {
267     "clamp", "repeat", "mirror"
268 };
269 
toDumpString(SkString * str) const270 bool SkBitmapProcShader::toDumpString(SkString* str) const {
271     str->printf("BitmapShader: [%d %d %d",
272                 fRawBitmap.width(), fRawBitmap.height(),
273                 fRawBitmap.bytesPerPixel());
274 
275     // add the pixelref
276     SkPixelRef* pr = fRawBitmap.pixelRef();
277     if (pr) {
278         const char* uri = pr->getURI();
279         if (uri) {
280             str->appendf(" \"%s\"", uri);
281         }
282     }
283 
284     // add the (optional) matrix
285     {
286         SkMatrix m;
287         if (this->getLocalMatrix(&m)) {
288             SkString info;
289             m.toDumpString(&info);
290             str->appendf(" %s", info.c_str());
291         }
292     }
293 
294     str->appendf(" [%s %s]]",
295                  gTileModeName[fState.fTileModeX],
296                  gTileModeName[fState.fTileModeY]);
297     return true;
298 }
299 
300