|
1 /* |
|
2 * Copyright 2006 The Android Open Source Project |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkAvoidXfermode.h" |
|
9 #include "SkColorPriv.h" |
|
10 #include "SkReadBuffer.h" |
|
11 #include "SkWriteBuffer.h" |
|
12 #include "SkString.h" |
|
13 |
|
14 SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) { |
|
15 if (tolerance > 255) { |
|
16 tolerance = 255; |
|
17 } |
|
18 |
|
19 fOpColor = opColor; |
|
20 fDistMul = (256 << 14) / (tolerance + 1); |
|
21 fMode = mode; |
|
22 } |
|
23 |
|
24 SkAvoidXfermode::SkAvoidXfermode(SkReadBuffer& buffer) |
|
25 : INHERITED(buffer) { |
|
26 fOpColor = buffer.readColor(); |
|
27 fDistMul = buffer.readUInt(); |
|
28 fMode = (Mode)buffer.readUInt(); |
|
29 } |
|
30 |
|
31 void SkAvoidXfermode::flatten(SkWriteBuffer& buffer) const { |
|
32 this->INHERITED::flatten(buffer); |
|
33 |
|
34 buffer.writeColor(fOpColor); |
|
35 buffer.writeUInt(fDistMul); |
|
36 buffer.writeUInt(fMode); |
|
37 } |
|
38 |
|
39 // returns 0..31 |
|
40 static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) { |
|
41 SkASSERT(r <= SK_R16_MASK); |
|
42 SkASSERT(g <= SK_G16_MASK); |
|
43 SkASSERT(b <= SK_B16_MASK); |
|
44 |
|
45 unsigned dr = SkAbs32(SkGetPackedR16(c) - r); |
|
46 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS); |
|
47 unsigned db = SkAbs32(SkGetPackedB16(c) - b); |
|
48 |
|
49 return SkMax32(dr, SkMax32(dg, db)); |
|
50 } |
|
51 |
|
52 // returns 0..255 |
|
53 static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) { |
|
54 SkASSERT(r <= 0xFF); |
|
55 SkASSERT(g <= 0xFF); |
|
56 SkASSERT(b <= 0xFF); |
|
57 |
|
58 unsigned dr = SkAbs32(SkGetPackedR32(c) - r); |
|
59 unsigned dg = SkAbs32(SkGetPackedG32(c) - g); |
|
60 unsigned db = SkAbs32(SkGetPackedB32(c) - b); |
|
61 |
|
62 return SkMax32(dr, SkMax32(dg, db)); |
|
63 } |
|
64 |
|
65 static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) { |
|
66 int tmp = dist * mul - sub; |
|
67 int result = (tmp + (1 << 13)) >> 14; |
|
68 |
|
69 return result; |
|
70 } |
|
71 |
|
72 static inline unsigned Accurate255To256(unsigned x) { |
|
73 return x + (x >> 7); |
|
74 } |
|
75 |
|
76 void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, |
|
77 const SkAlpha aa[]) const { |
|
78 unsigned opR = SkColorGetR(fOpColor); |
|
79 unsigned opG = SkColorGetG(fOpColor); |
|
80 unsigned opB = SkColorGetB(fOpColor); |
|
81 uint32_t mul = fDistMul; |
|
82 uint32_t sub = (fDistMul - (1 << 14)) << 8; |
|
83 |
|
84 int MAX, mask; |
|
85 |
|
86 if (kTargetColor_Mode == fMode) { |
|
87 mask = -1; |
|
88 MAX = 255; |
|
89 } else { |
|
90 mask = 0; |
|
91 MAX = 0; |
|
92 } |
|
93 |
|
94 for (int i = 0; i < count; i++) { |
|
95 int d = color_dist32(dst[i], opR, opG, opB); |
|
96 // now reverse d if we need to |
|
97 d = MAX + (d ^ mask) - mask; |
|
98 SkASSERT((unsigned)d <= 255); |
|
99 d = Accurate255To256(d); |
|
100 |
|
101 d = scale_dist_14(d, mul, sub); |
|
102 SkASSERT(d <= 256); |
|
103 |
|
104 if (d > 0) { |
|
105 if (NULL != aa) { |
|
106 d = SkAlphaMul(d, Accurate255To256(*aa++)); |
|
107 if (0 == d) { |
|
108 continue; |
|
109 } |
|
110 } |
|
111 dst[i] = SkFourByteInterp256(src[i], dst[i], d); |
|
112 } |
|
113 } |
|
114 } |
|
115 |
|
116 static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) { |
|
117 SkASSERT(scale <= 32); |
|
118 scale <<= 3; |
|
119 |
|
120 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale), |
|
121 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale), |
|
122 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale)); |
|
123 } |
|
124 |
|
125 void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, |
|
126 const SkAlpha aa[]) const { |
|
127 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS); |
|
128 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS); |
|
129 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS); |
|
130 uint32_t mul = fDistMul; |
|
131 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS; |
|
132 |
|
133 int MAX, mask; |
|
134 |
|
135 if (kTargetColor_Mode == fMode) { |
|
136 mask = -1; |
|
137 MAX = 31; |
|
138 } else { |
|
139 mask = 0; |
|
140 MAX = 0; |
|
141 } |
|
142 |
|
143 for (int i = 0; i < count; i++) { |
|
144 int d = color_dist16(dst[i], opR, opG, opB); |
|
145 // now reverse d if we need to |
|
146 d = MAX + (d ^ mask) - mask; |
|
147 SkASSERT((unsigned)d <= 31); |
|
148 // convert from 0..31 to 0..32 |
|
149 d += d >> 4; |
|
150 d = scale_dist_14(d, mul, sub); |
|
151 SkASSERT(d <= 32); |
|
152 |
|
153 if (d > 0) { |
|
154 if (NULL != aa) { |
|
155 d = SkAlphaMul(d, Accurate255To256(*aa++)); |
|
156 if (0 == d) { |
|
157 continue; |
|
158 } |
|
159 } |
|
160 dst[i] = SkBlend3216(src[i], dst[i], d); |
|
161 } |
|
162 } |
|
163 } |
|
164 |
|
165 void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, |
|
166 const SkAlpha aa[]) const { |
|
167 // override in subclass |
|
168 } |
|
169 |
|
170 #ifndef SK_IGNORE_TO_STRING |
|
171 void SkAvoidXfermode::toString(SkString* str) const { |
|
172 str->append("SkAvoidXfermode: opColor: "); |
|
173 str->appendHex(fOpColor); |
|
174 str->appendf("distMul: %d ", fDistMul); |
|
175 |
|
176 static const char* gModeStrings[] = { "Avoid", "Target" }; |
|
177 |
|
178 str->appendf("mode: %s", gModeStrings[fMode]); |
|
179 } |
|
180 #endif |