blob: 9f4e396005526804a0b38962bdee97f72aeab562 [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
reed@android.com370eeeb2010-03-12 19:23:27 +0000101static inline unsigned Accurate255To256(unsigned x) {
102 return x + (x >> 7);
103}
104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105void 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;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 if (kTargetColor_Mode == fMode) {
117 mask = -1;
118 MAX = 255;
119 } else {
120 mask = 0;
121 MAX = 0;
122 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 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);
reed@android.com370eeeb2010-03-12 19:23:27 +0000129 d = Accurate255To256(d);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 d = scale_dist_14(d, mul, sub);
132 SkASSERT(d <= 256);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 if (d > 0) {
135 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000136 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 if (0 == d) {
138 continue;
139 }
140 }
141 dst[i] = SkFourByteInterp(src[i], dst[i], d);
142 }
143 }
144}
145
146static 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
156void 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;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000163 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164
165 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 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;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 d = scale_dist_14(d, mul, sub);
183 SkASSERT(d <= 32);
184
185 if (d > 0) {
186 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000187 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 if (0 == d) {
189 continue;
190 }
191 }
192 dst[i] = SkBlend3216(src[i], dst[i], d);
193 }
194 }
195}
196
197void 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;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000204 uint32_t sub = (fDistMul - (1 << 14)) << 4;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000205
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000207
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 if (kTargetColor_Mode == fMode) {
209 mask = -1;
210 MAX = 15;
211 } else {
212 mask = 0;
213 MAX = 0;
214 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 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);
reed@android.com0db5a7f2009-11-09 16:01:36 +0000221 // convert from 0..15 to 0..16
222 d += d >> 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 d = scale_dist_14(d, mul, sub);
224 SkASSERT(d <= 16);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 if (d > 0) {
227 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000228 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 if (0 == d) {
230 continue;
231 }
232 }
233 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
234 }
235 }
236}
237
238void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
239{
240 // override in subclass
241}
242
caryclark@google.comd26147a2011-12-15 14:16:43 +0000243SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)