1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkCoreBlitters.h"
11#include "SkColorPriv.h"
12#include "SkShader.h"
13#include "SkXfermode.h"
14
15SkA8_Blitter::SkA8_Blitter(const SkBitmap& device, const SkPaint& paint)
16        : INHERITED(device) {
17    fSrcA = paint.getAlpha();
18}
19
20const SkBitmap* SkA8_Blitter::justAnOpaqueColor(uint32_t* value) {
21    if (255 == fSrcA) {
22        *value = 255;
23        return &fDevice;
24    }
25    return NULL;
26}
27
28void SkA8_Blitter::blitH(int x, int y, int width) {
29    SkASSERT(x >= 0 && y >= 0 &&
30             (unsigned)(x + width) <= (unsigned)fDevice.width());
31
32    if (fSrcA == 0) {
33        return;
34    }
35
36    uint8_t* device = fDevice.getAddr8(x, y);
37
38    if (fSrcA == 255) {
39        memset(device, 0xFF, width);
40    } else {
41        unsigned scale = 256 - SkAlpha255To256(fSrcA);
42        unsigned srcA = fSrcA;
43
44        for (int i = 0; i < width; i++) {
45            device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
46        }
47    }
48}
49
50void SkA8_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
51                             const int16_t runs[]) {
52    if (fSrcA == 0) {
53        return;
54    }
55
56    uint8_t*    device = fDevice.getAddr8(x, y);
57    unsigned    srcA = fSrcA;
58
59    for (;;) {
60        int count = runs[0];
61        SkASSERT(count >= 0);
62        if (count == 0) {
63            return;
64        }
65        unsigned aa = antialias[0];
66
67        if (aa == 255 && srcA == 255) {
68            memset(device, 0xFF, count);
69        } else {
70            unsigned sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
71            unsigned scale = 256 - sa;
72
73            for (int i = 0; i < count; i++) {
74                device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
75            }
76        }
77        runs += count;
78        antialias += count;
79        device += count;
80    }
81}
82
83/////////////////////////////////////////////////////////////////////////////////////
84
85#define solid_8_pixels(mask, dst)           \
86    do {                                    \
87        if (mask & 0x80) dst[0] = 0xFF;     \
88        if (mask & 0x40) dst[1] = 0xFF;     \
89        if (mask & 0x20) dst[2] = 0xFF;     \
90        if (mask & 0x10) dst[3] = 0xFF;     \
91        if (mask & 0x08) dst[4] = 0xFF;     \
92        if (mask & 0x04) dst[5] = 0xFF;     \
93        if (mask & 0x02) dst[6] = 0xFF;     \
94        if (mask & 0x01) dst[7] = 0xFF;     \
95    } while (0)
96
97#define SK_BLITBWMASK_NAME                  SkA8_BlitBW
98#define SK_BLITBWMASK_ARGS
99#define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst)
100#define SK_BLITBWMASK_GETADDR               getAddr8
101#define SK_BLITBWMASK_DEVTYPE               uint8_t
102#include "SkBlitBWMaskTemplate.h"
103
104static inline void blend_8_pixels(U8CPU bw, uint8_t dst[], U8CPU sa,
105                                  unsigned dst_scale) {
106    if (bw & 0x80) dst[0] = SkToU8(sa + SkAlphaMul(dst[0], dst_scale));
107    if (bw & 0x40) dst[1] = SkToU8(sa + SkAlphaMul(dst[1], dst_scale));
108    if (bw & 0x20) dst[2] = SkToU8(sa + SkAlphaMul(dst[2], dst_scale));
109    if (bw & 0x10) dst[3] = SkToU8(sa + SkAlphaMul(dst[3], dst_scale));
110    if (bw & 0x08) dst[4] = SkToU8(sa + SkAlphaMul(dst[4], dst_scale));
111    if (bw & 0x04) dst[5] = SkToU8(sa + SkAlphaMul(dst[5], dst_scale));
112    if (bw & 0x02) dst[6] = SkToU8(sa + SkAlphaMul(dst[6], dst_scale));
113    if (bw & 0x01) dst[7] = SkToU8(sa + SkAlphaMul(dst[7], dst_scale));
114}
115
116#define SK_BLITBWMASK_NAME                  SkA8_BlendBW
117#define SK_BLITBWMASK_ARGS                  , U8CPU sa, unsigned dst_scale
118#define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sa, dst_scale)
119#define SK_BLITBWMASK_GETADDR               getAddr8
120#define SK_BLITBWMASK_DEVTYPE               uint8_t
121#include "SkBlitBWMaskTemplate.h"
122
123void SkA8_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
124    if (fSrcA == 0) {
125        return;
126    }
127
128    if (mask.fFormat == SkMask::kBW_Format) {
129        if (fSrcA == 0xFF) {
130            SkA8_BlitBW(fDevice, mask, clip);
131        } else {
132            SkA8_BlendBW(fDevice, mask, clip, fSrcA,
133                         SkAlpha255To256(255 - fSrcA));
134        }
135        return;
136    }
137
138    int x = clip.fLeft;
139    int y = clip.fTop;
140    int width = clip.width();
141    int height = clip.height();
142    uint8_t* device = fDevice.getAddr8(x, y);
143    const uint8_t* alpha = mask.getAddr8(x, y);
144    unsigned    srcA = fSrcA;
145
146    while (--height >= 0) {
147        for (int i = width - 1; i >= 0; --i) {
148            unsigned sa;
149            // scale our src by the alpha value
150            {
151                int aa = alpha[i];
152                if (aa == 0) {
153                    continue;
154                }
155                if (aa == 255) {
156                    if (srcA == 255) {
157                        device[i] = 0xFF;
158                        continue;
159                    }
160                    sa = srcA;
161                } else {
162                    sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
163                }
164            }
165
166            int scale = 256 - SkAlpha255To256(sa);
167            device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
168        }
169        device += fDevice.rowBytes();
170        alpha += mask.fRowBytes;
171    }
172}
173
174///////////////////////////////////////////////////////////////////////////////
175
176void SkA8_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
177    if (fSrcA == 0) {
178        return;
179    }
180
181    unsigned sa = SkAlphaMul(fSrcA, SkAlpha255To256(alpha));
182    uint8_t* device = fDevice.getAddr8(x, y);
183    size_t   rowBytes = fDevice.rowBytes();
184
185    if (sa == 0xFF) {
186        for (int i = 0; i < height; i++) {
187            *device = SkToU8(sa);
188            device += rowBytes;
189        }
190    } else {
191        unsigned scale = 256 - SkAlpha255To256(sa);
192
193        for (int i = 0; i < height; i++) {
194            *device = SkToU8(sa + SkAlphaMul(*device, scale));
195            device += rowBytes;
196        }
197    }
198}
199
200void SkA8_Blitter::blitRect(int x, int y, int width, int height) {
201    SkASSERT(x >= 0 && y >= 0 &&
202             (unsigned)(x + width) <= (unsigned)fDevice.width() &&
203             (unsigned)(y + height) <= (unsigned)fDevice.height());
204
205    if (fSrcA == 0) {
206        return;
207    }
208
209    uint8_t*    device = fDevice.getAddr8(x, y);
210    unsigned    srcA = fSrcA;
211
212    if (srcA == 255) {
213        while (--height >= 0) {
214            memset(device, 0xFF, width);
215            device += fDevice.rowBytes();
216        }
217    } else {
218        unsigned scale = 256 - SkAlpha255To256(srcA);
219
220        while (--height >= 0) {
221            for (int i = 0; i < width; i++) {
222                device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
223            }
224            device += fDevice.rowBytes();
225        }
226    }
227}
228
229///////////////////////////////////////////////////////////////////////
230
231SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
232    : INHERITED(device, paint) {
233    if ((fXfermode = paint.getXfermode()) != NULL) {
234        fXfermode->ref();
235        SkASSERT(fShader);
236    }
237
238    int width = device.width();
239    fBuffer = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * (width + (SkAlign4(width) >> 2)));
240    fAAExpand = (uint8_t*)(fBuffer + width);
241}
242
243SkA8_Shader_Blitter::~SkA8_Shader_Blitter() {
244    if (fXfermode) SkSafeUnref(fXfermode);
245    sk_free(fBuffer);
246}
247
248void SkA8_Shader_Blitter::blitH(int x, int y, int width) {
249    SkASSERT(x >= 0 && y >= 0 &&
250             (unsigned)(x + width) <= (unsigned)fDevice.width());
251
252    uint8_t* device = fDevice.getAddr8(x, y);
253
254    if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
255        memset(device, 0xFF, width);
256    } else {
257        SkPMColor*  span = fBuffer;
258
259        fShader->shadeSpan(x, y, span, width);
260        if (fXfermode) {
261            fXfermode->xferA8(device, span, width, NULL);
262        } else {
263            for (int i = width - 1; i >= 0; --i) {
264                unsigned    srcA = SkGetPackedA32(span[i]);
265                unsigned    scale = 256 - SkAlpha255To256(srcA);
266
267                device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
268            }
269        }
270    }
271}
272
273static inline uint8_t aa_blend8(SkPMColor src, U8CPU da, int aa) {
274    SkASSERT((unsigned)aa <= 255);
275
276    int src_scale = SkAlpha255To256(aa);
277    int sa = SkGetPackedA32(src);
278    int dst_scale = 256 - SkAlphaMul(sa, src_scale);
279
280    return SkToU8((sa * src_scale + da * dst_scale) >> 8);
281}
282
283void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
284                                    const int16_t runs[]) {
285    SkShader*   shader = fShader;
286    SkXfermode* mode = fXfermode;
287    uint8_t*    aaExpand = fAAExpand;
288    SkPMColor*  span = fBuffer;
289    uint8_t*    device = fDevice.getAddr8(x, y);
290    int         opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag;
291
292    for (;;) {
293        int count = *runs;
294        if (count == 0) {
295            break;
296        }
297        int aa = *antialias;
298        if (aa) {
299            if (opaque && aa == 255 && mode == NULL) {
300                memset(device, 0xFF, count);
301            } else {
302                shader->shadeSpan(x, y, span, count);
303                if (mode) {
304                    memset(aaExpand, aa, count);
305                    mode->xferA8(device, span, count, aaExpand);
306                } else {
307                    for (int i = count - 1; i >= 0; --i) {
308                        device[i] = aa_blend8(span[i], device[i], aa);
309                    }
310                }
311            }
312        }
313        device += count;
314        runs += count;
315        antialias += count;
316        x += count;
317    }
318}
319
320void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
321    if (mask.fFormat == SkMask::kBW_Format) {
322        this->INHERITED::blitMask(mask, clip);
323        return;
324    }
325
326    int x = clip.fLeft;
327    int y = clip.fTop;
328    int width = clip.width();
329    int height = clip.height();
330    uint8_t* device = fDevice.getAddr8(x, y);
331    const uint8_t* alpha = mask.getAddr8(x, y);
332
333    SkPMColor*  span = fBuffer;
334
335    while (--height >= 0) {
336        fShader->shadeSpan(x, y, span, width);
337        if (fXfermode) {
338            fXfermode->xferA8(device, span, width, alpha);
339        }
340
341        y += 1;
342        device += fDevice.rowBytes();
343        alpha += mask.fRowBytes;
344    }
345}
346