Home | History | Annotate | Download | only in core
      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 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 
     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 
     40 void SkBitmapSampler::setPaint(const SkPaint& paint)
     41 {
     42 }
     43 
     44 class SkNullBitmapSampler : public SkBitmapSampler {
     45 public:
     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 
     76 class ARGB32_Bilinear_Sampler : public SkBitmapSampler {
     77 public:
     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 
    120 private:
    121     const SkFilterPtrProc* fPtrProcTable;
    122 };
    123 
    124 class RGB16_Bilinear_Sampler : public SkBitmapSampler {
    125 public:
    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 
    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:
    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 
    229 private:
    230     const SkFilterPtrProc* fPtrProcTable;
    231 };
    232 
    233 class A8_Bilinear_Sampler : public SkBitmapSampler {
    234 public:
    235     A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
    236         : SkBitmapSampler(bm, true, tmx, tmy)
    237         , fColor(0)
    238     {
    239         fProcTable = SkGetBilinearFilterProcTable();
    240     }
    241 
    242     virtual void setPaint(const SkPaint& paint)
    243     {
    244         fColor = SkPreMultiplyColor(paint.getColor());
    245     }
    246 
    247     virtual SkPMColor sample(SkFixed x, SkFixed y) const
    248     {
    249         const uint8_t *p00, *p01, *p10, *p11;
    250 
    251         // turn pixel centers into the top-left of our filter-box
    252         x -= SK_FixedHalf;
    253         y -= SK_FixedHalf;
    254 
    255         // compute our pointers
    256         {
    257             const SkBitmap* bitmap = &fBitmap;
    258             int ix = x >> 16;
    259             int iy = y >> 16;
    260 
    261             int             maxX = fMaxX;
    262             SkTileModeProc  procX = fTileProcX;
    263             int             maxY = fMaxY;
    264             SkTileModeProc  procY = fTileProcY;
    265 
    266             int tmpx = procX(ix, maxX);
    267             int tmpy = procY(iy, maxY);
    268             p00 = bitmap->getAddr8(tmpx, tmpy);
    269 
    270             int tmpx1 = procX(ix + 1, maxX);
    271             p01 = bitmap->getAddr8(tmpx1, tmpy);
    272 
    273             int tmpy1 = procY(iy + 1, maxY);
    274             p10 = bitmap->getAddr8(tmpx, tmpy1);
    275 
    276             p11 = bitmap->getAddr8(tmpx1, tmpy1);
    277         }
    278 
    279         SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
    280         int alpha = proc(*p00, *p01, *p10, *p11);
    281         return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
    282     }
    283 
    284 private:
    285     const SkFilterProc* fProcTable;
    286     SkPMColor           fColor;
    287 };
    288 
    289 class A8_NoFilter_Sampler : public SkBitmapSampler {
    290 public:
    291     A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
    292         : SkBitmapSampler(bm, false, tmx, tmy)
    293         , fProcTable(NULL)
    294     {
    295     }
    296 
    297     virtual void setPaint(const SkPaint& paint)
    298     {
    299         fColor = SkPreMultiplyColor(paint.getColor());
    300     }
    301 
    302     virtual SkPMColor sample(SkFixed x, SkFixed y) const
    303     {
    304         int ix = SkFixedFloor(x);
    305         int iy = SkFixedFloor(y);
    306 
    307         int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY));
    308         return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
    309     }
    310 
    311 private:
    312     const SkFilterProc* fProcTable;
    313     SkPMColor           fColor;
    314 };
    315 
    316 ///////////////////////////////////////////////////////////////////////////////
    317 ///////////////////////////////////////////////////////////////////////////////
    318 
    319 SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
    320                                          SkShader::TileMode tmx,
    321                                          SkShader::TileMode tmy)
    322 {
    323     switch (bm.getConfig()) {
    324     case SkBitmap::kARGB_8888_Config:
    325         if (doFilter)
    326             return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy));
    327 
    328         if (tmx == tmy) {
    329             switch (tmx) {
    330             case SkShader::kClamp_TileMode:
    331                 return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm));
    332             case SkShader::kRepeat_TileMode:
    333                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    334                     return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm));
    335                 else
    336                     return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm));
    337             case SkShader::kMirror_TileMode:
    338                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    339                     return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm));
    340                 else
    341                     return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm));
    342             default:
    343                 SkDEBUGFAIL("unknown mode");
    344             }
    345         }
    346         else {  // tmx != tmy
    347             return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy));
    348         }
    349         break;
    350 
    351     case SkBitmap::kRGB_565_Config:
    352         if (doFilter)
    353             return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy));
    354 
    355         if (tmx == tmy) {
    356             switch (tmx) {
    357             case SkShader::kClamp_TileMode:
    358                 return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm));
    359             case SkShader::kRepeat_TileMode:
    360                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    361                     return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm));
    362                 else
    363                     return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm));
    364             case SkShader::kMirror_TileMode:
    365                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    366                     return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm));
    367                 else
    368                     return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm));
    369             default:
    370                 SkDEBUGFAIL("unknown mode");
    371             }
    372         }
    373         else {  // tmx != tmy
    374             return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy));
    375         }
    376         break;
    377 
    378     case SkBitmap::kIndex8_Config:
    379         if (doFilter)
    380             return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy));
    381 
    382         if (tmx == tmy) {
    383             switch (tmx) {
    384             case SkShader::kClamp_TileMode:
    385                 return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm));
    386             case SkShader::kRepeat_TileMode:
    387                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    388                     return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm));
    389                 else
    390                     return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm));
    391             case SkShader::kMirror_TileMode:
    392                 if (is_pow2(bm.width()) && is_pow2(bm.height()))
    393                     return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm));
    394                 else
    395                     return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm));
    396             default:
    397                 SkDEBUGFAIL("unknown mode");
    398             }
    399         }
    400         else {  // tmx != tmy
    401             return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy));
    402         }
    403         break;
    404 
    405     case SkBitmap::kA8_Config:
    406         if (doFilter)
    407             return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy));
    408         else
    409             return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy));
    410         break;
    411 
    412     default:
    413         SkDEBUGFAIL("unknown device");
    414     }
    415     return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy));
    416 }
    417