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