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
12static 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
27SkBitmapSampler::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
40void SkBitmapSampler::setPaint(const SkPaint& paint)
41{
42}
43
44class SkNullBitmapSampler : public SkBitmapSampler {
45public:
46    SkNullBitmapSampler(const SkBitmap& bm, bool filter,
47                        SkShader::TileMode tmx, SkShader::TileMode tmy)
48        : SkBitmapSampler(bm, filter, tmx, tmy) {}
49
50    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
76class ARGB32_Bilinear_Sampler : public SkBitmapSampler {
77public:
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
84    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
120private:
121    const SkFilterPtrProc* fPtrProcTable;
122};
123
124class RGB16_Bilinear_Sampler : public SkBitmapSampler {
125public:
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
132    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
171private:
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
178class Index8_Bilinear_Sampler : public SkBitmapSampler {
179public:
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
186    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
229private:
230    const SkFilterPtrProc* fPtrProcTable;
231};
232
233class A8_Bilinear_Sampler : public SkBitmapSampler {
234public:
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
241    virtual void setPaint(const SkPaint& paint)
242    {
243        fColor = SkPreMultiplyColor(paint.getColor());
244    }
245
246    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
283private:
284    const SkFilterProc* fProcTable;
285    SkPMColor           fColor;
286};
287
288class A8_NoFilter_Sampler : public SkBitmapSampler {
289public:
290    A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
291        : SkBitmapSampler(bm, false, tmx, tmy)
292    {
293    }
294
295    virtual void setPaint(const SkPaint& paint)
296    {
297        fColor = SkPreMultiplyColor(paint.getColor());
298    }
299
300    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
309private:
310    const SkFilterProc* fProcTable;
311    SkPMColor           fColor;
312};
313
314///////////////////////////////////////////////////////////////////////////////
315///////////////////////////////////////////////////////////////////////////////
316
317SkBitmapSampler* 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