1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkAvoidXfermode.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
108b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
12b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com#include "SkString.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1430da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comSkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (tolerance > 255) {
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tolerance = 255;
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpColor = opColor;
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDistMul = (256 << 14) / (tolerance + 1);
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMode = mode;
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkAvoidXfermode::SkAvoidXfermode(SkReadBuffer& buffer)
2530da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com    : INHERITED(buffer) {
26c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fOpColor = buffer.readColor();
27c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fDistMul = buffer.readUInt();
28c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fMode = (Mode)buffer.readUInt();
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkAvoidXfermode::flatten(SkWriteBuffer& buffer) const {
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->INHERITED::flatten(buffer);
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
34c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeColor(fOpColor);
35c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fDistMul);
36c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fMode);
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// returns 0..31
4030da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(r <= SK_R16_MASK);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(g <= SK_G16_MASK);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b <= SK_B16_MASK);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
481447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMax32(dr, SkMax32(dg, db));
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// returns 0..255
5330da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(r <= 0xFF);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(g <= 0xFF);
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b <= 0xFF);
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
611447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMax32(dr, SkMax32(dg, db));
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6530da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int tmp = dist * mul - sub;
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int result = (tmp + (1 << 13)) >> 14;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return result;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
72370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.comstatic inline unsigned Accurate255To256(unsigned x) {
73370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com    return x + (x >> 7);
74370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com}
75370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
7730da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opR = SkColorGetR(fOpColor);
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opG = SkColorGetG(fOpColor);
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opB = SkColorGetB(fOpColor);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    mul = fDistMul;
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
831447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int MAX, mask;
851447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (kTargetColor_Mode == fMode) {
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = -1;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 255;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = 0;
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 0;
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
931447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < count; i++) {
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int d = color_dist32(dst[i], opR, opG, opB);
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now reverse d if we need to
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = MAX + (d ^ mask) - mask;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)d <= 255);
99370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com        d = Accurate255To256(d);
1001447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = scale_dist_14(d, mul, sub);
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= 256);
1031447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (d > 0) {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (NULL != aa) {
106370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (0 == d) {
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    continue;
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1118ff1e51c5afee90943c5a493be29343b280aaf1ddjsollen@google.com            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11630da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(scale <= 32);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scale <<= 3;
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
12630da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    mul = fDistMul;
1310db5a7fae596e4914250554402e4874c33fdf0d4reed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int MAX, mask;
1341447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (kTargetColor_Mode == fMode) {
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = -1;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 31;
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = 0;
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 0;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < count; i++) {
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int d = color_dist16(dst[i], opR, opG, opB);
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now reverse d if we need to
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = MAX + (d ^ mask) - mask;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)d <= 31);
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // convert from 0..31 to 0..32
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d += d >> 4;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = scale_dist_14(d, mul, sub);
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= 32);
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (d > 0) {
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (NULL != aa) {
155370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (0 == d) {
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    continue;
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst[i] = SkBlend3216(src[i], dst[i], d);
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16530da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comvoid SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
16630da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // override in subclass
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
169b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
1700f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
171b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.comvoid SkAvoidXfermode::toString(SkString* str) const {
172b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->append("SkAvoidXfermode: opColor: ");
173b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendHex(fOpColor);
174b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendf("distMul: %d ", fDistMul);
175b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
176b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    static const char* gModeStrings[] = { "Avoid", "Target" };
177b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
178b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendf("mode: %s", gModeStrings[fMode]);
179b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com}
180b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com#endif
181