Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkBlitMask.h"
      9 #include "SkColor.h"
     10 #include "SkColorPriv.h"
     11 
     12 static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB,
     13                          const void* SK_RESTRICT maskPtr, size_t maskRB,
     14                          SkColor color, int width, int height) {
     15     SkPMColor pmc = SkPreMultiplyColor(color);
     16     size_t dstOffset = dstRB - (width << 2);
     17     size_t maskOffset = maskRB - width;
     18     SkPMColor* SK_RESTRICT device = (SkPMColor *)dst;
     19     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
     20 
     21     do {
     22         int w = width;
     23         do {
     24             unsigned aa = *mask++;
     25             *device = SkBlendARGB32(pmc, *device, aa);
     26             device += 1;
     27         } while (--w != 0);
     28         device = (uint32_t*)((char*)device + dstOffset);
     29         mask += maskOffset;
     30     } while (--height != 0);
     31 }
     32 
     33 static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB,
     34                           const void* SK_RESTRICT maskPtr, size_t maskRB,
     35                           SkColor color, int width, int height) {
     36     SkPMColor pmc = SkPreMultiplyColor(color);
     37     SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
     38     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
     39 
     40     maskRB -= width;
     41     dstRB -= (width << 2);
     42     do {
     43         int w = width;
     44         do {
     45             unsigned aa = *mask++;
     46             *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
     47             device += 1;
     48         } while (--w != 0);
     49         device = (uint32_t*)((char*)device + dstRB);
     50         mask += maskRB;
     51     } while (--height != 0);
     52 }
     53 
     54 static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB,
     55                          const void* SK_RESTRICT maskPtr, size_t maskRB,
     56                          SkColor, int width, int height) {
     57     SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
     58     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
     59 
     60     maskRB -= width;
     61     dstRB -= (width << 2);
     62     do {
     63         int w = width;
     64         do {
     65             unsigned aa = *mask++;
     66             *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
     67             device += 1;
     68         } while (--w != 0);
     69         device = (uint32_t*)((char*)device + dstRB);
     70         mask += maskRB;
     71     } while (--height != 0);
     72 }
     73 
     74 SkBlitMask::BlitLCD16RowProc SkBlitMask::BlitLCD16RowFactory(bool isOpaque) {
     75     BlitLCD16RowProc proc = PlatformBlitRowProcs16(isOpaque);
     76     if (proc) {
     77         return proc;
     78     }
     79 
     80     if (isOpaque) {
     81         return  SkBlitLCD16OpaqueRow;
     82     } else {
     83         return  SkBlitLCD16Row;
     84     }
     85 }
     86 
     87 static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
     88                            const void* SK_RESTRICT mask, size_t maskRB,
     89                            SkColor color, int width, int height) {
     90 
     91     SkPMColor*        dstRow = (SkPMColor*)dst;
     92     const uint16_t* srcRow = (const uint16_t*)mask;
     93     SkPMColor       opaqueDst;
     94 
     95     SkBlitMask::BlitLCD16RowProc proc = NULL;
     96     bool isOpaque = (0xFF == SkColorGetA(color));
     97     proc = SkBlitMask::BlitLCD16RowFactory(isOpaque);
     98     SkASSERT(proc != NULL);
     99 
    100     if (isOpaque) {
    101         opaqueDst = SkPreMultiplyColor(color);
    102     } else {
    103         opaqueDst = 0;  // ignored
    104     }
    105 
    106     do {
    107         proc(dstRow, srcRow, color, width, opaqueDst);
    108         dstRow = (SkPMColor*)((char*)dstRow + dstRB);
    109         srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
    110     } while (--height != 0);
    111 }
    112 
    113 ///////////////////////////////////////////////////////////////////////////////
    114 
    115 static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) {
    116     if (SK_ColorBLACK == color) {
    117         return D32_A8_Black;
    118     } else if (0xFF == SkColorGetA(color)) {
    119         return D32_A8_Opaque;
    120     } else {
    121         return D32_A8_Color;
    122     }
    123 }
    124 
    125 SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkColorType ct,
    126                                                SkMask::Format format,
    127                                                SkColor color) {
    128     ColorProc proc = PlatformColorProcs(ct, format, color);
    129     if (proc) {
    130         return proc;
    131     }
    132 
    133     switch (ct) {
    134         case kN32_SkColorType:
    135             switch (format) {
    136                 case SkMask::kA8_Format:
    137                     return D32_A8_Factory(color);
    138                 case SkMask::kLCD16_Format:
    139                     return D32_LCD16_Proc;
    140                 default:
    141                     break;
    142             }
    143             break;
    144         default:
    145             break;
    146     }
    147     return NULL;
    148 }
    149 
    150 bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
    151                            const SkIRect& clip, SkColor color) {
    152     ColorProc proc = ColorFactory(device.colorType(), mask.fFormat, color);
    153     if (proc) {
    154         int x = clip.fLeft;
    155         int y = clip.fTop;
    156         proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y),
    157              mask.fRowBytes, color, clip.width(), clip.height());
    158         return true;
    159     }
    160     return false;
    161 }
    162 
    163 ///////////////////////////////////////////////////////////////////////////////
    164 ///////////////////////////////////////////////////////////////////////////////
    165 
    166 static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
    167                              const uint8_t* SK_RESTRICT mask,
    168                              const SkPMColor* SK_RESTRICT src, int count) {
    169     int i, octuple = (count + 7) >> 3;
    170     for (i = 0; i < octuple; ++i) {
    171         int m = *mask++;
    172         if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
    173         if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); }
    174         if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); }
    175         if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); }
    176         if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); }
    177         if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); }
    178         if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); }
    179         if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); }
    180         src += 8;
    181         dst += 8;
    182     }
    183     count &= 7;
    184     if (count > 0) {
    185         int m = *mask;
    186         do {
    187             if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
    188             m <<= 1;
    189             src += 1;
    190             dst += 1;
    191         } while (--count > 0);
    192     }
    193 }
    194 
    195 static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
    196                               const uint8_t* SK_RESTRICT mask,
    197                               const SkPMColor* SK_RESTRICT src, int count) {
    198     int i, octuple = (count + 7) >> 3;
    199     for (i = 0; i < octuple; ++i) {
    200         int m = *mask++;
    201         if (m & 0x80) { dst[0] = src[0]; }
    202         if (m & 0x40) { dst[1] = src[1]; }
    203         if (m & 0x20) { dst[2] = src[2]; }
    204         if (m & 0x10) { dst[3] = src[3]; }
    205         if (m & 0x08) { dst[4] = src[4]; }
    206         if (m & 0x04) { dst[5] = src[5]; }
    207         if (m & 0x02) { dst[6] = src[6]; }
    208         if (m & 0x01) { dst[7] = src[7]; }
    209         src += 8;
    210         dst += 8;
    211     }
    212     count &= 7;
    213     if (count > 0) {
    214         int m = *mask;
    215         do {
    216             if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
    217             m <<= 1;
    218             src += 1;
    219             dst += 1;
    220         } while (--count > 0);
    221     }
    222 }
    223 
    224 static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
    225                              const uint8_t* SK_RESTRICT mask,
    226                              const SkPMColor* SK_RESTRICT src, int count) {
    227     for (int i = 0; i < count; ++i) {
    228         if (mask[i]) {
    229             dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]);
    230         }
    231     }
    232 }
    233 
    234 // expand the steps that SkAlphaMulQ performs, but this way we can
    235 //  exand.. add.. combine
    236 // instead of
    237 // expand..combine add expand..combine
    238 //
    239 #define EXPAND0(v, m, s)    ((v) & (m)) * (s)
    240 #define EXPAND1(v, m, s)    (((v) >> 8) & (m)) * (s)
    241 #define COMBINE(e0, e1, m)  ((((e0) >> 8) & (m)) | ((e1) & ~(m)))
    242 
    243 static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
    244                               const uint8_t* SK_RESTRICT mask,
    245                               const SkPMColor* SK_RESTRICT src, int count) {
    246     for (int i = 0; i < count; ++i) {
    247         int m = mask[i];
    248         if (m) {
    249             m += (m >> 7);
    250 #if 1
    251             // this is slightly slower than the expand/combine version, but it
    252             // is much closer to the old results, so we use it for now to reduce
    253             // rebaselining.
    254             dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m);
    255 #else
    256             uint32_t v = src[i];
    257             uint32_t s0 = EXPAND0(v, rbmask, m);
    258             uint32_t s1 = EXPAND1(v, rbmask, m);
    259             v = dst[i];
    260             uint32_t d0 = EXPAND0(v, rbmask, m);
    261             uint32_t d1 = EXPAND1(v, rbmask, m);
    262             dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask);
    263 #endif
    264         }
    265     }
    266 }
    267 
    268 static int upscale31To255(int value) {
    269     value = (value << 3) | (value >> 2);
    270     return value;
    271 }
    272 
    273 static int src_alpha_blend(int src, int dst, int srcA, int mask) {
    274 
    275     return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask);
    276 }
    277 
    278 static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
    279                                 const uint16_t* SK_RESTRICT mask,
    280                                 const SkPMColor* SK_RESTRICT src, int count) {
    281     for (int i = 0; i < count; ++i) {
    282         uint16_t m = mask[i];
    283         if (0 == m) {
    284             continue;
    285         }
    286 
    287         SkPMColor s = src[i];
    288         SkPMColor d = dst[i];
    289 
    290         int srcA = SkGetPackedA32(s);
    291         int srcR = SkGetPackedR32(s);
    292         int srcG = SkGetPackedG32(s);
    293         int srcB = SkGetPackedB32(s);
    294 
    295         srcA += srcA >> 7;
    296 
    297         /*  We want all of these in 5bits, hence the shifts in case one of them
    298          *  (green) is 6bits.
    299          */
    300         int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
    301         int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
    302         int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
    303 
    304         maskR = upscale31To255(maskR);
    305         maskG = upscale31To255(maskG);
    306         maskB = upscale31To255(maskB);
    307 
    308         int dstR = SkGetPackedR32(d);
    309         int dstG = SkGetPackedG32(d);
    310         int dstB = SkGetPackedB32(d);
    311 
    312         // LCD blitting is only supported if the dst is known/required
    313         // to be opaque
    314         dst[i] = SkPackARGB32(0xFF,
    315                               src_alpha_blend(srcR, dstR, srcA, maskR),
    316                               src_alpha_blend(srcG, dstG, srcA, maskG),
    317                               src_alpha_blend(srcB, dstB, srcA, maskB));
    318     }
    319 }
    320 
    321 static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
    322                                  const uint16_t* SK_RESTRICT mask,
    323                                  const SkPMColor* SK_RESTRICT src, int count) {
    324     for (int i = 0; i < count; ++i) {
    325         uint16_t m = mask[i];
    326         if (0 == m) {
    327             continue;
    328         }
    329 
    330         SkPMColor s = src[i];
    331         SkPMColor d = dst[i];
    332 
    333         int srcR = SkGetPackedR32(s);
    334         int srcG = SkGetPackedG32(s);
    335         int srcB = SkGetPackedB32(s);
    336 
    337         /*  We want all of these in 5bits, hence the shifts in case one of them
    338          *  (green) is 6bits.
    339          */
    340         int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
    341         int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
    342         int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
    343 
    344         // Now upscale them to 0..32, so we can use blend32
    345         maskR = SkUpscale31To32(maskR);
    346         maskG = SkUpscale31To32(maskG);
    347         maskB = SkUpscale31To32(maskB);
    348 
    349         int dstR = SkGetPackedR32(d);
    350         int dstG = SkGetPackedG32(d);
    351         int dstB = SkGetPackedB32(d);
    352 
    353         // LCD blitting is only supported if the dst is known/required
    354         // to be opaque
    355         dst[i] = SkPackARGB32(0xFF,
    356                               SkBlend32(srcR, dstR, maskR),
    357                               SkBlend32(srcG, dstG, maskG),
    358                               SkBlend32(srcB, dstB, maskB));
    359     }
    360 }
    361 
    362 SkBlitMask::RowProc SkBlitMask::RowFactory(SkColorType ct,
    363                                            SkMask::Format format,
    364                                            RowFlags flags) {
    365 // make this opt-in until chrome can rebaseline
    366     RowProc proc = PlatformRowProcs(ct, format, flags);
    367     if (proc) {
    368         return proc;
    369     }
    370 
    371     static const RowProc gProcs[] = {
    372         // need X coordinate to handle BW
    373         false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning
    374         false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning
    375         (RowProc)A8_RowProc_Blend,      (RowProc)A8_RowProc_Opaque,
    376         (RowProc)LCD16_RowProc_Blend,   (RowProc)LCD16_RowProc_Opaque,
    377     };
    378 
    379     int index;
    380     switch (ct) {
    381         case kN32_SkColorType:
    382             switch (format) {
    383                 case SkMask::kBW_Format:    index = 0; break;
    384                 case SkMask::kA8_Format:    index = 2; break;
    385                 case SkMask::kLCD16_Format: index = 4; break;
    386                 default:
    387                     return NULL;
    388             }
    389             if (flags & kSrcIsOpaque_RowFlag) {
    390                 index |= 1;
    391             }
    392             SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs));
    393             return gProcs[index];
    394         default:
    395             break;
    396     }
    397     return NULL;
    398 }
    399