• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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