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