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