SkSwizzler.cpp revision dfdec78a5d02e8690998741a9fe5b71a08ca3232
1/*
2 * Copyright 2015 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 "SkColorPriv.h"
9#include "SkSwizzler.h"
10#include "SkTemplates.h"
11
12// index
13
14#define A32_MASK_IN_PLACE   (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
15
16static bool swizzle_index_to_n32(void* SK_RESTRICT dstRow,
17                                 const uint8_t* SK_RESTRICT src,
18                                 int width, int deltaSrc, int, const SkPMColor ctable[]) {
19
20    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
21    SkPMColor cc = A32_MASK_IN_PLACE;
22    for (int x = 0; x < width; x++) {
23        SkPMColor c = ctable[*src];
24        cc &= c;
25        dst[x] = c;
26        src += deltaSrc;
27    }
28    return cc != A32_MASK_IN_PLACE;
29}
30
31static bool swizzle_index_to_n32_skipZ(void* SK_RESTRICT dstRow,
32                                      const uint8_t* SK_RESTRICT src,
33                                      int width, int deltaSrc, int,
34                                      const SkPMColor ctable[]) {
35
36    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
37    SkPMColor cc = A32_MASK_IN_PLACE;
38    for (int x = 0; x < width; x++) {
39        SkPMColor c = ctable[*src];
40        cc &= c;
41        if (c != 0) {
42            dst[x] = c;
43        }
44        src += deltaSrc;
45    }
46    return cc != A32_MASK_IN_PLACE;
47}
48
49#undef A32_MASK_IN_PLACE
50
51// n32
52static bool swizzle_rgbx_to_n32(void* SK_RESTRICT dstRow,
53                                const uint8_t* SK_RESTRICT src,
54                                int width, int deltaSrc, int, const SkPMColor[]) {
55    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
56    for (int x = 0; x < width; x++) {
57        dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
58        src += deltaSrc;
59    }
60    return false;
61}
62
63static bool swizzle_rgba_to_n32_premul(void* SK_RESTRICT dstRow,
64                                       const uint8_t* SK_RESTRICT src,
65                                       int width, int deltaSrc, int, const SkPMColor[]) {
66    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
67    unsigned alphaMask = 0xFF;
68    for (int x = 0; x < width; x++) {
69        unsigned alpha = src[3];
70        dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
71        src += deltaSrc;
72        alphaMask &= alpha;
73    }
74    return alphaMask != 0xFF;
75}
76
77static bool swizzle_rgba_to_n32_unpremul(void* SK_RESTRICT dstRow,
78                                         const uint8_t* SK_RESTRICT src,
79                                         int width, int deltaSrc, int,
80                                         const SkPMColor[]) {
81    uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
82    unsigned alphaMask = 0xFF;
83    for (int x = 0; x < width; x++) {
84        unsigned alpha = src[3];
85        dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
86        src += deltaSrc;
87        alphaMask &= alpha;
88    }
89    return alphaMask != 0xFF;
90}
91
92static bool swizzle_rgba_to_n32_premul_skipZ(void* SK_RESTRICT dstRow,
93                                             const uint8_t* SK_RESTRICT src,
94                                             int width, int deltaSrc, int,
95                                             const SkPMColor[]) {
96    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
97    unsigned alphaMask = 0xFF;
98    for (int x = 0; x < width; x++) {
99        unsigned alpha = src[3];
100        if (0 != alpha) {
101            dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
102        }
103        src += deltaSrc;
104        alphaMask &= alpha;
105    }
106    return alphaMask != 0xFF;
107}
108
109/**
110    FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes.
111    This would be fine for drawing normally, but not for drawing with transfer modes. Being
112    honest means we can draw correctly with transfer modes, with the cost of not being able
113    to take advantage of Android's free unwritten pages. Something to keep in mind when we
114    decide whether to switch to unpremul default.
115static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
116                                               const uint8_t* SK_RESTRICT src,
117                                               int width, int deltaSrc, int,
118                                               const SkPMColor[]) {
119    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
120    unsigned alphaMask = 0xFF;
121    for (int x = 0; x < width; x++) {
122        unsigned alpha = src[3];
123        // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible
124        // the color components are not zero, but we skip them anyway, meaning they'll remain
125        // zero (implied by the request to skip zeroes).
126        if (0 != alpha) {
127            dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
128        }
129        src += deltaSrc;
130        alphaMask &= alpha;
131    }
132    return alphaMask != 0xFF;
133}
134*/
135
136SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, const SkPMColor* ctable,
137                                       const SkImageInfo& info, void* dst,
138                                       size_t dstRowBytes, bool skipZeroes) {
139    if (info.colorType() == kUnknown_SkColorType) {
140        return NULL;
141    }
142    if (info.minRowBytes() > dstRowBytes) {
143        return  NULL;
144    }
145    if (kIndex == sc && NULL == ctable) {
146        return NULL;
147    }
148    RowProc proc = NULL;
149    switch (sc) {
150        case kIndex:
151            switch (info.colorType()) {
152                case kN32_SkColorType:
153                    // We assume the color premultiplied ctable (or not) as desired.
154                    if (skipZeroes) {
155                        proc = &swizzle_index_to_n32_skipZ;
156                    } else {
157                        proc = &swizzle_index_to_n32;
158                    }
159                    break;
160
161                default:
162                    break;
163            }
164            break;
165        case kRGBX:
166            // TODO: Support other swizzles.
167            switch (info.colorType()) {
168                case kN32_SkColorType:
169                    proc = &swizzle_rgbx_to_n32;
170                    break;
171                default:
172                    break;
173            }
174            break;
175        case kRGBA:
176            switch (info.colorType()) {
177                case kN32_SkColorType:
178                    if (info.alphaType() == kUnpremul_SkAlphaType) {
179                        // Respect skipZeroes?
180                        proc = &swizzle_rgba_to_n32_unpremul;
181                    } else {
182                        if (skipZeroes) {
183                            proc = &swizzle_rgba_to_n32_premul_skipZ;
184                        } else {
185                            proc = &swizzle_rgba_to_n32_premul;
186                        }
187                    }
188                    break;
189                default:
190                    break;
191            }
192            break;
193        default:
194            break;
195    }
196    if (NULL == proc) {
197        return NULL;
198    }
199    return SkNEW_ARGS(SkSwizzler, (proc, ctable, BytesPerPixel(sc), info, dst, dstRowBytes));
200}
201
202SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcBpp,
203                       const SkImageInfo& info, void* dst, size_t rowBytes)
204    : fRowProc(proc)
205    , fColorTable(ctable)
206    , fSrcPixelSize(srcBpp)
207    , fDstInfo(info)
208    , fDstRow(dst)
209    , fDstRowBytes(rowBytes)
210    , fCurrY(0)
211{
212}
213
214bool SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
215    SkASSERT(fCurrY < fDstInfo.height());
216    const bool hadAlpha = fRowProc(fDstRow, src, fDstInfo.width(), fSrcPixelSize,
217                                   fCurrY, fColorTable);
218    fCurrY++;
219    fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
220    return hadAlpha;
221}
222