1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkBlitMask.h"
9 #include "SkColor.h"
10 #include "SkColorPriv.h"
11 
D32_A8_Color(void * SK_RESTRICT dst,size_t dstRB,const void * SK_RESTRICT maskPtr,size_t maskRB,SkColor color,int width,int height)12 static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB,
13                          const void* SK_RESTRICT maskPtr, size_t maskRB,
14                          SkColor color, int width, int height) {
15     SkPMColor pmc = SkPreMultiplyColor(color);
16     size_t dstOffset = dstRB - (width << 2);
17     size_t maskOffset = maskRB - width;
18     SkPMColor* SK_RESTRICT device = (SkPMColor *)dst;
19     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
20 
21     do {
22         int w = width;
23         do {
24             unsigned aa = *mask++;
25             *device = SkBlendARGB32(pmc, *device, aa);
26             device += 1;
27         } while (--w != 0);
28         device = (uint32_t*)((char*)device + dstOffset);
29         mask += maskOffset;
30     } while (--height != 0);
31 }
32 
D32_A8_Opaque(void * SK_RESTRICT dst,size_t dstRB,const void * SK_RESTRICT maskPtr,size_t maskRB,SkColor color,int width,int height)33 static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB,
34                           const void* SK_RESTRICT maskPtr, size_t maskRB,
35                           SkColor color, int width, int height) {
36     SkPMColor pmc = SkPreMultiplyColor(color);
37     SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
38     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
39 
40     maskRB -= width;
41     dstRB -= (width << 2);
42     do {
43         int w = width;
44         do {
45             unsigned aa = *mask++;
46             *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
47             device += 1;
48         } while (--w != 0);
49         device = (uint32_t*)((char*)device + dstRB);
50         mask += maskRB;
51     } while (--height != 0);
52 }
53 
D32_A8_Black(void * SK_RESTRICT dst,size_t dstRB,const void * SK_RESTRICT maskPtr,size_t maskRB,SkColor,int width,int height)54 static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB,
55                          const void* SK_RESTRICT maskPtr, size_t maskRB,
56                          SkColor, int width, int height) {
57     SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
58     const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
59 
60     maskRB -= width;
61     dstRB -= (width << 2);
62     do {
63         int w = width;
64         do {
65             unsigned aa = *mask++;
66             *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
67             device += 1;
68         } while (--w != 0);
69         device = (uint32_t*)((char*)device + dstRB);
70         mask += maskRB;
71     } while (--height != 0);
72 }
73 
BlitLCD16RowFactory(bool isOpaque)74 SkBlitMask::BlitLCD16RowProc SkBlitMask::BlitLCD16RowFactory(bool isOpaque) {
75     BlitLCD16RowProc proc = PlatformBlitRowProcs16(isOpaque);
76     if (proc) {
77         return proc;
78     }
79 
80     if (isOpaque) {
81         return  SkBlitLCD16OpaqueRow;
82     } else {
83         return  SkBlitLCD16Row;
84     }
85 }
86 
D32_LCD16_Proc(void * SK_RESTRICT dst,size_t dstRB,const void * SK_RESTRICT mask,size_t maskRB,SkColor color,int width,int height)87 static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
88                            const void* SK_RESTRICT mask, size_t maskRB,
89                            SkColor color, int width, int height) {
90 
91     SkPMColor*        dstRow = (SkPMColor*)dst;
92     const uint16_t* srcRow = (const uint16_t*)mask;
93     SkPMColor       opaqueDst;
94 
95     SkBlitMask::BlitLCD16RowProc proc = NULL;
96     bool isOpaque = (0xFF == SkColorGetA(color));
97     proc = SkBlitMask::BlitLCD16RowFactory(isOpaque);
98     SkASSERT(proc != NULL);
99 
100     if (isOpaque) {
101         opaqueDst = SkPreMultiplyColor(color);
102     } else {
103         opaqueDst = 0;  // ignored
104     }
105 
106     do {
107         proc(dstRow, srcRow, color, width, opaqueDst);
108         dstRow = (SkPMColor*)((char*)dstRow + dstRB);
109         srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
110     } while (--height != 0);
111 }
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 
D32_A8_Factory(SkColor color)115 static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) {
116     if (SK_ColorBLACK == color) {
117         return D32_A8_Black;
118     } else if (0xFF == SkColorGetA(color)) {
119         return D32_A8_Opaque;
120     } else {
121         return D32_A8_Color;
122     }
123 }
124 
ColorFactory(SkColorType ct,SkMask::Format format,SkColor color)125 SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkColorType ct,
126                                                SkMask::Format format,
127                                                SkColor color) {
128     ColorProc proc = PlatformColorProcs(ct, format, color);
129     if (proc) {
130         return proc;
131     }
132 
133     switch (ct) {
134         case kN32_SkColorType:
135             switch (format) {
136                 case SkMask::kA8_Format:
137                     return D32_A8_Factory(color);
138                 case SkMask::kLCD16_Format:
139                     return D32_LCD16_Proc;
140                 default:
141                     break;
142             }
143             break;
144         default:
145             break;
146     }
147     return NULL;
148 }
149 
BlitColor(const SkBitmap & device,const SkMask & mask,const SkIRect & clip,SkColor color)150 bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
151                            const SkIRect& clip, SkColor color) {
152     ColorProc proc = ColorFactory(device.colorType(), mask.fFormat, color);
153     if (proc) {
154         int x = clip.fLeft;
155         int y = clip.fTop;
156         proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y),
157              mask.fRowBytes, color, clip.width(), clip.height());
158         return true;
159     }
160     return false;
161 }
162 
163 ///////////////////////////////////////////////////////////////////////////////
164 ///////////////////////////////////////////////////////////////////////////////
165 
BW_RowProc_Blend(SkPMColor * SK_RESTRICT dst,const uint8_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)166 static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
167                              const uint8_t* SK_RESTRICT mask,
168                              const SkPMColor* SK_RESTRICT src, int count) {
169     int i, octuple = (count + 7) >> 3;
170     for (i = 0; i < octuple; ++i) {
171         int m = *mask++;
172         if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
173         if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); }
174         if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); }
175         if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); }
176         if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); }
177         if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); }
178         if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); }
179         if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); }
180         src += 8;
181         dst += 8;
182     }
183     count &= 7;
184     if (count > 0) {
185         int m = *mask;
186         do {
187             if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
188             m <<= 1;
189             src += 1;
190             dst += 1;
191         } while (--count > 0);
192     }
193 }
194 
BW_RowProc_Opaque(SkPMColor * SK_RESTRICT dst,const uint8_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)195 static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
196                               const uint8_t* SK_RESTRICT mask,
197                               const SkPMColor* SK_RESTRICT src, int count) {
198     int i, octuple = (count + 7) >> 3;
199     for (i = 0; i < octuple; ++i) {
200         int m = *mask++;
201         if (m & 0x80) { dst[0] = src[0]; }
202         if (m & 0x40) { dst[1] = src[1]; }
203         if (m & 0x20) { dst[2] = src[2]; }
204         if (m & 0x10) { dst[3] = src[3]; }
205         if (m & 0x08) { dst[4] = src[4]; }
206         if (m & 0x04) { dst[5] = src[5]; }
207         if (m & 0x02) { dst[6] = src[6]; }
208         if (m & 0x01) { dst[7] = src[7]; }
209         src += 8;
210         dst += 8;
211     }
212     count &= 7;
213     if (count > 0) {
214         int m = *mask;
215         do {
216             if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
217             m <<= 1;
218             src += 1;
219             dst += 1;
220         } while (--count > 0);
221     }
222 }
223 
A8_RowProc_Blend(SkPMColor * SK_RESTRICT dst,const uint8_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)224 static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
225                              const uint8_t* SK_RESTRICT mask,
226                              const SkPMColor* SK_RESTRICT src, int count) {
227     for (int i = 0; i < count; ++i) {
228         if (mask[i]) {
229             dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]);
230         }
231     }
232 }
233 
234 // expand the steps that SkAlphaMulQ performs, but this way we can
235 //  exand.. add.. combine
236 // instead of
237 // expand..combine add expand..combine
238 //
239 #define EXPAND0(v, m, s)    ((v) & (m)) * (s)
240 #define EXPAND1(v, m, s)    (((v) >> 8) & (m)) * (s)
241 #define COMBINE(e0, e1, m)  ((((e0) >> 8) & (m)) | ((e1) & ~(m)))
242 
A8_RowProc_Opaque(SkPMColor * SK_RESTRICT dst,const uint8_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)243 static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
244                               const uint8_t* SK_RESTRICT mask,
245                               const SkPMColor* SK_RESTRICT src, int count) {
246     for (int i = 0; i < count; ++i) {
247         int m = mask[i];
248         if (m) {
249             m += (m >> 7);
250 #if 1
251             // this is slightly slower than the expand/combine version, but it
252             // is much closer to the old results, so we use it for now to reduce
253             // rebaselining.
254             dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m);
255 #else
256             uint32_t v = src[i];
257             uint32_t s0 = EXPAND0(v, rbmask, m);
258             uint32_t s1 = EXPAND1(v, rbmask, m);
259             v = dst[i];
260             uint32_t d0 = EXPAND0(v, rbmask, m);
261             uint32_t d1 = EXPAND1(v, rbmask, m);
262             dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask);
263 #endif
264         }
265     }
266 }
267 
upscale31To255(int value)268 static int upscale31To255(int value) {
269     value = (value << 3) | (value >> 2);
270     return value;
271 }
272 
src_alpha_blend(int src,int dst,int srcA,int mask)273 static int src_alpha_blend(int src, int dst, int srcA, int mask) {
274 
275     return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask);
276 }
277 
LCD16_RowProc_Blend(SkPMColor * SK_RESTRICT dst,const uint16_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)278 static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
279                                 const uint16_t* SK_RESTRICT mask,
280                                 const SkPMColor* SK_RESTRICT src, int count) {
281     for (int i = 0; i < count; ++i) {
282         uint16_t m = mask[i];
283         if (0 == m) {
284             continue;
285         }
286 
287         SkPMColor s = src[i];
288         SkPMColor d = dst[i];
289 
290         int srcA = SkGetPackedA32(s);
291         int srcR = SkGetPackedR32(s);
292         int srcG = SkGetPackedG32(s);
293         int srcB = SkGetPackedB32(s);
294 
295         srcA += srcA >> 7;
296 
297         /*  We want all of these in 5bits, hence the shifts in case one of them
298          *  (green) is 6bits.
299          */
300         int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
301         int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
302         int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
303 
304         maskR = upscale31To255(maskR);
305         maskG = upscale31To255(maskG);
306         maskB = upscale31To255(maskB);
307 
308         int dstR = SkGetPackedR32(d);
309         int dstG = SkGetPackedG32(d);
310         int dstB = SkGetPackedB32(d);
311 
312         // LCD blitting is only supported if the dst is known/required
313         // to be opaque
314         dst[i] = SkPackARGB32(0xFF,
315                               src_alpha_blend(srcR, dstR, srcA, maskR),
316                               src_alpha_blend(srcG, dstG, srcA, maskG),
317                               src_alpha_blend(srcB, dstB, srcA, maskB));
318     }
319 }
320 
LCD16_RowProc_Opaque(SkPMColor * SK_RESTRICT dst,const uint16_t * SK_RESTRICT mask,const SkPMColor * SK_RESTRICT src,int count)321 static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
322                                  const uint16_t* SK_RESTRICT mask,
323                                  const SkPMColor* SK_RESTRICT src, int count) {
324     for (int i = 0; i < count; ++i) {
325         uint16_t m = mask[i];
326         if (0 == m) {
327             continue;
328         }
329 
330         SkPMColor s = src[i];
331         SkPMColor d = dst[i];
332 
333         int srcR = SkGetPackedR32(s);
334         int srcG = SkGetPackedG32(s);
335         int srcB = SkGetPackedB32(s);
336 
337         /*  We want all of these in 5bits, hence the shifts in case one of them
338          *  (green) is 6bits.
339          */
340         int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
341         int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
342         int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
343 
344         // Now upscale them to 0..32, so we can use blend32
345         maskR = SkUpscale31To32(maskR);
346         maskG = SkUpscale31To32(maskG);
347         maskB = SkUpscale31To32(maskB);
348 
349         int dstR = SkGetPackedR32(d);
350         int dstG = SkGetPackedG32(d);
351         int dstB = SkGetPackedB32(d);
352 
353         // LCD blitting is only supported if the dst is known/required
354         // to be opaque
355         dst[i] = SkPackARGB32(0xFF,
356                               SkBlend32(srcR, dstR, maskR),
357                               SkBlend32(srcG, dstG, maskG),
358                               SkBlend32(srcB, dstB, maskB));
359     }
360 }
361 
RowFactory(SkColorType ct,SkMask::Format format,RowFlags flags)362 SkBlitMask::RowProc SkBlitMask::RowFactory(SkColorType ct,
363                                            SkMask::Format format,
364                                            RowFlags flags) {
365 // make this opt-in until chrome can rebaseline
366     RowProc proc = PlatformRowProcs(ct, format, flags);
367     if (proc) {
368         return proc;
369     }
370 
371     static const RowProc gProcs[] = {
372         // need X coordinate to handle BW
373         false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning
374         false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning
375         (RowProc)A8_RowProc_Blend,      (RowProc)A8_RowProc_Opaque,
376         (RowProc)LCD16_RowProc_Blend,   (RowProc)LCD16_RowProc_Opaque,
377     };
378 
379     int index;
380     switch (ct) {
381         case kN32_SkColorType:
382             switch (format) {
383                 case SkMask::kBW_Format:    index = 0; break;
384                 case SkMask::kA8_Format:    index = 2; break;
385                 case SkMask::kLCD16_Format: index = 4; break;
386                 default:
387                     return NULL;
388             }
389             if (flags & kSrcIsOpaque_RowFlag) {
390                 index |= 1;
391             }
392             SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs));
393             return gProcs[index];
394         default:
395             break;
396     }
397     return NULL;
398 }
399