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
12static 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
33static 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
54static 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
74SkBlitMask::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
87static 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
115static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst,
116                                  const SkPMColor* SK_RESTRICT src,
117                                  SkColor color, int width) {
118    int srcR = SkColorGetR(color);
119    int srcG = SkColorGetG(color);
120    int srcB = SkColorGetB(color);
121
122    for (int i = 0; i < width; i++) {
123        SkPMColor mask = src[i];
124        if (0 == mask) {
125            continue;
126        }
127
128        SkPMColor d = dst[i];
129
130        int maskR = SkGetPackedR32(mask);
131        int maskG = SkGetPackedG32(mask);
132        int maskB = SkGetPackedB32(mask);
133
134        // Now upscale them to 0..256, so we can use SkAlphaBlend
135        maskR = SkAlpha255To256(maskR);
136        maskG = SkAlpha255To256(maskG);
137        maskB = SkAlpha255To256(maskB);
138
139        int dstR = SkGetPackedR32(d);
140        int dstG = SkGetPackedG32(d);
141        int dstB = SkGetPackedB32(d);
142
143        // LCD blitting is only supported if the dst is known/required
144        // to be opaque
145        dst[i] = SkPackARGB32(0xFF,
146                              SkAlphaBlend(srcR, dstR, maskR),
147                              SkAlphaBlend(srcG, dstG, maskG),
148                              SkAlphaBlend(srcB, dstB, maskB));
149    }
150}
151
152static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst,
153                           const SkPMColor* SK_RESTRICT src,
154                           SkColor color, int width) {
155    int srcA = SkColorGetA(color);
156    int srcR = SkColorGetR(color);
157    int srcG = SkColorGetG(color);
158    int srcB = SkColorGetB(color);
159
160    srcA = SkAlpha255To256(srcA);
161
162    for (int i = 0; i < width; i++) {
163        SkPMColor mask = src[i];
164        if (0 == mask) {
165            continue;
166        }
167
168        SkPMColor d = dst[i];
169
170        int maskR = SkGetPackedR32(mask);
171        int maskG = SkGetPackedG32(mask);
172        int maskB = SkGetPackedB32(mask);
173
174        // Now upscale them to 0..256, so we can use SkAlphaBlend
175        maskR = SkAlpha255To256(maskR);
176        maskG = SkAlpha255To256(maskG);
177        maskB = SkAlpha255To256(maskB);
178
179        maskR = maskR * srcA >> 8;
180        maskG = maskG * srcA >> 8;
181        maskB = maskB * srcA >> 8;
182
183        int dstR = SkGetPackedR32(d);
184        int dstG = SkGetPackedG32(d);
185        int dstB = SkGetPackedB32(d);
186
187        // LCD blitting is only supported if the dst is known/required
188        // to be opaque
189        dst[i] = SkPackARGB32(0xFF,
190                              SkAlphaBlend(srcR, dstR, maskR),
191                              SkAlphaBlend(srcG, dstG, maskG),
192                              SkAlphaBlend(srcB, dstB, maskB));
193    }
194}
195
196static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB,
197                            const void* SK_RESTRICT mask, size_t maskRB,
198                            SkColor color, int width, int height) {
199    SkASSERT(height > 0);
200    SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
201    const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
202
203    do {
204        blit_lcd32_row(dstRow, srcRow, color, width);
205        dstRow = (SkPMColor*)((char*)dstRow + dstRB);
206        srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
207    } while (--height != 0);
208}
209
210static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB,
211                             const void* SK_RESTRICT mask, size_t maskRB,
212                             SkColor color, int width, int height) {
213    SkASSERT(height > 0);
214    SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
215    const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
216
217    do {
218        blit_lcd32_opaque_row(dstRow, srcRow, color, width);
219        dstRow = (SkPMColor*)((char*)dstRow + dstRB);
220        srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
221    } while (--height != 0);
222}
223
224///////////////////////////////////////////////////////////////////////////////
225
226static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) {
227    if (SK_ColorBLACK == color) {
228        return D32_A8_Black;
229    } else if (0xFF == SkColorGetA(color)) {
230        return D32_A8_Opaque;
231    } else {
232        return D32_A8_Color;
233    }
234}
235
236static SkBlitMask::ColorProc D32_LCD32_Factory(SkColor color) {
237    return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend;
238}
239
240SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkColorType ct,
241                                               SkMask::Format format,
242                                               SkColor color) {
243    ColorProc proc = PlatformColorProcs(ct, format, color);
244    if (proc) {
245        return proc;
246    }
247
248    switch (ct) {
249        case kN32_SkColorType:
250            switch (format) {
251                case SkMask::kA8_Format:
252                    return D32_A8_Factory(color);
253                case SkMask::kLCD16_Format:
254                    return D32_LCD16_Proc;
255                case SkMask::kLCD32_Format:
256                    return D32_LCD32_Factory(color);
257                default:
258                    break;
259            }
260            break;
261        default:
262            break;
263    }
264    return NULL;
265}
266
267bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
268                           const SkIRect& clip, SkColor color) {
269    ColorProc proc = ColorFactory(device.colorType(), mask.fFormat, color);
270    if (proc) {
271        int x = clip.fLeft;
272        int y = clip.fTop;
273        proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y),
274             mask.fRowBytes, color, clip.width(), clip.height());
275        return true;
276    }
277    return false;
278}
279
280///////////////////////////////////////////////////////////////////////////////
281///////////////////////////////////////////////////////////////////////////////
282
283static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
284                             const uint8_t* SK_RESTRICT mask,
285                             const SkPMColor* SK_RESTRICT src, int count) {
286    int i, octuple = (count + 7) >> 3;
287    for (i = 0; i < octuple; ++i) {
288        int m = *mask++;
289        if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
290        if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); }
291        if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); }
292        if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); }
293        if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); }
294        if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); }
295        if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); }
296        if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); }
297        src += 8;
298        dst += 8;
299    }
300    count &= 7;
301    if (count > 0) {
302        int m = *mask;
303        do {
304            if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
305            m <<= 1;
306            src += 1;
307            dst += 1;
308        } while (--count > 0);
309    }
310}
311
312static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
313                              const uint8_t* SK_RESTRICT mask,
314                              const SkPMColor* SK_RESTRICT src, int count) {
315    int i, octuple = (count + 7) >> 3;
316    for (i = 0; i < octuple; ++i) {
317        int m = *mask++;
318        if (m & 0x80) { dst[0] = src[0]; }
319        if (m & 0x40) { dst[1] = src[1]; }
320        if (m & 0x20) { dst[2] = src[2]; }
321        if (m & 0x10) { dst[3] = src[3]; }
322        if (m & 0x08) { dst[4] = src[4]; }
323        if (m & 0x04) { dst[5] = src[5]; }
324        if (m & 0x02) { dst[6] = src[6]; }
325        if (m & 0x01) { dst[7] = src[7]; }
326        src += 8;
327        dst += 8;
328    }
329    count &= 7;
330    if (count > 0) {
331        int m = *mask;
332        do {
333            if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
334            m <<= 1;
335            src += 1;
336            dst += 1;
337        } while (--count > 0);
338    }
339}
340
341static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
342                             const uint8_t* SK_RESTRICT mask,
343                             const SkPMColor* SK_RESTRICT src, int count) {
344    for (int i = 0; i < count; ++i) {
345        if (mask[i]) {
346            dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]);
347        }
348    }
349}
350
351// expand the steps that SkAlphaMulQ performs, but this way we can
352//  exand.. add.. combine
353// instead of
354// expand..combine add expand..combine
355//
356#define EXPAND0(v, m, s)    ((v) & (m)) * (s)
357#define EXPAND1(v, m, s)    (((v) >> 8) & (m)) * (s)
358#define COMBINE(e0, e1, m)  ((((e0) >> 8) & (m)) | ((e1) & ~(m)))
359
360static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
361                              const uint8_t* SK_RESTRICT mask,
362                              const SkPMColor* SK_RESTRICT src, int count) {
363    for (int i = 0; i < count; ++i) {
364        int m = mask[i];
365        if (m) {
366            m += (m >> 7);
367#if 1
368            // this is slightly slower than the expand/combine version, but it
369            // is much closer to the old results, so we use it for now to reduce
370            // rebaselining.
371            dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m);
372#else
373            uint32_t v = src[i];
374            uint32_t s0 = EXPAND0(v, rbmask, m);
375            uint32_t s1 = EXPAND1(v, rbmask, m);
376            v = dst[i];
377            uint32_t d0 = EXPAND0(v, rbmask, m);
378            uint32_t d1 = EXPAND1(v, rbmask, m);
379            dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask);
380#endif
381        }
382    }
383}
384
385static int upscale31To255(int value) {
386    value = (value << 3) | (value >> 2);
387    return value;
388}
389
390static int src_alpha_blend(int src, int dst, int srcA, int mask) {
391
392    return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask);
393}
394
395static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
396                                const uint16_t* SK_RESTRICT mask,
397                                const SkPMColor* SK_RESTRICT src, int count) {
398    for (int i = 0; i < count; ++i) {
399        uint16_t m = mask[i];
400        if (0 == m) {
401            continue;
402        }
403
404        SkPMColor s = src[i];
405        SkPMColor d = dst[i];
406
407        int srcA = SkGetPackedA32(s);
408        int srcR = SkGetPackedR32(s);
409        int srcG = SkGetPackedG32(s);
410        int srcB = SkGetPackedB32(s);
411
412        srcA += srcA >> 7;
413
414        /*  We want all of these in 5bits, hence the shifts in case one of them
415         *  (green) is 6bits.
416         */
417        int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
418        int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
419        int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
420
421        maskR = upscale31To255(maskR);
422        maskG = upscale31To255(maskG);
423        maskB = upscale31To255(maskB);
424
425        int dstR = SkGetPackedR32(d);
426        int dstG = SkGetPackedG32(d);
427        int dstB = SkGetPackedB32(d);
428
429        // LCD blitting is only supported if the dst is known/required
430        // to be opaque
431        dst[i] = SkPackARGB32(0xFF,
432                              src_alpha_blend(srcR, dstR, srcA, maskR),
433                              src_alpha_blend(srcG, dstG, srcA, maskG),
434                              src_alpha_blend(srcB, dstB, srcA, maskB));
435    }
436}
437
438static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
439                                 const uint16_t* SK_RESTRICT mask,
440                                 const SkPMColor* SK_RESTRICT src, int count) {
441    for (int i = 0; i < count; ++i) {
442        uint16_t m = mask[i];
443        if (0 == m) {
444            continue;
445        }
446
447        SkPMColor s = src[i];
448        SkPMColor d = dst[i];
449
450        int srcR = SkGetPackedR32(s);
451        int srcG = SkGetPackedG32(s);
452        int srcB = SkGetPackedB32(s);
453
454        /*  We want all of these in 5bits, hence the shifts in case one of them
455         *  (green) is 6bits.
456         */
457        int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
458        int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
459        int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
460
461        // Now upscale them to 0..32, so we can use blend32
462        maskR = SkUpscale31To32(maskR);
463        maskG = SkUpscale31To32(maskG);
464        maskB = SkUpscale31To32(maskB);
465
466        int dstR = SkGetPackedR32(d);
467        int dstG = SkGetPackedG32(d);
468        int dstB = SkGetPackedB32(d);
469
470        // LCD blitting is only supported if the dst is known/required
471        // to be opaque
472        dst[i] = SkPackARGB32(0xFF,
473                              SkBlend32(srcR, dstR, maskR),
474                              SkBlend32(srcG, dstG, maskG),
475                              SkBlend32(srcB, dstB, maskB));
476    }
477}
478
479static void LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
480                                const SkPMColor* SK_RESTRICT mask,
481                                const SkPMColor* SK_RESTRICT src, int count) {
482    for (int i = 0; i < count; ++i) {
483        SkPMColor m = mask[i];
484        if (0 == m) {
485            continue;
486        }
487
488        SkPMColor s = src[i];
489        int srcA = SkGetPackedA32(s);
490        int srcR = SkGetPackedR32(s);
491        int srcG = SkGetPackedG32(s);
492        int srcB = SkGetPackedB32(s);
493
494        srcA = SkAlpha255To256(srcA);
495
496        SkPMColor d = dst[i];
497
498        int maskR = SkGetPackedR32(m);
499        int maskG = SkGetPackedG32(m);
500        int maskB = SkGetPackedB32(m);
501
502        // Now upscale them to 0..256
503        maskR = SkAlpha255To256(maskR);
504        maskG = SkAlpha255To256(maskG);
505        maskB = SkAlpha255To256(maskB);
506
507        int dstR = SkGetPackedR32(d);
508        int dstG = SkGetPackedG32(d);
509        int dstB = SkGetPackedB32(d);
510
511        // LCD blitting is only supported if the dst is known/required
512        // to be opaque
513        dst[i] = SkPackARGB32(0xFF,
514                              src_alpha_blend(srcR, dstR, srcA, maskR),
515                              src_alpha_blend(srcG, dstG, srcA, maskG),
516                              src_alpha_blend(srcB, dstB, srcA, maskB));
517    }
518}
519
520static void LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
521                                 const SkPMColor* SK_RESTRICT mask,
522                                 const SkPMColor* SK_RESTRICT src, int count) {
523    for (int i = 0; i < count; ++i) {
524        SkPMColor m = mask[i];
525        if (0 == m) {
526            continue;
527        }
528
529        SkPMColor s = src[i];
530        SkPMColor d = dst[i];
531
532        int maskR = SkGetPackedR32(m);
533        int maskG = SkGetPackedG32(m);
534        int maskB = SkGetPackedB32(m);
535
536        int srcR = SkGetPackedR32(s);
537        int srcG = SkGetPackedG32(s);
538        int srcB = SkGetPackedB32(s);
539
540        int dstR = SkGetPackedR32(d);
541        int dstG = SkGetPackedG32(d);
542        int dstB = SkGetPackedB32(d);
543
544        // Now upscale them to 0..256, so we can use SkAlphaBlend
545        maskR = SkAlpha255To256(maskR);
546        maskG = SkAlpha255To256(maskG);
547        maskB = SkAlpha255To256(maskB);
548
549        // LCD blitting is only supported if the dst is known/required
550        // to be opaque
551        dst[i] = SkPackARGB32(0xFF,
552                              SkAlphaBlend(srcR, dstR, maskR),
553                              SkAlphaBlend(srcG, dstG, maskG),
554                              SkAlphaBlend(srcB, dstB, maskB));
555    }
556}
557
558SkBlitMask::RowProc SkBlitMask::RowFactory(SkColorType ct,
559                                           SkMask::Format format,
560                                           RowFlags flags) {
561// make this opt-in until chrome can rebaseline
562    RowProc proc = PlatformRowProcs(ct, format, flags);
563    if (proc) {
564        return proc;
565    }
566
567    static const RowProc gProcs[] = {
568        // need X coordinate to handle BW
569        false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning
570        false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning
571        (RowProc)A8_RowProc_Blend,      (RowProc)A8_RowProc_Opaque,
572        (RowProc)LCD16_RowProc_Blend,   (RowProc)LCD16_RowProc_Opaque,
573        (RowProc)LCD32_RowProc_Blend,   (RowProc)LCD32_RowProc_Opaque,
574    };
575
576    int index;
577    switch (ct) {
578        case kN32_SkColorType:
579            switch (format) {
580                case SkMask::kBW_Format:    index = 0; break;
581                case SkMask::kA8_Format:    index = 2; break;
582                case SkMask::kLCD16_Format: index = 4; break;
583                case SkMask::kLCD32_Format: index = 6; break;
584                default:
585                    return NULL;
586            }
587            if (flags & kSrcIsOpaque_RowFlag) {
588                index |= 1;
589            }
590            SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs));
591            return gProcs[index];
592        default:
593            break;
594    }
595    return NULL;
596}
597