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