blob: d2cd49b2616a4efff5ba36a7b8cc8d45aa6bb185 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkAvoidXfermode.h"
11#include "SkColorPriv.h"
12
13SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000014{
reed@android.com8a1c16f2008-12-17 15:59:43 +000015 if (tolerance > 255) {
16 tolerance = 255;
17 }
18
19 fOpColor = opColor;
20 fDistMul = (256 << 14) / (tolerance + 1);
21 fMode = mode;
22}
23
24SkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer)
25 : INHERITED(buffer)
26{
27 fOpColor = buffer.readU32();
28 fDistMul = buffer.readU32();
29 fMode = (Mode)buffer.readU8();
30}
31
32void 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
41SkFlattenable* SkAvoidXfermode::Create(SkFlattenableReadBuffer& rb)
42{
43 return SkNEW_ARGS(SkAvoidXfermode, (rb));
44}
45
46SkFlattenable::Factory SkAvoidXfermode::getFactory()
47{
48 return Create;
49}
50
51// returns 0..31
52static 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000061
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 return SkMax32(dr, SkMax32(dg, db));
63}
64
65// returns 0..15
66static 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000071
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
73 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
74 unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000075
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 return SkMax32(dr, SkMax32(dg, db));
77}
78
79// returns 0..255
80static 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000089
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 return SkMax32(dr, SkMax32(dg, db));
91}
92
93static 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
101static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, unsigned scale)
102{
103 unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
104 unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
105 unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
106 unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
107
108 return SkPackARGB32(a, r, g, b);
109}
110
reed@android.com370eeeb2010-03-12 19:23:27 +0000111static inline unsigned Accurate255To256(unsigned x) {
112 return x + (x >> 7);
113}
114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
116 const SkAlpha aa[])
117{
118 unsigned opR = SkColorGetR(fOpColor);
119 unsigned opG = SkColorGetG(fOpColor);
120 unsigned opB = SkColorGetB(fOpColor);
121 uint32_t mul = fDistMul;
122 uint32_t sub = (fDistMul - (1 << 14)) << 8;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 if (kTargetColor_Mode == fMode) {
127 mask = -1;
128 MAX = 255;
129 } else {
130 mask = 0;
131 MAX = 0;
132 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 for (int i = 0; i < count; i++) {
135 int d = color_dist32(dst[i], opR, opG, opB);
136 // now reverse d if we need to
137 d = MAX + (d ^ mask) - mask;
138 SkASSERT((unsigned)d <= 255);
reed@android.com370eeeb2010-03-12 19:23:27 +0000139 d = Accurate255To256(d);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000140
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 d = scale_dist_14(d, mul, sub);
142 SkASSERT(d <= 256);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000143
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 if (d > 0) {
145 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000146 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 if (0 == d) {
148 continue;
149 }
150 }
151 dst[i] = SkFourByteInterp(src[i], dst[i], d);
152 }
153 }
154}
155
156static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
157{
158 SkASSERT(scale <= 32);
159 scale <<= 3;
160
161 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
162 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
163 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
164}
165
166void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
167 const SkAlpha aa[])
168{
169 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
170 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
171 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
172 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000173 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
175 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 if (kTargetColor_Mode == fMode) {
178 mask = -1;
179 MAX = 31;
180 } else {
181 mask = 0;
182 MAX = 0;
183 }
184
185 for (int i = 0; i < count; i++) {
186 int d = color_dist16(dst[i], opR, opG, opB);
187 // now reverse d if we need to
188 d = MAX + (d ^ mask) - mask;
189 SkASSERT((unsigned)d <= 31);
190 // convert from 0..31 to 0..32
191 d += d >> 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 d = scale_dist_14(d, mul, sub);
193 SkASSERT(d <= 32);
194
195 if (d > 0) {
196 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000197 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 if (0 == d) {
199 continue;
200 }
201 }
202 dst[i] = SkBlend3216(src[i], dst[i], d);
203 }
204 }
205}
206
207void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
208 const SkAlpha aa[])
209{
210 unsigned opR = SkColorGetR(fOpColor) >> 4;
211 unsigned opG = SkColorGetG(fOpColor) >> 4;
212 unsigned opB = SkColorGetB(fOpColor) >> 4;
213 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000214 uint32_t sub = (fDistMul - (1 << 14)) << 4;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 if (kTargetColor_Mode == fMode) {
219 mask = -1;
220 MAX = 15;
221 } else {
222 mask = 0;
223 MAX = 0;
224 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 for (int i = 0; i < count; i++) {
227 int d = color_dist4444(dst[i], opR, opG, opB);
228 // now reverse d if we need to
229 d = MAX + (d ^ mask) - mask;
230 SkASSERT((unsigned)d <= 15);
reed@android.com0db5a7f2009-11-09 16:01:36 +0000231 // convert from 0..15 to 0..16
232 d += d >> 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 d = scale_dist_14(d, mul, sub);
234 SkASSERT(d <= 16);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 if (d > 0) {
237 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000238 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 if (0 == d) {
240 continue;
241 }
242 }
243 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
244 }
245 }
246}
247
248void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
249{
250 // override in subclass
251}
252
caryclark@google.comd26147a2011-12-15 14:16:43 +0000253SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)