|
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) \ |
|
17 do { \ |
|
18 if (sc) { \ |
|
19 *dst = SkSrcOver32To16(sc, *dst); \ |
|
20 } \ |
|
21 } while (0) |
|
22 |
|
23 static 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 |
|
51 class Sprite_D16_S16_Opaque : public SkSpriteBlitter { |
|
52 public: |
|
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 |
|
167 static intptr_t asint(const void* ptr) { |
|
168 return reinterpret_cast<const char*>(ptr) - (const char*)0; |
|
169 } |
|
170 |
|
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) { |
|
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 |
|
259 class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter { |
|
260 public: |
|
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, SkBitmap::kRGB_565_Config); |
|
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 |
|
301 private: |
|
302 SkBlitRow::Proc fProc; |
|
303 |
|
304 typedef SkSpriteBlitter INHERITED; |
|
305 }; |
|
306 |
|
307 /////////////////////////////////////////////////////////////////////////////// |
|
308 |
|
309 SkSpriteBlitter* 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 kPMColor_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 } |