blob: de3fe285c55c6b9f3518c542739aa2d6e4e53840 [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**
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00005** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008**
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00009** http://www.apache.org/licenses/LICENSE-2.0
reed@android.com8a1c16f2008-12-17 15:59:43 +000010**
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000011** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000015** limitations under the License.
16*/
17
18#include "SkAvoidXfermode.h"
19#include "SkColorPriv.h"
20
21SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000022{
reed@android.com8a1c16f2008-12-17 15:59:43 +000023 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000069
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000079
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
81 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
82 unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000083
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 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);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000097
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 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
reed@android.com370eeeb2010-03-12 19:23:27 +0000119static inline unsigned Accurate255To256(unsigned x) {
120 return x + (x >> 7);
121}
122
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
124 const SkAlpha aa[])
125{
126 unsigned opR = SkColorGetR(fOpColor);
127 unsigned opG = SkColorGetG(fOpColor);
128 unsigned opB = SkColorGetB(fOpColor);
129 uint32_t mul = fDistMul;
130 uint32_t sub = (fDistMul - (1 << 14)) << 8;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000131
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 if (kTargetColor_Mode == fMode) {
135 mask = -1;
136 MAX = 255;
137 } else {
138 mask = 0;
139 MAX = 0;
140 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 for (int i = 0; i < count; i++) {
143 int d = color_dist32(dst[i], opR, opG, opB);
144 // now reverse d if we need to
145 d = MAX + (d ^ mask) - mask;
146 SkASSERT((unsigned)d <= 255);
reed@android.com370eeeb2010-03-12 19:23:27 +0000147 d = Accurate255To256(d);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000148
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 d = scale_dist_14(d, mul, sub);
150 SkASSERT(d <= 256);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000151
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 if (d > 0) {
153 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000154 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 if (0 == d) {
156 continue;
157 }
158 }
159 dst[i] = SkFourByteInterp(src[i], dst[i], d);
160 }
161 }
162}
163
164static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
165{
166 SkASSERT(scale <= 32);
167 scale <<= 3;
168
169 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
170 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
171 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
172}
173
174void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
175 const SkAlpha aa[])
176{
177 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
178 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
179 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
180 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000181 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182
183 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000184
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 if (kTargetColor_Mode == fMode) {
186 mask = -1;
187 MAX = 31;
188 } else {
189 mask = 0;
190 MAX = 0;
191 }
192
193 for (int i = 0; i < count; i++) {
194 int d = color_dist16(dst[i], opR, opG, opB);
195 // now reverse d if we need to
196 d = MAX + (d ^ mask) - mask;
197 SkASSERT((unsigned)d <= 31);
198 // convert from 0..31 to 0..32
199 d += d >> 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 d = scale_dist_14(d, mul, sub);
201 SkASSERT(d <= 32);
202
203 if (d > 0) {
204 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000205 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 if (0 == d) {
207 continue;
208 }
209 }
210 dst[i] = SkBlend3216(src[i], dst[i], d);
211 }
212 }
213}
214
215void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
216 const SkAlpha aa[])
217{
218 unsigned opR = SkColorGetR(fOpColor) >> 4;
219 unsigned opG = SkColorGetG(fOpColor) >> 4;
220 unsigned opB = SkColorGetB(fOpColor) >> 4;
221 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000222 uint32_t sub = (fDistMul - (1 << 14)) << 4;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 if (kTargetColor_Mode == fMode) {
227 mask = -1;
228 MAX = 15;
229 } else {
230 mask = 0;
231 MAX = 0;
232 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 for (int i = 0; i < count; i++) {
235 int d = color_dist4444(dst[i], opR, opG, opB);
236 // now reverse d if we need to
237 d = MAX + (d ^ mask) - mask;
238 SkASSERT((unsigned)d <= 15);
reed@android.com0db5a7f2009-11-09 16:01:36 +0000239 // convert from 0..15 to 0..16
240 d += d >> 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 d = scale_dist_14(d, mul, sub);
242 SkASSERT(d <= 16);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 if (d > 0) {
245 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000246 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 if (0 == d) {
248 continue;
249 }
250 }
251 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
252 }
253 }
254}
255
256void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
257{
258 // override in subclass
259}
260
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000261static SkFlattenable::Registrar
262 gSkAvoidXfermodeReg("SkAvoidXfermode", SkAvoidXfermode::CreateProc);