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 "SkSpriteBlitter.h"
11#include "SkBlitRow.h"
12#include "SkColorFilter.h"
13#include "SkColorPriv.h"
14#include "SkTemplates.h"
15#include "SkUtils.h"
16#include "SkXfermode.h"
17
18///////////////////////////////////////////////////////////////////////////////
19
20class Sprite_D32_S32 : public SkSpriteBlitter {
21public:
22    Sprite_D32_S32(const SkBitmap& src, U8CPU alpha)  : INHERITED(src) {
23        SkASSERT(src.colorType() == kN32_SkColorType);
24
25        unsigned flags32 = 0;
26        if (255 != alpha) {
27            flags32 |= SkBlitRow::kGlobalAlpha_Flag32;
28        }
29        if (!src.isOpaque()) {
30            flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32;
31        }
32
33        fProc32 = SkBlitRow::Factory32(flags32);
34        fAlpha = alpha;
35    }
36
37    void blitRect(int x, int y, int width, int height) override {
38        SkASSERT(width > 0 && height > 0);
39        uint32_t* SK_RESTRICT dst = fDevice->getAddr32(x, y);
40        const uint32_t* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
41                                                             y - fTop);
42        size_t dstRB = fDevice->rowBytes();
43        size_t srcRB = fSource->rowBytes();
44        SkBlitRow::Proc32 proc = fProc32;
45        U8CPU             alpha = fAlpha;
46
47        do {
48            proc(dst, src, width, alpha);
49            dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
50            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
51        } while (--height != 0);
52    }
53
54private:
55    SkBlitRow::Proc32   fProc32;
56    U8CPU               fAlpha;
57
58    typedef SkSpriteBlitter INHERITED;
59};
60
61///////////////////////////////////////////////////////////////////////////////
62
63class Sprite_D32_XferFilter : public SkSpriteBlitter {
64public:
65    Sprite_D32_XferFilter(const SkBitmap& source, const SkPaint& paint)
66        : SkSpriteBlitter(source) {
67        fColorFilter = paint.getColorFilter();
68        SkSafeRef(fColorFilter);
69
70        fXfermode = paint.getXfermode();
71        SkSafeRef(fXfermode);
72
73        fBufferSize = 0;
74        fBuffer = NULL;
75
76        unsigned flags32 = 0;
77        if (255 != paint.getAlpha()) {
78            flags32 |= SkBlitRow::kGlobalAlpha_Flag32;
79        }
80        if (!source.isOpaque()) {
81            flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32;
82        }
83
84        fProc32 = SkBlitRow::Factory32(flags32);
85        fAlpha = paint.getAlpha();
86    }
87
88    virtual ~Sprite_D32_XferFilter() {
89        delete[] fBuffer;
90        SkSafeUnref(fXfermode);
91        SkSafeUnref(fColorFilter);
92    }
93
94    virtual void setup(const SkBitmap& device, int left, int top,
95                       const SkPaint& paint) override {
96        this->INHERITED::setup(device, left, top, paint);
97
98        int width = device.width();
99        if (width > fBufferSize) {
100            fBufferSize = width;
101            delete[] fBuffer;
102            fBuffer = new SkPMColor[width];
103        }
104    }
105
106protected:
107    SkColorFilter*      fColorFilter;
108    SkXfermode*         fXfermode;
109    int                 fBufferSize;
110    SkPMColor*          fBuffer;
111    SkBlitRow::Proc32   fProc32;
112    U8CPU               fAlpha;
113
114private:
115    typedef SkSpriteBlitter INHERITED;
116};
117
118///////////////////////////////////////////////////////////////////////////////
119
120class Sprite_D32_S32A_XferFilter : public Sprite_D32_XferFilter {
121public:
122    Sprite_D32_S32A_XferFilter(const SkBitmap& source, const SkPaint& paint)
123        : Sprite_D32_XferFilter(source, paint) {}
124
125    void blitRect(int x, int y, int width, int height) override {
126        SkASSERT(width > 0 && height > 0);
127        uint32_t* SK_RESTRICT dst = fDevice->getAddr32(x, y);
128        const uint32_t* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
129                                                             y - fTop);
130        size_t dstRB = fDevice->rowBytes();
131        size_t srcRB = fSource->rowBytes();
132        SkColorFilter* colorFilter = fColorFilter;
133        SkXfermode* xfermode = fXfermode;
134
135        do {
136            const SkPMColor* tmp = src;
137
138            if (colorFilter) {
139                colorFilter->filterSpan(src, width, fBuffer);
140                tmp = fBuffer;
141            }
142
143            if (xfermode) {
144                xfermode->xfer32(dst, tmp, width, NULL);
145            } else {
146                fProc32(dst, tmp, width, fAlpha);
147            }
148
149            dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
150            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
151        } while (--height != 0);
152    }
153
154private:
155    typedef Sprite_D32_XferFilter INHERITED;
156};
157
158static void fillbuffer(SkPMColor* SK_RESTRICT dst,
159                       const SkPMColor16* SK_RESTRICT src, int count) {
160    SkASSERT(count > 0);
161
162    do {
163        *dst++ = SkPixel4444ToPixel32(*src++);
164    } while (--count != 0);
165}
166
167class Sprite_D32_S4444_XferFilter : public Sprite_D32_XferFilter {
168public:
169    Sprite_D32_S4444_XferFilter(const SkBitmap& source, const SkPaint& paint)
170        : Sprite_D32_XferFilter(source, paint) {}
171
172    void blitRect(int x, int y, int width, int height) override {
173        SkASSERT(width > 0 && height > 0);
174        SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
175        const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
176                                                                y - fTop);
177        size_t dstRB = fDevice->rowBytes();
178        size_t srcRB = fSource->rowBytes();
179        SkPMColor* SK_RESTRICT buffer = fBuffer;
180        SkColorFilter* colorFilter = fColorFilter;
181        SkXfermode* xfermode = fXfermode;
182
183        do {
184            fillbuffer(buffer, src, width);
185
186            if (colorFilter) {
187                colorFilter->filterSpan(buffer, width, buffer);
188            }
189            if (xfermode) {
190                xfermode->xfer32(dst, buffer, width, NULL);
191            } else {
192                fProc32(dst, buffer, width, fAlpha);
193            }
194
195            dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
196            src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
197        } while (--height != 0);
198    }
199
200private:
201    typedef Sprite_D32_XferFilter INHERITED;
202};
203
204///////////////////////////////////////////////////////////////////////////////
205
206static void src_row(SkPMColor* SK_RESTRICT dst,
207                    const SkPMColor16* SK_RESTRICT src, int count) {
208    do {
209        *dst = SkPixel4444ToPixel32(*src);
210        src += 1;
211        dst += 1;
212    } while (--count != 0);
213}
214
215class Sprite_D32_S4444_Opaque : public SkSpriteBlitter {
216public:
217    Sprite_D32_S4444_Opaque(const SkBitmap& source) : SkSpriteBlitter(source) {}
218
219    void blitRect(int x, int y, int width, int height) override {
220        SkASSERT(width > 0 && height > 0);
221        SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
222        const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
223                                                                y - fTop);
224        size_t dstRB = fDevice->rowBytes();
225        size_t srcRB = fSource->rowBytes();
226
227        do {
228            src_row(dst, src, width);
229            dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
230            src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
231        } while (--height != 0);
232    }
233};
234
235static void srcover_row(SkPMColor* SK_RESTRICT dst,
236                        const SkPMColor16* SK_RESTRICT src, int count) {
237    do {
238        *dst = SkPMSrcOver(SkPixel4444ToPixel32(*src), *dst);
239        src += 1;
240        dst += 1;
241    } while (--count != 0);
242}
243
244class Sprite_D32_S4444 : public SkSpriteBlitter {
245public:
246    Sprite_D32_S4444(const SkBitmap& source) : SkSpriteBlitter(source) {}
247
248    void blitRect(int x, int y, int width, int height) override {
249        SkASSERT(width > 0 && height > 0);
250        SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
251        const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
252                                                                y - fTop);
253        size_t dstRB = fDevice->rowBytes();
254        size_t srcRB = fSource->rowBytes();
255
256        do {
257            srcover_row(dst, src, width);
258            dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
259            src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
260        } while (--height != 0);
261    }
262};
263
264///////////////////////////////////////////////////////////////////////////////
265
266SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, const SkPaint& paint,
267        SkTBlitterAllocator* allocator) {
268    SkASSERT(allocator != NULL);
269
270    if (paint.getMaskFilter() != NULL) {
271        return NULL;
272    }
273
274    U8CPU       alpha = paint.getAlpha();
275    SkXfermode* xfermode = paint.getXfermode();
276    SkColorFilter* filter = paint.getColorFilter();
277    SkSpriteBlitter* blitter = NULL;
278
279    switch (source.colorType()) {
280        case kARGB_4444_SkColorType:
281            if (alpha != 0xFF) {
282                return NULL;    // we only have opaque sprites
283            }
284            if (xfermode || filter) {
285                blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint);
286            } else if (source.isOpaque()) {
287                blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source);
288            } else {
289                blitter = allocator->createT<Sprite_D32_S4444>(source);
290            }
291            break;
292        case kN32_SkColorType:
293            if (xfermode || filter) {
294                if (255 == alpha) {
295                    // this can handle xfermode or filter, but not alpha
296                    blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint);
297                }
298            } else {
299                // this can handle alpha, but not xfermode or filter
300                blitter = allocator->createT<Sprite_D32_S32>(source, alpha);
301            }
302            break;
303        default:
304            break;
305    }
306    return blitter;
307}
308