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
17static 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
43SkARGB32_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
57const 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
70void 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
77void 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
108void 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
116void 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
165void 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
189void 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
209void 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
217void 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
228void 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
248void 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
271void 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
302void 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
310void 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
323static 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
332SkARGB32_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
364SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
365    sk_free(fBuffer);
366}
367
368void 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
386void 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
462void 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
537void 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
594void 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