• 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 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