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