SkAvoidXfermode.cpp revision a0c2bc24381fea063008f9c8823756eb020603b3
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#include "SkFlattenableBuffers.h"
13
14SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode)
15{
16    if (tolerance > 255) {
17        tolerance = 255;
18    }
19
20    fOpColor = opColor;
21    fDistMul = (256 << 14) / (tolerance + 1);
22    fMode = mode;
23}
24
25SkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer)
26    : INHERITED(buffer)
27{
28    fOpColor = buffer.readColor();
29    fDistMul = buffer.readUInt();
30    fMode = (Mode)buffer.readUInt();
31}
32
33void SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer) const
34{
35    this->INHERITED::flatten(buffer);
36
37    buffer.writeColor(fOpColor);
38    buffer.writeUInt(fDistMul);
39    buffer.writeUInt(fMode);
40}
41
42// returns 0..31
43static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b)
44{
45    SkASSERT(r <= SK_R16_MASK);
46    SkASSERT(g <= SK_G16_MASK);
47    SkASSERT(b <= SK_B16_MASK);
48
49    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
50    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
51    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
52
53    return SkMax32(dr, SkMax32(dg, db));
54}
55
56// returns 0..15
57static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b)
58{
59    SkASSERT(r <= 0xF);
60    SkASSERT(g <= 0xF);
61    SkASSERT(b <= 0xF);
62
63    unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
64    unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
65    unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
66
67    return SkMax32(dr, SkMax32(dg, db));
68}
69
70// returns 0..255
71static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b)
72{
73    SkASSERT(r <= 0xFF);
74    SkASSERT(g <= 0xFF);
75    SkASSERT(b <= 0xFF);
76
77    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
78    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
79    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
80
81    return SkMax32(dr, SkMax32(dg, db));
82}
83
84static int scale_dist_14(int dist, uint32_t mul, uint32_t sub)
85{
86    int tmp = dist * mul - sub;
87    int result = (tmp + (1 << 13)) >> 14;
88
89    return result;
90}
91
92static inline unsigned Accurate255To256(unsigned x) {
93    return x + (x >> 7);
94}
95
96void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
97                             const SkAlpha aa[])
98{
99    unsigned    opR = SkColorGetR(fOpColor);
100    unsigned    opG = SkColorGetG(fOpColor);
101    unsigned    opB = SkColorGetB(fOpColor);
102    uint32_t    mul = fDistMul;
103    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
104
105    int MAX, mask;
106
107    if (kTargetColor_Mode == fMode) {
108        mask = -1;
109        MAX = 255;
110    } else {
111        mask = 0;
112        MAX = 0;
113    }
114
115    for (int i = 0; i < count; i++) {
116        int d = color_dist32(dst[i], opR, opG, opB);
117        // now reverse d if we need to
118        d = MAX + (d ^ mask) - mask;
119        SkASSERT((unsigned)d <= 255);
120        d = Accurate255To256(d);
121
122        d = scale_dist_14(d, mul, sub);
123        SkASSERT(d <= 256);
124
125        if (d > 0) {
126            if (NULL != aa) {
127                d = SkAlphaMul(d, Accurate255To256(*aa++));
128                if (0 == d) {
129                    continue;
130                }
131            }
132            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
133        }
134    }
135}
136
137static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
138{
139    SkASSERT(scale <= 32);
140    scale <<= 3;
141
142    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
143                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
144                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
145}
146
147void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
148                             const SkAlpha aa[])
149{
150    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
151    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
152    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
153    uint32_t    mul = fDistMul;
154    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
155
156    int MAX, mask;
157
158    if (kTargetColor_Mode == fMode) {
159        mask = -1;
160        MAX = 31;
161    } else {
162        mask = 0;
163        MAX = 0;
164    }
165
166    for (int i = 0; i < count; i++) {
167        int d = color_dist16(dst[i], opR, opG, opB);
168        // now reverse d if we need to
169        d = MAX + (d ^ mask) - mask;
170        SkASSERT((unsigned)d <= 31);
171        // convert from 0..31 to 0..32
172        d += d >> 4;
173        d = scale_dist_14(d, mul, sub);
174        SkASSERT(d <= 32);
175
176        if (d > 0) {
177            if (NULL != aa) {
178                d = SkAlphaMul(d, Accurate255To256(*aa++));
179                if (0 == d) {
180                    continue;
181                }
182            }
183            dst[i] = SkBlend3216(src[i], dst[i], d);
184        }
185    }
186}
187
188void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
189                               const SkAlpha aa[])
190{
191    unsigned    opR = SkColorGetR(fOpColor) >> 4;
192    unsigned    opG = SkColorGetG(fOpColor) >> 4;
193    unsigned    opB = SkColorGetB(fOpColor) >> 4;
194    uint32_t    mul = fDistMul;
195    uint32_t    sub = (fDistMul - (1 << 14)) << 4;
196
197    int MAX, mask;
198
199    if (kTargetColor_Mode == fMode) {
200        mask = -1;
201        MAX = 15;
202    } else {
203        mask = 0;
204        MAX = 0;
205    }
206
207    for (int i = 0; i < count; i++) {
208        int d = color_dist4444(dst[i], opR, opG, opB);
209        // now reverse d if we need to
210        d = MAX + (d ^ mask) - mask;
211        SkASSERT((unsigned)d <= 15);
212        // convert from 0..15 to 0..16
213        d += d >> 3;
214        d = scale_dist_14(d, mul, sub);
215        SkASSERT(d <= 16);
216
217        if (d > 0) {
218            if (NULL != aa) {
219                d = SkAlphaMul(d, Accurate255To256(*aa++));
220                if (0 == d) {
221                    continue;
222                }
223            }
224            dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
225        }
226    }
227}
228
229void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
230{
231    // override in subclass
232}
233