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