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