Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      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 "SkCoreBlitters.h"
      9 #include "SkColorData.h"
     10 #include "SkShader.h"
     11 #include "SkUtils.h"
     12 #include "SkXfermodePriv.h"
     13 #include "SkBlitMask.h"
     14 
     15 ///////////////////////////////////////////////////////////////////////////////
     16 
     17 static void SkARGB32_Blit32(const SkPixmap& device, const SkMask& mask,
     18                             const SkIRect& clip, SkPMColor srcColor) {
     19     U8CPU alpha = SkGetPackedA32(srcColor);
     20     unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32;
     21     if (alpha != 255) {
     22         flags |= SkBlitRow::kGlobalAlpha_Flag32;
     23     }
     24     SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags);
     25 
     26     int x = clip.fLeft;
     27     int y = clip.fTop;
     28     int width = clip.width();
     29     int height = clip.height();
     30 
     31     SkPMColor* dstRow = device.writable_addr32(x, y);
     32     const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr8(x, y));
     33 
     34     do {
     35         proc(dstRow, srcRow, width, alpha);
     36         dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
     37         srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes);
     38     } while (--height != 0);
     39 }
     40 
     41 //////////////////////////////////////////////////////////////////////////////////////
     42 
     43 SkARGB32_Blitter::SkARGB32_Blitter(const SkPixmap& device, const SkPaint& paint)
     44         : INHERITED(device) {
     45     SkColor color = paint.getColor();
     46     fColor = color;
     47 
     48     fSrcA = SkColorGetA(color);
     49     unsigned scale = SkAlpha255To256(fSrcA);
     50     fSrcR = SkAlphaMul(SkColorGetR(color), scale);
     51     fSrcG = SkAlphaMul(SkColorGetG(color), scale);
     52     fSrcB = SkAlphaMul(SkColorGetB(color), scale);
     53 
     54     fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
     55 }
     56 
     57 const SkPixmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
     58     if (255 == fSrcA) {
     59         *value = fPMColor;
     60         return &fDevice;
     61     }
     62     return nullptr;
     63 }
     64 
     65 #if defined _WIN32  // disable warning : local variable used without having been initialized
     66 #pragma warning ( push )
     67 #pragma warning ( disable : 4701 )
     68 #endif
     69 
     70 void SkARGB32_Blitter::blitH(int x, int y, int width) {
     71     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
     72 
     73     uint32_t* device = fDevice.writable_addr32(x, y);
     74     SkBlitRow::Color32(device, device, width, fPMColor);
     75 }
     76 
     77 void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
     78                                  const int16_t runs[]) {
     79     if (fSrcA == 0) {
     80         return;
     81     }
     82 
     83     uint32_t    color = fPMColor;
     84     uint32_t*   device = fDevice.writable_addr32(x, y);
     85     unsigned    opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
     86 
     87     for (;;) {
     88         int count = runs[0];
     89         SkASSERT(count >= 0);
     90         if (count <= 0) {
     91             return;
     92         }
     93         unsigned aa = antialias[0];
     94         if (aa) {
     95             if ((opaqueMask & aa) == 255) {
     96                 sk_memset32(device, color, count);
     97             } else {
     98                 uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa));
     99                 SkBlitRow::Color32(device, device, count, sc);
    100             }
    101         }
    102         runs += count;
    103         antialias += count;
    104         device += count;
    105     }
    106 }
    107 
    108 void SkARGB32_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
    109     uint32_t* device = fDevice.writable_addr32(x, y);
    110     SkDEBUGCODE((void)fDevice.writable_addr32(x + 1, y);)
    111 
    112     device[0] = SkBlendARGB32(fPMColor, device[0], a0);
    113     device[1] = SkBlendARGB32(fPMColor, device[1], a1);
    114 }
    115 
    116 void SkARGB32_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
    117     uint32_t* device = fDevice.writable_addr32(x, y);
    118     SkDEBUGCODE((void)fDevice.writable_addr32(x, y + 1);)
    119 
    120     device[0] = SkBlendARGB32(fPMColor, device[0], a0);
    121     device = (uint32_t*)((char*)device + fDevice.rowBytes());
    122     device[0] = SkBlendARGB32(fPMColor, device[0], a1);
    123 }
    124 
    125 //////////////////////////////////////////////////////////////////////////////////////
    126 
    127 #define solid_8_pixels(mask, dst, color)    \
    128     do {                                    \
    129         if (mask & 0x80) dst[0] = color;    \
    130         if (mask & 0x40) dst[1] = color;    \
    131         if (mask & 0x20) dst[2] = color;    \
    132         if (mask & 0x10) dst[3] = color;    \
    133         if (mask & 0x08) dst[4] = color;    \
    134         if (mask & 0x04) dst[5] = color;    \
    135         if (mask & 0x02) dst[6] = color;    \
    136         if (mask & 0x01) dst[7] = color;    \
    137     } while (0)
    138 
    139 #define SK_BLITBWMASK_NAME                  SkARGB32_BlitBW
    140 #define SK_BLITBWMASK_ARGS                  , SkPMColor color
    141 #define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst, color)
    142 #define SK_BLITBWMASK_GETADDR               writable_addr32
    143 #define SK_BLITBWMASK_DEVTYPE               uint32_t
    144 #include "SkBlitBWMaskTemplate.h"
    145 
    146 #define blend_8_pixels(mask, dst, sc, dst_scale)                            \
    147     do {                                                                    \
    148         if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); }  \
    149         if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); }  \
    150         if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); }  \
    151         if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); }  \
    152         if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); }  \
    153         if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); }  \
    154         if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); }  \
    155         if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); }  \
    156     } while (0)
    157 
    158 #define SK_BLITBWMASK_NAME                  SkARGB32_BlendBW
    159 #define SK_BLITBWMASK_ARGS                  , uint32_t sc, unsigned dst_scale
    160 #define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sc, dst_scale)
    161 #define SK_BLITBWMASK_GETADDR               writable_addr32
    162 #define SK_BLITBWMASK_DEVTYPE               uint32_t
    163 #include "SkBlitBWMaskTemplate.h"
    164 
    165 void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    166     SkASSERT(mask.fBounds.contains(clip));
    167     SkASSERT(fSrcA != 0xFF);
    168 
    169     if (fSrcA == 0) {
    170         return;
    171     }
    172 
    173     if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
    174         return;
    175     }
    176 
    177     switch (mask.fFormat) {
    178         case SkMask::kBW_Format:
    179             SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
    180             break;
    181         case SkMask::kARGB32_Format:
    182             SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
    183             break;
    184         default:
    185             SK_ABORT("Mask format not handled.");
    186     }
    187 }
    188 
    189 void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
    190                                        const SkIRect& clip) {
    191     SkASSERT(mask.fBounds.contains(clip));
    192 
    193     if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
    194         return;
    195     }
    196 
    197     switch (mask.fFormat) {
    198         case SkMask::kBW_Format:
    199             SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
    200             break;
    201         case SkMask::kARGB32_Format:
    202             SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
    203             break;
    204         default:
    205             SK_ABORT("Mask format not handled.");
    206     }
    207 }
    208 
    209 void SkARGB32_Opaque_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
    210     uint32_t* device = fDevice.writable_addr32(x, y);
    211     SkDEBUGCODE((void)fDevice.writable_addr32(x + 1, y);)
    212 
    213     device[0] = SkFastFourByteInterp(fPMColor, device[0], a0);
    214     device[1] = SkFastFourByteInterp(fPMColor, device[1], a1);
    215 }
    216 
    217 void SkARGB32_Opaque_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
    218     uint32_t* device = fDevice.writable_addr32(x, y);
    219     SkDEBUGCODE((void)fDevice.writable_addr32(x, y + 1);)
    220 
    221     device[0] = SkFastFourByteInterp(fPMColor, device[0], a0);
    222     device = (uint32_t*)((char*)device + fDevice.rowBytes());
    223     device[0] = SkFastFourByteInterp(fPMColor, device[0], a1);
    224 }
    225 
    226 ///////////////////////////////////////////////////////////////////////////////
    227 
    228 void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
    229     if (alpha == 0 || fSrcA == 0) {
    230         return;
    231     }
    232 
    233     uint32_t* device = fDevice.writable_addr32(x, y);
    234     uint32_t  color = fPMColor;
    235 
    236     if (alpha != 255) {
    237         color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
    238     }
    239 
    240     unsigned dst_scale = SkAlpha255To256(255 - SkGetPackedA32(color));
    241     size_t rowBytes = fDevice.rowBytes();
    242     while (--height >= 0) {
    243         device[0] = color + SkAlphaMulQ(device[0], dst_scale);
    244         device = (uint32_t*)((char*)device + rowBytes);
    245     }
    246 }
    247 
    248 void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
    249     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
    250 
    251     if (fSrcA == 0) {
    252         return;
    253     }
    254 
    255     uint32_t*   device = fDevice.writable_addr32(x, y);
    256     uint32_t    color = fPMColor;
    257     size_t      rowBytes = fDevice.rowBytes();
    258 
    259     while (--height >= 0) {
    260         SkBlitRow::Color32(device, device, width, color);
    261         device = (uint32_t*)((char*)device + rowBytes);
    262     }
    263 }
    264 
    265 #if defined _WIN32
    266 #pragma warning ( pop )
    267 #endif
    268 
    269 ///////////////////////////////////////////////////////////////////////
    270 
    271 void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    272                                        const int16_t runs[]) {
    273     uint32_t*   device = fDevice.writable_addr32(x, y);
    274     SkPMColor   black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
    275 
    276     for (;;) {
    277         int count = runs[0];
    278         SkASSERT(count >= 0);
    279         if (count <= 0) {
    280             return;
    281         }
    282         unsigned aa = antialias[0];
    283         if (aa) {
    284             if (aa == 255) {
    285                 sk_memset32(device, black, count);
    286             } else {
    287                 SkPMColor src = aa << SK_A32_SHIFT;
    288                 unsigned dst_scale = 256 - aa;
    289                 int n = count;
    290                 do {
    291                     --n;
    292                     device[n] = src + SkAlphaMulQ(device[n], dst_scale);
    293                 } while (n > 0);
    294             }
    295         }
    296         runs += count;
    297         antialias += count;
    298         device += count;
    299     }
    300 }
    301 
    302 void SkARGB32_Black_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
    303     uint32_t* device = fDevice.writable_addr32(x, y);
    304     SkDEBUGCODE((void)fDevice.writable_addr32(x + 1, y);)
    305 
    306     device[0] = (a0 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a0);
    307     device[1] = (a1 << SK_A32_SHIFT) + SkAlphaMulQ(device[1], 256 - a1);
    308 }
    309 
    310 void SkARGB32_Black_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
    311     uint32_t* device = fDevice.writable_addr32(x, y);
    312     SkDEBUGCODE((void)fDevice.writable_addr32(x, y + 1);)
    313 
    314     device[0] = (a0 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a0);
    315     device = (uint32_t*)((char*)device + fDevice.rowBytes());
    316     device[0] = (a1 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a1);
    317 }
    318 
    319 ///////////////////////////////////////////////////////////////////////////////
    320 
    321 // Special version of SkBlitRow::Factory32 that knows we're in kSrc_Mode,
    322 // instead of kSrcOver_Mode
    323 static void blend_srcmode(SkPMColor* SK_RESTRICT device,
    324                           const SkPMColor* SK_RESTRICT span,
    325                           int count, U8CPU aa) {
    326     int aa256 = SkAlpha255To256(aa);
    327     for (int i = 0; i < count; ++i) {
    328         device[i] = SkFourByteInterp256(span[i], device[i], aa256);
    329     }
    330 }
    331 
    332 SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device,
    333         const SkPaint& paint, SkShaderBase::Context* shaderContext)
    334     : INHERITED(device, paint, shaderContext)
    335 {
    336     fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
    337 
    338     fXfermode = SkXfermode::Peek(paint.getBlendMode());
    339 
    340     int flags = 0;
    341     if (!(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
    342         flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
    343     }
    344     // we call this on the output from the shader
    345     fProc32 = SkBlitRow::Factory32(flags);
    346     // we call this on the output from the shader + alpha from the aa buffer
    347     fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);
    348 
    349     fShadeDirectlyIntoDevice = false;
    350     if (fXfermode == nullptr) {
    351         if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
    352             fShadeDirectlyIntoDevice = true;
    353         }
    354     } else {
    355         if (SkBlendMode::kSrc == paint.getBlendMode()) {
    356             fShadeDirectlyIntoDevice = true;
    357             fProc32Blend = blend_srcmode;
    358         }
    359     }
    360 
    361     fConstInY = SkToBool(shaderContext->getFlags() & SkShaderBase::kConstInY32_Flag);
    362 }
    363 
    364 SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
    365     sk_free(fBuffer);
    366 }
    367 
    368 void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
    369     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
    370 
    371     uint32_t* device = fDevice.writable_addr32(x, y);
    372 
    373     if (fShadeDirectlyIntoDevice) {
    374         fShaderContext->shadeSpan(x, y, device, width);
    375     } else {
    376         SkPMColor*  span = fBuffer;
    377         fShaderContext->shadeSpan(x, y, span, width);
    378         if (fXfermode) {
    379             fXfermode->xfer32(device, span, width, nullptr);
    380         } else {
    381             fProc32(device, span, width, 255);
    382         }
    383     }
    384 }
    385 
    386 void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
    387     SkASSERT(x >= 0 && y >= 0 &&
    388              x + width <= fDevice.width() && y + height <= fDevice.height());
    389 
    390     uint32_t*  device = fDevice.writable_addr32(x, y);
    391     size_t     deviceRB = fDevice.rowBytes();
    392     auto*      shaderContext = fShaderContext;
    393     SkPMColor* span = fBuffer;
    394 
    395     if (fConstInY) {
    396         if (fShadeDirectlyIntoDevice) {
    397             // shade the first row directly into the device
    398             shaderContext->shadeSpan(x, y, device, width);
    399             span = device;
    400             while (--height > 0) {
    401                 device = (uint32_t*)((char*)device + deviceRB);
    402                 memcpy(device, span, width << 2);
    403             }
    404         } else {
    405             shaderContext->shadeSpan(x, y, span, width);
    406             SkXfermode* xfer = fXfermode;
    407             if (xfer) {
    408                 do {
    409                     xfer->xfer32(device, span, width, nullptr);
    410                     y += 1;
    411                     device = (uint32_t*)((char*)device + deviceRB);
    412                 } while (--height > 0);
    413             } else {
    414                 SkBlitRow::Proc32 proc = fProc32;
    415                 do {
    416                     proc(device, span, width, 255);
    417                     y += 1;
    418                     device = (uint32_t*)((char*)device + deviceRB);
    419                 } while (--height > 0);
    420             }
    421         }
    422         return;
    423     }
    424 
    425     if (fShadeDirectlyIntoDevice) {
    426         do {
    427             shaderContext->shadeSpan(x, y, device, width);
    428             y += 1;
    429             device = (uint32_t*)((char*)device + deviceRB);
    430         } while (--height > 0);
    431     } else {
    432         SkXfermode* xfer = fXfermode;
    433         if (xfer) {
    434             do {
    435                 shaderContext->shadeSpan(x, y, span, width);
    436                 xfer->xfer32(device, span, width, nullptr);
    437                 y += 1;
    438                 device = (uint32_t*)((char*)device + deviceRB);
    439             } while (--height > 0);
    440         } else {
    441             SkBlitRow::Proc32 proc = fProc32;
    442             do {
    443                 shaderContext->shadeSpan(x, y, span, width);
    444                 proc(device, span, width, 255);
    445                 y += 1;
    446                 device = (uint32_t*)((char*)device + deviceRB);
    447             } while (--height > 0);
    448         }
    449     }
    450 }
    451 
    452 void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    453                                         const int16_t runs[]) {
    454     SkPMColor* span = fBuffer;
    455     uint32_t*  device = fDevice.writable_addr32(x, y);
    456     auto*      shaderContext = fShaderContext;
    457 
    458     if (fXfermode && !fShadeDirectlyIntoDevice) {
    459         for (;;) {
    460             SkXfermode* xfer = fXfermode;
    461 
    462             int count = *runs;
    463             if (count <= 0)
    464                 break;
    465             int aa = *antialias;
    466             if (aa) {
    467                 shaderContext->shadeSpan(x, y, span, count);
    468                 if (aa == 255) {
    469                     xfer->xfer32(device, span, count, nullptr);
    470                 } else {
    471                     // count is almost always 1
    472                     for (int i = count - 1; i >= 0; --i) {
    473                         xfer->xfer32(&device[i], &span[i], 1, antialias);
    474                     }
    475                 }
    476             }
    477             device += count;
    478             runs += count;
    479             antialias += count;
    480             x += count;
    481         }
    482     } else if (fShadeDirectlyIntoDevice ||
    483                (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
    484         for (;;) {
    485             int count = *runs;
    486             if (count <= 0) {
    487                 break;
    488             }
    489             int aa = *antialias;
    490             if (aa) {
    491                 if (aa == 255) {
    492                     // cool, have the shader draw right into the device
    493                     shaderContext->shadeSpan(x, y, device, count);
    494                 } else {
    495                     shaderContext->shadeSpan(x, y, span, count);
    496                     fProc32Blend(device, span, count, aa);
    497                 }
    498             }
    499             device += count;
    500             runs += count;
    501             antialias += count;
    502             x += count;
    503         }
    504     } else {
    505         for (;;) {
    506             int count = *runs;
    507             if (count <= 0) {
    508                 break;
    509             }
    510             int aa = *antialias;
    511             if (aa) {
    512                 shaderContext->shadeSpan(x, y, span, count);
    513                 if (aa == 255) {
    514                     fProc32(device, span, count, 255);
    515                 } else {
    516                     fProc32Blend(device, span, count, aa);
    517                 }
    518             }
    519             device += count;
    520             runs += count;
    521             antialias += count;
    522             x += count;
    523         }
    524     }
    525 }
    526 
    527 void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    528     // we only handle kA8 with an xfermode
    529     if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) {
    530         this->INHERITED::blitMask(mask, clip);
    531         return;
    532     }
    533 
    534     SkASSERT(mask.fBounds.contains(clip));
    535 
    536     auto* shaderContext = fShaderContext;
    537     SkBlitMask::RowProc proc = nullptr;
    538     if (!fXfermode) {
    539         unsigned flags = 0;
    540         if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
    541             flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
    542         }
    543         proc = SkBlitMask::RowFactory(kN32_SkColorType, mask.fFormat,
    544                                       (SkBlitMask::RowFlags)flags);
    545         if (nullptr == proc) {
    546             this->INHERITED::blitMask(mask, clip);
    547             return;
    548         }
    549     }
    550 
    551     const int x = clip.fLeft;
    552     const int width = clip.width();
    553     int y = clip.fTop;
    554     int height = clip.height();
    555 
    556     char* dstRow = (char*)fDevice.writable_addr32(x, y);
    557     const size_t dstRB = fDevice.rowBytes();
    558     const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
    559     const size_t maskRB = mask.fRowBytes;
    560 
    561     SkPMColor* span = fBuffer;
    562 
    563     if (fXfermode) {
    564         SkASSERT(SkMask::kA8_Format == mask.fFormat);
    565         SkXfermode* xfer = fXfermode;
    566         do {
    567             shaderContext->shadeSpan(x, y, span, width);
    568             xfer->xfer32(reinterpret_cast<SkPMColor*>(dstRow), span, width, maskRow);
    569             dstRow += dstRB;
    570             maskRow += maskRB;
    571             y += 1;
    572         } while (--height > 0);
    573     } else {
    574         do {
    575             shaderContext->shadeSpan(x, y, span, width);
    576             proc(reinterpret_cast<SkPMColor*>(dstRow), maskRow, span, width);
    577             dstRow += dstRB;
    578             maskRow += maskRB;
    579             y += 1;
    580         } while (--height > 0);
    581     }
    582 }
    583 
    584 void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
    585     SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
    586 
    587     uint32_t* device = fDevice.writable_addr32(x, y);
    588     size_t    deviceRB = fDevice.rowBytes();
    589     auto*     shaderContext = fShaderContext;
    590 
    591     if (fConstInY) {
    592         SkPMColor c;
    593         shaderContext->shadeSpan(x, y, &c, 1);
    594 
    595         if (fShadeDirectlyIntoDevice) {
    596             if (255 == alpha) {
    597                 do {
    598                     *device = c;
    599                     device = (uint32_t*)((char*)device + deviceRB);
    600                 } while (--height > 0);
    601             } else {
    602                 do {
    603                     *device = SkFourByteInterp(c, *device, alpha);
    604                     device = (uint32_t*)((char*)device + deviceRB);
    605                 } while (--height > 0);
    606             }
    607         } else {
    608             SkXfermode* xfer = fXfermode;
    609             if (xfer) {
    610                 do {
    611                     xfer->xfer32(device, &c, 1, &alpha);
    612                     device = (uint32_t*)((char*)device + deviceRB);
    613                 } while (--height > 0);
    614             } else {
    615                 SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
    616                 do {
    617                     proc(device, &c, 1, alpha);
    618                     device = (uint32_t*)((char*)device + deviceRB);
    619                 } while (--height > 0);
    620             }
    621         }
    622         return;
    623     }
    624 
    625     if (fShadeDirectlyIntoDevice) {
    626         if (255 == alpha) {
    627             do {
    628                 shaderContext->shadeSpan(x, y, device, 1);
    629                 y += 1;
    630                 device = (uint32_t*)((char*)device + deviceRB);
    631             } while (--height > 0);
    632         } else {
    633             do {
    634                 SkPMColor c;
    635                 shaderContext->shadeSpan(x, y, &c, 1);
    636                 *device = SkFourByteInterp(c, *device, alpha);
    637                 y += 1;
    638                 device = (uint32_t*)((char*)device + deviceRB);
    639             } while (--height > 0);
    640         }
    641     } else {
    642         SkPMColor* span = fBuffer;
    643         SkXfermode* xfer = fXfermode;
    644         if (xfer) {
    645             do {
    646                 shaderContext->shadeSpan(x, y, span, 1);
    647                 xfer->xfer32(device, span, 1, &alpha);
    648                 y += 1;
    649                 device = (uint32_t*)((char*)device + deviceRB);
    650             } while (--height > 0);
    651         } else {
    652             SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
    653             do {
    654                 shaderContext->shadeSpan(x, y, span, 1);
    655                 proc(device, span, 1, alpha);
    656                 y += 1;
    657                 device = (uint32_t*)((char*)device + deviceRB);
    658             } while (--height > 0);
    659         }
    660     }
    661 }
    662