xref: /third_party/skia/src/codec/SkMasks.cpp (revision cb93a386)
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 "include/core/SkTypes.h"
9#include "src/codec/SkCodecPriv.h"
10#include "src/codec/SkMasks.h"
11
12/*
13 *
14 * Used to convert 1-7 bit color components into 8-bit color components
15 *
16 */
17static constexpr uint8_t n_bit_to_8_bit_lookup_table[] = {
18    // 1 bit
19    0, 255,
20    // 2 bits
21    0, 85, 170, 255,
22    // 3 bits
23    0, 36, 73, 109, 146, 182, 219, 255,
24    // 4 bits
25    0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255,
26    // 5 bits
27    0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140,
28    148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255,
29    // 6 bits
30    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73,
31    77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138,
32    142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198,
33    202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255,
34    // 7 bits
35    0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
36    40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76,
37    78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110,
38    112, 114, 116, 118, 120, 122, 124, 126, 129, 131, 133, 135, 137, 139, 141,
39    143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171,
40    173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201,
41    203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231,
42    233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255
43};
44
45/*
46 *
47 * Convert an n bit component to an 8-bit component
48 *
49 */
50static uint8_t convert_to_8(uint8_t component, uint32_t n) {
51    if (0 == n) {
52        return 0;
53    } else if (8 > n) {
54        return n_bit_to_8_bit_lookup_table[(1 << n) - 2 + component];
55    } else {
56        SkASSERT(8 == n);
57        return component;
58    }
59}
60
61static uint8_t get_comp(uint32_t pixel, uint32_t mask, uint32_t shift,
62                        uint32_t size) {
63    return convert_to_8((pixel & mask) >> shift, size);
64}
65
66/*
67 *
68 * Get a color component
69 *
70 */
71uint8_t SkMasks::getRed(uint32_t pixel) const {
72    return get_comp(pixel, fRed.mask, fRed.shift, fRed.size);
73}
74uint8_t SkMasks::getGreen(uint32_t pixel) const {
75    return get_comp(pixel, fGreen.mask, fGreen.shift, fGreen.size);
76}
77uint8_t SkMasks::getBlue(uint32_t pixel) const {
78    return get_comp(pixel, fBlue.mask, fBlue.shift, fBlue.size);
79}
80uint8_t SkMasks::getAlpha(uint32_t pixel) const {
81    return get_comp(pixel, fAlpha.mask, fAlpha.shift, fAlpha.size);
82}
83
84/*
85 *
86 * Process an input mask to obtain the necessary information
87 *
88 */
89static SkMasks::MaskInfo process_mask(uint32_t mask) {
90    // Determine properties of the mask
91    uint32_t tempMask = mask;
92    uint32_t shift = 0;
93    uint32_t size = 0;
94    if (tempMask != 0) {
95        // Count trailing zeros on masks
96        for (; (tempMask & 1) == 0; tempMask >>= 1) {
97            shift++;
98        }
99        // Count the size of the mask
100        for (; tempMask & 1; tempMask >>= 1) {
101            size++;
102        }
103        // Verify that the mask is continuous
104        if (tempMask) {
105            SkCodecPrintf("Warning: Bit mask is not continuous.\n");
106            // Finish processing the mask
107            for (; tempMask; tempMask >>= 1) {
108                size++;
109            }
110        }
111        // Truncate masks greater than 8 bits
112        if (size > 8) {
113            shift += size - 8;
114            size = 8;
115            mask &= 0xFF << shift;
116        }
117    }
118
119    return { mask, shift, size };
120}
121
122/*
123 *
124 * Create the masks object
125 *
126 */
127SkMasks* SkMasks::CreateMasks(InputMasks masks, int bytesPerPixel) {
128    SkASSERT(0 < bytesPerPixel && bytesPerPixel <= 4);
129
130    // Trim the input masks to match bytesPerPixel.
131    if (bytesPerPixel < 4) {
132        int bitsPerPixel = 8*bytesPerPixel;
133        masks.red   &= (1 << bitsPerPixel) - 1;
134        masks.green &= (1 << bitsPerPixel) - 1;
135        masks.blue  &= (1 << bitsPerPixel) - 1;
136        masks.alpha &= (1 << bitsPerPixel) - 1;
137    }
138
139    // Check that masks do not overlap.
140    if (((masks.red   & masks.green) |
141         (masks.red   & masks.blue ) |
142         (masks.red   & masks.alpha) |
143         (masks.green & masks.blue ) |
144         (masks.green & masks.alpha) |
145         (masks.blue  & masks.alpha) ) != 0) {
146        return nullptr;
147    }
148
149    return new SkMasks(process_mask(masks.red  ),
150                       process_mask(masks.green),
151                       process_mask(masks.blue ),
152                       process_mask(masks.alpha));
153}
154
155