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