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