1/* libs/graphics/sgl/SkBlitter_ARGB32.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkCoreBlitters.h"
19#include "SkColorPriv.h"
20#include "SkShader.h"
21#include "SkUtils.h"
22#include "SkXfermode.h"
23
24#if defined(SK_SUPPORT_LCDTEXT)
25namespace skia_blitter_support {
26// subpixel helper functions from SkBlitter_ARGB32_Subpixel.cpp
27uint32_t* adjustForSubpixelClip(const SkMask& mask,
28                                const SkIRect& clip, const SkBitmap& device,
29                                int* widthAdjustment, int* heightAdjustment,
30                                const uint32_t** alpha32);
31extern uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel,
32                                       const uint32_t sourcePixel);
33extern uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel,
34                                             const uint32_t sourcePixel);
35extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel);
36}
37
38using namespace skia_blitter_support;
39#endif
40
41///////////////////////////////////////////////////////////////////////////////
42
43static inline int upscale31To32(int value) {
44    SkASSERT((unsigned)value <= 31);
45    return value + (value >> 4);
46}
47
48static inline int blend32(int src, int dst, int scale) {
49    SkASSERT((unsigned)src <= 0xFF);
50    SkASSERT((unsigned)dst <= 0xFF);
51    SkASSERT((unsigned)scale <= 32);
52    return dst + ((src - dst) * scale >> 5);
53}
54
55static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[],
56                              SkPMColor color, int width) {
57    int srcR = SkGetPackedR32(color);
58    int srcG = SkGetPackedG32(color);
59    int srcB = SkGetPackedB32(color);
60
61    for (int i = 0; i < width; i++) {
62        uint16_t mask = src[i];
63        if (0 == mask) {
64            continue;
65        }
66
67        SkPMColor d = dst[i];
68
69        /*  We want all of these in 5bits, hence the shifts in case one of them
70         *  (green) is 6bits.
71         */
72        int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
73        int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
74        int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
75
76        // Now upscale them to 0..256, so we can use SkAlphaBlend
77        maskR = upscale31To32(maskR);
78        maskG = upscale31To32(maskG);
79        maskB = upscale31To32(maskB);
80
81        int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
82
83        int dstA = SkGetPackedA32(d);
84        int dstR = SkGetPackedR32(d);
85        int dstG = SkGetPackedG32(d);
86        int dstB = SkGetPackedB32(d);
87
88        dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA),
89                              blend32(srcR, dstR, maskR),
90                              blend32(srcG, dstG, maskG),
91                              blend32(srcB, dstB, maskB));
92    }
93}
94
95static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
96                           const SkIRect& clip, SkPMColor srcColor) {
97    int x = clip.fLeft;
98    int y = clip.fTop;
99    int width = clip.width();
100    int height = clip.height();
101
102    SkPMColor*		dstRow = device.getAddr32(x, y);
103    const uint16_t* srcRow = mask.getAddrLCD16(x, y);
104
105    do {
106        blit_lcd16_opaque(dstRow, srcRow, srcColor, width);
107        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
108        srcRow = (const uint16_t*)((const char*)srcRow + mask.fRowBytes);
109    } while (--height != 0);
110}
111
112//////////////////////////////////////////////////////////////////////////////////////
113
114static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
115							const SkIRect& clip, SkPMColor srcColor) {
116	U8CPU alpha = SkGetPackedA32(srcColor);
117	unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32;
118	if (alpha != 255) {
119		flags |= SkBlitRow::kGlobalAlpha_Flag32;
120	}
121	SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags);
122
123    int x = clip.fLeft;
124    int y = clip.fTop;
125    int width = clip.width();
126    int height = clip.height();
127
128    SkPMColor*		 dstRow = device.getAddr32(x, y);
129    const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr(x, y));
130
131    do {
132		proc(dstRow, srcRow, width, alpha);
133        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
134        srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes);
135    } while (--height != 0);
136}
137
138//////////////////////////////////////////////////////////////////////////////////////
139
140SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
141        : INHERITED(device) {
142    SkColor color = paint.getColor();
143    fColor = color;
144
145    fSrcA = SkColorGetA(color);
146    unsigned scale = SkAlpha255To256(fSrcA);
147    fSrcR = SkAlphaMul(SkColorGetR(color), scale);
148    fSrcG = SkAlphaMul(SkColorGetG(color), scale);
149    fSrcB = SkAlphaMul(SkColorGetB(color), scale);
150
151    fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
152    fColor32Proc = SkBlitRow::ColorProcFactory();
153
154    // init the pro for blitmask
155    fBlitMaskProc = SkBlitMask::Factory(SkBitmap::kARGB_8888_Config, color);
156}
157
158const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
159    if (255 == fSrcA) {
160        *value = fPMColor;
161        return &fDevice;
162    }
163    return NULL;
164}
165
166#if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
167#pragma warning ( push )
168#pragma warning ( disable : 4701 )
169#endif
170
171void SkARGB32_Blitter::blitH(int x, int y, int width) {
172    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
173
174    uint32_t*   device = fDevice.getAddr32(x, y);
175    fColor32Proc(device, device, width, fPMColor);
176}
177
178void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
179                                 const int16_t runs[]) {
180    if (fSrcA == 0) {
181        return;
182    }
183
184    uint32_t    color = fPMColor;
185    uint32_t*   device = fDevice.getAddr32(x, y);
186    unsigned    opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
187
188    for (;;) {
189        int count = runs[0];
190        SkASSERT(count >= 0);
191        if (count <= 0) {
192            return;
193        }
194        unsigned aa = antialias[0];
195        if (aa) {
196            if ((opaqueMask & aa) == 255) {
197                sk_memset32(device, color, count);
198            } else {
199                uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa));
200                fColor32Proc(device, device, count, sc);
201            }
202        }
203        runs += count;
204        antialias += count;
205        device += count;
206    }
207}
208
209//////////////////////////////////////////////////////////////////////////////////////
210
211#define solid_8_pixels(mask, dst, color)    \
212    do {                                    \
213        if (mask & 0x80) dst[0] = color;    \
214        if (mask & 0x40) dst[1] = color;    \
215        if (mask & 0x20) dst[2] = color;    \
216        if (mask & 0x10) dst[3] = color;    \
217        if (mask & 0x08) dst[4] = color;    \
218        if (mask & 0x04) dst[5] = color;    \
219        if (mask & 0x02) dst[6] = color;    \
220        if (mask & 0x01) dst[7] = color;    \
221    } while (0)
222
223#define SK_BLITBWMASK_NAME                  SkARGB32_BlitBW
224#define SK_BLITBWMASK_ARGS                  , SkPMColor color
225#define SK_BLITBWMASK_BLIT8(mask, dst)      solid_8_pixels(mask, dst, color)
226#define SK_BLITBWMASK_GETADDR               getAddr32
227#define SK_BLITBWMASK_DEVTYPE               uint32_t
228#include "SkBlitBWMaskTemplate.h"
229
230#define blend_8_pixels(mask, dst, sc, dst_scale)                            \
231    do {                                                                    \
232        if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); }  \
233        if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); }  \
234        if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); }  \
235        if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); }  \
236        if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); }  \
237        if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); }  \
238        if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); }  \
239        if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); }  \
240    } while (0)
241
242#define SK_BLITBWMASK_NAME                  SkARGB32_BlendBW
243#define SK_BLITBWMASK_ARGS                  , uint32_t sc, unsigned dst_scale
244#define SK_BLITBWMASK_BLIT8(mask, dst)      blend_8_pixels(mask, dst, sc, dst_scale)
245#define SK_BLITBWMASK_GETADDR               getAddr32
246#define SK_BLITBWMASK_DEVTYPE               uint32_t
247#include "SkBlitBWMaskTemplate.h"
248
249void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
250    SkASSERT(mask.fBounds.contains(clip));
251    SkASSERT(fSrcA != 0xFF);
252
253    if (fSrcA == 0) {
254        return;
255    }
256
257    if (mask.fFormat == SkMask::kBW_Format) {
258        SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
259        return;
260    } else if (SkMask::kARGB32_Format == mask.fFormat) {
261		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
262		return;
263    } else if (SkMask::kLCD16_Format == mask.fFormat) {
264        blitmask_lcd16(fDevice, mask, clip, fPMColor);
265        return;
266    }
267
268    int x = clip.fLeft;
269    int y = clip.fTop;
270
271    fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
272                  SkBitmap::kARGB_8888_Config,
273                  mask.getAddr(x, y), mask.fRowBytes,
274                  fColor, clip.width(), clip.height());
275}
276
277void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
278                                       const SkIRect& clip) {
279    SkASSERT(mask.fBounds.contains(clip));
280
281    if (mask.fFormat == SkMask::kBW_Format) {
282        SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
283        return;
284    } else if (SkMask::kARGB32_Format == mask.fFormat) {
285		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
286		return;
287    } else if (SkMask::kLCD16_Format == mask.fFormat) {
288        blitmask_lcd16(fDevice, mask, clip, fPMColor);
289        return;
290	}
291
292    int x = clip.fLeft;
293    int y = clip.fTop;
294    int width = clip.width();
295    int height = clip.height();
296
297#if defined(SK_SUPPORT_LCDTEXT)
298    const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
299    const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
300
301    // In LCD mode the masks have either an extra couple of rows or columns on the edges.
302    if (lcdMode || verticalLCDMode) {
303        int widthAdjustment, heightAdjustment;
304        const uint32_t* alpha32;
305        uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
306
307        width += widthAdjustment;
308        height += heightAdjustment;
309
310        unsigned devRB = fDevice.rowBytes() - (width << 2);
311        unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
312        SkPMColor srcColor = fPMColor;
313
314        do {
315            unsigned w = width;
316            do {
317                const uint32_t alphaPixel = *alpha32++;
318                const uint32_t originalPixel = *device;
319                *device++ = BlendLCDPixelWithOpaqueColor(alphaPixel, originalPixel, srcColor);
320            } while (--w != 0);
321            device = (uint32_t*)((char*)device + devRB);
322            alpha32 += alphaExtraRowWords;
323        } while (--height != 0);
324
325        return;
326    }
327#endif
328
329    fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
330                  SkBitmap::kARGB_8888_Config,
331                  mask.getAddr(x, y), mask.fRowBytes, fColor, width, height);
332}
333
334//////////////////////////////////////////////////////////////////////////////////////
335
336void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
337    if (alpha == 0 || fSrcA == 0) {
338        return;
339    }
340
341    uint32_t* device = fDevice.getAddr32(x, y);
342    uint32_t  color = fPMColor;
343
344    if (alpha != 255) {
345        color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
346    }
347
348    unsigned dst_scale = 255 - SkGetPackedA32(color);
349    uint32_t prevDst = ~device[0];
350    uint32_t result  SK_INIT_TO_AVOID_WARNING;
351    uint32_t rowBytes = fDevice.rowBytes();
352
353    while (--height >= 0) {
354        uint32_t dst = device[0];
355        if (dst != prevDst) {
356            result = color + SkAlphaMulQ(dst, dst_scale);
357            prevDst = dst;
358        }
359        device[0] = result;
360        device = (uint32_t*)((char*)device + rowBytes);
361    }
362}
363
364void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
365    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
366
367    if (fSrcA == 0) {
368        return;
369    }
370
371    uint32_t*   device = fDevice.getAddr32(x, y);
372    uint32_t    color = fPMColor;
373    size_t      rowBytes = fDevice.rowBytes();
374
375    while (--height >= 0) {
376        fColor32Proc(device, device, width, color);
377        device = (uint32_t*)((char*)device + rowBytes);
378    }
379}
380
381#if defined _WIN32 && _MSC_VER >= 1300
382#pragma warning ( pop )
383#endif
384
385///////////////////////////////////////////////////////////////////////
386
387void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
388    SkASSERT(mask.fBounds.contains(clip));
389
390    if (mask.fFormat == SkMask::kBW_Format) {
391        SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
392
393        SkARGB32_BlitBW(fDevice, mask, clip, black);
394    } else if (SkMask::kARGB32_Format == mask.fFormat) {
395		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
396    } else if (SkMask::kLCD16_Format == mask.fFormat) {
397        blitmask_lcd16(fDevice, mask, clip, fPMColor);
398    } else {
399#if defined(SK_SUPPORT_LCDTEXT)
400        const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
401        const bool      verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
402#endif
403
404        // In LCD mode the masks have either an extra couple of rows or columns on the edges.
405        unsigned        width = clip.width();
406        unsigned        height = clip.height();
407
408        SkASSERT((int)height > 0);
409        SkASSERT((int)width > 0);
410
411#if defined(SK_SUPPORT_LCDTEXT)
412        if (lcdMode || verticalLCDMode) {
413            int widthAdjustment, heightAdjustment;
414            const uint32_t* alpha32;
415            uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
416
417            width += widthAdjustment;
418            height += heightAdjustment;
419
420            unsigned deviceRB = fDevice.rowBytes() - (width << 2);
421            unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
422
423            do {
424                unsigned w = width;
425                do {
426                    const uint32_t alphaPixel = *alpha32++;
427                    const uint32_t originalPixel = *device;
428                    *device++ = BlendLCDPixelWithBlack(alphaPixel, originalPixel);
429                } while (--w != 0);
430                device = (uint32_t*)((char*)device + deviceRB);
431                alpha32 += alphaExtraRowWords;
432            } while (--height != 0);
433
434            return;
435        }
436#endif
437
438        uint32_t*      device = fDevice.getAddr32(clip.fLeft, clip.fTop);
439        unsigned       maskRB = mask.fRowBytes - width;
440        unsigned       deviceRB = fDevice.rowBytes() - (width << 2);
441        const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop);
442        do {
443            unsigned w = width;
444            do {
445                unsigned aa = *alpha++;
446                *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
447                device += 1;
448            } while (--w != 0);
449            device = (uint32_t*)((char*)device + deviceRB);
450            alpha += maskRB;
451        } while (--height != 0);
452    }
453}
454
455void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
456                                       const int16_t runs[]) {
457    uint32_t*   device = fDevice.getAddr32(x, y);
458    SkPMColor   black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
459
460    for (;;) {
461        int count = runs[0];
462        SkASSERT(count >= 0);
463        if (count <= 0) {
464            return;
465        }
466        unsigned aa = antialias[0];
467        if (aa) {
468            if (aa == 255) {
469                sk_memset32(device, black, count);
470            } else {
471                SkPMColor src = aa << SK_A32_SHIFT;
472                unsigned dst_scale = 256 - aa;
473                int n = count;
474                do {
475                    --n;
476                    device[n] = src + SkAlphaMulQ(device[n], dst_scale);
477                } while (n > 0);
478            }
479        }
480        runs += count;
481        antialias += count;
482        device += count;
483    }
484}
485
486//////////////////////////////////////////////////////////////////////////////////////////
487
488SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
489                            const SkPaint& paint) : INHERITED(device, paint) {
490    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
491
492    fXfermode = paint.getXfermode();
493    SkSafeRef(fXfermode);
494
495    int flags = 0;
496    if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
497        flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
498    }
499    // we call this on the output from the shader
500    fProc32 = SkBlitRow::Factory32(flags);
501    // we call this on the output from the shader + alpha from the aa buffer
502    fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);
503}
504
505SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
506    SkSafeUnref(fXfermode);
507    sk_free(fBuffer);
508}
509
510void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
511    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
512
513    uint32_t*   device = fDevice.getAddr32(x, y);
514
515    if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
516        fShader->shadeSpan(x, y, device, width);
517    } else {
518        SkPMColor*  span = fBuffer;
519        fShader->shadeSpan(x, y, span, width);
520        if (fXfermode) {
521            fXfermode->xfer32(device, span, width, NULL);
522        } else {
523            fProc32(device, span, width, 255);
524        }
525    }
526}
527
528///////////////////////////////////////////////////////////////////////////////////////////////
529
530void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
531                                        const int16_t runs[]) {
532    SkPMColor*  span = fBuffer;
533    uint32_t*   device = fDevice.getAddr32(x, y);
534    SkShader*   shader = fShader;
535
536    if (fXfermode) {
537        for (;;) {
538            SkXfermode* xfer = fXfermode;
539
540            int count = *runs;
541            if (count <= 0)
542                break;
543            int aa = *antialias;
544            if (aa) {
545                shader->shadeSpan(x, y, span, count);
546                if (aa == 255) {
547                    xfer->xfer32(device, span, count, NULL);
548                } else {
549                    // count is almost always 1
550                    for (int i = count - 1; i >= 0; --i) {
551                        xfer->xfer32(&device[i], &span[i], 1, antialias);
552                    }
553                }
554            }
555            device += count;
556            runs += count;
557            antialias += count;
558            x += count;
559        }
560    } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
561        for (;;) {
562            int count = *runs;
563            if (count <= 0) {
564                break;
565            }
566            int aa = *antialias;
567            if (aa) {
568                if (aa == 255) {
569                    // cool, have the shader draw right into the device
570                    shader->shadeSpan(x, y, device, count);
571                } else {
572                    shader->shadeSpan(x, y, span, count);
573                    fProc32Blend(device, span, count, aa);
574                }
575            }
576            device += count;
577            runs += count;
578            antialias += count;
579            x += count;
580        }
581    } else {    // no xfermode but the shader not opaque
582        for (;;) {
583            int count = *runs;
584            if (count <= 0) {
585                break;
586            }
587            int aa = *antialias;
588            if (aa) {
589                fShader->shadeSpan(x, y, span, count);
590                if (aa == 255) {
591                    fProc32(device, span, count, 255);
592                } else {
593                    fProc32Blend(device, span, count, aa);
594                }
595            }
596            device += count;
597            runs += count;
598            antialias += count;
599            x += count;
600        }
601    }
602}
603