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 "SkCoreBlitters.h"
11 : #include "SkColorPriv.h"
12 : #include "SkDither.h"
13 : #include "SkShader.h"
14 : #include "SkTemplatesPriv.h"
15 : #include "SkUtils.h"
16 : #include "SkXfermode.h"
17 :
18 0 : static inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst,
19 : U8CPU aa) {
20 0 : SkASSERT((unsigned)aa <= 255);
21 :
22 0 : unsigned src_scale = SkAlpha255To256(aa) >> 4;
23 0 : unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale));
24 :
25 0 : uint32_t src32 = SkExpand_4444(src) * src_scale;
26 0 : uint32_t dst32 = SkExpand_4444(dst) * dst_scale;
27 0 : return SkCompact_4444((src32 + dst32) >> 4);
28 : }
29 :
30 : ///////////////////////////////////////////////////////////////////////////////
31 :
32 0 : class SkARGB4444_Blitter : public SkRasterBlitter {
33 : public:
34 : SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint);
35 : virtual void blitH(int x, int y, int width);
36 : virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
37 : const int16_t runs[]);
38 : virtual void blitV(int x, int y, int height, SkAlpha alpha);
39 : virtual void blitRect(int x, int y, int width, int height);
40 : virtual void blitMask(const SkMask&, const SkIRect&);
41 : virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
42 :
43 : protected:
44 : SkPMColor16 fPMColor16, fPMColor16Other;
45 : SkPMColor16 fRawColor16, fRawColor16Other;
46 : uint8_t fScale16;
47 :
48 : private:
49 : // illegal
50 : SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&);
51 :
52 : typedef SkRasterBlitter INHERITED;
53 : };
54 :
55 :
56 0 : SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device,
57 0 : const SkPaint& paint) : INHERITED(device) {
58 : // cache premultiplied versions in 4444
59 0 : SkPMColor c = SkPreMultiplyColor(paint.getColor());
60 0 : fPMColor16 = SkPixel32ToPixel4444(c);
61 0 : if (paint.isDither()) {
62 0 : fPMColor16Other = SkDitherPixel32To4444(c);
63 : } else {
64 0 : fPMColor16Other = fPMColor16;
65 : }
66 :
67 : // cache raw versions in 4444
68 : fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
69 0 : SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
70 0 : if (paint.isDither()) {
71 : fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
72 0 : SkColorGetG(c), SkColorGetB(c));
73 : } else {
74 0 : fRawColor16Other = fRawColor16;
75 : }
76 :
77 0 : fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
78 0 : if (16 == fScale16) {
79 : // force the original to also be opaque
80 0 : fPMColor16 |= (0xF << SK_A4444_SHIFT);
81 : }
82 0 : }
83 :
84 0 : const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) {
85 0 : if (16 == fScale16) {
86 0 : *value = fPMColor16;
87 0 : return &fDevice;
88 : }
89 0 : return NULL;
90 : }
91 :
92 0 : static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color,
93 : SkPMColor16 other, unsigned invScale, int count) {
94 0 : int twice = count >> 1;
95 0 : while (--twice >= 0) {
96 0 : *dst = color + SkAlphaMulQ4(*dst, invScale);
97 0 : dst++;
98 0 : *dst = other + SkAlphaMulQ4(*dst, invScale);
99 0 : dst++;
100 : }
101 0 : if (count & 1) {
102 0 : *dst = color + SkAlphaMulQ4(*dst, invScale);
103 : }
104 0 : }
105 :
106 0 : static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) {
107 0 : uint32_t c32 = SkExpand_4444(c);
108 0 : return c32 | (c32 << 4);
109 : }
110 :
111 0 : static void src_over_4444x(SkPMColor16 dst[], uint32_t color,
112 : uint32_t other, unsigned invScale, int count) {
113 0 : int twice = count >> 1;
114 : uint32_t tmp;
115 0 : while (--twice >= 0) {
116 0 : tmp = SkExpand_4444(*dst) * invScale;
117 0 : *dst++ = SkCompact_4444((color + tmp) >> 4);
118 0 : tmp = SkExpand_4444(*dst) * invScale;
119 0 : *dst++ = SkCompact_4444((other + tmp) >> 4);
120 : }
121 0 : if (count & 1) {
122 0 : tmp = SkExpand_4444(*dst) * invScale;
123 0 : *dst = SkCompact_4444((color + tmp) >> 4);
124 : }
125 0 : }
126 :
127 0 : void SkARGB4444_Blitter::blitH(int x, int y, int width) {
128 0 : SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
129 :
130 0 : if (0 == fScale16) {
131 0 : return;
132 : }
133 :
134 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
135 0 : SkPMColor16 color = fPMColor16;
136 0 : SkPMColor16 other = fPMColor16Other;
137 :
138 0 : if ((x ^ y) & 1) {
139 0 : SkTSwap<SkPMColor16>(color, other);
140 : }
141 :
142 0 : if (16 == fScale16) {
143 0 : sk_dither_memset16(device, color, other, width);
144 : } else {
145 : src_over_4444x(device, SkExpand_4444_Replicate(color),
146 : SkExpand_4444_Replicate(other),
147 0 : 16 - fScale16, width);
148 : }
149 : }
150 :
151 0 : void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
152 0 : if (0 == alpha || 0 == fScale16) {
153 0 : return;
154 : }
155 :
156 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
157 0 : SkPMColor16 color = fPMColor16;
158 0 : SkPMColor16 other = fPMColor16Other;
159 0 : unsigned rb = fDevice.rowBytes();
160 :
161 0 : if ((x ^ y) & 1) {
162 0 : SkTSwap<SkPMColor16>(color, other);
163 : }
164 :
165 0 : if (16 == fScale16 && 255 == alpha) {
166 0 : while (--height >= 0) {
167 0 : *device = color;
168 0 : device = (SkPMColor16*)((char*)device + rb);
169 0 : SkTSwap<SkPMColor16>(color, other);
170 : }
171 : } else {
172 0 : unsigned alphaScale = SkAlpha255To256(alpha);
173 0 : uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4);
174 : // need to normalize the low nibble of each expanded component
175 : // so we don't overflow the add with d32
176 0 : c32 = SkCompact_4444(c32 >> 4);
177 0 : unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32));
178 : // now re-expand and replicate
179 0 : c32 = SkExpand_4444_Replicate(c32);
180 :
181 0 : while (--height >= 0) {
182 0 : uint32_t d32 = SkExpand_4444(*device) * invScale;
183 0 : *device = SkCompact_4444((c32 + d32) >> 4);
184 0 : device = (SkPMColor16*)((char*)device + rb);
185 : }
186 : }
187 : }
188 :
189 0 : void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) {
190 0 : SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() &&
191 : y + height <= fDevice.height());
192 :
193 0 : if (0 == fScale16) {
194 0 : return;
195 : }
196 :
197 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
198 0 : SkPMColor16 color = fPMColor16;
199 0 : SkPMColor16 other = fPMColor16Other;
200 :
201 0 : if ((x ^ y) & 1) {
202 0 : SkTSwap<SkPMColor16>(color, other);
203 : }
204 :
205 0 : if (16 == fScale16) {
206 0 : while (--height >= 0) {
207 0 : sk_dither_memset16(device, color, other, width);
208 0 : device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
209 0 : SkTSwap<SkPMColor16>(color, other);
210 : }
211 : } else {
212 0 : unsigned invScale = 16 - fScale16;
213 :
214 0 : uint32_t c32 = SkExpand_4444_Replicate(color);
215 0 : uint32_t o32 = SkExpand_4444_Replicate(other);
216 0 : while (--height >= 0) {
217 0 : src_over_4444x(device, c32, o32, invScale, width);
218 0 : device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
219 0 : SkTSwap<uint32_t>(c32, o32);
220 : }
221 : }
222 : }
223 :
224 0 : void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
225 : const int16_t runs[]) {
226 0 : if (0 == fScale16) {
227 0 : return;
228 : }
229 :
230 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
231 0 : SkPMColor16 color = fPMColor16;
232 0 : SkPMColor16 other = fPMColor16Other;
233 :
234 0 : if ((x ^ y) & 1) {
235 0 : SkTSwap<SkPMColor16>(color, other);
236 : }
237 :
238 0 : for (;;) {
239 0 : int count = runs[0];
240 0 : SkASSERT(count >= 0);
241 0 : if (count <= 0) {
242 0 : return;
243 : }
244 :
245 0 : unsigned aa = antialias[0];
246 0 : if (aa) {
247 0 : if (0xFF == aa) {
248 0 : if (16 == fScale16) {
249 0 : sk_dither_memset16(device, color, other, count);
250 : } else {
251 0 : src_over_4444(device, color, other, 16 - fScale16, count);
252 : }
253 : } else {
254 : // todo: respect dithering
255 0 : aa = SkAlpha255To256(aa); // FIX
256 0 : SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4);
257 0 : unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX
258 0 : int n = count;
259 0 : do {
260 0 : --n;
261 0 : device[n] = src + SkAlphaMulQ4(device[n], dst_scale);
262 : } while (n > 0);
263 : }
264 : }
265 :
266 0 : runs += count;
267 0 : antialias += count;
268 0 : device += count;
269 :
270 0 : if (count & 1) {
271 0 : SkTSwap<SkPMColor16>(color, other);
272 : }
273 : }
274 : }
275 :
276 : ///////////////////////////////////////////////////////////////////////////////
277 :
278 : #define solid_8_pixels(mask, dst, color) \
279 : do { \
280 : if (mask & 0x80) dst[0] = color; \
281 : if (mask & 0x40) dst[1] = color; \
282 : if (mask & 0x20) dst[2] = color; \
283 : if (mask & 0x10) dst[3] = color; \
284 : if (mask & 0x08) dst[4] = color; \
285 : if (mask & 0x04) dst[5] = color; \
286 : if (mask & 0x02) dst[6] = color; \
287 : if (mask & 0x01) dst[7] = color; \
288 : } while (0)
289 :
290 : #define SK_BLITBWMASK_NAME SkARGB4444_BlitBW
291 : #define SK_BLITBWMASK_ARGS , SkPMColor16 color
292 : #define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
293 : #define SK_BLITBWMASK_GETADDR getAddr16
294 : #define SK_BLITBWMASK_DEVTYPE uint16_t
295 : #include "SkBlitBWMaskTemplate.h"
296 :
297 : #define blend_8_pixels(mask, dst, sc, dst_scale) \
298 : do { \
299 : if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); } \
300 : if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); } \
301 : if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); } \
302 : if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); } \
303 : if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); } \
304 : if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); } \
305 : if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); } \
306 : if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); } \
307 : } while (0)
308 :
309 : #define SK_BLITBWMASK_NAME SkARGB4444_BlendBW
310 : #define SK_BLITBWMASK_ARGS , uint16_t sc, unsigned dst_scale
311 : #define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale)
312 : #define SK_BLITBWMASK_GETADDR getAddr16
313 : #define SK_BLITBWMASK_DEVTYPE uint16_t
314 : #include "SkBlitBWMaskTemplate.h"
315 :
316 0 : void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
317 0 : SkASSERT(mask.fBounds.contains(clip));
318 :
319 0 : if (0 == fScale16) {
320 0 : return;
321 : }
322 :
323 0 : if (mask.fFormat == SkMask::kBW_Format) {
324 0 : if (16 == fScale16) {
325 0 : SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16);
326 : } else {
327 0 : SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16);
328 : }
329 0 : return;
330 : }
331 :
332 0 : int x = clip.fLeft;
333 0 : int y = clip.fTop;
334 0 : int width = clip.width();
335 0 : int height = clip.height();
336 :
337 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
338 0 : const uint8_t* alpha = mask.getAddr8(x, y);
339 0 : SkPMColor16 srcColor = fPMColor16;
340 0 : unsigned devRB = fDevice.rowBytes() - (width << 1);
341 0 : unsigned maskRB = mask.fRowBytes - width;
342 :
343 0 : do {
344 0 : int w = width;
345 0 : do {
346 0 : unsigned aa = *alpha++;
347 0 : *device = SkBlendARGB4444(srcColor, *device, aa);
348 0 : device += 1;
349 : } while (--w != 0);
350 0 : device = (SkPMColor16*)((char*)device + devRB);
351 0 : alpha += maskRB;
352 : } while (--height != 0);
353 : }
354 :
355 : ///////////////////////////////////////////////////////////////////////////////
356 :
357 : class SkARGB4444_Shader_Blitter : public SkShaderBlitter {
358 : SkXfermode* fXfermode;
359 : SkBlitRow::Proc fOpaqueProc;
360 : SkBlitRow::Proc fAlphaProc;
361 : SkPMColor* fBuffer;
362 : uint8_t* fAAExpand;
363 : public:
364 :
365 0 : SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
366 0 : : INHERITED(device, paint) {
367 0 : const int width = device.width();
368 0 : fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width);
369 0 : fAAExpand = (uint8_t*)(fBuffer + width);
370 :
371 0 : fXfermode = paint.getXfermode();
372 0 : SkSafeRef(fXfermode);
373 :
374 0 : unsigned flags = 0;
375 0 : if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
376 0 : flags |= SkBlitRow::kSrcPixelAlpha_Flag;
377 : }
378 0 : if (paint.isDither()) {
379 0 : flags |= SkBlitRow::kDither_Flag;
380 : }
381 0 : fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config);
382 : fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
383 0 : SkBitmap::kARGB_4444_Config);
384 0 : }
385 :
386 0 : virtual ~SkARGB4444_Shader_Blitter() {
387 0 : SkSafeUnref(fXfermode);
388 0 : sk_free(fBuffer);
389 0 : }
390 :
391 0 : virtual void blitH(int x, int y, int width) {
392 0 : SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
393 :
394 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
395 0 : SkPMColor* span = fBuffer;
396 :
397 0 : fShader->shadeSpan(x, y, span, width);
398 0 : if (fXfermode) {
399 0 : fXfermode->xfer4444(device, span, width, NULL);
400 : } else {
401 0 : fOpaqueProc(device, span, width, 0xFF, x, y);
402 : }
403 0 : }
404 :
405 0 : virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
406 : const int16_t runs[]) {
407 0 : SkPMColor* SK_RESTRICT span = fBuffer;
408 0 : uint8_t* SK_RESTRICT aaExpand = fAAExpand;
409 0 : SkPMColor16* device = fDevice.getAddr16(x, y);
410 0 : SkShader* shader = fShader;
411 0 : SkXfermode* xfer = fXfermode;
412 :
413 0 : if (NULL != xfer) {
414 0 : for (;;) {
415 0 : int count = *runs;
416 0 : if (count <= 0) {
417 : break;
418 : }
419 0 : int aa = *antialias;
420 0 : if (aa) {
421 0 : shader->shadeSpan(x, y, span, count);
422 0 : if (255 == aa) {
423 0 : xfer->xfer4444(device, span, count, NULL);
424 : } else {
425 0 : const uint8_t* aaBuffer = antialias;
426 0 : if (count > 1) {
427 0 : memset(aaExpand, aa, count);
428 0 : aaBuffer = aaExpand;
429 : }
430 0 : xfer->xfer4444(device, span, count, aaBuffer);
431 : }
432 : }
433 0 : device += count;
434 0 : runs += count;
435 0 : antialias += count;
436 0 : x += count;
437 : }
438 : } else { // no xfermode
439 0 : for (;;) {
440 0 : int count = *runs;
441 0 : if (count <= 0) {
442 0 : break;
443 : }
444 0 : int aa = *antialias;
445 0 : if (aa) {
446 0 : fShader->shadeSpan(x, y, span, count);
447 0 : if (255 == aa) {
448 0 : fOpaqueProc(device, span, count, aa, x, y);
449 : } else {
450 0 : fAlphaProc(device, span, count, aa, x, y);
451 : }
452 : }
453 0 : device += count;
454 0 : runs += count;
455 0 : antialias += count;
456 0 : x += count;
457 : }
458 : }
459 0 : }
460 :
461 : private:
462 : typedef SkShaderBlitter INHERITED;
463 : };
464 :
465 : ///////////////////////////////////////////////////////////////////////////////
466 : ///////////////////////////////////////////////////////////////////////////////
467 :
468 0 : SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device,
469 : const SkPaint& paint,
470 : void* storage, size_t storageSize)
471 : {
472 : SkBlitter* blitter;
473 :
474 0 : if (paint.getShader()) {
475 0 : SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint));
476 : } else {
477 0 : SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint));
478 : }
479 0 : return blitter;
480 : }
481 :
|