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