SkBlitter_ARGB32.cpp revision e74e28df11abbe069d82221ee029d281a81ea328
1/* libs/graphics/sgl/SkBlitter_ARGB32.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkCoreBlitters.h"
19#include "SkColorPriv.h"
20#include "SkShader.h"
21#include "SkUtils.h"
22#include "SkXfermode.h"
23
24///////////////////////////////////////////////////////////////////////////////
25
26static inline int upscale31To32(int value) {
27    SkASSERT((unsigned)value <= 31);
28    return value + (value >> 4);
29}
30
31static inline int blend32(int src, int dst, int scale) {
32    SkASSERT((unsigned)src <= 0xFF);
33    SkASSERT((unsigned)dst <= 0xFF);
34    SkASSERT((unsigned)scale <= 32);
35    return dst + ((src - dst) * scale >> 5);
36}
37
38static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[],
39                              SkPMColor color, int width) {
40    int srcR = SkGetPackedR32(color);
41    int srcG = SkGetPackedG32(color);
42    int srcB = SkGetPackedB32(color);
43
44    for (int i = 0; i < width; i++) {
45        uint16_t mask = src[i];
46        if (0 == mask) {
47            continue;
48        }
49
50        SkPMColor d = dst[i];
51
52        /*  We want all of these in 5bits, hence the shifts in case one of them
53         *  (green) is 6bits.
54         */
55        int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
56        int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
57        int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
58
59        // Now upscale them to 0..256, so we can use SkAlphaBlend
60        maskR = upscale31To32(maskR);
61        maskG = upscale31To32(maskG);
62        maskB = upscale31To32(maskB);
63
64        int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
65
66        int dstA = SkGetPackedA32(d);
67        int dstR = SkGetPackedR32(d);
68        int dstG = SkGetPackedG32(d);
69        int dstB = SkGetPackedB32(d);
70
71        dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA),
72                              blend32(srcR, dstR, maskR),
73                              blend32(srcG, dstG, maskG),
74                              blend32(srcB, dstB, maskB));
75    }
76}
77
78static void blit_lcd32_opaque(SkPMColor dst[], const uint32_t src[],
79                              SkPMColor color, int width) {
80    int srcR = SkGetPackedR32(color);
81    int srcG = SkGetPackedG32(color);
82    int srcB = SkGetPackedB32(color);
83
84    for (int i = 0; i < width; i++) {
85        uint32_t mask = src[i];
86        if (0 == mask) {
87            continue;
88        }
89
90        SkPMColor d = dst[i];
91
92        int maskR = SkGetPackedR32(mask);
93        int maskG = SkGetPackedG32(mask);
94        int maskB = SkGetPackedB32(mask);
95
96        // Now upscale them to 0..256, so we can use SkAlphaBlend
97        maskR = SkAlpha255To256(maskR);
98        maskG = SkAlpha255To256(maskG);
99        maskB = SkAlpha255To256(maskB);
100
101        int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
102
103        int dstA = SkGetPackedA32(d);
104        int dstR = SkGetPackedR32(d);
105        int dstG = SkGetPackedG32(d);
106        int dstB = SkGetPackedB32(d);
107
108        dst[i] = SkPackARGB32(SkAlphaBlend(0xFF, dstA, maskA),
109                              SkAlphaBlend(srcR, dstR, maskR),
110                              SkAlphaBlend(srcG, dstG, maskG),
111                              SkAlphaBlend(srcB, dstB, maskB));
112    }
113}
114
115static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
116                           const SkIRect& clip, SkPMColor srcColor) {
117    int x = clip.fLeft;
118    int y = clip.fTop;
119    int width = clip.width();
120    int height = clip.height();
121
122    SkPMColor*		dstRow = device.getAddr32(x, y);
123    const uint16_t* srcRow = mask.getAddrLCD16(x, y);
124
125    do {
126        blit_lcd16_opaque(dstRow, srcRow, srcColor, width);
127        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
128        srcRow = (const uint16_t*)((const char*)srcRow + mask.fRowBytes);
129    } while (--height != 0);
130}
131
132static void blitmask_lcd32(const SkBitmap& device, const SkMask& mask,
133                           const SkIRect& clip, SkPMColor srcColor) {
134    int x = clip.fLeft;
135    int y = clip.fTop;
136    int width = clip.width();
137    int height = clip.height();
138
139    SkPMColor*		dstRow = device.getAddr32(x, y);
140    const uint32_t* srcRow = mask.getAddrLCD32(x, y);
141
142    do {
143        blit_lcd32_opaque(dstRow, srcRow, srcColor, width);
144        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
145        srcRow = (const uint32_t*)((const char*)srcRow + mask.fRowBytes);
146    } while (--height != 0);
147}
148
149//////////////////////////////////////////////////////////////////////////////////////
150
151static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
152							const SkIRect& clip, SkPMColor srcColor) {
153	U8CPU alpha = SkGetPackedA32(srcColor);
154	unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32;
155	if (alpha != 255) {
156		flags |= SkBlitRow::kGlobalAlpha_Flag32;
157	}
158	SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags);
159
160    int x = clip.fLeft;
161    int y = clip.fTop;
162    int width = clip.width();
163    int height = clip.height();
164
165    SkPMColor*		 dstRow = device.getAddr32(x, y);
166    const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr(x, y));
167
168    do {
169		proc(dstRow, srcRow, width, alpha);
170        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
171        srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes);
172    } while (--height != 0);
173}
174
175//////////////////////////////////////////////////////////////////////////////////////
176
177SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
178        : INHERITED(device) {
179    SkColor color = paint.getColor();
180    fColor = color;
181
182    fSrcA = SkColorGetA(color);
183    unsigned scale = SkAlpha255To256(fSrcA);
184    fSrcR = SkAlphaMul(SkColorGetR(color), scale);
185    fSrcG = SkAlphaMul(SkColorGetG(color), scale);
186    fSrcB = SkAlphaMul(SkColorGetB(color), scale);
187
188    fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
189    fColor32Proc = SkBlitRow::ColorProcFactory();
190
191    // init the pro for blitmask
192    fBlitMaskProc = SkBlitMask::Factory(SkBitmap::kARGB_8888_Config, color);
193}
194
195const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
196    if (255 == fSrcA) {
197        *value = fPMColor;
198        return &fDevice;
199    }
200    return NULL;
201}
202
203#if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
204#pragma warning ( push )
205#pragma warning ( disable : 4701 )
206#endif
207
208void SkARGB32_Blitter::blitH(int x, int y, int width) {
209    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
210
211    uint32_t*   device = fDevice.getAddr32(x, y);
212    fColor32Proc(device, device, width, fPMColor);
213}
214
215void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
216                                 const int16_t runs[]) {
217    if (fSrcA == 0) {
218        return;
219    }
220
221    uint32_t    color = fPMColor;
222    uint32_t*   device = fDevice.getAddr32(x, y);
223    unsigned    opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
224
225    for (;;) {
226        int count = runs[0];
227        SkASSERT(count >= 0);
228        if (count <= 0) {
229            return;
230        }
231        unsigned aa = antialias[0];
232        if (aa) {
233            if ((opaqueMask & aa) == 255) {
234                sk_memset32(device, color, count);
235            } else {
236                uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa));
237                fColor32Proc(device, device, count, sc);
238            }
239        }
240        runs += count;
241        antialias += count;
242        device += count;
243    }
244}
245
246//////////////////////////////////////////////////////////////////////////////////////
247
248#define solid_8_pixels(mask, dst, color)    \
249    do {                                    \
250        if (mask & 0x80) dst[0] = color;    \
251        if (mask & 0x40) dst[1] = color;    \
252        if (mask & 0x20) dst[2] = color;    \
253        if (mask & 0x10) dst[3] = color;    \
254        if (mask & 0x08) dst[4] = color;    \
255        if (mask & 0x04) dst[5] = color;    \
256        if (mask & 0x02) dst[6] = color;    \
257        if (mask & 0x01) dst[7] = color;    \
258    } while (0)
259
260#define SK_BLITBWMASK_NAME                  SkARGB32_BlitBW
261#define SK_BLITBWMASK_ARGS                  , SkPMColor color
262#define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst, color)
263#define SK_BLITBWMASK_GETADDR               getAddr32
264#define SK_BLITBWMASK_DEVTYPE               uint32_t
265#include "SkBlitBWMaskTemplate.h"
266
267#define blend_8_pixels(mask, dst, sc, dst_scale)                            \
268    do {                                                                    \
269        if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); }  \
270        if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); }  \
271        if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); }  \
272        if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); }  \
273        if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); }  \
274        if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); }  \
275        if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); }  \
276        if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); }  \
277    } while (0)
278
279#define SK_BLITBWMASK_NAME                  SkARGB32_BlendBW
280#define SK_BLITBWMASK_ARGS                  , uint32_t sc, unsigned dst_scale
281#define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sc, dst_scale)
282#define SK_BLITBWMASK_GETADDR               getAddr32
283#define SK_BLITBWMASK_DEVTYPE               uint32_t
284#include "SkBlitBWMaskTemplate.h"
285
286void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
287    SkASSERT(mask.fBounds.contains(clip));
288    SkASSERT(fSrcA != 0xFF);
289
290    if (fSrcA == 0) {
291        return;
292    }
293
294    if (mask.fFormat == SkMask::kBW_Format) {
295        SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
296        return;
297    } else if (SkMask::kARGB32_Format == mask.fFormat) {
298		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
299		return;
300    } else if (SkMask::kLCD16_Format == mask.fFormat) {
301        blitmask_lcd16(fDevice, mask, clip, fPMColor);
302        return;
303    } else if (SkMask::kLCD32_Format == mask.fFormat) {
304        blitmask_lcd32(fDevice, mask, clip, fPMColor);
305        return;
306    }
307
308    int x = clip.fLeft;
309    int y = clip.fTop;
310
311    fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
312                  SkBitmap::kARGB_8888_Config,
313                  mask.getAddr(x, y), mask.fRowBytes,
314                  fColor, clip.width(), clip.height());
315}
316
317void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
318                                       const SkIRect& clip) {
319    SkASSERT(mask.fBounds.contains(clip));
320
321    if (mask.fFormat == SkMask::kBW_Format) {
322        SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
323        return;
324    } else if (SkMask::kARGB32_Format == mask.fFormat) {
325		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
326		return;
327    } else if (SkMask::kLCD16_Format == mask.fFormat) {
328        blitmask_lcd16(fDevice, mask, clip, fPMColor);
329        return;
330    } else if (SkMask::kLCD32_Format == mask.fFormat) {
331        blitmask_lcd32(fDevice, mask, clip, fPMColor);
332        return;
333	}
334
335    int x = clip.fLeft;
336    int y = clip.fTop;
337    int width = clip.width();
338    int height = clip.height();
339
340    fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
341                  SkBitmap::kARGB_8888_Config,
342                  mask.getAddr(x, y), mask.fRowBytes, fColor, width, height);
343}
344
345//////////////////////////////////////////////////////////////////////////////////////
346
347void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
348    if (alpha == 0 || fSrcA == 0) {
349        return;
350    }
351
352    uint32_t* device = fDevice.getAddr32(x, y);
353    uint32_t  color = fPMColor;
354
355    if (alpha != 255) {
356        color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
357    }
358
359    unsigned dst_scale = 255 - SkGetPackedA32(color);
360    uint32_t prevDst = ~device[0];
361    uint32_t result  SK_INIT_TO_AVOID_WARNING;
362    uint32_t rowBytes = fDevice.rowBytes();
363
364    while (--height >= 0) {
365        uint32_t dst = device[0];
366        if (dst != prevDst) {
367            result = color + SkAlphaMulQ(dst, dst_scale);
368            prevDst = dst;
369        }
370        device[0] = result;
371        device = (uint32_t*)((char*)device + rowBytes);
372    }
373}
374
375void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
376    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
377
378    if (fSrcA == 0) {
379        return;
380    }
381
382    uint32_t*   device = fDevice.getAddr32(x, y);
383    uint32_t    color = fPMColor;
384    size_t      rowBytes = fDevice.rowBytes();
385
386    while (--height >= 0) {
387        fColor32Proc(device, device, width, color);
388        device = (uint32_t*)((char*)device + rowBytes);
389    }
390}
391
392#if defined _WIN32 && _MSC_VER >= 1300
393#pragma warning ( pop )
394#endif
395
396///////////////////////////////////////////////////////////////////////
397
398void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
399    SkASSERT(mask.fBounds.contains(clip));
400    SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
401
402    if (mask.fFormat == SkMask::kBW_Format) {
403        SkARGB32_BlitBW(fDevice, mask, clip, black);
404    } else if (SkMask::kARGB32_Format == mask.fFormat) {
405		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
406    } else if (SkMask::kLCD16_Format == mask.fFormat) {
407        blitmask_lcd16(fDevice, mask, clip, fPMColor);
408    } else if (SkMask::kLCD32_Format == mask.fFormat) {
409        blitmask_lcd32(fDevice, mask, clip, fPMColor);
410    } else {
411        fBlitMaskProc(fDevice.getAddr32(clip.fLeft, clip.fTop),
412                      fDevice.rowBytes(),
413                      SkBitmap::kARGB_8888_Config,
414                      mask.getAddr(clip.fLeft, clip.fTop), mask.fRowBytes,
415                      black, clip.width(), clip.height());
416    }
417}
418
419void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
420                                       const int16_t runs[]) {
421    uint32_t*   device = fDevice.getAddr32(x, y);
422    SkPMColor   black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
423
424    for (;;) {
425        int count = runs[0];
426        SkASSERT(count >= 0);
427        if (count <= 0) {
428            return;
429        }
430        unsigned aa = antialias[0];
431        if (aa) {
432            if (aa == 255) {
433                sk_memset32(device, black, count);
434            } else {
435                SkPMColor src = aa << SK_A32_SHIFT;
436                unsigned dst_scale = 256 - aa;
437                int n = count;
438                do {
439                    --n;
440                    device[n] = src + SkAlphaMulQ(device[n], dst_scale);
441                } while (n > 0);
442            }
443        }
444        runs += count;
445        antialias += count;
446        device += count;
447    }
448}
449
450//////////////////////////////////////////////////////////////////////////////////////////
451
452SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
453                            const SkPaint& paint) : INHERITED(device, paint) {
454    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
455
456    fXfermode = paint.getXfermode();
457    SkSafeRef(fXfermode);
458
459    int flags = 0;
460    if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
461        flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
462    }
463    // we call this on the output from the shader
464    fProc32 = SkBlitRow::Factory32(flags);
465    // we call this on the output from the shader + alpha from the aa buffer
466    fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);
467}
468
469SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
470    SkSafeUnref(fXfermode);
471    sk_free(fBuffer);
472}
473
474void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
475    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
476
477    uint32_t*   device = fDevice.getAddr32(x, y);
478
479    if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
480        fShader->shadeSpan(x, y, device, width);
481    } else {
482        SkPMColor*  span = fBuffer;
483        fShader->shadeSpan(x, y, span, width);
484        if (fXfermode) {
485            fXfermode->xfer32(device, span, width, NULL);
486        } else {
487            fProc32(device, span, width, 255);
488        }
489    }
490}
491
492///////////////////////////////////////////////////////////////////////////////////////////////
493
494void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
495                                        const int16_t runs[]) {
496    SkPMColor*  span = fBuffer;
497    uint32_t*   device = fDevice.getAddr32(x, y);
498    SkShader*   shader = fShader;
499
500    if (fXfermode) {
501        for (;;) {
502            SkXfermode* xfer = fXfermode;
503
504            int count = *runs;
505            if (count <= 0)
506                break;
507            int aa = *antialias;
508            if (aa) {
509                shader->shadeSpan(x, y, span, count);
510                if (aa == 255) {
511                    xfer->xfer32(device, span, count, NULL);
512                } else {
513                    // count is almost always 1
514                    for (int i = count - 1; i >= 0; --i) {
515                        xfer->xfer32(&device[i], &span[i], 1, antialias);
516                    }
517                }
518            }
519            device += count;
520            runs += count;
521            antialias += count;
522            x += count;
523        }
524    } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
525        for (;;) {
526            int count = *runs;
527            if (count <= 0) {
528                break;
529            }
530            int aa = *antialias;
531            if (aa) {
532                if (aa == 255) {
533                    // cool, have the shader draw right into the device
534                    shader->shadeSpan(x, y, device, count);
535                } else {
536                    shader->shadeSpan(x, y, span, count);
537                    fProc32Blend(device, span, count, aa);
538                }
539            }
540            device += count;
541            runs += count;
542            antialias += count;
543            x += count;
544        }
545    } else {    // no xfermode but the shader not opaque
546        for (;;) {
547            int count = *runs;
548            if (count <= 0) {
549                break;
550            }
551            int aa = *antialias;
552            if (aa) {
553                fShader->shadeSpan(x, y, span, count);
554                if (aa == 255) {
555                    fProc32(device, span, count, 255);
556                } else {
557                    fProc32Blend(device, span, count, aa);
558                }
559            }
560            device += count;
561            runs += count;
562            antialias += count;
563            x += count;
564        }
565    }
566}
567