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