SkConfig8888.h revision 5194e1507dbf77fb6a6feb731c6e19571faee452
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkCanvas.h"
11#include "SkColorPriv.h"
12
13namespace {
14
15/**
16  Copies all pixels from a bitmap to a dst ptr with a given rowBytes and
17  Config8888. The bitmap must have kARGB_8888_Config.
18 */
19inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels,
20                                     size_t dstRowBytes,
21                                     SkCanvas::Config8888 dstConfig8888,
22                                     const SkBitmap& srcBmp);
23
24/**
25 * Copies all pixels in a bitmap to a dst ptr with row bytes. The src bitmap
26 * is assumed to have pixels and be kARGB_8888_Config. No conversion is applied
27 */
28inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels,
29                                   size_t dstRowBytes,
30                                   const SkBitmap& srcBmp);
31
32/**
33  Copies over all pixels in a bitmap from a src ptr with a given rowBytes and
34  Config8888. The bitmap must have pixels and be kARGB_8888_Config.
35 */
36inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
37                                     const uint32_t* srcPixels,
38                                     size_t srcRowBytes,
39                                     SkCanvas::Config8888 srcConfig8888);
40
41}
42
43///////////////////////////////////////////////////////////////////////////////
44// Implementation
45
46namespace {
47
48template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
49inline uint32_t pack_config8888(uint32_t a, uint32_t r,
50                                uint32_t g, uint32_t b) {
51#ifdef SK_CPU_LENDIAN
52    return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) |
53           (g << (G_IDX * 8)) | (b << (B_IDX * 8));
54#else
55    return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) |
56           (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8));
57#endif
58}
59
60template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
61inline void unpack_config8888(uint32_t color,
62                              uint32_t* a, uint32_t* r,
63                              uint32_t* g, uint32_t* b) {
64#ifdef SK_CPU_LENDIAN
65    *a = (color >> (A_IDX * 8)) & 0xff;
66    *r = (color >> (R_IDX * 8)) & 0xff;
67    *g = (color >> (G_IDX * 8)) & 0xff;
68    *b = (color >> (B_IDX * 8)) & 0xff;
69#else
70    *a = (color >> ((3 - A_IDX) * 8)) & 0xff;
71    *r = (color >> ((3 - R_IDX) * 8)) & 0xff;
72    *g = (color >> ((3 - G_IDX) * 8)) & 0xff;
73    *b = (color >> ((3 - B_IDX) * 8)) & 0xff;
74#endif
75}
76
77template <bool UNPM, int A_IDX, int R_IDX, int G_IDX, int B_IDX>
78inline void bitmap_copy_to_config8888(uint32_t* dstPixels,
79                                      size_t dstRowBytes,
80                                      const SkBitmap& srcBmp) {
81    SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
82    SkAutoLockPixels alp(srcBmp);
83    int w = srcBmp.width();
84    int h = srcBmp.height();
85    size_t srcRowBytes = srcBmp.rowBytes();
86
87    intptr_t src = reinterpret_cast<intptr_t>(srcBmp.getPixels());
88    intptr_t dst = reinterpret_cast<intptr_t>(dstPixels);
89
90    for (int y = 0; y < h; ++y) {
91        const SkPMColor* srcRow = reinterpret_cast<SkPMColor*>(src);
92        uint32_t* dstRow  = reinterpret_cast<uint32_t*>(dst);
93        for (int x = 0; x < w; ++x) {
94            SkPMColor pmcolor = srcRow[x];
95            if (UNPM) {
96                U8CPU a, r, g, b;
97                a = SkGetPackedA32(pmcolor);
98                if (a) {
99                    // We're doing the explicit divide to match WebKit layout
100                    // test expectations. We can modify and rebaseline if there
101                    // it can be shown that there is a more performant way to
102                    // unpremul.
103                    r = SkGetPackedR32(pmcolor) * 0xff / a;
104                    g = SkGetPackedG32(pmcolor) * 0xff / a;
105                    b = SkGetPackedB32(pmcolor) * 0xff / a;
106                    dstRow[x] = pack_config8888<A_IDX, R_IDX,
107                                                G_IDX, B_IDX>(a, r, g, b);
108                } else {
109                    dstRow[x] = 0;
110                }
111            } else {
112                dstRow[x] = pack_config8888<A_IDX, R_IDX,
113                                            G_IDX, B_IDX>(
114                                                   SkGetPackedA32(pmcolor),
115                                                   SkGetPackedR32(pmcolor),
116                                                   SkGetPackedG32(pmcolor),
117                                                   SkGetPackedB32(pmcolor));
118            }
119        }
120        dst += dstRowBytes;
121        src += srcRowBytes;
122    }
123}
124
125template <bool PM, int A_IDX, int R_IDX, int G_IDX, int B_IDX>
126inline void config8888_copy_to_bitmap(const SkBitmap& dstBmp,
127                                      const uint32_t* srcPixels,
128                                      size_t srcRowBytes) {
129    SkASSERT(SkBitmap::kARGB_8888_Config == dstBmp.config());
130    SkAutoLockPixels alp(dstBmp);
131    int w = dstBmp.width();
132    int h = dstBmp.height();
133    size_t dstRowBytes = dstBmp.rowBytes();
134
135    intptr_t src = reinterpret_cast<intptr_t>(srcPixels);
136    intptr_t dst = reinterpret_cast<intptr_t>(dstBmp.getPixels());
137
138    for (int y = 0; y < h; ++y) {
139        const uint32_t* srcRow  = reinterpret_cast<uint32_t*>(src);
140        SkPMColor* dstRow = reinterpret_cast<SkPMColor*>(dst);
141        for (int x = 0; x < w; ++x) {
142            uint32_t c8888 = srcRow[x];
143            uint32_t a, r, g, b;
144            unpack_config8888<A_IDX, R_IDX, G_IDX, B_IDX>(c8888, &a, &r,
145                                                                 &g, &b);
146            if (PM) {
147                // This matches WebKit's conversion which we are replacing.
148                // We can consider alternative rounding rules for performance.
149                r = SkMulDiv255Ceiling(r, a);
150                g = SkMulDiv255Ceiling(g, a);
151                b = SkMulDiv255Ceiling(b, a);
152            }
153            // NoCheck: https://bugs.webkit.org/show_bug.cgi?id=74025
154            dstRow[x] = SkPackARGB32NoCheck(a, r, g, b);
155        }
156        src += srcRowBytes;
157        dst += dstRowBytes;
158    }
159}
160
161#ifdef SK_CPU_LENDIAN
162    static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8;
163    static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8;
164    static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8;
165    static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8;
166#else
167    static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8);
168    static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8);
169    static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8);
170    static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8);
171#endif
172
173inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels,
174                                     size_t dstRowBytes,
175                                     SkCanvas::Config8888 dstConfig8888,
176                                     const SkBitmap& srcBmp) {
177    switch (dstConfig8888) {
178        case SkCanvas::kNative_Premul_Config8888:
179            bitmap_copy_to_config8888<false,
180                                      SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
181                                      SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
182                                            dstPixels,
183                                            dstRowBytes,
184                                            srcBmp);
185            break;
186        case SkCanvas::kNative_Unpremul_Config8888:
187            bitmap_copy_to_config8888<true,
188                                      SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
189                                      SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
190                                            dstPixels,
191                                            dstRowBytes,
192                                            srcBmp);
193            break;
194        case SkCanvas::kBGRA_Premul_Config8888:
195            bitmap_copy_to_config8888<false, 3, 2, 1, 0> (
196                                    dstPixels, dstRowBytes, srcBmp);
197            break;
198        case SkCanvas::kBGRA_Unpremul_Config8888:
199            bitmap_copy_to_config8888<true, 3, 2, 1, 0> (
200                                    dstPixels, dstRowBytes, srcBmp);
201            break;
202        case SkCanvas::kRGBA_Premul_Config8888:
203            bitmap_copy_to_config8888<false, 3, 0, 1, 2> (
204                                    dstPixels, dstRowBytes, srcBmp);
205            break;
206        case SkCanvas::kRGBA_Unpremul_Config8888:
207            bitmap_copy_to_config8888<true, 3, 0, 1, 2> (
208                                    dstPixels, dstRowBytes, srcBmp);
209            break;
210        default:
211            SkASSERT(false && "unexpected Config8888");
212            break;
213    }
214}
215
216inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
217                                     const uint32_t* srcPixels,
218                                     size_t srcRowBytes,
219                                     SkCanvas::Config8888 srcConfig8888) {
220    switch (srcConfig8888) {
221        case SkCanvas::kNative_Premul_Config8888:
222            config8888_copy_to_bitmap<false,
223                                      SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
224                                      SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
225                                            dstBmp,
226                                            srcPixels,
227                                            srcRowBytes);
228            break;
229        case SkCanvas::kNative_Unpremul_Config8888:
230            config8888_copy_to_bitmap<true,
231                                      SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
232                                      SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
233                                            dstBmp,
234                                            srcPixels,
235                                            srcRowBytes);
236            break;
237        case SkCanvas::kBGRA_Premul_Config8888:
238            config8888_copy_to_bitmap<false, 3, 2, 1, 0> (
239                                    dstBmp, srcPixels, srcRowBytes);
240            break;
241        case SkCanvas::kBGRA_Unpremul_Config8888:
242            config8888_copy_to_bitmap<true, 3, 2, 1, 0> (
243                                    dstBmp, srcPixels, srcRowBytes);
244            break;
245        case SkCanvas::kRGBA_Premul_Config8888:
246            config8888_copy_to_bitmap<false, 3, 0, 1, 2> (
247                                    dstBmp, srcPixels, srcRowBytes);
248            break;
249        case SkCanvas::kRGBA_Unpremul_Config8888:
250            config8888_copy_to_bitmap<true, 3, 0, 1, 2> (
251                                    dstBmp, srcPixels, srcRowBytes);
252            break;
253        default:
254            SkASSERT(false && "unexpected Config8888");
255            break;
256    }
257}
258
259inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels,
260                                   size_t dstRowBytes,
261                                   const SkBitmap& srcBmp) {
262    SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
263
264    SkAutoLockPixels alp(srcBmp);
265
266    int w = srcBmp.width();
267    int h = srcBmp.height();
268    size_t srcRowBytes = srcBmp.rowBytes();
269
270    size_t tightRowBytes = w * 4;
271
272    char* src = reinterpret_cast<char*>(srcBmp.getPixels());
273    char* dst = reinterpret_cast<char*>(dstPixels);
274
275    if (tightRowBytes == srcRowBytes &&
276        tightRowBytes == dstRowBytes) {
277        memcpy(dst, src, tightRowBytes * h);
278    } else {
279        for (int y = 0; y < h; ++y) {
280            memcpy(dst, src, tightRowBytes);
281            dst += dstRowBytes;
282            src += srcRowBytes;
283        }
284    }
285}
286
287}
288