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 "SkShader.h"
     21 #include "SkUtils.h"
     22 #include "SkXfermode.h"
     23 
     24 #if defined(SK_SUPPORT_LCDTEXT)
     25 namespace skia_blitter_support {
     26 // subpixel helper functions from SkBlitter_ARGB32_Subpixel.cpp
     27 uint32_t* adjustForSubpixelClip(const SkMask& mask,
     28                                 const SkIRect& clip, const SkBitmap& device,
     29                                 int* widthAdjustment, int* heightAdjustment,
     30                                 const uint32_t** alpha32);
     31 extern uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel,
     32                                        const uint32_t sourcePixel);
     33 extern uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel,
     34                                              const uint32_t sourcePixel);
     35 extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel);
     36 }
     37 
     38 using namespace skia_blitter_support;
     39 #endif
     40 
     41 //////////////////////////////////////////////////////////////////////////////////////
     42 
     43 SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
     44         : INHERITED(device) {
     45     uint32_t color = paint.getColor();
     46 
     47     fSrcA = SkColorGetA(color);
     48     unsigned scale = SkAlpha255To256(fSrcA);
     49     fSrcR = SkAlphaMul(SkColorGetR(color), scale);
     50     fSrcG = SkAlphaMul(SkColorGetG(color), scale);
     51     fSrcB = SkAlphaMul(SkColorGetB(color), scale);
     52 
     53     fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
     54 }
     55 
     56 const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
     57     if (255 == fSrcA) {
     58         *value = fPMColor;
     59         return &fDevice;
     60     }
     61     return NULL;
     62 }
     63 
     64 #if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
     65 #pragma warning ( push )
     66 #pragma warning ( disable : 4701 )
     67 #endif
     68 
     69 void SkARGB32_Blitter::blitH(int x, int y, int width) {
     70     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
     71 
     72     SkBlitRow::Color32(fDevice.getAddr32(x, y), width, fPMColor);
     73 }
     74 
     75 void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
     76                                  const int16_t runs[]) {
     77     if (fSrcA == 0) {
     78         return;
     79     }
     80 
     81     uint32_t    color = fPMColor;
     82     uint32_t*   device = fDevice.getAddr32(x, y);
     83     unsigned    opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
     84 
     85     for (;;) {
     86         int count = runs[0];
     87         SkASSERT(count >= 0);
     88         if (count <= 0) {
     89             return;
     90         }
     91         unsigned aa = antialias[0];
     92         if (aa) {
     93             if ((opaqueMask & aa) == 255) {
     94                 sk_memset32(device, color, count);
     95             } else {
     96                 uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa));
     97                 SkBlitRow::Color32(device, count, sc);
     98             }
     99         }
    100         runs += count;
    101         antialias += count;
    102         device += count;
    103     }
    104 }
    105 
    106 //////////////////////////////////////////////////////////////////////////////////////
    107 
    108 #define solid_8_pixels(mask, dst, color)    \
    109     do {                                    \
    110         if (mask & 0x80) dst[0] = color;    \
    111         if (mask & 0x40) dst[1] = color;    \
    112         if (mask & 0x20) dst[2] = color;    \
    113         if (mask & 0x10) dst[3] = color;    \
    114         if (mask & 0x08) dst[4] = color;    \
    115         if (mask & 0x04) dst[5] = color;    \
    116         if (mask & 0x02) dst[6] = color;    \
    117         if (mask & 0x01) dst[7] = color;    \
    118     } while (0)
    119 
    120 #define SK_BLITBWMASK_NAME                  SkARGB32_BlitBW
    121 #define SK_BLITBWMASK_ARGS                  , SkPMColor color
    122 #define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst, color)
    123 #define SK_BLITBWMASK_GETADDR               getAddr32
    124 #define SK_BLITBWMASK_DEVTYPE               uint32_t
    125 #include "SkBlitBWMaskTemplate.h"
    126 
    127 #define blend_8_pixels(mask, dst, sc, dst_scale)                            \
    128     do {                                                                    \
    129         if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); }  \
    130         if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); }  \
    131         if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); }  \
    132         if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); }  \
    133         if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); }  \
    134         if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); }  \
    135         if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); }  \
    136         if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); }  \
    137     } while (0)
    138 
    139 #define SK_BLITBWMASK_NAME                  SkARGB32_BlendBW
    140 #define SK_BLITBWMASK_ARGS                  , uint32_t sc, unsigned dst_scale
    141 #define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sc, dst_scale)
    142 #define SK_BLITBWMASK_GETADDR               getAddr32
    143 #define SK_BLITBWMASK_DEVTYPE               uint32_t
    144 #include "SkBlitBWMaskTemplate.h"
    145 
    146 void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    147     SkASSERT(mask.fBounds.contains(clip));
    148     SkASSERT(fSrcA != 0xFF);
    149 
    150     if (fSrcA == 0) {
    151         return;
    152     }
    153 
    154     if (mask.fFormat == SkMask::kBW_Format) {
    155         SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
    156         return;
    157     }
    158 
    159     int x = clip.fLeft;
    160     int y = clip.fTop;
    161     int width = clip.width();
    162     int height = clip.height();
    163 
    164     uint32_t*       device = fDevice.getAddr32(x, y);
    165     const uint8_t*  alpha = mask.getAddr(x, y);
    166     uint32_t        srcColor = fPMColor;
    167     unsigned        devRB = fDevice.rowBytes() - (width << 2);
    168     unsigned        maskRB = mask.fRowBytes - width;
    169 
    170     do {
    171         int w = width;
    172         do {
    173             unsigned aa = *alpha++;
    174             *device = SkBlendARGB32(srcColor, *device, aa);
    175             device += 1;
    176         } while (--w != 0);
    177         device = (uint32_t*)((char*)device + devRB);
    178         alpha += maskRB;
    179     } while (--height != 0);
    180 }
    181 
    182 void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
    183                                        const SkIRect& clip) {
    184     SkASSERT(mask.fBounds.contains(clip));
    185 
    186     if (mask.fFormat == SkMask::kBW_Format) {
    187         SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
    188         return;
    189     }
    190 
    191     int x = clip.fLeft;
    192     int y = clip.fTop;
    193     int width = clip.width();
    194     int height = clip.height();
    195 
    196 #if defined(SK_SUPPORT_LCDTEXT)
    197     const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
    198     const bool      verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
    199 #endif
    200 
    201     // In LCD mode the masks have either an extra couple of rows or columns on the edges.
    202     uint32_t        srcColor = fPMColor;
    203 
    204 #if defined(SK_SUPPORT_LCDTEXT)
    205     if (lcdMode || verticalLCDMode) {
    206         int widthAdjustment, heightAdjustment;
    207         const uint32_t* alpha32;
    208         uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
    209 
    210         width += widthAdjustment;
    211         height += heightAdjustment;
    212 
    213         unsigned devRB = fDevice.rowBytes() - (width << 2);
    214         unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
    215 
    216         do {
    217             unsigned w = width;
    218             do {
    219                 const uint32_t alphaPixel = *alpha32++;
    220                 const uint32_t originalPixel = *device;
    221                 *device++ = BlendLCDPixelWithOpaqueColor(alphaPixel, originalPixel, srcColor);
    222             } while (--w != 0);
    223             device = (uint32_t*)((char*)device + devRB);
    224             alpha32 += alphaExtraRowWords;
    225         } while (--height != 0);
    226 
    227         return;
    228     }
    229 #endif
    230 
    231     uint32_t*      device = fDevice.getAddr32(x, y);
    232     const uint8_t* alpha = mask.getAddr(x, y);
    233     unsigned       maskRB = mask.fRowBytes - width;
    234     unsigned       devRB = fDevice.rowBytes() - (width << 2);
    235     do {
    236         int w = width;
    237         do {
    238             unsigned aa = *alpha++;
    239             *device = SkAlphaMulQ(srcColor, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
    240             device += 1;
    241         } while (--w != 0);
    242         device = (uint32_t*)((char*)device + devRB);
    243         alpha += maskRB;
    244     } while (--height != 0);
    245 }
    246 
    247 //////////////////////////////////////////////////////////////////////////////////////
    248 
    249 void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
    250     if (alpha == 0 || fSrcA == 0) {
    251         return;
    252     }
    253 
    254     uint32_t* device = fDevice.getAddr32(x, y);
    255     uint32_t  color = fPMColor;
    256 
    257     if (alpha != 255) {
    258         color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
    259     }
    260 
    261     unsigned dst_scale = 255 - SkGetPackedA32(color);
    262     uint32_t prevDst = ~device[0];
    263     uint32_t result  SK_INIT_TO_AVOID_WARNING;
    264     uint32_t rowBytes = fDevice.rowBytes();
    265 
    266     while (--height >= 0) {
    267         uint32_t dst = device[0];
    268         if (dst != prevDst) {
    269             result = color + SkAlphaMulQ(dst, dst_scale);
    270             prevDst = dst;
    271         }
    272         device[0] = result;
    273         device = (uint32_t*)((char*)device + rowBytes);
    274     }
    275 }
    276 
    277 void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
    278     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
    279 
    280     if (fSrcA == 0) {
    281         return;
    282     }
    283 
    284     uint32_t*   device = fDevice.getAddr32(x, y);
    285     uint32_t    color = fPMColor;
    286     size_t      rowBytes = fDevice.rowBytes();
    287 
    288     while (--height >= 0) {
    289         SkBlitRow::Color32(device, width, color);
    290         device = (uint32_t*)((char*)device + rowBytes);
    291     }
    292 }
    293 
    294 #if defined _WIN32 && _MSC_VER >= 1300
    295 #pragma warning ( pop )
    296 #endif
    297 
    298 ///////////////////////////////////////////////////////////////////////
    299 
    300 void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    301     SkASSERT(mask.fBounds.contains(clip));
    302 
    303     if (mask.fFormat == SkMask::kBW_Format) {
    304         SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
    305 
    306         SkARGB32_BlitBW(fDevice, mask, clip, black);
    307     } else {
    308 #if defined(SK_SUPPORT_LCDTEXT)
    309         const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
    310         const bool      verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
    311 #endif
    312 
    313         // In LCD mode the masks have either an extra couple of rows or columns on the edges.
    314         unsigned        width = clip.width();
    315         unsigned        height = clip.height();
    316 
    317         SkASSERT((int)height > 0);
    318         SkASSERT((int)width > 0);
    319 
    320 #if defined(SK_SUPPORT_LCDTEXT)
    321         if (lcdMode || verticalLCDMode) {
    322             int widthAdjustment, heightAdjustment;
    323             const uint32_t* alpha32;
    324             uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
    325 
    326             width += widthAdjustment;
    327             height += heightAdjustment;
    328 
    329             unsigned deviceRB = fDevice.rowBytes() - (width << 2);
    330             unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
    331 
    332             do {
    333                 unsigned w = width;
    334                 do {
    335                     const uint32_t alphaPixel = *alpha32++;
    336                     const uint32_t originalPixel = *device;
    337                     *device++ = BlendLCDPixelWithBlack(alphaPixel, originalPixel);
    338                 } while (--w != 0);
    339                 device = (uint32_t*)((char*)device + deviceRB);
    340                 alpha32 += alphaExtraRowWords;
    341             } while (--height != 0);
    342 
    343             return;
    344         }
    345 #endif
    346 
    347         uint32_t*      device = fDevice.getAddr32(clip.fLeft, clip.fTop);
    348         unsigned       maskRB = mask.fRowBytes - width;
    349         unsigned       deviceRB = fDevice.rowBytes() - (width << 2);
    350         const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop);
    351         do {
    352             unsigned w = width;
    353             do {
    354                 unsigned aa = *alpha++;
    355                 *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
    356                 device += 1;
    357             } while (--w != 0);
    358             device = (uint32_t*)((char*)device + deviceRB);
    359             alpha += maskRB;
    360         } while (--height != 0);
    361     }
    362 }
    363 
    364 void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    365                                        const int16_t runs[]) {
    366     uint32_t*   device = fDevice.getAddr32(x, y);
    367     SkPMColor   black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
    368 
    369     for (;;) {
    370         int count = runs[0];
    371         SkASSERT(count >= 0);
    372         if (count <= 0) {
    373             return;
    374         }
    375         unsigned aa = antialias[0];
    376         if (aa) {
    377             if (aa == 255) {
    378                 sk_memset32(device, black, count);
    379             } else {
    380                 SkPMColor src = aa << SK_A32_SHIFT;
    381                 unsigned dst_scale = 256 - aa;
    382                 int n = count;
    383                 do {
    384                     --n;
    385                     device[n] = src + SkAlphaMulQ(device[n], dst_scale);
    386                 } while (n > 0);
    387             }
    388         }
    389         runs += count;
    390         antialias += count;
    391         device += count;
    392     }
    393 }
    394 
    395 //////////////////////////////////////////////////////////////////////////////////////////
    396 
    397 SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
    398                             const SkPaint& paint) : INHERITED(device, paint) {
    399     fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
    400 
    401     fXfermode = paint.getXfermode();
    402     SkSafeRef(fXfermode);
    403 
    404     int flags = 0;
    405     if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
    406         flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
    407     }
    408     // we call this on the output from the shader
    409     fProc32 = SkBlitRow::Factory32(flags);
    410     // we call this on the output from the shader + alpha from the aa buffer
    411     fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);
    412 }
    413 
    414 SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
    415     fXfermode->safeUnref();
    416     sk_free(fBuffer);
    417 }
    418 
    419 void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
    420     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
    421 
    422     uint32_t*   device = fDevice.getAddr32(x, y);
    423 
    424     if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
    425         fShader->shadeSpan(x, y, device, width);
    426     } else {
    427         SkPMColor*  span = fBuffer;
    428         fShader->shadeSpan(x, y, span, width);
    429         if (fXfermode) {
    430             fXfermode->xfer32(device, span, width, NULL);
    431         } else {
    432             fProc32(device, span, width, 255);
    433         }
    434     }
    435 }
    436 
    437 ///////////////////////////////////////////////////////////////////////////////////////////////
    438 
    439 void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    440                                         const int16_t runs[]) {
    441     SkPMColor*  span = fBuffer;
    442     uint32_t*   device = fDevice.getAddr32(x, y);
    443     SkShader*   shader = fShader;
    444 
    445     if (fXfermode) {
    446         for (;;) {
    447             SkXfermode* xfer = fXfermode;
    448 
    449             int count = *runs;
    450             if (count <= 0)
    451                 break;
    452             int aa = *antialias;
    453             if (aa) {
    454                 shader->shadeSpan(x, y, span, count);
    455                 if (aa == 255) {
    456                     xfer->xfer32(device, span, count, NULL);
    457                 } else {
    458                     // count is almost always 1
    459                     for (int i = count - 1; i >= 0; --i) {
    460                         xfer->xfer32(&device[i], &span[i], 1, antialias);
    461                     }
    462                 }
    463             }
    464             device += count;
    465             runs += count;
    466             antialias += count;
    467             x += count;
    468         }
    469     } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
    470         for (;;) {
    471             int count = *runs;
    472             if (count <= 0) {
    473                 break;
    474             }
    475             int aa = *antialias;
    476             if (aa) {
    477                 if (aa == 255) {
    478                     // cool, have the shader draw right into the device
    479                     shader->shadeSpan(x, y, device, count);
    480                 } else {
    481                     shader->shadeSpan(x, y, span, count);
    482                     fProc32Blend(device, span, count, aa);
    483                 }
    484             }
    485             device += count;
    486             runs += count;
    487             antialias += count;
    488             x += count;
    489         }
    490     } else {    // no xfermode but the shader not opaque
    491         for (;;) {
    492             int count = *runs;
    493             if (count <= 0) {
    494                 break;
    495             }
    496             int aa = *antialias;
    497             if (aa) {
    498                 fShader->shadeSpan(x, y, span, count);
    499                 if (aa == 255) {
    500                     fProc32(device, span, count, 255);
    501                 } else {
    502                     fProc32Blend(device, span, count, aa);
    503                 }
    504             }
    505             device += count;
    506             runs += count;
    507             antialias += count;
    508             x += count;
    509         }
    510     }
    511 }
    512