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