1
2 /*
3 * Copyright 2006 The Android Open Source Project
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
9
10 #include "SkBitmapSampler.h"
11
get_tilemode_proc(SkShader::TileMode mode)12 static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode)
13 {
14 switch (mode) {
15 case SkShader::kClamp_TileMode:
16 return do_clamp;
17 case SkShader::kRepeat_TileMode:
18 return do_repeat_mod;
19 case SkShader::kMirror_TileMode:
20 return do_mirror_mod;
21 default:
22 SkDEBUGFAIL("unknown mode");
23 return NULL;
24 }
25 }
26
SkBitmapSampler(const SkBitmap & bm,bool filter,SkShader::TileMode tmx,SkShader::TileMode tmy)27 SkBitmapSampler::SkBitmapSampler(const SkBitmap& bm, bool filter,
28 SkShader::TileMode tmx, SkShader::TileMode tmy)
29 : fBitmap(bm), fFilterBitmap(filter), fTileModeX(tmx), fTileModeY(tmy)
30 {
31 SkASSERT(bm.width() > 0 && bm.height() > 0);
32
33 fMaxX = SkToU16(bm.width() - 1);
34 fMaxY = SkToU16(bm.height() - 1);
35
36 fTileProcX = get_tilemode_proc(tmx);
37 fTileProcY = get_tilemode_proc(tmy);
38 }
39
setPaint(const SkPaint & paint)40 void SkBitmapSampler::setPaint(const SkPaint& paint)
41 {
42 }
43
44 class SkNullBitmapSampler : public SkBitmapSampler {
45 public:
SkNullBitmapSampler(const SkBitmap & bm,bool filter,SkShader::TileMode tmx,SkShader::TileMode tmy)46 SkNullBitmapSampler(const SkBitmap& bm, bool filter,
47 SkShader::TileMode tmx, SkShader::TileMode tmy)
48 : SkBitmapSampler(bm, filter, tmx, tmy) {}
49
sample(SkFixed x,SkFixed y) const50 virtual SkPMColor sample(SkFixed x, SkFixed y) const { return 0; }
51 };
52
53 /////////////////////////////////////////////////////////////////////////////////
54 /////////////////////////////////////////////////////////////////////////////////
55
56 #define BITMAP_CLASSNAME_PREFIX(name) ARGB32##name
57 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) *bitmap.getAddr32(x, y)
58 #include "SkBitmapSamplerTemplate.h"
59
60 #include "SkColorPriv.h"
61
62 #define BITMAP_CLASSNAME_PREFIX(name) RGB16##name
63 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) SkPixel16ToPixel32(*bitmap.getAddr16(x, y))
64 #include "SkBitmapSamplerTemplate.h"
65
66 #define BITMAP_CLASSNAME_PREFIX(name) Index8##name
67 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) bitmap.getIndex8Color(x, y)
68 #include "SkBitmapSamplerTemplate.h"
69
70 /////////////////////////////////////////////////////////////////////////////////
71 /////////////////////////////////////////////////////////////////////////////////
72 ///////////////// The Bilinear versions
73
74 #include "SkFilterProc.h"
75
76 class ARGB32_Bilinear_Sampler : public SkBitmapSampler {
77 public:
ARGB32_Bilinear_Sampler(const SkBitmap & bm,SkShader::TileMode tmx,SkShader::TileMode tmy)78 ARGB32_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
79 : SkBitmapSampler(bm, true, tmx, tmy)
80 {
81 fPtrProcTable = SkGetBilinearFilterPtrProcTable();
82 }
83
sample(SkFixed x,SkFixed y) const84 virtual SkPMColor sample(SkFixed x, SkFixed y) const
85 {
86 const uint32_t *p00, *p01, *p10, *p11;
87
88 // turn pixel centers into the top-left of our filter-box
89 x -= SK_FixedHalf;
90 y -= SK_FixedHalf;
91
92 // compute our pointers
93 {
94 const SkBitmap* bitmap = &fBitmap;
95 int ix = x >> 16;
96 int iy = y >> 16;
97
98 int maxX = fMaxX;
99 SkTileModeProc procX = fTileProcX;
100 int maxY = fMaxY;
101 SkTileModeProc procY = fTileProcY;
102
103 int tmpx = procX(ix, maxX);
104 int tmpy = procY(iy, maxY);
105 p00 = bitmap->getAddr32(tmpx, tmpy);
106
107 int tmpx1 = procX(ix + 1, maxX);
108 p01 = bitmap->getAddr32(tmpx1, tmpy);
109
110 int tmpy1 = procY(iy + 1, maxY);
111 p10 = bitmap->getAddr32(tmpx, tmpy1);
112
113 p11 = bitmap->getAddr32(tmpx1, tmpy1);
114 }
115
116 SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y);
117 return proc(p00, p01, p10, p11);
118 }
119
120 private:
121 const SkFilterPtrProc* fPtrProcTable;
122 };
123
124 class RGB16_Bilinear_Sampler : public SkBitmapSampler {
125 public:
RGB16_Bilinear_Sampler(const SkBitmap & bm,SkShader::TileMode tmx,SkShader::TileMode tmy)126 RGB16_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
127 : SkBitmapSampler(bm, true, tmx, tmy)
128 {
129 fProcTable = SkGetBilinearFilterProcTable();
130 }
131
sample(SkFixed x,SkFixed y) const132 virtual SkPMColor sample(SkFixed x, SkFixed y) const
133 {
134 const uint16_t *p00, *p01, *p10, *p11;
135
136 // turn pixel centers into the top-left of our filter-box
137 x -= SK_FixedHalf;
138 y -= SK_FixedHalf;
139
140 // compute our pointers
141 {
142 const SkBitmap* bitmap = &fBitmap;
143 int ix = x >> 16;
144 int iy = y >> 16;
145
146 int maxX = fMaxX;
147 SkTileModeProc procX = fTileProcX;
148 int maxY = fMaxY;
149 SkTileModeProc procY = fTileProcY;
150
151 int tmpx = procX(ix, maxX);
152 int tmpy = procY(iy, maxY);
153 p00 = bitmap->getAddr16(tmpx, tmpy);
154
155 int tmpx1 = procX(ix + 1, maxX);
156 p01 = bitmap->getAddr16(tmpx1, tmpy);
157
158 int tmpy1 = procY(iy + 1, maxY);
159 p10 = bitmap->getAddr16(tmpx, tmpy1);
160
161 p11 = bitmap->getAddr16(tmpx1, tmpy1);
162 }
163
164 SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
165 uint32_t c = proc(SkExpand_rgb_16(*p00), SkExpand_rgb_16(*p01),
166 SkExpand_rgb_16(*p10), SkExpand_rgb_16(*p11));
167
168 return SkPixel16ToPixel32((uint16_t)SkCompact_rgb_16(c));
169 }
170
171 private:
172 const SkFilterProc* fProcTable;
173 };
174
175 // If we had a init/term method on sampler, we could avoid the per-pixel
176 // call to lockColors/unlockColors
177
178 class Index8_Bilinear_Sampler : public SkBitmapSampler {
179 public:
Index8_Bilinear_Sampler(const SkBitmap & bm,SkShader::TileMode tmx,SkShader::TileMode tmy)180 Index8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
181 : SkBitmapSampler(bm, true, tmx, tmy)
182 {
183 fPtrProcTable = SkGetBilinearFilterPtrProcTable();
184 }
185
sample(SkFixed x,SkFixed y) const186 virtual SkPMColor sample(SkFixed x, SkFixed y) const
187 {
188 const SkBitmap* bitmap = &fBitmap;
189
190 const uint8_t *p00, *p01, *p10, *p11;
191
192 // turn pixel centers into the top-left of our filter-box
193 x -= SK_FixedHalf;
194 y -= SK_FixedHalf;
195
196 // compute our pointers
197 {
198 int ix = x >> 16;
199 int iy = y >> 16;
200
201 int maxX = fMaxX;
202 SkTileModeProc procX = fTileProcX;
203 int maxY = fMaxY;
204 SkTileModeProc procY = fTileProcY;
205
206 int tmpx = procX(ix, maxX);
207 int tmpy = procY(iy, maxY);
208 p00 = bitmap->getAddr8(tmpx, tmpy);
209
210 int tmpx1 = procX(ix + 1, maxX);
211 p01 = bitmap->getAddr8(tmpx1, tmpy);
212
213 int tmpy1 = procY(iy + 1, maxY);
214 p10 = bitmap->getAddr8(tmpx, tmpy1);
215
216 p11 = bitmap->getAddr8(tmpx1, tmpy1);
217 }
218
219 const SkPMColor* colors = bitmap->getColorTable()->lockColors();
220
221 SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y);
222 uint32_t c = proc(&colors[*p00], &colors[*p01], &colors[*p10], &colors[*p11]);
223
224 bitmap->getColorTable()->unlockColors(false);
225
226 return c;
227 }
228
229 private:
230 const SkFilterPtrProc* fPtrProcTable;
231 };
232
233 class A8_Bilinear_Sampler : public SkBitmapSampler {
234 public:
A8_Bilinear_Sampler(const SkBitmap & bm,SkShader::TileMode tmx,SkShader::TileMode tmy)235 A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
236 : SkBitmapSampler(bm, true, tmx, tmy)
237 {
238 fProcTable = SkGetBilinearFilterProcTable();
239 }
240
setPaint(const SkPaint & paint)241 virtual void setPaint(const SkPaint& paint)
242 {
243 fColor = SkPreMultiplyColor(paint.getColor());
244 }
245
sample(SkFixed x,SkFixed y) const246 virtual SkPMColor sample(SkFixed x, SkFixed y) const
247 {
248 const uint8_t *p00, *p01, *p10, *p11;
249
250 // turn pixel centers into the top-left of our filter-box
251 x -= SK_FixedHalf;
252 y -= SK_FixedHalf;
253
254 // compute our pointers
255 {
256 const SkBitmap* bitmap = &fBitmap;
257 int ix = x >> 16;
258 int iy = y >> 16;
259
260 int maxX = fMaxX;
261 SkTileModeProc procX = fTileProcX;
262 int maxY = fMaxY;
263 SkTileModeProc procY = fTileProcY;
264
265 int tmpx = procX(ix, maxX);
266 int tmpy = procY(iy, maxY);
267 p00 = bitmap->getAddr8(tmpx, tmpy);
268
269 int tmpx1 = procX(ix + 1, maxX);
270 p01 = bitmap->getAddr8(tmpx1, tmpy);
271
272 int tmpy1 = procY(iy + 1, maxY);
273 p10 = bitmap->getAddr8(tmpx, tmpy1);
274
275 p11 = bitmap->getAddr8(tmpx1, tmpy1);
276 }
277
278 SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
279 int alpha = proc(*p00, *p01, *p10, *p11);
280 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
281 }
282
283 private:
284 const SkFilterProc* fProcTable;
285 SkPMColor fColor;
286 };
287
288 class A8_NoFilter_Sampler : public SkBitmapSampler {
289 public:
A8_NoFilter_Sampler(const SkBitmap & bm,SkShader::TileMode tmx,SkShader::TileMode tmy)290 A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
291 : SkBitmapSampler(bm, false, tmx, tmy)
292 {
293 }
294
setPaint(const SkPaint & paint)295 virtual void setPaint(const SkPaint& paint)
296 {
297 fColor = SkPreMultiplyColor(paint.getColor());
298 }
299
sample(SkFixed x,SkFixed y) const300 virtual SkPMColor sample(SkFixed x, SkFixed y) const
301 {
302 int ix = SkFixedFloor(x);
303 int iy = SkFixedFloor(y);
304
305 int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY));
306 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
307 }
308
309 private:
310 const SkFilterProc* fProcTable;
311 SkPMColor fColor;
312 };
313
314 ///////////////////////////////////////////////////////////////////////////////
315 ///////////////////////////////////////////////////////////////////////////////
316
Create(const SkBitmap & bm,bool doFilter,SkShader::TileMode tmx,SkShader::TileMode tmy)317 SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
318 SkShader::TileMode tmx,
319 SkShader::TileMode tmy)
320 {
321 switch (bm.getConfig()) {
322 case SkBitmap::kARGB_8888_Config:
323 if (doFilter)
324 return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy));
325
326 if (tmx == tmy) {
327 switch (tmx) {
328 case SkShader::kClamp_TileMode:
329 return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm));
330 case SkShader::kRepeat_TileMode:
331 if (is_pow2(bm.width()) && is_pow2(bm.height()))
332 return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm));
333 else
334 return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm));
335 case SkShader::kMirror_TileMode:
336 if (is_pow2(bm.width()) && is_pow2(bm.height()))
337 return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm));
338 else
339 return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm));
340 default:
341 SkDEBUGFAIL("unknown mode");
342 }
343 }
344 else { // tmx != tmy
345 return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy));
346 }
347 break;
348
349 case SkBitmap::kRGB_565_Config:
350 if (doFilter)
351 return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy));
352
353 if (tmx == tmy) {
354 switch (tmx) {
355 case SkShader::kClamp_TileMode:
356 return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm));
357 case SkShader::kRepeat_TileMode:
358 if (is_pow2(bm.width()) && is_pow2(bm.height()))
359 return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm));
360 else
361 return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm));
362 case SkShader::kMirror_TileMode:
363 if (is_pow2(bm.width()) && is_pow2(bm.height()))
364 return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm));
365 else
366 return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm));
367 default:
368 SkDEBUGFAIL("unknown mode");
369 }
370 }
371 else { // tmx != tmy
372 return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy));
373 }
374 break;
375
376 case SkBitmap::kIndex8_Config:
377 if (doFilter)
378 return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy));
379
380 if (tmx == tmy) {
381 switch (tmx) {
382 case SkShader::kClamp_TileMode:
383 return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm));
384 case SkShader::kRepeat_TileMode:
385 if (is_pow2(bm.width()) && is_pow2(bm.height()))
386 return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm));
387 else
388 return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm));
389 case SkShader::kMirror_TileMode:
390 if (is_pow2(bm.width()) && is_pow2(bm.height()))
391 return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm));
392 else
393 return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm));
394 default:
395 SkDEBUGFAIL("unknown mode");
396 }
397 }
398 else { // tmx != tmy
399 return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy));
400 }
401 break;
402
403 case SkBitmap::kA8_Config:
404 if (doFilter)
405 return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy));
406 else
407 return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy));
408 break;
409
410 default:
411 SkDEBUGFAIL("unknown device");
412 }
413 return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy));
414 }
415
416