blob: b5375e602f2ecda6e3f180cc389ffe256e610a94 [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
djsollen@google.com54924242012-03-29 15:18:04 +000032void SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer) const
reed@android.com8a1c16f2008-12-17 15:59:43 +000033{
34 this->INHERITED::flatten(buffer);
35
36 buffer.write32(fOpColor);
37 buffer.write32(fDistMul);
38 buffer.write8(fMode);
39}
40
reed@android.com8a1c16f2008-12-17 15:59:43 +000041// returns 0..31
42static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b)
43{
44 SkASSERT(r <= SK_R16_MASK);
45 SkASSERT(g <= SK_G16_MASK);
46 SkASSERT(b <= SK_B16_MASK);
47
48 unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
49 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
50 unsigned db = SkAbs32(SkGetPackedB16(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000051
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 return SkMax32(dr, SkMax32(dg, db));
53}
54
55// returns 0..15
56static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b)
57{
58 SkASSERT(r <= 0xF);
59 SkASSERT(g <= 0xF);
60 SkASSERT(b <= 0xF);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000061
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
63 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
64 unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000065
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 return SkMax32(dr, SkMax32(dg, db));
67}
68
69// returns 0..255
70static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b)
71{
72 SkASSERT(r <= 0xFF);
73 SkASSERT(g <= 0xFF);
74 SkASSERT(b <= 0xFF);
75
76 unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
77 unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
78 unsigned db = SkAbs32(SkGetPackedB32(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000079
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 return SkMax32(dr, SkMax32(dg, db));
81}
82
83static int scale_dist_14(int dist, uint32_t mul, uint32_t sub)
84{
85 int tmp = dist * mul - sub;
86 int result = (tmp + (1 << 13)) >> 14;
87
88 return result;
89}
90
reed@android.com370eeeb2010-03-12 19:23:27 +000091static inline unsigned Accurate255To256(unsigned x) {
92 return x + (x >> 7);
93}
94
reed@android.com8a1c16f2008-12-17 15:59:43 +000095void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
96 const SkAlpha aa[])
97{
98 unsigned opR = SkColorGetR(fOpColor);
99 unsigned opG = SkColorGetG(fOpColor);
100 unsigned opB = SkColorGetB(fOpColor);
101 uint32_t mul = fDistMul;
102 uint32_t sub = (fDistMul - (1 << 14)) << 8;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000103
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 if (kTargetColor_Mode == fMode) {
107 mask = -1;
108 MAX = 255;
109 } else {
110 mask = 0;
111 MAX = 0;
112 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 for (int i = 0; i < count; i++) {
115 int d = color_dist32(dst[i], opR, opG, opB);
116 // now reverse d if we need to
117 d = MAX + (d ^ mask) - mask;
118 SkASSERT((unsigned)d <= 255);
reed@android.com370eeeb2010-03-12 19:23:27 +0000119 d = Accurate255To256(d);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000120
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 d = scale_dist_14(d, mul, sub);
122 SkASSERT(d <= 256);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 if (d > 0) {
125 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000126 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 if (0 == d) {
128 continue;
129 }
130 }
djsollen@google.com8ff1e512012-03-12 14:39:20 +0000131 dst[i] = SkFourByteInterp256(src[i], dst[i], d);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 }
133 }
134}
135
136static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
137{
138 SkASSERT(scale <= 32);
139 scale <<= 3;
140
141 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
142 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
143 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
144}
145
146void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
147 const SkAlpha aa[])
148{
149 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
150 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
151 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
152 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000153 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154
155 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000156
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 if (kTargetColor_Mode == fMode) {
158 mask = -1;
159 MAX = 31;
160 } else {
161 mask = 0;
162 MAX = 0;
163 }
164
165 for (int i = 0; i < count; i++) {
166 int d = color_dist16(dst[i], opR, opG, opB);
167 // now reverse d if we need to
168 d = MAX + (d ^ mask) - mask;
169 SkASSERT((unsigned)d <= 31);
170 // convert from 0..31 to 0..32
171 d += d >> 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 d = scale_dist_14(d, mul, sub);
173 SkASSERT(d <= 32);
174
175 if (d > 0) {
176 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000177 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 if (0 == d) {
179 continue;
180 }
181 }
182 dst[i] = SkBlend3216(src[i], dst[i], d);
183 }
184 }
185}
186
187void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
188 const SkAlpha aa[])
189{
190 unsigned opR = SkColorGetR(fOpColor) >> 4;
191 unsigned opG = SkColorGetG(fOpColor) >> 4;
192 unsigned opB = SkColorGetB(fOpColor) >> 4;
193 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000194 uint32_t sub = (fDistMul - (1 << 14)) << 4;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000197
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 if (kTargetColor_Mode == fMode) {
199 mask = -1;
200 MAX = 15;
201 } else {
202 mask = 0;
203 MAX = 0;
204 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000205
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 for (int i = 0; i < count; i++) {
207 int d = color_dist4444(dst[i], opR, opG, opB);
208 // now reverse d if we need to
209 d = MAX + (d ^ mask) - mask;
210 SkASSERT((unsigned)d <= 15);
reed@android.com0db5a7f2009-11-09 16:01:36 +0000211 // convert from 0..15 to 0..16
212 d += d >> 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 d = scale_dist_14(d, mul, sub);
214 SkASSERT(d <= 16);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 if (d > 0) {
217 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000218 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 if (0 == d) {
220 continue;
221 }
222 }
223 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
224 }
225 }
226}
227
228void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
229{
230 // override in subclass
231}
232
caryclark@google.comd26147a2011-12-15 14:16:43 +0000233SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)