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 "SkTemplates.h"
13#include "SkUtils.h"
14#include "SkColorPriv.h"
15
16#define D16_S32A_Opaque_Pixel(dst, sc)                                        \
17do {                                                                          \
18    if (sc) {                                                                 \
19        *dst = SkSrcOver32To16(sc, *dst);                                     \
20    }                                                                         \
21} while (0)
22
23static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
24                                               unsigned src_scale) {
25    uint16_t dc = *dst;
26    unsigned sa = SkGetPackedA32(sc);
27    unsigned dr, dg, db;
28
29    if (255 == sa) {
30        dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
31        dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
32        db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
33    } else {
34        unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale);
35        dr = (SkPacked32ToR16(sc) * src_scale +
36              SkGetPackedR16(dc) * dst_scale) >> 8;
37        dg = (SkPacked32ToG16(sc) * src_scale +
38              SkGetPackedG16(dc) * dst_scale) >> 8;
39        db = (SkPacked32ToB16(sc) * src_scale +
40              SkGetPackedB16(dc) * dst_scale) >> 8;
41    }
42    *dst = SkPackRGB16(dr, dg, db);
43}
44
45#define D16_S32A_Blend_Pixel(dst, sc, src_scale) \
46    do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)
47
48
49///////////////////////////////////////////////////////////////////////////////
50
51class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
52public:
53    Sprite_D16_S16_Opaque(const SkBitmap& source)
54        : SkSpriteBlitter(source) {}
55
56    // overrides
57    virtual void blitRect(int x, int y, int width, int height) {
58        uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
59        const uint16_t* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
60                                                             y - fTop);
61        size_t dstRB = fDevice->rowBytes();
62        size_t srcRB = fSource->rowBytes();
63
64        while (--height >= 0) {
65            memcpy(dst, src, width << 1);
66            dst = (uint16_t*)((char*)dst + dstRB);
67            src = (const uint16_t*)((const char*)src + srcRB);
68        }
69    }
70};
71
72#define D16_S16_Blend_Pixel(dst, sc, scale)     \
73    do {                                        \
74        uint16_t dc = *dst;                     \
75        *dst = SkBlendRGB16(sc, dc, scale);     \
76    } while (0)
77
78#define SkSPRITE_CLASSNAME                  Sprite_D16_S16_Blend
79#define SkSPRITE_ARGS                       , uint8_t alpha
80#define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
81#define SkSPRITE_INIT                       fSrcAlpha = alpha;
82#define SkSPRITE_DST_TYPE                   uint16_t
83#define SkSPRITE_SRC_TYPE                   uint16_t
84#define SkSPRITE_DST_GETADDR                getAddr16
85#define SkSPRITE_SRC_GETADDR                getAddr16
86#define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha255To256(fSrcAlpha);
87#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, src, scale)
88#define SkSPRITE_NEXT_ROW
89#define SkSPRITE_POSTAMBLE(srcBM)
90#include "SkSpriteBlitterTemplate.h"
91
92///////////////////////////////////////////////////////////////////////////////
93
94#define D16_S4444_Opaque(dst, sc)           \
95    do {                                    \
96        uint16_t dc = *dst;                 \
97        *dst = SkSrcOver4444To16(sc, dc);   \
98    } while (0)
99
100#define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Opaque
101#define SkSPRITE_ARGS
102#define SkSPRITE_FIELDS
103#define SkSPRITE_INIT
104#define SkSPRITE_DST_TYPE                   uint16_t
105#define SkSPRITE_SRC_TYPE                   SkPMColor16
106#define SkSPRITE_DST_GETADDR                getAddr16
107#define SkSPRITE_SRC_GETADDR                getAddr16
108#define SkSPRITE_PREAMBLE(srcBM, x, y)
109#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Opaque(dst, src)
110#define SkSPRITE_NEXT_ROW
111#define SkSPRITE_POSTAMBLE(srcBM)
112#include "SkSpriteBlitterTemplate.h"
113
114#define D16_S4444_Blend(dst, sc, scale16)           \
115    do {                                            \
116        uint16_t dc = *dst;                         \
117        *dst = SkBlend4444To16(sc, dc, scale16);    \
118    } while (0)
119
120
121#define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Blend
122#define SkSPRITE_ARGS                       , uint8_t alpha
123#define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
124#define SkSPRITE_INIT                       fSrcAlpha = alpha;
125#define SkSPRITE_DST_TYPE                   uint16_t
126#define SkSPRITE_SRC_TYPE                   uint16_t
127#define SkSPRITE_DST_GETADDR                getAddr16
128#define SkSPRITE_SRC_GETADDR                getAddr16
129#define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha15To16(fSrcAlpha);
130#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Blend(dst, src, scale)
131#define SkSPRITE_NEXT_ROW
132#define SkSPRITE_POSTAMBLE(srcBM)
133#include "SkSpriteBlitterTemplate.h"
134
135///////////////////////////////////////////////////////////////////////////////
136
137#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Opaque
138#define SkSPRITE_ARGS
139#define SkSPRITE_FIELDS
140#define SkSPRITE_INIT
141#define SkSPRITE_DST_TYPE                   uint16_t
142#define SkSPRITE_SRC_TYPE                   uint8_t
143#define SkSPRITE_DST_GETADDR                getAddr16
144#define SkSPRITE_SRC_GETADDR                getAddr8
145#define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors()
146#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Opaque_Pixel(dst, ctable[src])
147#define SkSPRITE_NEXT_ROW
148#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors()
149#include "SkSpriteBlitterTemplate.h"
150
151#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Blend
152#define SkSPRITE_ARGS                       , uint8_t alpha
153#define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
154#define SkSPRITE_INIT                       fSrcAlpha = alpha;
155#define SkSPRITE_DST_TYPE                   uint16_t
156#define SkSPRITE_SRC_TYPE                   uint8_t
157#define SkSPRITE_DST_GETADDR                getAddr16
158#define SkSPRITE_SRC_GETADDR                getAddr8
159#define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
160#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
161#define SkSPRITE_NEXT_ROW
162#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors();
163#include "SkSpriteBlitterTemplate.h"
164
165///////////////////////////////////////////////////////////////////////////////
166
167static intptr_t asint(const void* ptr) {
168    return reinterpret_cast<const char*>(ptr) - (const char*)0;
169}
170
171static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
172                            const uint8_t* SK_RESTRICT src, int count,
173                            const uint16_t* SK_RESTRICT ctable) {
174    if (count <= 8) {
175        do {
176            *dst++ = ctable[*src++];
177        } while (--count);
178        return;
179    }
180
181    // eat src until we're on a 4byte boundary
182    while (asint(src) & 3) {
183        *dst++ = ctable[*src++];
184        count -= 1;
185    }
186
187    int qcount = count >> 2;
188    SkASSERT(qcount > 0);
189    const uint32_t* qsrc = reinterpret_cast<const uint32_t*>(src);
190    if (asint(dst) & 2) {
191        do {
192            uint32_t s4 = *qsrc++;
193#ifdef SK_CPU_LENDIAN
194            *dst++ = ctable[s4 & 0xFF];
195            *dst++ = ctable[(s4 >> 8) & 0xFF];
196            *dst++ = ctable[(s4 >> 16) & 0xFF];
197            *dst++ = ctable[s4 >> 24];
198#else   // BENDIAN
199            *dst++ = ctable[s4 >> 24];
200            *dst++ = ctable[(s4 >> 16) & 0xFF];
201            *dst++ = ctable[(s4 >> 8) & 0xFF];
202            *dst++ = ctable[s4 & 0xFF];
203#endif
204        } while (--qcount);
205    } else {    // dst is on a 4byte boundary
206        uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
207        do {
208            uint32_t s4 = *qsrc++;
209#ifdef SK_CPU_LENDIAN
210            *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
211            *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
212#else   // BENDIAN
213            *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
214            *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
215#endif
216        } while (--qcount);
217        dst = reinterpret_cast<uint16_t*>(ddst);
218    }
219    src = reinterpret_cast<const uint8_t*>(qsrc);
220    count &= 3;
221    // catch any remaining (will be < 4)
222    while (--count >= 0) {
223        *dst++ = ctable[*src++];
224    }
225}
226
227#define SkSPRITE_ROW_PROC(d, s, n, x, y)    blitrow_d16_si8(d, s, n, ctable)
228
229#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Opaque
230#define SkSPRITE_ARGS
231#define SkSPRITE_FIELDS
232#define SkSPRITE_INIT
233#define SkSPRITE_DST_TYPE                   uint16_t
234#define SkSPRITE_SRC_TYPE                   uint8_t
235#define SkSPRITE_DST_GETADDR                getAddr16
236#define SkSPRITE_SRC_GETADDR                getAddr8
237#define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache()
238#define SkSPRITE_BLIT_PIXEL(dst, src)       *dst = ctable[src]
239#define SkSPRITE_NEXT_ROW
240#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlock16BitCache()
241#include "SkSpriteBlitterTemplate.h"
242
243#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Blend
244#define SkSPRITE_ARGS                       , uint8_t alpha
245#define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
246#define SkSPRITE_INIT                       fSrcAlpha = alpha;
247#define SkSPRITE_DST_TYPE                   uint16_t
248#define SkSPRITE_SRC_TYPE                   uint8_t
249#define SkSPRITE_DST_GETADDR                getAddr16
250#define SkSPRITE_SRC_GETADDR                getAddr8
251#define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
252#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
253#define SkSPRITE_NEXT_ROW
254#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlock16BitCache();
255#include "SkSpriteBlitterTemplate.h"
256
257///////////////////////////////////////////////////////////////////////////////
258
259class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
260public:
261    Sprite_D16_S32_BlitRowProc(const SkBitmap& source)
262        : SkSpriteBlitter(source) {}
263
264    // overrides
265
266    virtual void setup(const SkBitmap& device, int left, int top,
267                       const SkPaint& paint) {
268        this->INHERITED::setup(device, left, top, paint);
269
270        unsigned flags = 0;
271
272        if (paint.getAlpha() < 0xFF) {
273            flags |= SkBlitRow::kGlobalAlpha_Flag;
274        }
275        if (!fSource->isOpaque()) {
276            flags |= SkBlitRow::kSrcPixelAlpha_Flag;
277        }
278        if (paint.isDither()) {
279            flags |= SkBlitRow::kDither_Flag;
280        }
281        fProc = SkBlitRow::Factory(flags, kRGB_565_SkColorType);
282    }
283
284    virtual void blitRect(int x, int y, int width, int height) {
285        uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
286        const SkPMColor* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
287                                                              y - fTop);
288        size_t dstRB = fDevice->rowBytes();
289        size_t srcRB = fSource->rowBytes();
290        SkBlitRow::Proc proc = fProc;
291        U8CPU alpha = fPaint->getAlpha();
292
293        while (--height >= 0) {
294            proc(dst, src, width, alpha, x, y);
295            y += 1;
296            dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
297            src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
298        }
299    }
300
301private:
302    SkBlitRow::Proc fProc;
303
304    typedef SkSpriteBlitter INHERITED;
305};
306
307///////////////////////////////////////////////////////////////////////////////
308
309SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint,
310        SkTBlitterAllocator* allocator) {
311
312    SkASSERT(allocator != NULL);
313
314    if (paint.getMaskFilter() != NULL) { // may add cases for this
315        return NULL;
316    }
317    if (paint.getXfermode() != NULL) { // may add cases for this
318        return NULL;
319    }
320    if (paint.getColorFilter() != NULL) { // may add cases for this
321        return NULL;
322    }
323
324    SkSpriteBlitter* blitter = NULL;
325    unsigned alpha = paint.getAlpha();
326
327    switch (source.colorType()) {
328        case kN32_SkColorType: {
329            blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
330            break;
331        }
332        case kARGB_4444_SkColorType:
333            if (255 == alpha) {
334                blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
335            } else {
336                blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
337            }
338            break;
339        case kRGB_565_SkColorType:
340            if (255 == alpha) {
341                blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
342            } else {
343                blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
344            }
345            break;
346        case kIndex_8_SkColorType:
347            if (paint.isDither()) {
348                // we don't support dither yet in these special cases
349                break;
350            }
351            if (source.isOpaque()) {
352                if (255 == alpha) {
353                    blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
354                } else {
355                    blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
356                }
357            } else {
358                if (255 == alpha) {
359                    blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
360                } else {
361                    blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);
362                }
363            }
364            break;
365        default:
366            break;
367    }
368    return blitter;
369}
370