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 "SkColorPriv.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             SkFAIL("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             SkFAIL("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         void* ctx;
    427         auto shadeProc = shaderContext->asAShadeProc(&ctx);
    428         if (shadeProc) {
    429             do {
    430                 shadeProc(ctx, x, y, device, width);
    431                 y += 1;
    432                 device = (uint32_t*)((char*)device + deviceRB);
    433             } while (--height > 0);
    434         } else {
    435             do {
    436                 shaderContext->shadeSpan(x, y, device, width);
    437                 y += 1;
    438                 device = (uint32_t*)((char*)device + deviceRB);
    439             } while (--height > 0);
    440         }
    441     } else {
    442         SkXfermode* xfer = fXfermode;
    443         if (xfer) {
    444             do {
    445                 shaderContext->shadeSpan(x, y, span, width);
    446                 xfer->xfer32(device, span, width, nullptr);
    447                 y += 1;
    448                 device = (uint32_t*)((char*)device + deviceRB);
    449             } while (--height > 0);
    450         } else {
    451             SkBlitRow::Proc32 proc = fProc32;
    452             do {
    453                 shaderContext->shadeSpan(x, y, span, width);
    454                 proc(device, span, width, 255);
    455                 y += 1;
    456                 device = (uint32_t*)((char*)device + deviceRB);
    457             } while (--height > 0);
    458         }
    459     }
    460 }
    461 
    462 void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
    463                                         const int16_t runs[]) {
    464     SkPMColor* span = fBuffer;
    465     uint32_t*  device = fDevice.writable_addr32(x, y);
    466     auto*      shaderContext = fShaderContext;
    467 
    468     if (fXfermode && !fShadeDirectlyIntoDevice) {
    469         for (;;) {
    470             SkXfermode* xfer = fXfermode;
    471 
    472             int count = *runs;
    473             if (count <= 0)
    474                 break;
    475             int aa = *antialias;
    476             if (aa) {
    477                 shaderContext->shadeSpan(x, y, span, count);
    478                 if (aa == 255) {
    479                     xfer->xfer32(device, span, count, nullptr);
    480                 } else {
    481                     // count is almost always 1
    482                     for (int i = count - 1; i >= 0; --i) {
    483                         xfer->xfer32(&device[i], &span[i], 1, antialias);
    484                     }
    485                 }
    486             }
    487             device += count;
    488             runs += count;
    489             antialias += count;
    490             x += count;
    491         }
    492     } else if (fShadeDirectlyIntoDevice ||
    493                (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
    494         for (;;) {
    495             int count = *runs;
    496             if (count <= 0) {
    497                 break;
    498             }
    499             int aa = *antialias;
    500             if (aa) {
    501                 if (aa == 255) {
    502                     // cool, have the shader draw right into the device
    503                     shaderContext->shadeSpan(x, y, device, count);
    504                 } else {
    505                     shaderContext->shadeSpan(x, y, span, count);
    506                     fProc32Blend(device, span, count, aa);
    507                 }
    508             }
    509             device += count;
    510             runs += count;
    511             antialias += count;
    512             x += count;
    513         }
    514     } else {
    515         for (;;) {
    516             int count = *runs;
    517             if (count <= 0) {
    518                 break;
    519             }
    520             int aa = *antialias;
    521             if (aa) {
    522                 shaderContext->shadeSpan(x, y, span, count);
    523                 if (aa == 255) {
    524                     fProc32(device, span, count, 255);
    525                 } else {
    526                     fProc32Blend(device, span, count, aa);
    527                 }
    528             }
    529             device += count;
    530             runs += count;
    531             antialias += count;
    532             x += count;
    533         }
    534     }
    535 }
    536 
    537 void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    538     // we only handle kA8 with an xfermode
    539     if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) {
    540         this->INHERITED::blitMask(mask, clip);
    541         return;
    542     }
    543 
    544     SkASSERT(mask.fBounds.contains(clip));
    545 
    546     auto* shaderContext = fShaderContext;
    547     SkBlitMask::RowProc proc = nullptr;
    548     if (!fXfermode) {
    549         unsigned flags = 0;
    550         if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
    551             flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
    552         }
    553         proc = SkBlitMask::RowFactory(kN32_SkColorType, mask.fFormat,
    554                                       (SkBlitMask::RowFlags)flags);
    555         if (nullptr == proc) {
    556             this->INHERITED::blitMask(mask, clip);
    557             return;
    558         }
    559     }
    560 
    561     const int x = clip.fLeft;
    562     const int width = clip.width();
    563     int y = clip.fTop;
    564     int height = clip.height();
    565 
    566     char* dstRow = (char*)fDevice.writable_addr32(x, y);
    567     const size_t dstRB = fDevice.rowBytes();
    568     const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
    569     const size_t maskRB = mask.fRowBytes;
    570 
    571     SkPMColor* span = fBuffer;
    572 
    573     if (fXfermode) {
    574         SkASSERT(SkMask::kA8_Format == mask.fFormat);
    575         SkXfermode* xfer = fXfermode;
    576         do {
    577             shaderContext->shadeSpan(x, y, span, width);
    578             xfer->xfer32(reinterpret_cast<SkPMColor*>(dstRow), span, width, maskRow);
    579             dstRow += dstRB;
    580             maskRow += maskRB;
    581             y += 1;
    582         } while (--height > 0);
    583     } else {
    584         do {
    585             shaderContext->shadeSpan(x, y, span, width);
    586             proc(reinterpret_cast<SkPMColor*>(dstRow), maskRow, span, width);
    587             dstRow += dstRB;
    588             maskRow += maskRB;
    589             y += 1;
    590         } while (--height > 0);
    591     }
    592 }
    593 
    594 void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
    595     SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
    596 
    597     uint32_t* device = fDevice.writable_addr32(x, y);
    598     size_t    deviceRB = fDevice.rowBytes();
    599     auto*     shaderContext = fShaderContext;
    600 
    601     if (fConstInY) {
    602         SkPMColor c;
    603         shaderContext->shadeSpan(x, y, &c, 1);
    604 
    605         if (fShadeDirectlyIntoDevice) {
    606             if (255 == alpha) {
    607                 do {
    608                     *device = c;
    609                     device = (uint32_t*)((char*)device + deviceRB);
    610                 } while (--height > 0);
    611             } else {
    612                 do {
    613                     *device = SkFourByteInterp(c, *device, alpha);
    614                     device = (uint32_t*)((char*)device + deviceRB);
    615                 } while (--height > 0);
    616             }
    617         } else {
    618             SkXfermode* xfer = fXfermode;
    619             if (xfer) {
    620                 do {
    621                     xfer->xfer32(device, &c, 1, &alpha);
    622                     device = (uint32_t*)((char*)device + deviceRB);
    623                 } while (--height > 0);
    624             } else {
    625                 SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
    626                 do {
    627                     proc(device, &c, 1, alpha);
    628                     device = (uint32_t*)((char*)device + deviceRB);
    629                 } while (--height > 0);
    630             }
    631         }
    632         return;
    633     }
    634 
    635     if (fShadeDirectlyIntoDevice) {
    636         void* ctx;
    637         auto shadeProc = shaderContext->asAShadeProc(&ctx);
    638         if (255 == alpha) {
    639             if (shadeProc) {
    640                 do {
    641                     shadeProc(ctx, x, y, device, 1);
    642                     y += 1;
    643                     device = (uint32_t*)((char*)device + deviceRB);
    644                 } while (--height > 0);
    645             } else {
    646                 do {
    647                     shaderContext->shadeSpan(x, y, device, 1);
    648                     y += 1;
    649                     device = (uint32_t*)((char*)device + deviceRB);
    650                 } while (--height > 0);
    651             }
    652         } else {    // alpha < 255
    653             SkPMColor c;
    654             if (shadeProc) {
    655                 do {
    656                     shadeProc(ctx, x, y, &c, 1);
    657                     *device = SkFourByteInterp(c, *device, alpha);
    658                     y += 1;
    659                     device = (uint32_t*)((char*)device + deviceRB);
    660                 } while (--height > 0);
    661             } else {
    662                 do {
    663                     shaderContext->shadeSpan(x, y, &c, 1);
    664                     *device = SkFourByteInterp(c, *device, alpha);
    665                     y += 1;
    666                     device = (uint32_t*)((char*)device + deviceRB);
    667                 } while (--height > 0);
    668             }
    669         }
    670     } else {
    671         SkPMColor* span = fBuffer;
    672         SkXfermode* xfer = fXfermode;
    673         if (xfer) {
    674             do {
    675                 shaderContext->shadeSpan(x, y, span, 1);
    676                 xfer->xfer32(device, span, 1, &alpha);
    677                 y += 1;
    678                 device = (uint32_t*)((char*)device + deviceRB);
    679             } while (--height > 0);
    680         } else {
    681             SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
    682             do {
    683                 shaderContext->shadeSpan(x, y, span, 1);
    684                 proc(device, span, 1, alpha);
    685                 y += 1;
    686                 device = (uint32_t*)((char*)device + deviceRB);
    687             } while (--height > 0);
    688         }
    689     }
    690 }
    691