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 "SkReadBuffer.h" 11 #include "SkWriteBuffer.h" 12 #include "SkString.h" 13 14 SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) { 15 if (tolerance > 255) { 16 tolerance = 255; 17 } 18 fTolerance = SkToU8(tolerance); 19 fOpColor = opColor; 20 fDistMul = (256 << 14) / (tolerance + 1); 21 fMode = mode; 22 } 23 24 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 25 SkAvoidXfermode::SkAvoidXfermode(SkReadBuffer& buffer) : INHERITED(buffer) { 26 fOpColor = buffer.readColor(); 27 fDistMul = buffer.readUInt(); 28 fMode = (Mode)buffer.readUInt(); 29 } 30 #endif 31 32 SkFlattenable* SkAvoidXfermode::CreateProc(SkReadBuffer& buffer) { 33 const SkColor color = buffer.readColor(); 34 const unsigned tolerance = buffer.readUInt(); 35 const unsigned mode = buffer.readUInt(); 36 return Create(color, tolerance, (Mode)mode); 37 } 38 39 void SkAvoidXfermode::flatten(SkWriteBuffer& buffer) const { 40 buffer.writeColor(fOpColor); 41 buffer.writeUInt(fTolerance); 42 buffer.writeUInt(fMode); 43 } 44 45 // returns 0..31 46 static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) { 47 SkASSERT(r <= SK_R16_MASK); 48 SkASSERT(g <= SK_G16_MASK); 49 SkASSERT(b <= SK_B16_MASK); 50 51 unsigned dr = SkAbs32(SkGetPackedR16(c) - r); 52 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS); 53 unsigned db = SkAbs32(SkGetPackedB16(c) - b); 54 55 return SkMax32(dr, SkMax32(dg, db)); 56 } 57 58 // returns 0..255 59 static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) { 60 SkASSERT(r <= 0xFF); 61 SkASSERT(g <= 0xFF); 62 SkASSERT(b <= 0xFF); 63 64 unsigned dr = SkAbs32(SkGetPackedR32(c) - r); 65 unsigned dg = SkAbs32(SkGetPackedG32(c) - g); 66 unsigned db = SkAbs32(SkGetPackedB32(c) - b); 67 68 return SkMax32(dr, SkMax32(dg, db)); 69 } 70 71 static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) { 72 int tmp = dist * mul - sub; 73 int result = (tmp + (1 << 13)) >> 14; 74 75 return result; 76 } 77 78 static inline unsigned Accurate255To256(unsigned x) { 79 return x + (x >> 7); 80 } 81 82 void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, 83 const SkAlpha aa[]) const { 84 unsigned opR = SkColorGetR(fOpColor); 85 unsigned opG = SkColorGetG(fOpColor); 86 unsigned opB = SkColorGetB(fOpColor); 87 uint32_t mul = fDistMul; 88 uint32_t sub = (fDistMul - (1 << 14)) << 8; 89 90 int MAX, mask; 91 92 if (kTargetColor_Mode == fMode) { 93 mask = -1; 94 MAX = 255; 95 } else { 96 mask = 0; 97 MAX = 0; 98 } 99 100 for (int i = 0; i < count; i++) { 101 int d = color_dist32(dst[i], opR, opG, opB); 102 // now reverse d if we need to 103 d = MAX + (d ^ mask) - mask; 104 SkASSERT((unsigned)d <= 255); 105 d = Accurate255To256(d); 106 107 d = scale_dist_14(d, mul, sub); 108 SkASSERT(d <= 256); 109 110 if (d > 0) { 111 if (aa) { 112 d = SkAlphaMul(d, Accurate255To256(*aa++)); 113 if (0 == d) { 114 continue; 115 } 116 } 117 dst[i] = SkFourByteInterp256(src[i], dst[i], d); 118 } 119 } 120 } 121 122 static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) { 123 SkASSERT(scale <= 32); 124 scale <<= 3; 125 126 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale), 127 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale), 128 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale)); 129 } 130 131 void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, 132 const SkAlpha aa[]) const { 133 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS); 134 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS); 135 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS); 136 uint32_t mul = fDistMul; 137 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS; 138 139 int MAX, mask; 140 141 if (kTargetColor_Mode == fMode) { 142 mask = -1; 143 MAX = 31; 144 } else { 145 mask = 0; 146 MAX = 0; 147 } 148 149 for (int i = 0; i < count; i++) { 150 int d = color_dist16(dst[i], opR, opG, opB); 151 // now reverse d if we need to 152 d = MAX + (d ^ mask) - mask; 153 SkASSERT((unsigned)d <= 31); 154 // convert from 0..31 to 0..32 155 d += d >> 4; 156 d = scale_dist_14(d, mul, sub); 157 SkASSERT(d <= 32); 158 159 if (d > 0) { 160 if (aa) { 161 d = SkAlphaMul(d, Accurate255To256(*aa++)); 162 if (0 == d) { 163 continue; 164 } 165 } 166 dst[i] = SkBlend3216(src[i], dst[i], d); 167 } 168 } 169 } 170 171 void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, 172 const SkAlpha aa[]) const { 173 // override in subclass 174 } 175 176 #ifndef SK_IGNORE_TO_STRING 177 void SkAvoidXfermode::toString(SkString* str) const { 178 str->append("SkAvoidXfermode: opColor: "); 179 str->appendHex(fOpColor); 180 str->appendf("distMul: %d ", fDistMul); 181 182 static const char* gModeStrings[] = { "Avoid", "Target" }; 183 184 str->appendf("mode: %s", gModeStrings[fMode]); 185 } 186 #endif 187