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