SkAvoidXfermode.cpp revision b83b6b4f7690fe929d8d6b1a3d2b7ed562b95ba6
1/* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkAvoidXfermode.h" 9#include "SkColorPriv.h" 10#include "SkFlattenableBuffers.h" 11#include "SkString.h" 12 13SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) { 14 if (tolerance > 255) { 15 tolerance = 255; 16 } 17 18 fOpColor = opColor; 19 fDistMul = (256 << 14) / (tolerance + 1); 20 fMode = mode; 21} 22 23SkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer) 24 : INHERITED(buffer) { 25 fOpColor = buffer.readColor(); 26 fDistMul = buffer.readUInt(); 27 fMode = (Mode)buffer.readUInt(); 28} 29 30void SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer) const { 31 this->INHERITED::flatten(buffer); 32 33 buffer.writeColor(fOpColor); 34 buffer.writeUInt(fDistMul); 35 buffer.writeUInt(fMode); 36} 37 38// returns 0..31 39static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) { 40 SkASSERT(r <= SK_R16_MASK); 41 SkASSERT(g <= SK_G16_MASK); 42 SkASSERT(b <= SK_B16_MASK); 43 44 unsigned dr = SkAbs32(SkGetPackedR16(c) - r); 45 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS); 46 unsigned db = SkAbs32(SkGetPackedB16(c) - b); 47 48 return SkMax32(dr, SkMax32(dg, db)); 49} 50 51// returns 0..15 52static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b) { 53 SkASSERT(r <= 0xF); 54 SkASSERT(g <= 0xF); 55 SkASSERT(b <= 0xF); 56 57 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r); 58 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g); 59 unsigned db = SkAbs32(SkGetPackedB4444(c) - b); 60 61 return SkMax32(dr, SkMax32(dg, db)); 62} 63 64// returns 0..255 65static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) { 66 SkASSERT(r <= 0xFF); 67 SkASSERT(g <= 0xFF); 68 SkASSERT(b <= 0xFF); 69 70 unsigned dr = SkAbs32(SkGetPackedR32(c) - r); 71 unsigned dg = SkAbs32(SkGetPackedG32(c) - g); 72 unsigned db = SkAbs32(SkGetPackedB32(c) - b); 73 74 return SkMax32(dr, SkMax32(dg, db)); 75} 76 77static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) { 78 int tmp = dist * mul - sub; 79 int result = (tmp + (1 << 13)) >> 14; 80 81 return result; 82} 83 84static inline unsigned Accurate255To256(unsigned x) { 85 return x + (x >> 7); 86} 87 88void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, 89 const SkAlpha aa[]) const { 90 unsigned opR = SkColorGetR(fOpColor); 91 unsigned opG = SkColorGetG(fOpColor); 92 unsigned opB = SkColorGetB(fOpColor); 93 uint32_t mul = fDistMul; 94 uint32_t sub = (fDistMul - (1 << 14)) << 8; 95 96 int MAX, mask; 97 98 if (kTargetColor_Mode == fMode) { 99 mask = -1; 100 MAX = 255; 101 } else { 102 mask = 0; 103 MAX = 0; 104 } 105 106 for (int i = 0; i < count; i++) { 107 int d = color_dist32(dst[i], opR, opG, opB); 108 // now reverse d if we need to 109 d = MAX + (d ^ mask) - mask; 110 SkASSERT((unsigned)d <= 255); 111 d = Accurate255To256(d); 112 113 d = scale_dist_14(d, mul, sub); 114 SkASSERT(d <= 256); 115 116 if (d > 0) { 117 if (NULL != aa) { 118 d = SkAlphaMul(d, Accurate255To256(*aa++)); 119 if (0 == d) { 120 continue; 121 } 122 } 123 dst[i] = SkFourByteInterp256(src[i], dst[i], d); 124 } 125 } 126} 127 128static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) { 129 SkASSERT(scale <= 32); 130 scale <<= 3; 131 132 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale), 133 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale), 134 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale)); 135} 136 137void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, 138 const SkAlpha aa[]) const { 139 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS); 140 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS); 141 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS); 142 uint32_t mul = fDistMul; 143 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS; 144 145 int MAX, mask; 146 147 if (kTargetColor_Mode == fMode) { 148 mask = -1; 149 MAX = 31; 150 } else { 151 mask = 0; 152 MAX = 0; 153 } 154 155 for (int i = 0; i < count; i++) { 156 int d = color_dist16(dst[i], opR, opG, opB); 157 // now reverse d if we need to 158 d = MAX + (d ^ mask) - mask; 159 SkASSERT((unsigned)d <= 31); 160 // convert from 0..31 to 0..32 161 d += d >> 4; 162 d = scale_dist_14(d, mul, sub); 163 SkASSERT(d <= 32); 164 165 if (d > 0) { 166 if (NULL != aa) { 167 d = SkAlphaMul(d, Accurate255To256(*aa++)); 168 if (0 == d) { 169 continue; 170 } 171 } 172 dst[i] = SkBlend3216(src[i], dst[i], d); 173 } 174 } 175} 176 177void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count, 178 const SkAlpha aa[]) const { 179 unsigned opR = SkColorGetR(fOpColor) >> 4; 180 unsigned opG = SkColorGetG(fOpColor) >> 4; 181 unsigned opB = SkColorGetB(fOpColor) >> 4; 182 uint32_t mul = fDistMul; 183 uint32_t sub = (fDistMul - (1 << 14)) << 4; 184 185 int MAX, mask; 186 187 if (kTargetColor_Mode == fMode) { 188 mask = -1; 189 MAX = 15; 190 } else { 191 mask = 0; 192 MAX = 0; 193 } 194 195 for (int i = 0; i < count; i++) { 196 int d = color_dist4444(dst[i], opR, opG, opB); 197 // now reverse d if we need to 198 d = MAX + (d ^ mask) - mask; 199 SkASSERT((unsigned)d <= 15); 200 // convert from 0..15 to 0..16 201 d += d >> 3; 202 d = scale_dist_14(d, mul, sub); 203 SkASSERT(d <= 16); 204 205 if (d > 0) { 206 if (NULL != aa) { 207 d = SkAlphaMul(d, Accurate255To256(*aa++)); 208 if (0 == d) { 209 continue; 210 } 211 } 212 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d); 213 } 214 } 215} 216 217void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, 218 const SkAlpha aa[]) const { 219 // override in subclass 220} 221 222#ifdef SK_DEVELOPER 223void SkAvoidXfermode::toString(SkString* str) const { 224 str->append("SkAvoidXfermode: opColor: "); 225 str->appendHex(fOpColor); 226 str->appendf("distMul: %d ", fDistMul); 227 228 static const char* gModeStrings[] = { "Avoid", "Target" }; 229 230 str->appendf("mode: %s", gModeStrings[fMode]); 231} 232#endif 233