SkAvoidXfermode.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
1/* libs/graphics/effects/SkAvoidXfermode.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** 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
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** 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
15** limitations under the License.
16*/
17
18#include "SkAvoidXfermode.h"
19#include "SkColorPriv.h"
20
21SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
22{
23    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);
69
70    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);
79
80    unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
81    unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
82    unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
83
84    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);
97
98    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
119void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
120                             const SkAlpha aa[])
121{
122    unsigned    opR = SkColorGetR(fOpColor);
123    unsigned    opG = SkColorGetG(fOpColor);
124    unsigned    opB = SkColorGetB(fOpColor);
125    uint32_t    mul = fDistMul;
126    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
127
128    int MAX, mask;
129
130    if (kTargetColor_Mode == fMode) {
131        mask = -1;
132        MAX = 255;
133    } else {
134        mask = 0;
135        MAX = 0;
136    }
137
138    for (int i = 0; i < count; i++) {
139        int d = color_dist32(dst[i], opR, opG, opB);
140        // now reverse d if we need to
141        d = MAX + (d ^ mask) - mask;
142        SkASSERT((unsigned)d <= 255);
143        d = SkAlpha255To256(d);
144
145        d = scale_dist_14(d, mul, sub);
146        SkASSERT(d <= 256);
147
148        if (d > 0) {
149            if (NULL != aa) {
150                d = SkAlphaMul(d, SkAlpha255To256(*aa++));
151                if (0 == d) {
152                    continue;
153                }
154            }
155            dst[i] = SkFourByteInterp(src[i], dst[i], d);
156        }
157    }
158}
159
160static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
161{
162    SkASSERT(scale <= 32);
163    scale <<= 3;
164
165    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
166                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
167                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
168}
169
170void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
171                             const SkAlpha aa[])
172{
173    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
174    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
175    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
176    uint32_t    mul = fDistMul;
177    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
178
179    int MAX, mask;
180
181    if (kTargetColor_Mode == fMode) {
182        mask = -1;
183        MAX = 31;
184    } else {
185        mask = 0;
186        MAX = 0;
187    }
188
189    for (int i = 0; i < count; i++) {
190        int d = color_dist16(dst[i], opR, opG, opB);
191        // now reverse d if we need to
192        d = MAX + (d ^ mask) - mask;
193        SkASSERT((unsigned)d <= 31);
194        // convert from 0..31 to 0..32
195        d += d >> 4;
196
197        d = scale_dist_14(d, mul, sub);
198        SkASSERT(d <= 32);
199
200        if (d > 0) {
201            if (NULL != aa) {
202                d = SkAlphaMul(d, SkAlpha255To256(*aa++));
203                if (0 == d) {
204                    continue;
205                }
206            }
207            dst[i] = SkBlend3216(src[i], dst[i], d);
208        }
209    }
210}
211
212void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
213                               const SkAlpha aa[])
214{
215    unsigned    opR = SkColorGetR(fOpColor) >> 4;
216    unsigned    opG = SkColorGetG(fOpColor) >> 4;
217    unsigned    opB = SkColorGetB(fOpColor) >> 4;
218    uint32_t    mul = fDistMul;
219    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
220
221    int MAX, mask;
222
223    if (kTargetColor_Mode == fMode) {
224        mask = -1;
225        MAX = 15;
226    } else {
227        mask = 0;
228        MAX = 0;
229    }
230
231    for (int i = 0; i < count; i++) {
232        int d = color_dist4444(dst[i], opR, opG, opB);
233        // now reverse d if we need to
234        d = MAX + (d ^ mask) - mask;
235        SkASSERT((unsigned)d <= 15);
236        d = SkAlpha255To256(d);
237
238        d = scale_dist_14(d, mul, sub);
239        SkASSERT(d <= 16);
240
241        if (d > 0) {
242            if (NULL != aa) {
243                d = SkAlphaMul(d, SkAlpha255To256(*aa++));
244                if (0 == d) {
245                    continue;
246                }
247            }
248            dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
249        }
250    }
251}
252
253void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
254{
255    // override in subclass
256}
257
258