Home | History | Annotate | Download | only in core
      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 
     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 
     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 
     48 void SkBitmapSampler::setPaint(const SkPaint& paint)
     49 {
     50 }
     51 
     52 class SkNullBitmapSampler : public SkBitmapSampler {
     53 public:
     54     SkNullBitmapSampler(const SkBitmap& bm, bool filter,
     55                         SkShader::TileMode tmx, SkShader::TileMode tmy)
     56         : SkBitmapSampler(bm, filter, tmx, tmy) {}
     57 
     58     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:
     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 
     92     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:
    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 
    140     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:
    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 
    194     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:
    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 
    249     virtual void setPaint(const SkPaint& paint)
    250     {
    251         fColor = SkPreMultiplyColor(paint.getColor());
    252     }
    253 
    254     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:
    298     A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
    299         : SkBitmapSampler(bm, false, tmx, tmy)
    300     {
    301     }
    302 
    303     virtual void setPaint(const SkPaint& paint)
    304     {
    305         fColor = SkPreMultiplyColor(paint.getColor());
    306     }
    307 
    308     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 
    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