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