1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkAvoidXfermode.h"
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkColorPriv.h"
109ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h"
112c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com#include "SkString.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1353153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comSkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (tolerance > 255) {
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        tolerance = 255;
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fOpColor = opColor;
19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fDistMul = (256 << 14) / (tolerance + 1);
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMode = mode;
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer)
2453153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.com    : INHERITED(buffer) {
259ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fOpColor = buffer.readColor();
269ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fDistMul = buffer.readUInt();
279ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fMode = (Mode)buffer.readUInt();
28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
3053153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comvoid SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->INHERITED::flatten(buffer);
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
339ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeColor(fOpColor);
349ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeUInt(fDistMul);
359ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeUInt(fMode);
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// returns 0..31
3953153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comstatic unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(r <= SK_R16_MASK);
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(g <= SK_G16_MASK);
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(b <= SK_B16_MASK);
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
470713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return SkMax32(dr, SkMax32(dg, db));
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// returns 0..255
5253153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comstatic unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(r <= 0xFF);
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(g <= 0xFF);
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(b <= 0xFF);
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
600713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return SkMax32(dr, SkMax32(dg, db));
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6453153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comstatic int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int tmp = dist * mul - sub;
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int result = (tmp + (1 << 13)) >> 14;
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return result;
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
718911eb015d52befd9ab45357a8aab2c924df8b32reed@android.comstatic inline unsigned Accurate255To256(unsigned x) {
728911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com    return x + (x >> 7);
738911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com}
748911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com
75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
7653153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.com                             const SkAlpha aa[]) const {
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opR = SkColorGetR(fOpColor);
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opG = SkColorGetG(fOpColor);
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opB = SkColorGetB(fOpColor);
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t    mul = fDistMul;
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
820713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int MAX, mask;
840713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (kTargetColor_Mode == fMode) {
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mask = -1;
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        MAX = 255;
88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mask = 0;
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        MAX = 0;
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
920713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int i = 0; i < count; i++) {
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int d = color_dist32(dst[i], opR, opG, opB);
95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // now reverse d if we need to
96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        d = MAX + (d ^ mask) - mask;
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT((unsigned)d <= 255);
988911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com        d = Accurate255To256(d);
990713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        d = scale_dist_14(d, mul, sub);
101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(d <= 256);
1020713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (d > 0) {
104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (NULL != aa) {
1058911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                if (0 == d) {
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    continue;
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
1105929b203d63833c01db8ddc5eb1c68bad4c12af3djsollen@google.com            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
11553153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comstatic inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(scale <= 32);
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    scale <<= 3;
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
12553153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.com                             const SkAlpha aa[]) const {
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t    mul = fDistMul;
1306585d55e80d5a31a2ac7ace5e564c0bc6b3e4d52reed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int MAX, mask;
1330713e24c92ac1a25ce27732f8cf3945180bf3543tomhudson@google.com
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (kTargetColor_Mode == fMode) {
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mask = -1;
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        MAX = 31;
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mask = 0;
139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        MAX = 0;
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int i = 0; i < count; i++) {
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int d = color_dist16(dst[i], opR, opG, opB);
144bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // now reverse d if we need to
145bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        d = MAX + (d ^ mask) - mask;
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT((unsigned)d <= 31);
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // convert from 0..31 to 0..32
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        d += d >> 4;
149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        d = scale_dist_14(d, mul, sub);
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(d <= 32);
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (d > 0) {
153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (NULL != aa) {
1548911eb015d52befd9ab45357a8aab2c924df8b32reed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                if (0 == d) {
156bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    continue;
157bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
158bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
159bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            dst[i] = SkBlend3216(src[i], dst[i], d);
160bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
162bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
163bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
16453153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.comvoid SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
16553153593bb7113904149b46dbc10baaaa8d2bdc5reed@google.com                             const SkAlpha aa[]) const {
166bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // override in subclass
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
1682c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com
1692c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com#ifdef SK_DEVELOPER
1702c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.comvoid SkAvoidXfermode::toString(SkString* str) const {
1712c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com    str->append("SkAvoidXfermode: opColor: ");
1722c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com    str->appendHex(fOpColor);
1732c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com    str->appendf("distMul: %d ", fDistMul);
1742c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com
1752c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com    static const char* gModeStrings[] = { "Avoid", "Target" };
1762c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com
1772c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com    str->appendf("mode: %s", gModeStrings[fMode]);
1782c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com}
1792c1db75f44f4edffc0a50bba2085330ed8254589robertphillips@google.com#endif
180