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