3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkSpriteBlitter.h"
11 #include "SkBlitRow.h"
12 #include "SkTemplates.h"
14 #include "SkColorPriv.h"
16 #define D16_S32A_Opaque_Pixel(dst, sc) \
19 *dst = SkSrcOver32To16(sc, *dst); \
23 static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
26 unsigned sa = SkGetPackedA32(sc);
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);
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;
42 *dst = SkPackRGB16(dr, dg, db);
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)
49 ///////////////////////////////////////////////////////////////////////////////
51 class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
53 Sprite_D16_S16_Opaque(const SkBitmap& source)
54 : SkSpriteBlitter(source) {}
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,
61 size_t dstRB = fDevice->rowBytes();
62 size_t srcRB = fSource->rowBytes();
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);
72 #define D16_S16_Blend_Pixel(dst, sc, scale) \
75 *dst = SkBlendRGB16(sc, dc, scale); \
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"
92 ///////////////////////////////////////////////////////////////////////////////
94 #define D16_S4444_Opaque(dst, sc) \
97 *dst = SkSrcOver4444To16(sc, dc); \
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"
114 #define D16_S4444_Blend(dst, sc, scale16) \
116 uint16_t dc = *dst; \
117 *dst = SkBlend4444To16(sc, dc, scale16); \
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"
135 ///////////////////////////////////////////////////////////////////////////////
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"
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"
165 ///////////////////////////////////////////////////////////////////////////////
167 static intptr_t asint(const void* ptr) {
168 return reinterpret_cast<const char*>(ptr) - (const char*)0;
171 static 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) {
176 *dst++ = ctable[*src++];
181 // eat src until we're on a 4byte boundary
182 while (asint(src) & 3) {
183 *dst++ = ctable[*src++];
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) {
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];
199 *dst++ = ctable[s4 >> 24];
200 *dst++ = ctable[(s4 >> 16) & 0xFF];
201 *dst++ = ctable[(s4 >> 8) & 0xFF];
202 *dst++ = ctable[s4 & 0xFF];
205 } else { // dst is on a 4byte boundary
206 uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
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];
213 *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
214 *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
217 dst = reinterpret_cast<uint16_t*>(ddst);
219 src = reinterpret_cast<const uint8_t*>(qsrc);
221 // catch any remaining (will be < 4)
222 while (--count >= 0) {
223 *dst++ = ctable[*src++];
227 #define SkSPRITE_ROW_PROC(d, s, n, x, y) blitrow_d16_si8(d, s, n, ctable)
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"
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"
257 ///////////////////////////////////////////////////////////////////////////////
259 class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
261 Sprite_D16_S32_BlitRowProc(const SkBitmap& source)
262 : SkSpriteBlitter(source) {}
266 virtual void setup(const SkBitmap& device, int left, int top,
267 const SkPaint& paint) {
268 this->INHERITED::setup(device, left, top, paint);
272 if (paint.getAlpha() < 0xFF) {
273 flags |= SkBlitRow::kGlobalAlpha_Flag;
275 if (!fSource->isOpaque()) {
276 flags |= SkBlitRow::kSrcPixelAlpha_Flag;
278 if (paint.isDither()) {
279 flags |= SkBlitRow::kDither_Flag;
281 fProc = SkBlitRow::Factory(flags, SkBitmap::kRGB_565_Config);
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,
288 size_t dstRB = fDevice->rowBytes();
289 size_t srcRB = fSource->rowBytes();
290 SkBlitRow::Proc proc = fProc;
291 U8CPU alpha = fPaint->getAlpha();
293 while (--height >= 0) {
294 proc(dst, src, width, alpha, x, y);
296 dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
297 src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
302 SkBlitRow::Proc fProc;
304 typedef SkSpriteBlitter INHERITED;
307 ///////////////////////////////////////////////////////////////////////////////
309 SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint,
310 SkTBlitterAllocator* allocator) {
312 SkASSERT(allocator != NULL);
314 if (paint.getMaskFilter() != NULL) { // may add cases for this
317 if (paint.getXfermode() != NULL) { // may add cases for this
320 if (paint.getColorFilter() != NULL) { // may add cases for this
324 SkSpriteBlitter* blitter = NULL;
325 unsigned alpha = paint.getAlpha();
327 switch (source.colorType()) {
328 case kN32_SkColorType: {
329 blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
332 case kARGB_4444_SkColorType:
334 blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
336 blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
339 case kRGB_565_SkColorType:
341 blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
343 blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
346 case kIndex_8_SkColorType:
347 if (paint.isDither()) {
348 // we don't support dither yet in these special cases
351 if (source.isOpaque()) {
353 blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
355 blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
359 blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
361 blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);