SkAvoidXfermode.cpp revision 54924243c1b65b3ee6d8fa064b50a9b1bb2a19a5
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) const
33{
34    this->INHERITED::flatten(buffer);
35
36    buffer.write32(fOpColor);
37    buffer.write32(fDistMul);
38    buffer.write8(fMode);
39}
40
41// 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);
51
52    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);
61
62    unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
63    unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
64    unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
65
66    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);
79
80    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
91static inline unsigned Accurate255To256(unsigned x) {
92    return x + (x >> 7);
93}
94
95void 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;
103
104    int MAX, mask;
105
106    if (kTargetColor_Mode == fMode) {
107        mask = -1;
108        MAX = 255;
109    } else {
110        mask = 0;
111        MAX = 0;
112    }
113
114    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);
119        d = Accurate255To256(d);
120
121        d = scale_dist_14(d, mul, sub);
122        SkASSERT(d <= 256);
123
124        if (d > 0) {
125            if (NULL != aa) {
126                d = SkAlphaMul(d, Accurate255To256(*aa++));
127                if (0 == d) {
128                    continue;
129                }
130            }
131            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
132        }
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;
153    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
154
155    int MAX, mask;
156
157    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;
172        d = scale_dist_14(d, mul, sub);
173        SkASSERT(d <= 32);
174
175        if (d > 0) {
176            if (NULL != aa) {
177                d = SkAlphaMul(d, Accurate255To256(*aa++));
178                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;
194    uint32_t    sub = (fDistMul - (1 << 14)) << 4;
195
196    int MAX, mask;
197
198    if (kTargetColor_Mode == fMode) {
199        mask = -1;
200        MAX = 15;
201    } else {
202        mask = 0;
203        MAX = 0;
204    }
205
206    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);
211        // convert from 0..15 to 0..16
212        d += d >> 3;
213        d = scale_dist_14(d, mul, sub);
214        SkASSERT(d <= 16);
215
216        if (d > 0) {
217            if (NULL != aa) {
218                d = SkAlphaMul(d, Accurate255To256(*aa++));
219                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
233SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)
234