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 "SkCodecPriv.h"
9#include "SkColorPriv.h"
10#include "SkMaskSwizzler.h"
11
12static void swizzle_mask16_to_n32_opaque(
13        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
14        uint32_t startX, uint32_t sampleX) {
15
16    // Use the masks to decode to the destination
17    uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
18    SkPMColor* dstPtr = (SkPMColor*) dstRow;
19    for (int i = 0; i < width; i++) {
20        uint16_t p = srcPtr[0];
21        uint8_t red = masks->getRed(p);
22        uint8_t green = masks->getGreen(p);
23        uint8_t blue = masks->getBlue(p);
24        dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
25        srcPtr += sampleX;
26    }
27}
28
29static void swizzle_mask16_to_n32_unpremul(
30        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
31        uint32_t startX, uint32_t sampleX) {
32
33    // Use the masks to decode to the destination
34    uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
35    SkPMColor* dstPtr = (SkPMColor*) dstRow;
36    for (int i = 0; i < width; i++) {
37        uint16_t p = srcPtr[0];
38        uint8_t red = masks->getRed(p);
39        uint8_t green = masks->getGreen(p);
40        uint8_t blue = masks->getBlue(p);
41        uint8_t alpha = masks->getAlpha(p);
42        dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
43        srcPtr += sampleX;
44    }
45}
46
47static void swizzle_mask16_to_n32_premul(
48        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
49        uint32_t startX, uint32_t sampleX) {
50
51    // Use the masks to decode to the destination
52    uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
53    SkPMColor* dstPtr = (SkPMColor*) dstRow;
54    for (int i = 0; i < width; i++) {
55        uint16_t p = srcPtr[0];
56        uint8_t red = masks->getRed(p);
57        uint8_t green = masks->getGreen(p);
58        uint8_t blue = masks->getBlue(p);
59        uint8_t alpha = masks->getAlpha(p);
60        dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
61        srcPtr += sampleX;
62    }
63}
64
65// TODO (msarett): We have promoted a two byte per pixel image to 8888, only to
66// convert it back to 565. Instead, we should swizzle to 565 directly.
67static void swizzle_mask16_to_565(
68        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
69        uint32_t startX, uint32_t sampleX) {
70
71    // Use the masks to decode to the destination
72    uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
73    uint16_t* dstPtr = (uint16_t*) dstRow;
74    for (int i = 0; i < width; i++) {
75        uint16_t p = srcPtr[0];
76        uint8_t red = masks->getRed(p);
77        uint8_t green = masks->getGreen(p);
78        uint8_t blue = masks->getBlue(p);
79        dstPtr[i] = SkPack888ToRGB16(red, green, blue);
80        srcPtr += sampleX;
81    }
82}
83
84static void swizzle_mask24_to_n32_opaque(
85        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
86        uint32_t startX, uint32_t sampleX) {
87
88    // Use the masks to decode to the destination
89    srcRow += 3 * startX;
90    SkPMColor* dstPtr = (SkPMColor*) dstRow;
91    for (int i = 0; i < width; i++) {
92        uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
93        uint8_t red = masks->getRed(p);
94        uint8_t green = masks->getGreen(p);
95        uint8_t blue = masks->getBlue(p);
96        dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
97        srcRow += 3 * sampleX;
98    }
99}
100
101static void swizzle_mask24_to_n32_unpremul(
102        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
103        uint32_t startX, uint32_t sampleX) {
104
105    // Use the masks to decode to the destination
106    srcRow += 3 * startX;
107    SkPMColor* dstPtr = (SkPMColor*) dstRow;
108    for (int i = 0; i < width; i++) {
109        uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
110        uint8_t red = masks->getRed(p);
111        uint8_t green = masks->getGreen(p);
112        uint8_t blue = masks->getBlue(p);
113        uint8_t alpha = masks->getAlpha(p);
114        dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
115        srcRow += 3 * sampleX;
116    }
117}
118
119static void swizzle_mask24_to_n32_premul(
120        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
121        uint32_t startX, uint32_t sampleX) {
122
123    // Use the masks to decode to the destination
124    srcRow += 3 * startX;
125    SkPMColor* dstPtr = (SkPMColor*) dstRow;
126    for (int i = 0; i < width; i++) {
127        uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
128        uint8_t red = masks->getRed(p);
129        uint8_t green = masks->getGreen(p);
130        uint8_t blue = masks->getBlue(p);
131        uint8_t alpha = masks->getAlpha(p);
132        dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
133        srcRow += 3 * sampleX;
134    }
135}
136
137static void swizzle_mask24_to_565(
138        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
139        uint32_t startX, uint32_t sampleX) {
140
141    // Use the masks to decode to the destination
142    srcRow += 3 * startX;
143    uint16_t* dstPtr = (uint16_t*) dstRow;
144    for (int i = 0; i < width; i++) {
145        uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
146        uint8_t red = masks->getRed(p);
147        uint8_t green = masks->getGreen(p);
148        uint8_t blue = masks->getBlue(p);
149        dstPtr[i] = SkPack888ToRGB16(red, green, blue);
150        srcRow += 3 * sampleX;
151    }
152}
153
154static void swizzle_mask32_to_n32_opaque(
155        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
156        uint32_t startX, uint32_t sampleX) {
157
158    // Use the masks to decode to the destination
159    uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
160    SkPMColor* dstPtr = (SkPMColor*) dstRow;
161    for (int i = 0; i < width; i++) {
162        uint32_t p = srcPtr[0];
163        uint8_t red = masks->getRed(p);
164        uint8_t green = masks->getGreen(p);
165        uint8_t blue = masks->getBlue(p);
166        dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
167        srcPtr += sampleX;
168    }
169}
170
171static void swizzle_mask32_to_n32_unpremul(
172        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
173        uint32_t startX, uint32_t sampleX) {
174
175    // Use the masks to decode to the destination
176    uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
177    SkPMColor* dstPtr = (SkPMColor*) dstRow;
178    for (int i = 0; i < width; i++) {
179        uint32_t p = srcPtr[0];
180        uint8_t red = masks->getRed(p);
181        uint8_t green = masks->getGreen(p);
182        uint8_t blue = masks->getBlue(p);
183        uint8_t alpha = masks->getAlpha(p);
184        dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
185        srcPtr += sampleX;
186    }
187}
188
189static void swizzle_mask32_to_n32_premul(
190        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
191        uint32_t startX, uint32_t sampleX) {
192
193    // Use the masks to decode to the destination
194    uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
195    SkPMColor* dstPtr = (SkPMColor*) dstRow;
196    for (int i = 0; i < width; i++) {
197        uint32_t p = srcPtr[0];
198        uint8_t red = masks->getRed(p);
199        uint8_t green = masks->getGreen(p);
200        uint8_t blue = masks->getBlue(p);
201        uint8_t alpha = masks->getAlpha(p);
202        dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
203        srcPtr += sampleX;
204    }
205}
206
207static void swizzle_mask32_to_565(
208        void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
209        uint32_t startX, uint32_t sampleX) {
210    // Use the masks to decode to the destination
211    uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
212    uint16_t* dstPtr = (uint16_t*) dstRow;
213    for (int i = 0; i < width; i++) {
214        uint32_t p = srcPtr[0];
215        uint8_t red = masks->getRed(p);
216        uint8_t green = masks->getGreen(p);
217        uint8_t blue = masks->getBlue(p);
218        dstPtr[i] = SkPack888ToRGB16(red, green, blue);
219        srcPtr += sampleX;
220    }
221}
222
223/*
224 *
225 * Create a new mask swizzler
226 *
227 */
228SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo,
229        const SkImageInfo& srcInfo, SkMasks* masks, uint32_t bitsPerPixel,
230        const SkCodec::Options& options) {
231
232    // Choose the appropriate row procedure
233    RowProc proc = nullptr;
234    switch (bitsPerPixel) {
235        case 16:
236            switch (dstInfo.colorType()) {
237                case kN32_SkColorType:
238                    if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
239                        proc = &swizzle_mask16_to_n32_opaque;
240                    } else {
241                        switch (dstInfo.alphaType()) {
242                            case kUnpremul_SkAlphaType:
243                                proc = &swizzle_mask16_to_n32_unpremul;
244                                break;
245                            case kPremul_SkAlphaType:
246                                proc = &swizzle_mask16_to_n32_premul;
247                                break;
248                            default:
249                                break;
250                        }
251                    }
252                    break;
253                case kRGB_565_SkColorType:
254                    proc = &swizzle_mask16_to_565;
255                    break;
256                default:
257                    break;
258            }
259            break;
260        case 24:
261            switch (dstInfo.colorType()) {
262                case kN32_SkColorType:
263                    if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
264                        proc = &swizzle_mask24_to_n32_opaque;
265                    } else {
266                        switch (dstInfo.alphaType()) {
267                            case kUnpremul_SkAlphaType:
268                                proc = &swizzle_mask24_to_n32_unpremul;
269                                break;
270                            case kPremul_SkAlphaType:
271                                proc = &swizzle_mask24_to_n32_premul;
272                                break;
273                            default:
274                                break;
275                        }
276                    }
277                    break;
278                case kRGB_565_SkColorType:
279                    proc = &swizzle_mask24_to_565;
280                    break;
281                default:
282                    break;
283            }
284            break;
285        case 32:
286            switch (dstInfo.colorType()) {
287                case kN32_SkColorType:
288                    if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
289                        proc = &swizzle_mask32_to_n32_opaque;
290                    } else {
291                        switch (dstInfo.alphaType()) {
292                            case kUnpremul_SkAlphaType:
293                                proc = &swizzle_mask32_to_n32_unpremul;
294                                break;
295                            case kPremul_SkAlphaType:
296                                proc = &swizzle_mask32_to_n32_premul;
297                                break;
298                            default:
299                                break;
300                        }
301                    }
302                    break;
303                case kRGB_565_SkColorType:
304                    proc = &swizzle_mask32_to_565;
305                    break;
306                default:
307                    break;
308            }
309            break;
310        default:
311            SkASSERT(false);
312            return nullptr;
313    }
314
315    int srcOffset = 0;
316    int srcWidth = dstInfo.width();
317    if (options.fSubset) {
318        srcOffset = options.fSubset->left();
319        srcWidth = options.fSubset->width();
320    }
321
322    return new SkMaskSwizzler(masks, proc, srcOffset, srcWidth);
323}
324
325/*
326 *
327 * Constructor for mask swizzler
328 *
329 */
330SkMaskSwizzler::SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcOffset, int subsetWidth)
331    : fMasks(masks)
332    , fRowProc(proc)
333    , fSubsetWidth(subsetWidth)
334    , fDstWidth(subsetWidth)
335    , fSampleX(1)
336    , fSrcOffset(srcOffset)
337    , fX0(srcOffset)
338{}
339
340int SkMaskSwizzler::onSetSampleX(int sampleX) {
341    // FIXME: Share this function with SkSwizzler?
342    SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
343                           // way to report failure?
344    fSampleX = sampleX;
345    fX0 = get_start_coord(sampleX) + fSrcOffset;
346    fDstWidth = get_scaled_dimension(fSubsetWidth, sampleX);
347
348    // check that fX0 is valid
349    SkASSERT(fX0 >= 0);
350    return fDstWidth;
351}
352
353/*
354 *
355 * Swizzle the specified row
356 *
357 */
358void SkMaskSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
359    SkASSERT(nullptr != dst && nullptr != src);
360    fRowProc(dst, src, fDstWidth, fMasks, fX0, fSampleX);
361}
362