• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkBlendARGB4444(SkPMColor16 src,SkPMColor16 dst,U8CPU aa)18 static inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst,
19                                         U8CPU aa) {
20     SkASSERT((unsigned)aa <= 255);
21 
22     unsigned src_scale = SkAlpha255To256(aa) >> 4;
23     unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale));
24 
25     uint32_t src32 = SkExpand_4444(src) * src_scale;
26     uint32_t dst32 = SkExpand_4444(dst) * dst_scale;
27     return SkCompact_4444((src32 + dst32) >> 4);
28 }
29 
30 ///////////////////////////////////////////////////////////////////////////////
31 
32 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 
SkARGB4444_Blitter(const SkBitmap & device,const SkPaint & paint)56 SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device,
57                                    const SkPaint& paint) : INHERITED(device) {
58     // cache premultiplied versions in 4444
59     SkPMColor c = SkPreMultiplyColor(paint.getColor());
60     fPMColor16 = SkPixel32ToPixel4444(c);
61     if (paint.isDither()) {
62         fPMColor16Other = SkDitherPixel32To4444(c);
63     } else {
64         fPMColor16Other = fPMColor16;
65     }
66 
67     // cache raw versions in 4444
68     fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
69                                  SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
70     if (paint.isDither()) {
71         fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
72                                                 SkColorGetG(c), SkColorGetB(c));
73     } else {
74         fRawColor16Other = fRawColor16;
75     }
76 
77     fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
78     if (16 == fScale16) {
79         // force the original to also be opaque
80         fPMColor16 |= (0xF << SK_A4444_SHIFT);
81     }
82 }
83 
justAnOpaqueColor(uint32_t * value)84 const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) {
85     if (16 == fScale16) {
86         *value = fPMColor16;
87         return &fDevice;
88     }
89     return NULL;
90 }
91 
src_over_4444(SkPMColor16 dst[],SkPMColor16 color,SkPMColor16 other,unsigned invScale,int count)92 static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color,
93                           SkPMColor16 other, unsigned invScale, int count) {
94     int twice = count >> 1;
95     while (--twice >= 0) {
96         *dst = color + SkAlphaMulQ4(*dst, invScale);
97         dst++;
98         *dst = other + SkAlphaMulQ4(*dst, invScale);
99         dst++;
100     }
101     if (count & 1) {
102         *dst = color + SkAlphaMulQ4(*dst, invScale);
103     }
104 }
105 
SkExpand_4444_Replicate(SkPMColor16 c)106 static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) {
107     uint32_t c32 = SkExpand_4444(c);
108     return c32 | (c32 << 4);
109 }
110 
src_over_4444x(SkPMColor16 dst[],uint32_t color,uint32_t other,unsigned invScale,int count)111 static void src_over_4444x(SkPMColor16 dst[], uint32_t color,
112                            uint32_t other, unsigned invScale, int count) {
113     int twice = count >> 1;
114     uint32_t tmp;
115     while (--twice >= 0) {
116         tmp = SkExpand_4444(*dst) * invScale;
117         *dst++ = SkCompact_4444((color + tmp) >> 4);
118         tmp = SkExpand_4444(*dst) * invScale;
119         *dst++ = SkCompact_4444((other + tmp) >> 4);
120     }
121     if (count & 1) {
122         tmp = SkExpand_4444(*dst) * invScale;
123         *dst = SkCompact_4444((color + tmp) >> 4);
124     }
125 }
126 
blitH(int x,int y,int width)127 void SkARGB4444_Blitter::blitH(int x, int y, int width) {
128     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
129 
130     if (0 == fScale16) {
131         return;
132     }
133 
134     SkPMColor16* device = fDevice.getAddr16(x, y);
135     SkPMColor16  color = fPMColor16;
136     SkPMColor16  other = fPMColor16Other;
137 
138     if ((x ^ y) & 1) {
139         SkTSwap<SkPMColor16>(color, other);
140     }
141 
142     if (16 == fScale16) {
143         sk_dither_memset16(device, color, other, width);
144     } else {
145         src_over_4444x(device, SkExpand_4444_Replicate(color),
146                        SkExpand_4444_Replicate(other),
147                        16 - fScale16, width);
148     }
149 }
150 
blitV(int x,int y,int height,SkAlpha alpha)151 void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
152     if (0 == alpha || 0 == fScale16) {
153         return;
154     }
155 
156     SkPMColor16* device = fDevice.getAddr16(x, y);
157     SkPMColor16  color = fPMColor16;
158     SkPMColor16  other = fPMColor16Other;
159     unsigned     rb = fDevice.rowBytes();
160 
161     if ((x ^ y) & 1) {
162         SkTSwap<SkPMColor16>(color, other);
163     }
164 
165     if (16 == fScale16 && 255 == alpha) {
166         while (--height >= 0) {
167             *device = color;
168             device = (SkPMColor16*)((char*)device + rb);
169             SkTSwap<SkPMColor16>(color, other);
170         }
171     } else {
172         unsigned alphaScale = SkAlpha255To256(alpha);
173         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         c32 = SkCompact_4444(c32 >> 4);
177         unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32));
178         // now re-expand and replicate
179         c32 = SkExpand_4444_Replicate(c32);
180 
181         while (--height >= 0) {
182             uint32_t d32 = SkExpand_4444(*device) * invScale;
183             *device = SkCompact_4444((c32 + d32) >> 4);
184             device = (SkPMColor16*)((char*)device + rb);
185         }
186     }
187 }
188 
blitRect(int x,int y,int width,int height)189 void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) {
190     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() &&
191              y + height <= fDevice.height());
192 
193     if (0 == fScale16) {
194         return;
195     }
196 
197     SkPMColor16* device = fDevice.getAddr16(x, y);
198     SkPMColor16  color = fPMColor16;
199     SkPMColor16  other = fPMColor16Other;
200 
201     if ((x ^ y) & 1) {
202         SkTSwap<SkPMColor16>(color, other);
203     }
204 
205     if (16 == fScale16) {
206         while (--height >= 0) {
207             sk_dither_memset16(device, color, other, width);
208             device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
209             SkTSwap<SkPMColor16>(color, other);
210         }
211     } else {
212         unsigned invScale = 16 - fScale16;
213 
214         uint32_t c32 = SkExpand_4444_Replicate(color);
215         uint32_t o32 = SkExpand_4444_Replicate(other);
216         while (--height >= 0) {
217             src_over_4444x(device, c32, o32, invScale, width);
218             device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
219             SkTSwap<uint32_t>(c32, o32);
220         }
221     }
222 }
223 
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])224 void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
225                                    const int16_t runs[]) {
226     if (0 == fScale16) {
227         return;
228     }
229 
230     SkPMColor16* device = fDevice.getAddr16(x, y);
231     SkPMColor16  color = fPMColor16;
232     SkPMColor16  other = fPMColor16Other;
233 
234     if ((x ^ y) & 1) {
235         SkTSwap<SkPMColor16>(color, other);
236     }
237 
238     for (;;) {
239         int count = runs[0];
240         SkASSERT(count >= 0);
241         if (count <= 0) {
242             return;
243         }
244 
245         unsigned aa = antialias[0];
246         if (aa) {
247             if (0xFF == aa) {
248                 if (16 == fScale16) {
249                     sk_dither_memset16(device, color, other, count);
250                 } else {
251                     src_over_4444(device, color, other, 16 - fScale16, count);
252                 }
253             } else {
254                 // todo: respect dithering
255                 aa = SkAlpha255To256(aa);   // FIX
256                 SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4);
257                 unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX
258                 int n = count;
259                 do {
260                     --n;
261                     device[n] = src + SkAlphaMulQ4(device[n], dst_scale);
262                 } while (n > 0);
263             }
264         }
265 
266         runs += count;
267         antialias += count;
268         device += count;
269 
270         if (count & 1) {
271             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 
blitMask(const SkMask & mask,const SkIRect & clip)316 void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
317     SkASSERT(mask.fBounds.contains(clip));
318 
319     if (0 == fScale16) {
320         return;
321     }
322 
323     if (mask.fFormat == SkMask::kBW_Format) {
324         if (16 == fScale16) {
325             SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16);
326         } else {
327             SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16);
328         }
329         return;
330     }
331 
332     int x = clip.fLeft;
333     int y = clip.fTop;
334     int width = clip.width();
335     int height = clip.height();
336 
337     SkPMColor16*    device = fDevice.getAddr16(x, y);
338     const uint8_t*  alpha = mask.getAddr8(x, y);
339     SkPMColor16     srcColor = fPMColor16;
340     unsigned        devRB = fDevice.rowBytes() - (width << 1);
341     unsigned        maskRB = mask.fRowBytes - width;
342 
343     do {
344         int w = width;
345         do {
346             unsigned aa = *alpha++;
347             *device = SkBlendARGB4444(srcColor, *device, aa);
348             device += 1;
349         } while (--w != 0);
350         device = (SkPMColor16*)((char*)device + devRB);
351         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 
SkARGB4444_Shader_Blitter(const SkBitmap & device,const SkPaint & paint)365 SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
366         : INHERITED(device, paint) {
367     const int width = device.width();
368     fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width);
369     fAAExpand = (uint8_t*)(fBuffer + width);
370 
371     fXfermode = paint.getXfermode();
372     SkSafeRef(fXfermode);
373 
374     unsigned flags = 0;
375     if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
376         flags |= SkBlitRow::kSrcPixelAlpha_Flag;
377     }
378     if (paint.isDither()) {
379         flags |= SkBlitRow::kDither_Flag;
380     }
381     fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config);
382     fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
383                                     SkBitmap::kARGB_4444_Config);
384 }
385 
~SkARGB4444_Shader_Blitter()386 virtual ~SkARGB4444_Shader_Blitter() {
387     SkSafeUnref(fXfermode);
388     sk_free(fBuffer);
389 }
390 
blitH(int x,int y,int width)391 virtual void blitH(int x, int y, int width) {
392     SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
393 
394     SkPMColor16* device = fDevice.getAddr16(x, y);
395     SkPMColor*   span = fBuffer;
396 
397     fShader->shadeSpan(x, y, span, width);
398     if (fXfermode) {
399         fXfermode->xfer4444(device, span, width, NULL);
400     } else {
401         fOpaqueProc(device, span, width, 0xFF, x, y);
402     }
403 }
404 
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])405 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
406                        const int16_t runs[]) {
407     SkPMColor* SK_RESTRICT span = fBuffer;
408     uint8_t* SK_RESTRICT aaExpand = fAAExpand;
409     SkPMColor16* device = fDevice.getAddr16(x, y);
410     SkShader*    shader = fShader;
411     SkXfermode*  xfer = fXfermode;
412 
413     if (NULL != xfer) {
414         for (;;) {
415             int count = *runs;
416             if (count <= 0) {
417                 break;
418             }
419             int aa = *antialias;
420             if (aa) {
421                 shader->shadeSpan(x, y, span, count);
422                 if (255 == aa) {
423                     xfer->xfer4444(device, span, count, NULL);
424                 } else {
425                     const uint8_t* aaBuffer = antialias;
426                     if (count > 1) {
427                         memset(aaExpand, aa, count);
428                         aaBuffer = aaExpand;
429                     }
430                     xfer->xfer4444(device, span, count, aaBuffer);
431                 }
432             }
433             device += count;
434             runs += count;
435             antialias += count;
436             x += count;
437         }
438     } else {    // no xfermode
439         for (;;) {
440             int count = *runs;
441             if (count <= 0) {
442                 break;
443             }
444             int aa = *antialias;
445             if (aa) {
446                 fShader->shadeSpan(x, y, span, count);
447                 if (255 == aa) {
448                     fOpaqueProc(device, span, count, aa, x, y);
449                 } else {
450                     fAlphaProc(device, span, count, aa, x, y);
451                 }
452             }
453             device += count;
454             runs += count;
455             antialias += count;
456             x += count;
457         }
458     }
459 }
460 
461 private:
462     typedef SkShaderBlitter INHERITED;
463 };
464 
465 ///////////////////////////////////////////////////////////////////////////////
466 ///////////////////////////////////////////////////////////////////////////////
467 
SkBlitter_ChooseD4444(const SkBitmap & device,const SkPaint & paint,void * storage,size_t storageSize)468 SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device,
469                                  const SkPaint& paint,
470                                  void* storage, size_t storageSize)
471 {
472     SkBlitter* blitter;
473 
474     if (paint.getShader()) {
475         SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint));
476     } else {
477         SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint));
478     }
479     return blitter;
480 }
481 
482