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    }
189fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    fTolerance = SkToU8(tolerance);
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpColor = opColor;
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDistMul = (256 << 14) / (tolerance + 1);
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMode = mode;
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
249fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
259fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkAvoidXfermode::SkAvoidXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
26c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fOpColor = buffer.readColor();
27c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fDistMul = buffer.readUInt();
28c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fMode = (Mode)buffer.readUInt();
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
309fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
329fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkAvoidXfermode::CreateProc(SkReadBuffer& buffer) {
339fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkColor color = buffer.readColor();
349fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const unsigned tolerance = buffer.readUInt();
359fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const unsigned mode = buffer.readUInt();
369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    return Create(color, tolerance, (Mode)mode);
379fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedvoid SkAvoidXfermode::flatten(SkWriteBuffer& buffer) const {
40c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeColor(fOpColor);
419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.writeUInt(fTolerance);
42c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fMode);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// returns 0..31
4630da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(r <= SK_R16_MASK);
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(g <= SK_G16_MASK);
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b <= SK_B16_MASK);
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
541447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMax32(dr, SkMax32(dg, db));
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// returns 0..255
5930da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(r <= 0xFF);
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(g <= 0xFF);
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b <= 0xFF);
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
671447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMax32(dr, SkMax32(dg, db));
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7130da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int tmp = dist * mul - sub;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int result = (tmp + (1 << 13)) >> 14;
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return result;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
78370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.comstatic inline unsigned Accurate255To256(unsigned x) {
79370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com    return x + (x >> 7);
80370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com}
81370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
8330da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opR = SkColorGetR(fOpColor);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opG = SkColorGetG(fOpColor);
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opB = SkColorGetB(fOpColor);
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    mul = fDistMul;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
891447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int MAX, mask;
911447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (kTargetColor_Mode == fMode) {
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = -1;
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 255;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = 0;
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 0;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
991447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < count; i++) {
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int d = color_dist32(dst[i], opR, opG, opB);
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now reverse d if we need to
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = MAX + (d ^ mask) - mask;
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)d <= 255);
105370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com        d = Accurate255To256(d);
1061447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = scale_dist_14(d, mul, sub);
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= 256);
1091447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (d > 0) {
11149f085dddff10473b6ebf832a974288300224e60bsalomon            if (aa) {
112370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (0 == d) {
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    continue;
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1178ff1e51c5afee90943c5a493be29343b280aaf1ddjsollen@google.com            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12230da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comstatic inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(scale <= 32);
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scale <<= 3;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
13230da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    mul = fDistMul;
1370db5a7fae596e4914250554402e4874c33fdf0d4reed@android.com    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int MAX, mask;
1401447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (kTargetColor_Mode == fMode) {
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = -1;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 31;
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mask = 0;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MAX = 0;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < count; i++) {
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int d = color_dist16(dst[i], opR, opG, opB);
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now reverse d if we need to
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = MAX + (d ^ mask) - mask;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)d <= 31);
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // convert from 0..31 to 0..32
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d += d >> 4;
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        d = scale_dist_14(d, mul, sub);
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= 32);
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (d > 0) {
16049f085dddff10473b6ebf832a974288300224e60bsalomon            if (aa) {
161370eeeb03291db7e93d98d437f39fe8053b8c6fdreed@android.com                d = SkAlphaMul(d, Accurate255To256(*aa++));
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (0 == d) {
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    continue;
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst[i] = SkBlend3216(src[i], dst[i], d);
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17130da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.comvoid SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
17230da745bbf67a0ee0f305ca7bbdb685cc8a9e686reed@google.com                             const SkAlpha aa[]) const {
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // override in subclass
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
175b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
1760f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
177b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.comvoid SkAvoidXfermode::toString(SkString* str) const {
178b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->append("SkAvoidXfermode: opColor: ");
179b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendHex(fOpColor);
180b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendf("distMul: %d ", fDistMul);
181b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
182b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    static const char* gModeStrings[] = { "Avoid", "Target" };
183b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com
184b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com    str->appendf("mode: %s", gModeStrings[fMode]);
185b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com}
186b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6robertphillips@google.com#endif
187