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 "SkSwizzler.h"
11#include "SkTemplates.h"
12#include "SkUtils.h"
13
14SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha,
15                                              uint8_t maxAlpha) {
16    // In the transparent case, this returns 0x0000
17    // In the opaque case, this returns 0xFFFF
18    // If the row is neither transparent nor opaque, returns something else
19    return (((uint16_t) maxAlpha) << 8) | zeroAlpha;
20}
21
22// kIndex1, kIndex2, kIndex4
23
24static SkSwizzler::ResultAlpha swizzle_small_index_to_index(
25        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
26        int bitsPerPixel, int y, const SkPMColor ctable[]) {
27
28    uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow;
29    INIT_RESULT_ALPHA;
30    const uint32_t pixelsPerByte = 8 / bitsPerPixel;
31    const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte);
32    const uint8_t mask = (1 << bitsPerPixel) - 1;
33    int x = 0;
34    for (uint32_t byte = 0; byte < rowBytes; byte++) {
35        uint8_t pixelData = src[byte];
36        for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) {
37            uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask;
38            UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT);
39            dst[x] = index;
40            pixelData <<= bitsPerPixel;
41            x++;
42        }
43    }
44    return COMPUTE_RESULT_ALPHA;
45}
46
47static SkSwizzler::ResultAlpha swizzle_small_index_to_n32(
48        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
49        int bitsPerPixel, int y, const SkPMColor ctable[]) {
50
51    SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow;
52    INIT_RESULT_ALPHA;
53    const uint32_t pixelsPerByte = 8 / bitsPerPixel;
54    const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte);
55    const uint8_t mask = (1 << bitsPerPixel) - 1;
56    int x = 0;
57    for (uint32_t byte = 0; byte < rowBytes; byte++) {
58        uint8_t pixelData = src[byte];
59        for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) {
60            uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask;
61            SkPMColor c = ctable[index];
62            UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
63            dst[x] = c;
64            pixelData <<= bitsPerPixel;
65            x++;
66        }
67    }
68    return COMPUTE_RESULT_ALPHA;
69}
70
71// kIndex
72
73static SkSwizzler::ResultAlpha swizzle_index_to_index(
74        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
75        int bytesPerPixel, int y, const SkPMColor ctable[]) {
76
77    uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow;
78    memcpy(dst, src, width);
79    // TODO (msarett): Should we skip the loop here and guess that the row is opaque/not opaque?
80    //                 SkScaledBitmap sampler just guesses that it is opaque.  This is dangerous
81    //                 and probably wrong since gif and bmp (rarely) may have alpha.
82    INIT_RESULT_ALPHA;
83    for (int x = 0; x < width; x++) {
84        UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT);
85    }
86    return COMPUTE_RESULT_ALPHA;
87}
88
89static SkSwizzler::ResultAlpha swizzle_index_to_n32(
90        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
91        int bytesPerPixel, int y, const SkPMColor ctable[]) {
92
93    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
94    INIT_RESULT_ALPHA;
95    for (int x = 0; x < width; x++) {
96        SkPMColor c = ctable[src[x]];
97        UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
98        dst[x] = c;
99    }
100    return COMPUTE_RESULT_ALPHA;
101}
102
103static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ(
104        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
105        int bytesPerPixel, int y, const SkPMColor ctable[]) {
106
107    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
108    INIT_RESULT_ALPHA;
109    for (int x = 0; x < width; x++) {
110        SkPMColor c = ctable[src[x]];
111        UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
112        if (c != 0) {
113            dst[x] = c;
114        }
115    }
116    return COMPUTE_RESULT_ALPHA;
117}
118
119#undef A32_MASK_IN_PLACE
120
121// kGray
122
123static SkSwizzler::ResultAlpha swizzle_gray_to_n32(
124        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
125        int bytesPerPixel, int y, const SkPMColor ctable[]) {
126
127    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
128    for (int x = 0; x < width; x++) {
129        dst[x] = SkPackARGB32NoCheck(0xFF, src[x], src[x], src[x]);
130    }
131    return SkSwizzler::kOpaque_ResultAlpha;
132}
133
134static SkSwizzler::ResultAlpha swizzle_gray_to_gray(
135        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
136        int bytesPerPixel, int y, const SkPMColor ctable[]) {
137    memcpy(dstRow, src, width);
138    return SkSwizzler::kOpaque_ResultAlpha;
139}
140
141// kBGRX
142
143static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32(
144        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
145        int bytesPerPixel, int y, const SkPMColor ctable[]) {
146
147    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
148    for (int x = 0; x < width; x++) {
149        dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]);
150        src += bytesPerPixel;
151    }
152    return SkSwizzler::kOpaque_ResultAlpha;
153}
154
155// kBGRA
156
157static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_unpremul(
158        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
159        int bytesPerPixel, int y, const SkPMColor ctable[]) {
160
161    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
162    INIT_RESULT_ALPHA;
163    for (int x = 0; x < width; x++) {
164        uint8_t alpha = src[3];
165        UPDATE_RESULT_ALPHA(alpha);
166        dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]);
167        src += bytesPerPixel;
168    }
169    return COMPUTE_RESULT_ALPHA;
170}
171
172static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_premul(
173        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
174        int bytesPerPixel, int y, const SkPMColor ctable[]) {
175
176    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
177    INIT_RESULT_ALPHA;
178    for (int x = 0; x < width; x++) {
179        uint8_t alpha = src[3];
180        UPDATE_RESULT_ALPHA(alpha);
181        dst[x] = SkPreMultiplyARGB(alpha, src[2], src[1], src[0]);
182        src += bytesPerPixel;
183    }
184    return COMPUTE_RESULT_ALPHA;
185}
186
187// n32
188static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32(
189        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
190        int bytesPerPixel, int y, const SkPMColor ctable[]) {
191
192    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
193    for (int x = 0; x < width; x++) {
194        dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
195        src += bytesPerPixel;
196    }
197    return SkSwizzler::kOpaque_ResultAlpha;
198}
199
200static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul(
201        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
202        int bytesPerPixel, int y, const SkPMColor ctable[]) {
203
204    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
205    INIT_RESULT_ALPHA;
206    for (int x = 0; x < width; x++) {
207        unsigned alpha = src[3];
208        UPDATE_RESULT_ALPHA(alpha);
209        dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
210        src += bytesPerPixel;
211    }
212    return COMPUTE_RESULT_ALPHA;
213}
214
215static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_unpremul(
216        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
217        int bytesPerPixel, int y, const SkPMColor ctable[]) {
218
219    uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
220    INIT_RESULT_ALPHA;
221    for (int x = 0; x < width; x++) {
222        unsigned alpha = src[3];
223        UPDATE_RESULT_ALPHA(alpha);
224        dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
225        src += bytesPerPixel;
226    }
227    return COMPUTE_RESULT_ALPHA;
228}
229
230static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ(
231        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
232        int bytesPerPixel, int y, const SkPMColor ctable[]) {
233
234    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
235    INIT_RESULT_ALPHA;
236    for (int x = 0; x < width; x++) {
237        unsigned alpha = src[3];
238        UPDATE_RESULT_ALPHA(alpha);
239        if (0 != alpha) {
240            dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
241        }
242        src += bytesPerPixel;
243    }
244    return COMPUTE_RESULT_ALPHA;
245}
246
247/**
248    FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes.
249    This would be fine for drawing normally, but not for drawing with transfer modes. Being
250    honest means we can draw correctly with transfer modes, with the cost of not being able
251    to take advantage of Android's free unwritten pages. Something to keep in mind when we
252    decide whether to switch to unpremul default.
253static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
254                                               const uint8_t* SK_RESTRICT src,
255                                               int width, int bitsPerPixel,
256                                               const SkPMColor[]) {
257    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
258    unsigned alphaMask = 0xFF;
259    for (int x = 0; x < width; x++) {
260        unsigned alpha = src[3];
261        // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible
262        // the color components are not zero, but we skip them anyway, meaning they'll remain
263        // zero (implied by the request to skip zeroes).
264        if (0 != alpha) {
265            dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
266        }
267        src += deltaSrc;
268        alphaMask &= alpha;
269    }
270    return alphaMask != 0xFF;
271}
272*/
273
274SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
275                                       const SkPMColor* ctable,
276                                       const SkImageInfo& info, void* dst,
277                                       size_t dstRowBytes,
278                                       SkImageGenerator::ZeroInitialized zeroInit) {
279    if (info.colorType() == kUnknown_SkColorType || kUnknown == sc) {
280        return NULL;
281    }
282    if (info.minRowBytes() > dstRowBytes) {
283        return  NULL;
284    }
285    if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc)
286            && NULL == ctable) {
287        return NULL;
288    }
289    RowProc proc = NULL;
290    switch (sc) {
291        case kIndex1:
292        case kIndex2:
293        case kIndex4:
294            switch (info.colorType()) {
295                case kN32_SkColorType:
296                    proc = &swizzle_small_index_to_n32;
297                    break;
298                case kIndex_8_SkColorType:
299                    proc = &swizzle_small_index_to_index;
300                    break;
301                default:
302                    break;
303            }
304            break;
305        case kIndex:
306            switch (info.colorType()) {
307                case kN32_SkColorType:
308                    // We assume the color premultiplied ctable (or not) as desired.
309                    if (SkImageGenerator::kYes_ZeroInitialized == zeroInit) {
310                        proc = &swizzle_index_to_n32_skipZ;
311                        break;
312                    } else {
313                        proc = &swizzle_index_to_n32;
314                        break;
315                    }
316                    break;
317                case kIndex_8_SkColorType:
318                    proc = &swizzle_index_to_index;
319                    break;
320                default:
321                    break;
322            }
323            break;
324        case kGray:
325            switch (info.colorType()) {
326                case kN32_SkColorType:
327                    proc = &swizzle_gray_to_n32;
328                    break;
329                case kGray_8_SkColorType:
330                    proc = &swizzle_gray_to_gray;
331                default:
332                    break;
333            }
334            break;
335        case kBGR:
336        case kBGRX:
337            switch (info.colorType()) {
338                case kN32_SkColorType:
339                    proc = &swizzle_bgrx_to_n32;
340                    break;
341                default:
342                    break;
343            }
344            break;
345        case kBGRA:
346            switch (info.colorType()) {
347                case kN32_SkColorType:
348                    switch (info.alphaType()) {
349                        case kUnpremul_SkAlphaType:
350                            proc = &swizzle_bgra_to_n32_unpremul;
351                            break;
352                        case kPremul_SkAlphaType:
353                            proc = &swizzle_bgra_to_n32_premul;
354                            break;
355                        default:
356                            break;
357                    }
358                    break;
359                default:
360                    break;
361            }
362            break;
363        case kRGBX:
364            // TODO: Support other swizzles.
365            switch (info.colorType()) {
366                case kN32_SkColorType:
367                    proc = &swizzle_rgbx_to_n32;
368                    break;
369                default:
370                    break;
371            }
372            break;
373        case kRGBA:
374            switch (info.colorType()) {
375                case kN32_SkColorType:
376                    if (info.alphaType() == kUnpremul_SkAlphaType) {
377                        // Respect zeroInit?
378                        proc = &swizzle_rgba_to_n32_unpremul;
379                    } else {
380                        if (SkImageGenerator::kYes_ZeroInitialized == zeroInit) {
381                            proc = &swizzle_rgba_to_n32_premul_skipZ;
382                        } else {
383                            proc = &swizzle_rgba_to_n32_premul;
384                        }
385                    }
386                    break;
387                default:
388                    break;
389            }
390            break;
391        case kRGB:
392            switch (info.colorType()) {
393                case kN32_SkColorType:
394                    proc = &swizzle_rgbx_to_n32;
395                    break;
396                default:
397                    break;
398            }
399            break;
400        default:
401            break;
402    }
403    if (NULL == proc) {
404        return NULL;
405    }
406
407    // Store deltaSrc in bytes if it is an even multiple, otherwise use bits
408    int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) :
409            BitsPerPixel(sc);
410    return SkNEW_ARGS(SkSwizzler, (proc, ctable, deltaSrc, info, dst,
411                                   dstRowBytes));
412}
413
414SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable,
415                       int deltaSrc, const SkImageInfo& info, void* dst,
416                       size_t rowBytes)
417    : fRowProc(proc)
418    , fColorTable(ctable)
419    , fDeltaSrc(deltaSrc)
420    , fDstInfo(info)
421    , fDstRow(dst)
422    , fDstRowBytes(rowBytes)
423    , fCurrY(0)
424{
425    SkDEBUGCODE(fNextMode = kUninitialized_NextMode);
426}
427
428SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
429    SkASSERT(0 <= fCurrY && fCurrY < fDstInfo.height());
430    SkASSERT(fDstRow != NULL);
431    SkASSERT(kDesignateRow_NextMode != fNextMode);
432    SkDEBUGCODE(fNextMode = kConsecutive_NextMode);
433
434    // Decode a row
435    const ResultAlpha result = fRowProc(fDstRow, src, fDstInfo.width(),
436            fDeltaSrc, fCurrY, fColorTable);
437
438    // Move to the next row and return the result
439    fCurrY++;
440    fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
441    return result;
442}
443
444SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src,
445        int y) {
446    SkASSERT(0 <= y && y < fDstInfo.height());
447    SkASSERT(kConsecutive_NextMode != fNextMode);
448    SkDEBUGCODE(fNextMode = kDesignateRow_NextMode);
449
450    // Choose the row
451    void* row = SkTAddOffset<void>(fDstRow, y*fDstRowBytes);
452
453    // Decode the row
454    return fRowProc(row, src, fDstInfo.width(), fDeltaSrc, fCurrY,
455            fColorTable);
456}
457
458void SkSwizzler::Fill(void* dstStartRow, const SkImageInfo& dstInfo, size_t dstRowBytes,
459        uint32_t numRows, uint32_t colorOrIndex, const SkPMColor* colorTable) {
460    SkASSERT(dstStartRow != NULL);
461    SkASSERT(numRows <= (uint32_t) dstInfo.height());
462
463    // Calculate bytes to fill.  We use getSafeSize since the last row may not be padded.
464    const size_t bytesToFill = dstInfo.makeWH(dstInfo.width(), numRows).getSafeSize(dstRowBytes);
465
466    // Use the proper memset routine to fill the remaining bytes
467    switch(dstInfo.colorType()) {
468        case kN32_SkColorType:
469            // Assume input is an index if we have a color table
470            uint32_t color;
471            if (NULL != colorTable) {
472                SkASSERT(colorOrIndex == (uint8_t) colorOrIndex);
473                color = colorTable[colorOrIndex];
474            // Otherwise, assume the input is a color
475            } else {
476                color = colorOrIndex;
477            }
478
479            // We must fill row by row in the case of unaligned row bytes
480            if (SkIsAlign4((size_t) dstStartRow) && SkIsAlign4(dstRowBytes)) {
481                sk_memset32((uint32_t*) dstStartRow, color,
482                        (uint32_t) bytesToFill / sizeof(SkPMColor));
483            } else {
484                // This is an unlikely, slow case
485                SkCodecPrintf("Warning: Strange number of row bytes, fill will be slow.\n");
486                uint32_t* dstRow = (uint32_t*) dstStartRow;
487                for (uint32_t row = 0; row < numRows; row++) {
488                    for (int32_t col = 0; col < dstInfo.width(); col++) {
489                        dstRow[col] = color;
490                    }
491                    dstRow = SkTAddOffset<uint32_t>(dstRow, dstRowBytes);
492                }
493            }
494            break;
495        // On an index destination color type, always assume the input is an index
496        case kIndex_8_SkColorType:
497            SkASSERT(colorOrIndex == (uint8_t) colorOrIndex);
498            memset(dstStartRow, colorOrIndex, bytesToFill);
499            break;
500        case kGray_8_SkColorType:
501            // If the destination is kGray, the caller passes in an 8-bit color.
502            // We will not assert that the high bits of colorOrIndex must be zeroed.
503            // This allows us to take advantage of the fact that the low 8 bits of an
504            // SKPMColor may be a valid a grayscale color.  For example, the low 8
505            // bits of SK_ColorBLACK are identical to the grayscale representation
506            // for black.
507            memset(dstStartRow, (uint8_t) colorOrIndex, bytesToFill);
508            break;
509        default:
510            SkCodecPrintf("Error: Unsupported dst color type for fill().  Doing nothing.\n");
511            SkASSERT(false);
512            break;
513    }
514}
515