1
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
9
10#include "SkAvoidXfermode.h"
11#include "SkColorPriv.h"
12
13SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
14{
15    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);
61
62    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);
71
72    unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
73    unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
74    unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
75
76    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);
89
90    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
101static inline unsigned Accurate255To256(unsigned x) {
102    return x + (x >> 7);
103}
104
105void 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;
113
114    int MAX, mask;
115
116    if (kTargetColor_Mode == fMode) {
117        mask = -1;
118        MAX = 255;
119    } else {
120        mask = 0;
121        MAX = 0;
122    }
123
124    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);
129        d = Accurate255To256(d);
130
131        d = scale_dist_14(d, mul, sub);
132        SkASSERT(d <= 256);
133
134        if (d > 0) {
135            if (NULL != aa) {
136                d = SkAlphaMul(d, Accurate255To256(*aa++));
137                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;
163    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
164
165    int MAX, mask;
166
167    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;
182        d = scale_dist_14(d, mul, sub);
183        SkASSERT(d <= 32);
184
185        if (d > 0) {
186            if (NULL != aa) {
187                d = SkAlphaMul(d, Accurate255To256(*aa++));
188                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;
204    uint32_t    sub = (fDistMul - (1 << 14)) << 4;
205
206    int MAX, mask;
207
208    if (kTargetColor_Mode == fMode) {
209        mask = -1;
210        MAX = 15;
211    } else {
212        mask = 0;
213        MAX = 0;
214    }
215
216    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);
221        // convert from 0..15 to 0..16
222        d += d >> 3;
223        d = scale_dist_14(d, mul, sub);
224        SkASSERT(d <= 16);
225
226        if (d > 0) {
227            if (NULL != aa) {
228                d = SkAlphaMul(d, Accurate255To256(*aa++));
229                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
243SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)
244