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