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 "SkSpriteBlitter.h"
     11 #include "SkBlitRow.h"
     12 #include "SkTemplates.h"
     13 #include "SkUtils.h"
     14 #include "SkColorPriv.h"
     15 
     16 #define D16_S32A_Opaque_Pixel(dst, sc)                                        \
     17 do {                                                                          \
     18     if (sc) {                                                                 \
     19         *dst = SkSrcOver32To16(sc, *dst);                                     \
     20     }                                                                         \
     21 } while (0)
     22 
     23 static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
     24                                                unsigned src_scale) {
     25     uint16_t dc = *dst;
     26     unsigned sa = SkGetPackedA32(sc);
     27     unsigned dr, dg, db;
     28 
     29     if (255 == sa) {
     30         dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
     31         dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
     32         db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
     33     } else {
     34         unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale);
     35         dr = (SkPacked32ToR16(sc) * src_scale +
     36               SkGetPackedR16(dc) * dst_scale) >> 8;
     37         dg = (SkPacked32ToG16(sc) * src_scale +
     38               SkGetPackedG16(dc) * dst_scale) >> 8;
     39         db = (SkPacked32ToB16(sc) * src_scale +
     40               SkGetPackedB16(dc) * dst_scale) >> 8;
     41     }
     42     *dst = SkPackRGB16(dr, dg, db);
     43 }
     44 
     45 #define D16_S32A_Blend_Pixel(dst, sc, src_scale) \
     46     do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)
     47 
     48 
     49 ///////////////////////////////////////////////////////////////////////////////
     50 
     51 class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
     52 public:
     53     Sprite_D16_S16_Opaque(const SkBitmap& source)
     54         : SkSpriteBlitter(source) {}
     55 
     56     // overrides
     57     virtual void blitRect(int x, int y, int width, int height) {
     58         uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
     59         const uint16_t* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
     60                                                              y - fTop);
     61         unsigned dstRB = fDevice->rowBytes();
     62         unsigned srcRB = fSource->rowBytes();
     63 
     64         while (--height >= 0) {
     65             memcpy(dst, src, width << 1);
     66             dst = (uint16_t*)((char*)dst + dstRB);
     67             src = (const uint16_t*)((const char*)src + srcRB);
     68         }
     69     }
     70 };
     71 
     72 #define D16_S16_Blend_Pixel(dst, sc, scale)     \
     73     do {                                        \
     74         uint16_t dc = *dst;                     \
     75         *dst = SkBlendRGB16(sc, dc, scale);     \
     76     } while (0)
     77 
     78 #define SkSPRITE_CLASSNAME                  Sprite_D16_S16_Blend
     79 #define SkSPRITE_ARGS                       , uint8_t alpha
     80 #define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
     81 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
     82 #define SkSPRITE_DST_TYPE                   uint16_t
     83 #define SkSPRITE_SRC_TYPE                   uint16_t
     84 #define SkSPRITE_DST_GETADDR                getAddr16
     85 #define SkSPRITE_SRC_GETADDR                getAddr16
     86 #define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha255To256(fSrcAlpha);
     87 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, src, scale)
     88 #define SkSPRITE_NEXT_ROW
     89 #define SkSPRITE_POSTAMBLE(srcBM)
     90 #include "SkSpriteBlitterTemplate.h"
     91 
     92 ///////////////////////////////////////////////////////////////////////////////
     93 
     94 #define D16_S4444_Opaque(dst, sc)           \
     95     do {                                    \
     96         uint16_t dc = *dst;                 \
     97         *dst = SkSrcOver4444To16(sc, dc);   \
     98     } while (0)
     99 
    100 #define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Opaque
    101 #define SkSPRITE_ARGS
    102 #define SkSPRITE_FIELDS
    103 #define SkSPRITE_INIT
    104 #define SkSPRITE_DST_TYPE                   uint16_t
    105 #define SkSPRITE_SRC_TYPE                   SkPMColor16
    106 #define SkSPRITE_DST_GETADDR                getAddr16
    107 #define SkSPRITE_SRC_GETADDR                getAddr16
    108 #define SkSPRITE_PREAMBLE(srcBM, x, y)
    109 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Opaque(dst, src)
    110 #define SkSPRITE_NEXT_ROW
    111 #define SkSPRITE_POSTAMBLE(srcBM)
    112 #include "SkSpriteBlitterTemplate.h"
    113 
    114 #define D16_S4444_Blend(dst, sc, scale16)           \
    115     do {                                            \
    116         uint16_t dc = *dst;                         \
    117         *dst = SkBlend4444To16(sc, dc, scale16);    \
    118     } while (0)
    119 
    120 
    121 #define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Blend
    122 #define SkSPRITE_ARGS                       , uint8_t alpha
    123 #define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
    124 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    125 #define SkSPRITE_DST_TYPE                   uint16_t
    126 #define SkSPRITE_SRC_TYPE                   uint16_t
    127 #define SkSPRITE_DST_GETADDR                getAddr16
    128 #define SkSPRITE_SRC_GETADDR                getAddr16
    129 #define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha15To16(fSrcAlpha);
    130 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Blend(dst, src, scale)
    131 #define SkSPRITE_NEXT_ROW
    132 #define SkSPRITE_POSTAMBLE(srcBM)
    133 #include "SkSpriteBlitterTemplate.h"
    134 
    135 ///////////////////////////////////////////////////////////////////////////////
    136 
    137 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Opaque
    138 #define SkSPRITE_ARGS
    139 #define SkSPRITE_FIELDS
    140 #define SkSPRITE_INIT
    141 #define SkSPRITE_DST_TYPE                   uint16_t
    142 #define SkSPRITE_SRC_TYPE                   uint8_t
    143 #define SkSPRITE_DST_GETADDR                getAddr16
    144 #define SkSPRITE_SRC_GETADDR                getAddr8
    145 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors()
    146 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Opaque_Pixel(dst, ctable[src])
    147 #define SkSPRITE_NEXT_ROW
    148 #define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors(false)
    149 #include "SkSpriteBlitterTemplate.h"
    150 
    151 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Blend
    152 #define SkSPRITE_ARGS                       , uint8_t alpha
    153 #define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
    154 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    155 #define SkSPRITE_DST_TYPE                   uint16_t
    156 #define SkSPRITE_SRC_TYPE                   uint8_t
    157 #define SkSPRITE_DST_GETADDR                getAddr16
    158 #define SkSPRITE_SRC_GETADDR                getAddr8
    159 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
    160 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
    161 #define SkSPRITE_NEXT_ROW
    162 #define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors(false);
    163 #include "SkSpriteBlitterTemplate.h"
    164 
    165 ///////////////////////////////////////////////////////////////////////////////
    166 
    167 static intptr_t asint(const void* ptr) {
    168     return reinterpret_cast<const char*>(ptr) - (const char*)0;
    169 }
    170 
    171 static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
    172                             const uint8_t* SK_RESTRICT src, int count,
    173                             const uint16_t* SK_RESTRICT ctable) {
    174     if (count <= 8) {
    175         do {
    176             *dst++ = ctable[*src++];
    177         } while (--count);
    178         return;
    179     }
    180 
    181     // eat src until we're on a 4byte boundary
    182     while (asint(src) & 3) {
    183         *dst++ = ctable[*src++];
    184         count -= 1;
    185     }
    186 
    187     int qcount = count >> 2;
    188     SkASSERT(qcount > 0);
    189     const uint32_t* qsrc = reinterpret_cast<const uint32_t*>(src);
    190     if (asint(dst) & 2) {
    191         do {
    192             uint32_t s4 = *qsrc++;
    193 #ifdef SK_CPU_LENDIAN
    194             *dst++ = ctable[s4 & 0xFF];
    195             *dst++ = ctable[(s4 >> 8) & 0xFF];
    196             *dst++ = ctable[(s4 >> 16) & 0xFF];
    197             *dst++ = ctable[s4 >> 24];
    198 #else   // BENDIAN
    199             *dst++ = ctable[s4 >> 24];
    200             *dst++ = ctable[(s4 >> 16) & 0xFF];
    201             *dst++ = ctable[(s4 >> 8) & 0xFF];
    202             *dst++ = ctable[s4 & 0xFF];
    203 #endif
    204         } while (--qcount);
    205     } else {    // dst is on a 4byte boundary
    206         uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
    207         do {
    208             uint32_t s4 = *qsrc++;
    209 #ifdef SK_CPU_LENDIAN
    210             *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
    211             *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
    212 #else   // BENDIAN
    213             *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
    214             *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
    215 #endif
    216         } while (--qcount);
    217         dst = reinterpret_cast<uint16_t*>(ddst);
    218     }
    219     src = reinterpret_cast<const uint8_t*>(qsrc);
    220     count &= 3;
    221     // catch any remaining (will be < 4)
    222     while (--count >= 0) {
    223         *dst++ = ctable[*src++];
    224     }
    225 }
    226 
    227 #define SkSPRITE_ROW_PROC(d, s, n, x, y)    blitrow_d16_si8(d, s, n, ctable)
    228 
    229 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Opaque
    230 #define SkSPRITE_ARGS
    231 #define SkSPRITE_FIELDS
    232 #define SkSPRITE_INIT
    233 #define SkSPRITE_DST_TYPE                   uint16_t
    234 #define SkSPRITE_SRC_TYPE                   uint8_t
    235 #define SkSPRITE_DST_GETADDR                getAddr16
    236 #define SkSPRITE_SRC_GETADDR                getAddr8
    237 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache()
    238 #define SkSPRITE_BLIT_PIXEL(dst, src)       *dst = ctable[src]
    239 #define SkSPRITE_NEXT_ROW
    240 #define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlock16BitCache()
    241 #include "SkSpriteBlitterTemplate.h"
    242 
    243 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Blend
    244 #define SkSPRITE_ARGS                       , uint8_t alpha
    245 #define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
    246 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    247 #define SkSPRITE_DST_TYPE                   uint16_t
    248 #define SkSPRITE_SRC_TYPE                   uint8_t
    249 #define SkSPRITE_DST_GETADDR                getAddr16
    250 #define SkSPRITE_SRC_GETADDR                getAddr8
    251 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
    252 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
    253 #define SkSPRITE_NEXT_ROW
    254 #define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlock16BitCache();
    255 #include "SkSpriteBlitterTemplate.h"
    256 
    257 ///////////////////////////////////////////////////////////////////////////////
    258 
    259 class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
    260 public:
    261     Sprite_D16_S32_BlitRowProc(const SkBitmap& source)
    262         : SkSpriteBlitter(source) {}
    263 
    264     // overrides
    265 
    266     virtual void setup(const SkBitmap& device, int left, int top,
    267                        const SkPaint& paint) {
    268         this->INHERITED::setup(device, left, top, paint);
    269 
    270         unsigned flags = 0;
    271 
    272         if (paint.getAlpha() < 0xFF) {
    273             flags |= SkBlitRow::kGlobalAlpha_Flag;
    274         }
    275         if (!fSource->isOpaque()) {
    276             flags |= SkBlitRow::kSrcPixelAlpha_Flag;
    277         }
    278         if (paint.isDither()) {
    279             flags |= SkBlitRow::kDither_Flag;
    280         }
    281         fProc = SkBlitRow::Factory(flags, SkBitmap::kRGB_565_Config);
    282     }
    283 
    284     virtual void blitRect(int x, int y, int width, int height) {
    285         uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
    286         const SkPMColor* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
    287                                                               y - fTop);
    288         unsigned dstRB = fDevice->rowBytes();
    289         unsigned srcRB = fSource->rowBytes();
    290         SkBlitRow::Proc proc = fProc;
    291         U8CPU alpha = fPaint->getAlpha();
    292 
    293         while (--height >= 0) {
    294             proc(dst, src, width, alpha, x, y);
    295             y += 1;
    296             dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
    297             src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
    298         }
    299     }
    300 
    301 private:
    302     SkBlitRow::Proc fProc;
    303 
    304     typedef SkSpriteBlitter INHERITED;
    305 };
    306 
    307 ///////////////////////////////////////////////////////////////////////////////
    308 
    309 #include "SkTemplatesPriv.h"
    310 
    311 SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source,
    312                                             const SkPaint& paint,
    313                                             void* storage, size_t storageSize) {
    314     if (paint.getMaskFilter() != NULL) { // may add cases for this
    315         return NULL;
    316     }
    317     if (paint.getXfermode() != NULL) { // may add cases for this
    318         return NULL;
    319     }
    320     if (paint.getColorFilter() != NULL) { // may add cases for this
    321         return NULL;
    322     }
    323 
    324     SkSpriteBlitter* blitter = NULL;
    325     unsigned alpha = paint.getAlpha();
    326 
    327     switch (source.getConfig()) {
    328         case SkBitmap::kARGB_8888_Config:
    329             SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_BlitRowProc,
    330                                   storage, storageSize, (source));
    331             break;
    332         case SkBitmap::kARGB_4444_Config:
    333             if (255 == alpha) {
    334                 SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Opaque,
    335                                       storage, storageSize, (source));
    336             } else {
    337                 SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Blend,
    338                                     storage, storageSize, (source, alpha >> 4));
    339             }
    340             break;
    341         case SkBitmap::kRGB_565_Config:
    342             if (255 == alpha) {
    343                 SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Opaque,
    344                                       storage, storageSize, (source));
    345             } else {
    346                 SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Blend,
    347                                       storage, storageSize, (source, alpha));
    348             }
    349             break;
    350         case SkBitmap::kIndex8_Config:
    351             if (paint.isDither()) {
    352                 // we don't support dither yet in these special cases
    353                 break;
    354             }
    355             if (source.isOpaque()) {
    356                 if (255 == alpha) {
    357                     SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Opaque,
    358                                           storage, storageSize, (source));
    359                 } else {
    360                     SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Blend,
    361                                          storage, storageSize, (source, alpha));
    362                 }
    363             } else {
    364                 if (255 == alpha) {
    365                     SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Opaque,
    366                                           storage, storageSize, (source));
    367                 } else {
    368                     SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Blend,
    369                                          storage, storageSize, (source, alpha));
    370                 }
    371             }
    372             break;
    373         default:
    374             break;
    375     }
    376     return blitter;
    377 }
    378