blob: 45d2d119a9cd0125cf6c2c962d92421577e0fc4f [file] [log] [blame]
reed@google.comedb606c2011-10-18 13:56:50 +00001#include "SkBlitMask.h"
2#include "SkColor.h"
3#include "SkColorPriv.h"
4
5static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB,
6 const void* SK_RESTRICT maskPtr, size_t maskRB,
7 SkColor color, int width, int height) {
8 SkPMColor pmc = SkPreMultiplyColor(color);
9 size_t dstOffset = dstRB - (width << 2);
10 size_t maskOffset = maskRB - width;
11 SkPMColor* SK_RESTRICT device = (SkPMColor *)dst;
12 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
13
14 do {
15 int w = width;
16 do {
17 unsigned aa = *mask++;
18 *device = SkBlendARGB32(pmc, *device, aa);
19 device += 1;
20 } while (--w != 0);
21 device = (uint32_t*)((char*)device + dstOffset);
22 mask += maskOffset;
23 } while (--height != 0);
24}
25
26static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB,
27 const void* SK_RESTRICT maskPtr, size_t maskRB,
28 SkColor color, int width, int height) {
29 SkPMColor pmc = SkPreMultiplyColor(color);
30 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
31 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
32
33 maskRB -= width;
34 dstRB -= (width << 2);
35 do {
36 int w = width;
37 do {
38 unsigned aa = *mask++;
39 *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
40 device += 1;
41 } while (--w != 0);
42 device = (uint32_t*)((char*)device + dstRB);
43 mask += maskRB;
44 } while (--height != 0);
45}
46
47static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB,
48 const void* SK_RESTRICT maskPtr, size_t maskRB,
49 SkColor, int width, int height) {
50 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
51 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
52
53 maskRB -= width;
54 dstRB -= (width << 2);
55 do {
56 int w = width;
57 do {
58 unsigned aa = *mask++;
59 *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
60 device += 1;
61 } while (--w != 0);
62 device = (uint32_t*)((char*)device + dstRB);
63 mask += maskRB;
64 } while (--height != 0);
65}
66
67///////////////////////////////////////////////////////////////////////////////
68
69static inline int upscale31To32(int value) {
70 SkASSERT((unsigned)value <= 31);
71 return value + (value >> 4);
72}
73
74static inline int blend32(int src, int dst, int scale) {
75 SkASSERT((unsigned)src <= 0xFF);
76 SkASSERT((unsigned)dst <= 0xFF);
77 SkASSERT((unsigned)scale <= 32);
78 return dst + ((src - dst) * scale >> 5);
79}
80
81static void blit_lcd16_row(SkPMColor dst[], const uint16_t src[],
82 SkColor color, int width, SkPMColor) {
83 int srcA = SkColorGetA(color);
84 int srcR = SkColorGetR(color);
85 int srcG = SkColorGetG(color);
86 int srcB = SkColorGetB(color);
87
88 srcA = SkAlpha255To256(srcA);
89
90 for (int i = 0; i < width; i++) {
91 uint16_t mask = src[i];
92 if (0 == mask) {
93 continue;
94 }
95
96 SkPMColor d = dst[i];
97
98 /* We want all of these in 5bits, hence the shifts in case one of them
99 * (green) is 6bits.
100 */
101 int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
102 int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
103 int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
104
105 // Now upscale them to 0..32, so we can use blend32
106 maskR = upscale31To32(maskR);
107 maskG = upscale31To32(maskG);
108 maskB = upscale31To32(maskB);
109
110 maskR = maskR * srcA >> 8;
111 maskG = maskG * srcA >> 8;
112 maskB = maskB * srcA >> 8;
113
114 int dstR = SkGetPackedR32(d);
115 int dstG = SkGetPackedG32(d);
116 int dstB = SkGetPackedB32(d);
117
118 // LCD blitting is only supported if the dst is known/required\
119 // to be opaque
120 dst[i] = SkPackARGB32(0xFF,
121 blend32(srcR, dstR, maskR),
122 blend32(srcG, dstG, maskG),
123 blend32(srcB, dstB, maskB));
124 }
125}
126
127static void blit_lcd16_opaque_row(SkPMColor dst[], const uint16_t src[],
128 SkColor color, int width, SkPMColor opaqueDst) {
129 int srcR = SkColorGetR(color);
130 int srcG = SkColorGetG(color);
131 int srcB = SkColorGetB(color);
132
133 for (int i = 0; i < width; i++) {
134 uint16_t mask = src[i];
135 if (0 == mask) {
136 continue;
137 }
138 if (0xFFFF == mask) {
139 dst[i] = opaqueDst;
140 continue;
141 }
142
143 SkPMColor d = dst[i];
144
145 /* We want all of these in 5bits, hence the shifts in case one of them
146 * (green) is 6bits.
147 */
148 int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
149 int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
150 int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
151
152 // Now upscale them to 0..32, so we can use blend32
153 maskR = upscale31To32(maskR);
154 maskG = upscale31To32(maskG);
155 maskB = upscale31To32(maskB);
156
157 int dstR = SkGetPackedR32(d);
158 int dstG = SkGetPackedG32(d);
159 int dstB = SkGetPackedB32(d);
160
161 // LCD blitting is only supported if the dst is known/required
162 // to be opaque
163 dst[i] = SkPackARGB32(0xFF,
164 blend32(srcR, dstR, maskR),
165 blend32(srcG, dstG, maskG),
166 blend32(srcB, dstB, maskB));
167 }
168}
169
170static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
171 const void* SK_RESTRICT mask, size_t maskRB,
172 SkColor color, int width, int height) {
173
174 SkPMColor* dstRow = (SkPMColor*)dst;
175 const uint16_t* srcRow = (const uint16_t*)mask;
176 SkPMColor opaqueDst;
177
178 void (*proc)(SkPMColor dst[], const uint16_t src[],
179 SkColor color, int width, SkPMColor);
180 if (0xFF == SkColorGetA(color)) {
181 proc = blit_lcd16_opaque_row;
182 opaqueDst = SkPreMultiplyColor(color);
183 } else {
184 proc = blit_lcd16_row;
185 opaqueDst = 0; // ignored
186 }
187
188 do {
189 proc(dstRow, srcRow, color, width, opaqueDst);
190 dstRow = (SkPMColor*)((char*)dstRow + dstRB);
191 srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
192 } while (--height != 0);
193}
194
195///////////////////////////////////////////////////////////////////////////////
196
197static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst,
198 const SkPMColor* SK_RESTRICT src,
199 SkColor color, int width) {
200 int srcR = SkColorGetR(color);
201 int srcG = SkColorGetG(color);
202 int srcB = SkColorGetB(color);
203
204 for (int i = 0; i < width; i++) {
205 SkPMColor mask = src[i];
206 if (0 == mask) {
207 continue;
208 }
209
210 SkPMColor d = dst[i];
211
212 int maskR = SkGetPackedR32(mask);
213 int maskG = SkGetPackedG32(mask);
214 int maskB = SkGetPackedB32(mask);
215
216 // Now upscale them to 0..256, so we can use SkAlphaBlend
217 maskR = SkAlpha255To256(maskR);
218 maskG = SkAlpha255To256(maskG);
219 maskB = SkAlpha255To256(maskB);
220
221 int dstR = SkGetPackedR32(d);
222 int dstG = SkGetPackedG32(d);
223 int dstB = SkGetPackedB32(d);
224
225 // LCD blitting is only supported if the dst is known/required
226 // to be opaque
227 dst[i] = SkPackARGB32(0xFF,
228 SkAlphaBlend(srcR, dstR, maskR),
229 SkAlphaBlend(srcG, dstG, maskG),
230 SkAlphaBlend(srcB, dstB, maskB));
231 }
232}
233
234static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst,
235 const SkPMColor* SK_RESTRICT src,
236 SkColor color, int width) {
237 int srcA = SkColorGetA(color);
238 int srcR = SkColorGetR(color);
239 int srcG = SkColorGetG(color);
240 int srcB = SkColorGetB(color);
241
242 srcA = SkAlpha255To256(srcA);
243
244 for (int i = 0; i < width; i++) {
245 SkPMColor mask = src[i];
246 if (0 == mask) {
247 continue;
248 }
249
250 SkPMColor d = dst[i];
251
252 int maskR = SkGetPackedR32(mask);
253 int maskG = SkGetPackedG32(mask);
254 int maskB = SkGetPackedB32(mask);
255
256 // Now upscale them to 0..256, so we can use SkAlphaBlend
257 maskR = SkAlpha255To256(maskR);
258 maskG = SkAlpha255To256(maskG);
259 maskB = SkAlpha255To256(maskB);
260
261 maskR = maskR * srcA >> 8;
262 maskG = maskG * srcA >> 8;
263 maskB = maskB * srcA >> 8;
264
265 int dstR = SkGetPackedR32(d);
266 int dstG = SkGetPackedG32(d);
267 int dstB = SkGetPackedB32(d);
268
269 // LCD blitting is only supported if the dst is known/required
270 // to be opaque
271 dst[i] = SkPackARGB32(0xFF,
272 SkAlphaBlend(srcR, dstR, maskR),
273 SkAlphaBlend(srcG, dstG, maskG),
274 SkAlphaBlend(srcB, dstB, maskB));
275 }
276}
277
278static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB,
279 const void* SK_RESTRICT mask, size_t maskRB,
280 SkColor color, int width, int height) {
281 SkASSERT(height > 0);
282 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
283 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
284
285 do {
286 blit_lcd32_row(dstRow, srcRow, color, width);
287 dstRow = (SkPMColor*)((char*)dstRow + dstRB);
288 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
289 } while (--height != 0);
290}
291
292static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB,
293 const void* SK_RESTRICT mask, size_t maskRB,
294 SkColor color, int width, int height) {
295 SkASSERT(height > 0);
296 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
297 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
298
299 do {
300 blit_lcd32_opaque_row(dstRow, srcRow, color, width);
301 dstRow = (SkPMColor*)((char*)dstRow + dstRB);
302 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
303 } while (--height != 0);
304}
305
306///////////////////////////////////////////////////////////////////////////////
307
308static SkBlitMask::Proc D32_A8_Factory(SkColor color) {
309 if (SK_ColorBLACK == color) {
310 return D32_A8_Black;
311 } else if (0xFF == SkColorGetA(color)) {
312 return D32_A8_Opaque;
313 } else {
314 return D32_A8_Color;
315 }
316}
317
318static SkBlitMask::Proc D32_LCD32_Factory(SkColor color) {
319 return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend;
320}
321
322SkBlitMask::Proc SkBlitMask::Factory(SkBitmap::Config config,
323 SkMask::Format format, SkColor color) {
324 SkBlitMask::Proc proc = PlatformProcs(config, format, color);
325 if (proc) {
326 return proc;
327 }
328
329 switch (config) {
330 case SkBitmap::kARGB_8888_Config:
331 switch (format) {
332 case SkMask::kA8_Format:
333 return D32_A8_Factory(color);
334 case SkMask::kLCD16_Format:
335 return D32_LCD16_Proc;
336 case SkMask::kLCD32_Format:
337 return D32_LCD32_Factory(color);
338 }
339 break;
340 default:
341 break;
342 }
343 return NULL;
344}
345
346static const int gMaskFormatToShift[] = {
347 ~0, // BW
348 0, // A8
349 0, // 3D
350 2, // ARGB32
351 1, // LCD16
352 2 // LCD32
353};
354
355static int maskFormatToShift(SkMask::Format format) {
356 SkASSERT((unsigned)format < SK_ARRAY_COUNT(gMaskFormatToShift));
357 SkASSERT(SkMask::kBW_Format != format);
358 return gMaskFormatToShift[format];
359}
360
361static const void* getAddr(const SkMask& mask, int x, int y) {
362 SkASSERT(mask.fBounds.contains(x, y));
363 SkASSERT(mask.fImage);
364
365 const char* addr = (const char*)mask.fImage;
366 addr += (y - mask.fBounds.fTop) * mask.fRowBytes;
367 addr += (x - mask.fBounds.fLeft) << maskFormatToShift(mask.fFormat);
368 return addr;
369}
370
371bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
372 const SkIRect& clip, SkColor color) {
373 Proc proc = Factory(device.config(), mask.fFormat, color);
374 if (proc) {
375 int x = clip.fLeft;
376 int y = clip.fTop;
377 proc(device.getAddr32(x, y), device.rowBytes(), getAddr(mask, x, y),
378 mask.fRowBytes, color, clip.width(), clip.height());
379 return true;
380 }
381 return false;
382}
383
384