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     {
    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 
    283 private:
    284     const SkFilterProc* fProcTable;
    285     SkPMColor           fColor;
    286 };
    287 
    288 class A8_NoFilter_Sampler : public SkBitmapSampler {
    289 public:
    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 
    309 private:
    310     const SkFilterProc* fProcTable;
    311     SkPMColor           fColor;
    312 };
    313 
    314 ///////////////////////////////////////////////////////////////////////////////
    315 ///////////////////////////////////////////////////////////////////////////////
    316 
    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