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