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