blob: eed40122c262316fd9c13c5841dc51952f6d3511 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/effects/SkAvoidXfermode.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkAvoidXfermode.h"
19#include "SkColorPriv.h"
20
21SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
22{
23 if (tolerance > 255) {
24 tolerance = 255;
25 }
26
27 fOpColor = opColor;
28 fDistMul = (256 << 14) / (tolerance + 1);
29 fMode = mode;
30}
31
32SkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer)
33 : INHERITED(buffer)
34{
35 fOpColor = buffer.readU32();
36 fDistMul = buffer.readU32();
37 fMode = (Mode)buffer.readU8();
38}
39
40void SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer)
41{
42 this->INHERITED::flatten(buffer);
43
44 buffer.write32(fOpColor);
45 buffer.write32(fDistMul);
46 buffer.write8(fMode);
47}
48
49SkFlattenable* SkAvoidXfermode::Create(SkFlattenableReadBuffer& rb)
50{
51 return SkNEW_ARGS(SkAvoidXfermode, (rb));
52}
53
54SkFlattenable::Factory SkAvoidXfermode::getFactory()
55{
56 return Create;
57}
58
59// returns 0..31
60static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b)
61{
62 SkASSERT(r <= SK_R16_MASK);
63 SkASSERT(g <= SK_G16_MASK);
64 SkASSERT(b <= SK_B16_MASK);
65
66 unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
67 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
68 unsigned db = SkAbs32(SkGetPackedB16(c) - b);
69
70 return SkMax32(dr, SkMax32(dg, db));
71}
72
73// returns 0..15
74static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b)
75{
76 SkASSERT(r <= 0xF);
77 SkASSERT(g <= 0xF);
78 SkASSERT(b <= 0xF);
79
80 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
81 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
82 unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
83
84 return SkMax32(dr, SkMax32(dg, db));
85}
86
87// returns 0..255
88static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b)
89{
90 SkASSERT(r <= 0xFF);
91 SkASSERT(g <= 0xFF);
92 SkASSERT(b <= 0xFF);
93
94 unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
95 unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
96 unsigned db = SkAbs32(SkGetPackedB32(c) - b);
97
98 return SkMax32(dr, SkMax32(dg, db));
99}
100
101static int scale_dist_14(int dist, uint32_t mul, uint32_t sub)
102{
103 int tmp = dist * mul - sub;
104 int result = (tmp + (1 << 13)) >> 14;
105
106 return result;
107}
108
109static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, unsigned scale)
110{
111 unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
112 unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
113 unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
114 unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
115
116 return SkPackARGB32(a, r, g, b);
117}
118
119void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
120 const SkAlpha aa[])
121{
122 unsigned opR = SkColorGetR(fOpColor);
123 unsigned opG = SkColorGetG(fOpColor);
124 unsigned opB = SkColorGetB(fOpColor);
125 uint32_t mul = fDistMul;
126 uint32_t sub = (fDistMul - (1 << 14)) << 8;
127
128 int MAX, mask;
129
130 if (kTargetColor_Mode == fMode) {
131 mask = -1;
132 MAX = 255;
133 } else {
134 mask = 0;
135 MAX = 0;
136 }
137
138 for (int i = 0; i < count; i++) {
139 int d = color_dist32(dst[i], opR, opG, opB);
140 // now reverse d if we need to
141 d = MAX + (d ^ mask) - mask;
142 SkASSERT((unsigned)d <= 255);
143 d = SkAlpha255To256(d);
144
145 d = scale_dist_14(d, mul, sub);
146 SkASSERT(d <= 256);
147
148 if (d > 0) {
149 if (NULL != aa) {
150 d = SkAlphaMul(d, SkAlpha255To256(*aa++));
151 if (0 == d) {
152 continue;
153 }
154 }
155 dst[i] = SkFourByteInterp(src[i], dst[i], d);
156 }
157 }
158}
159
160static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
161{
162 SkASSERT(scale <= 32);
163 scale <<= 3;
164
165 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
166 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
167 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
168}
169
170void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
171 const SkAlpha aa[])
172{
173 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
174 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
175 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
176 uint32_t mul = fDistMul;
177 uint32_t sub = (fDistMul - (1 << 14)) << 8;
178
179 int MAX, mask;
180
181 if (kTargetColor_Mode == fMode) {
182 mask = -1;
183 MAX = 31;
184 } else {
185 mask = 0;
186 MAX = 0;
187 }
188
189 for (int i = 0; i < count; i++) {
190 int d = color_dist16(dst[i], opR, opG, opB);
191 // now reverse d if we need to
192 d = MAX + (d ^ mask) - mask;
193 SkASSERT((unsigned)d <= 31);
194 // convert from 0..31 to 0..32
195 d += d >> 4;
196
197 d = scale_dist_14(d, mul, sub);
198 SkASSERT(d <= 32);
199
200 if (d > 0) {
201 if (NULL != aa) {
202 d = SkAlphaMul(d, SkAlpha255To256(*aa++));
203 if (0 == d) {
204 continue;
205 }
206 }
207 dst[i] = SkBlend3216(src[i], dst[i], d);
208 }
209 }
210}
211
212void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
213 const SkAlpha aa[])
214{
215 unsigned opR = SkColorGetR(fOpColor) >> 4;
216 unsigned opG = SkColorGetG(fOpColor) >> 4;
217 unsigned opB = SkColorGetB(fOpColor) >> 4;
218 uint32_t mul = fDistMul;
219 uint32_t sub = (fDistMul - (1 << 14)) << 8;
220
221 int MAX, mask;
222
223 if (kTargetColor_Mode == fMode) {
224 mask = -1;
225 MAX = 15;
226 } else {
227 mask = 0;
228 MAX = 0;
229 }
230
231 for (int i = 0; i < count; i++) {
232 int d = color_dist4444(dst[i], opR, opG, opB);
233 // now reverse d if we need to
234 d = MAX + (d ^ mask) - mask;
235 SkASSERT((unsigned)d <= 15);
236 d = SkAlpha255To256(d);
237
238 d = scale_dist_14(d, mul, sub);
239 SkASSERT(d <= 16);
240
241 if (d > 0) {
242 if (NULL != aa) {
243 d = SkAlphaMul(d, SkAlpha255To256(*aa++));
244 if (0 == d) {
245 continue;
246 }
247 }
248 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
249 }
250 }
251}
252
253void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
254{
255 // override in subclass
256}
257