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