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 "SkCoreBlitters.h"
     11 #include "SkColorPriv.h"
     12 #include "SkDither.h"
     13 #include "SkShader.h"
     14 #include "SkTemplatesPriv.h"
     15 #include "SkUtils.h"
     16 #include "SkXfermode.h"
     17 
     18 static inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst,
     19                                         U8CPU aa) {
     20     SkASSERT((unsigned)aa <= 255);
     21 
     22     unsigned src_scale = SkAlpha255To256(aa) >> 4;
     23     unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale));
     24 
     25     uint32_t src32 = SkExpand_4444(src) * src_scale;
     26     uint32_t dst32 = SkExpand_4444(dst) * dst_scale;
     27     return SkCompact_4444((src32 + dst32) >> 4);
     28 }
     29 
     30 ///////////////////////////////////////////////////////////////////////////////
     31 
     32 class SkARGB4444_Blitter : public SkRasterBlitter {
     33 public:
     34     SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint);
     35     virtual void blitH(int x, int y, int width);
     36     virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
     37                            const int16_t runs[]);
     38     virtual void blitV(int x, int y, int height, SkAlpha alpha);
     39     virtual void blitRect(int x, int y, int width, int height);
     40     virtual void blitMask(const SkMask&, const SkIRect&);
     41     virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
     42 
     43 protected:
     44     SkPMColor16 fPMColor16, fPMColor16Other;
     45     SkPMColor16 fRawColor16, fRawColor16Other;
     46     uint8_t     fScale16;
     47 
     48 private:
     49     // illegal
     50     SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&);
     51 
     52     typedef SkRasterBlitter INHERITED;
     53 };
     54 
     55 
     56 SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device,
     57                                    const SkPaint& paint) : INHERITED(device) {
     58     // cache premultiplied versions in 4444
     59     SkPMColor c = SkPreMultiplyColor(paint.getColor());
     60     fPMColor16 = SkPixel32ToPixel4444(c);
     61     if (paint.isDither()) {
     62         fPMColor16Other = SkDitherPixel32To4444(c);
     63     } else {
     64         fPMColor16Other = fPMColor16;
     65     }
     66 
     67     // cache raw versions in 4444
     68     fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
     69                                  SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
     70     if (paint.isDither()) {
     71         fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
     72                                                 SkColorGetG(c), SkColorGetB(c));
     73     } else {
     74         fRawColor16Other = fRawColor16;
     75     }
     76 
     77     fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
     78     if (16 == fScale16) {
     79         // force the original to also be opaque
     80         fPMColor16 |= (0xF << SK_A4444_SHIFT);
     81     }
     82 }
     83 
     84 const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) {
     85     if (16 == fScale16) {
     86         *value = fPMColor16;
     87         return &fDevice;
     88     }
     89     return NULL;
     90 }
     91 
     92 static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color,
     93                           SkPMColor16 other, unsigned invScale, int count) {
     94     int twice = count >> 1;
     95     while (--twice >= 0) {
     96         *dst = color + SkAlphaMulQ4(*dst, invScale);
     97         dst++;
     98         *dst = other + SkAlphaMulQ4(*dst, invScale);
     99         dst++;
    100     }
    101     if (count & 1) {
    102         *dst = color + SkAlphaMulQ4(*dst, invScale);
    103     }
    104 }
    105 
    106 static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) {
    107     uint32_t c32 = SkExpand_4444(c);
    108     return c32 | (c32 << 4);
    109 }
    110 
    111 static void src_over_4444x(SkPMColor16 dst[], uint32_t color,
    112                            uint32_t other, unsigned invScale, int count) {
    113     int twice = count >> 1;
    114     uint32_t tmp;
    115     while (--twice >= 0) {
    116         tmp = SkExpand_4444(*dst) * invScale;
    117         *dst++ = SkCompact_4444((color + tmp) >> 4);
    118         tmp = SkExpand_4444(*dst) * invScale;
    119         *dst++ = SkCompact_4444((other + tmp) >> 4);
    120     }
    121     if (count & 1) {
    122         tmp = SkExpand_4444(*dst) * invScale;
    123         *dst = SkCompact_4444((color + tmp) >> 4);
    124     }
    125 }
    126 
    127 void SkARGB4444_Blitter::blitH(int x, int y, int width) {
    128     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
    129 
    130     if (0 == fScale16) {
    131         return;
    132     }
    133 
    134     SkPMColor16* device = fDevice.getAddr16(x, y);
    135     SkPMColor16  color = fPMColor16;
    136     SkPMColor16  other = fPMColor16Other;
    137 
    138     if ((x ^ y) & 1) {
    139         SkTSwap<SkPMColor16>(color, other);
    140     }
    141 
    142     if (16 == fScale16) {
    143         sk_dither_memset16(device, color, other, width);
    144     } else {
    145         src_over_4444x(device, SkExpand_4444_Replicate(color),
    146                        SkExpand_4444_Replicate(other),
    147                        16 - fScale16, width);
    148     }
    149 }
    150 
    151 void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
    152     if (0 == alpha || 0 == fScale16) {
    153         return;
    154     }
    155 
    156     SkPMColor16* device = fDevice.getAddr16(x, y);
    157     SkPMColor16  color = fPMColor16;
    158     SkPMColor16  other = fPMColor16Other;
    159     unsigned     rb = fDevice.rowBytes();
    160 
    161     if ((x ^ y) & 1) {
    162         SkTSwap<SkPMColor16>(color, other);
    163     }
    164 
    165     if (16 == fScale16 && 255 == alpha) {
    166         while (--height >= 0) {
    167             *device = color;
    168             device = (SkPMColor16*)((char*)device + rb);
    169             SkTSwap<SkPMColor16>(color, other);
    170         }
    171     } else {
    172         unsigned alphaScale = SkAlpha255To256(alpha);
    173         uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4);
    174         // need to normalize the low nibble of each expanded component
    175         // so we don't overflow the add with d32
    176         c32 = SkCompact_4444(c32 >> 4);
    177         unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32));
    178         // now re-expand and replicate
    179         c32 = SkExpand_4444_Replicate(c32);
    180 
    181         while (--height >= 0) {
    182             uint32_t d32 = SkExpand_4444(*device) * invScale;
    183             *device = SkCompact_4444((c32 + d32) >> 4);
    184             device = (SkPMColor16*)((char*)device + rb);
    185         }
    186     }
    187 }
    188 
    189 void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) {
    190     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() &&
    191              y + height <= fDevice.height());
    192 
    193     if (0 == fScale16) {
    194         return;
    195     }
    196 
    197     SkPMColor16* device = fDevice.getAddr16(x, y);
    198     SkPMColor16  color = fPMColor16;
    199     SkPMColor16  other = fPMColor16Other;
    200 
    201     if ((x ^ y) & 1) {
    202         SkTSwap<SkPMColor16>(color, other);
    203     }
    204 
    205     if (16 == fScale16) {
    206         while (--height >= 0) {
    207             sk_dither_memset16(device, color, other, width);
    208             device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
    209             SkTSwap<SkPMColor16>(color, other);
    210         }
    211     } else {
    212         unsigned invScale = 16 - fScale16;
    213 
    214         uint32_t c32 = SkExpand_4444_Replicate(color);
    215         uint32_t o32 = SkExpand_4444_Replicate(other);
    216         while (--height >= 0) {
    217             src_over_4444x(device, c32, o32, invScale, width);
    218             device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
    219             SkTSwap<uint32_t>(c32, o32);
    220         }
    221     }
    222 }
    223 
    224 void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    225                                    const int16_t runs[]) {
    226     if (0 == fScale16) {
    227         return;
    228     }
    229 
    230     SkPMColor16* device = fDevice.getAddr16(x, y);
    231     SkPMColor16  color = fPMColor16;
    232     SkPMColor16  other = fPMColor16Other;
    233 
    234     if ((x ^ y) & 1) {
    235         SkTSwap<SkPMColor16>(color, other);
    236     }
    237 
    238     for (;;) {
    239         int count = runs[0];
    240         SkASSERT(count >= 0);
    241         if (count <= 0) {
    242             return;
    243         }
    244 
    245         unsigned aa = antialias[0];
    246         if (aa) {
    247             if (0xFF == aa) {
    248                 if (16 == fScale16) {
    249                     sk_dither_memset16(device, color, other, count);
    250                 } else {
    251                     src_over_4444(device, color, other, 16 - fScale16, count);
    252                 }
    253             } else {
    254                 // todo: respect dithering
    255                 aa = SkAlpha255To256(aa);   // FIX
    256                 SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4);
    257                 unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX
    258                 int n = count;
    259                 do {
    260                     --n;
    261                     device[n] = src + SkAlphaMulQ4(device[n], dst_scale);
    262                 } while (n > 0);
    263             }
    264         }
    265 
    266         runs += count;
    267         antialias += count;
    268         device += count;
    269 
    270         if (count & 1) {
    271             SkTSwap<SkPMColor16>(color, other);
    272         }
    273     }
    274 }
    275 
    276 ///////////////////////////////////////////////////////////////////////////////
    277 
    278 #define solid_8_pixels(mask, dst, color)    \
    279     do {                                    \
    280         if (mask & 0x80) dst[0] = color;    \
    281         if (mask & 0x40) dst[1] = color;    \
    282         if (mask & 0x20) dst[2] = color;    \
    283         if (mask & 0x10) dst[3] = color;    \
    284         if (mask & 0x08) dst[4] = color;    \
    285         if (mask & 0x04) dst[5] = color;    \
    286         if (mask & 0x02) dst[6] = color;    \
    287         if (mask & 0x01) dst[7] = color;    \
    288     } while (0)
    289 
    290 #define SK_BLITBWMASK_NAME                  SkARGB4444_BlitBW
    291 #define SK_BLITBWMASK_ARGS                  , SkPMColor16 color
    292 #define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst, color)
    293 #define SK_BLITBWMASK_GETADDR               getAddr16
    294 #define SK_BLITBWMASK_DEVTYPE               uint16_t
    295 #include "SkBlitBWMaskTemplate.h"
    296 
    297 #define blend_8_pixels(mask, dst, sc, dst_scale)                             \
    298     do {                                                                     \
    299         if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); }  \
    300         if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); }  \
    301         if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); }  \
    302         if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); }  \
    303         if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); }  \
    304         if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); }  \
    305         if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); }  \
    306         if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); }  \
    307     } while (0)
    308 
    309 #define SK_BLITBWMASK_NAME                  SkARGB4444_BlendBW
    310 #define SK_BLITBWMASK_ARGS                  , uint16_t sc, unsigned dst_scale
    311 #define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sc, dst_scale)
    312 #define SK_BLITBWMASK_GETADDR               getAddr16
    313 #define SK_BLITBWMASK_DEVTYPE               uint16_t
    314 #include "SkBlitBWMaskTemplate.h"
    315 
    316 void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    317     SkASSERT(mask.fBounds.contains(clip));
    318 
    319     if (0 == fScale16) {
    320         return;
    321     }
    322 
    323     if (mask.fFormat == SkMask::kBW_Format) {
    324         if (16 == fScale16) {
    325             SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16);
    326         } else {
    327             SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16);
    328         }
    329         return;
    330     }
    331 
    332     int x = clip.fLeft;
    333     int y = clip.fTop;
    334     int width = clip.width();
    335     int height = clip.height();
    336 
    337     SkPMColor16*    device = fDevice.getAddr16(x, y);
    338     const uint8_t*  alpha = mask.getAddr8(x, y);
    339     SkPMColor16     srcColor = fPMColor16;
    340     unsigned        devRB = fDevice.rowBytes() - (width << 1);
    341     unsigned        maskRB = mask.fRowBytes - width;
    342 
    343     do {
    344         int w = width;
    345         do {
    346             unsigned aa = *alpha++;
    347             *device = SkBlendARGB4444(srcColor, *device, aa);
    348             device += 1;
    349         } while (--w != 0);
    350         device = (SkPMColor16*)((char*)device + devRB);
    351         alpha += maskRB;
    352     } while (--height != 0);
    353 }
    354 
    355 ///////////////////////////////////////////////////////////////////////////////
    356 
    357 class SkARGB4444_Shader_Blitter : public SkShaderBlitter {
    358     SkXfermode*     fXfermode;
    359     SkBlitRow::Proc fOpaqueProc;
    360     SkBlitRow::Proc fAlphaProc;
    361     SkPMColor*      fBuffer;
    362     uint8_t*        fAAExpand;
    363 public:
    364 
    365 SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
    366         : INHERITED(device, paint) {
    367     const int width = device.width();
    368     fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width);
    369     fAAExpand = (uint8_t*)(fBuffer + width);
    370 
    371     fXfermode = paint.getXfermode();
    372     SkSafeRef(fXfermode);
    373 
    374     unsigned flags = 0;
    375     if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
    376         flags |= SkBlitRow::kSrcPixelAlpha_Flag;
    377     }
    378     if (paint.isDither()) {
    379         flags |= SkBlitRow::kDither_Flag;
    380     }
    381     fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config);
    382     fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
    383                                     SkBitmap::kARGB_4444_Config);
    384 }
    385 
    386 virtual ~SkARGB4444_Shader_Blitter() {
    387     SkSafeUnref(fXfermode);
    388     sk_free(fBuffer);
    389 }
    390 
    391 virtual void blitH(int x, int y, int width) {
    392     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
    393 
    394     SkPMColor16* device = fDevice.getAddr16(x, y);
    395     SkPMColor*   span = fBuffer;
    396 
    397     fShader->shadeSpan(x, y, span, width);
    398     if (fXfermode) {
    399         fXfermode->xfer4444(device, span, width, NULL);
    400     } else {
    401         fOpaqueProc(device, span, width, 0xFF, x, y);
    402     }
    403 }
    404 
    405 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
    406                        const int16_t runs[]) {
    407     SkPMColor* SK_RESTRICT span = fBuffer;
    408     uint8_t* SK_RESTRICT aaExpand = fAAExpand;
    409     SkPMColor16* device = fDevice.getAddr16(x, y);
    410     SkShader*    shader = fShader;
    411     SkXfermode*  xfer = fXfermode;
    412 
    413     if (NULL != xfer) {
    414         for (;;) {
    415             int count = *runs;
    416             if (count <= 0) {
    417                 break;
    418             }
    419             int aa = *antialias;
    420             if (aa) {
    421                 shader->shadeSpan(x, y, span, count);
    422                 if (255 == aa) {
    423                     xfer->xfer4444(device, span, count, NULL);
    424                 } else {
    425                     const uint8_t* aaBuffer = antialias;
    426                     if (count > 1) {
    427                         memset(aaExpand, aa, count);
    428                         aaBuffer = aaExpand;
    429                     }
    430                     xfer->xfer4444(device, span, count, aaBuffer);
    431                 }
    432             }
    433             device += count;
    434             runs += count;
    435             antialias += count;
    436             x += count;
    437         }
    438     } else {    // no xfermode
    439         for (;;) {
    440             int count = *runs;
    441             if (count <= 0) {
    442                 break;
    443             }
    444             int aa = *antialias;
    445             if (aa) {
    446                 fShader->shadeSpan(x, y, span, count);
    447                 if (255 == aa) {
    448                     fOpaqueProc(device, span, count, aa, x, y);
    449                 } else {
    450                     fAlphaProc(device, span, count, aa, x, y);
    451                 }
    452             }
    453             device += count;
    454             runs += count;
    455             antialias += count;
    456             x += count;
    457         }
    458     }
    459 }
    460 
    461 private:
    462     typedef SkShaderBlitter INHERITED;
    463 };
    464 
    465 ///////////////////////////////////////////////////////////////////////////////
    466 ///////////////////////////////////////////////////////////////////////////////
    467 
    468 SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device,
    469                                  const SkPaint& paint,
    470                                  void* storage, size_t storageSize)
    471 {
    472     SkBlitter* blitter;
    473 
    474     if (paint.getShader()) {
    475         SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint));
    476     } else {
    477         SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint));
    478     }
    479     return blitter;
    480 }
    481 
    482