blob: f39ee747d9f711b2e2b28d7544a6f332fb12101f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkAvoidXfermode.h"
9#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000010#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011
reed@google.com30da7452012-12-17 19:55:24 +000012SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000013 if (tolerance > 255) {
14 tolerance = 255;
15 }
16
17 fOpColor = opColor;
18 fDistMul = (256 << 14) / (tolerance + 1);
19 fMode = mode;
20}
21
22SkAvoidXfermode::SkAvoidXfermode(SkFlattenableReadBuffer& buffer)
reed@google.com30da7452012-12-17 19:55:24 +000023 : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000024 fOpColor = buffer.readColor();
25 fDistMul = buffer.readUInt();
26 fMode = (Mode)buffer.readUInt();
reed@android.com8a1c16f2008-12-17 15:59:43 +000027}
28
reed@google.com30da7452012-12-17 19:55:24 +000029void SkAvoidXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 this->INHERITED::flatten(buffer);
31
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000032 buffer.writeColor(fOpColor);
33 buffer.writeUInt(fDistMul);
34 buffer.writeUInt(fMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000035}
36
reed@android.com8a1c16f2008-12-17 15:59:43 +000037// returns 0..31
reed@google.com30da7452012-12-17 19:55:24 +000038static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 SkASSERT(r <= SK_R16_MASK);
40 SkASSERT(g <= SK_G16_MASK);
41 SkASSERT(b <= SK_B16_MASK);
42
43 unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
44 unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
45 unsigned db = SkAbs32(SkGetPackedB16(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000046
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 return SkMax32(dr, SkMax32(dg, db));
48}
49
50// returns 0..15
reed@google.com30da7452012-12-17 19:55:24 +000051static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 SkASSERT(r <= 0xF);
53 SkASSERT(g <= 0xF);
54 SkASSERT(b <= 0xF);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000055
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 unsigned dr = SkAbs32(SkGetPackedR4444(c) - r);
57 unsigned dg = SkAbs32(SkGetPackedG4444(c) - g);
58 unsigned db = SkAbs32(SkGetPackedB4444(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000059
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 return SkMax32(dr, SkMax32(dg, db));
61}
62
63// returns 0..255
reed@google.com30da7452012-12-17 19:55:24 +000064static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 SkASSERT(r <= 0xFF);
66 SkASSERT(g <= 0xFF);
67 SkASSERT(b <= 0xFF);
68
69 unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
70 unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
71 unsigned db = SkAbs32(SkGetPackedB32(c) - b);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000072
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 return SkMax32(dr, SkMax32(dg, db));
74}
75
reed@google.com30da7452012-12-17 19:55:24 +000076static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 int tmp = dist * mul - sub;
78 int result = (tmp + (1 << 13)) >> 14;
79
80 return result;
81}
82
reed@android.com370eeeb2010-03-12 19:23:27 +000083static inline unsigned Accurate255To256(unsigned x) {
84 return x + (x >> 7);
85}
86
reed@android.com8a1c16f2008-12-17 15:59:43 +000087void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +000088 const SkAlpha aa[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 unsigned opR = SkColorGetR(fOpColor);
90 unsigned opG = SkColorGetG(fOpColor);
91 unsigned opB = SkColorGetB(fOpColor);
92 uint32_t mul = fDistMul;
93 uint32_t sub = (fDistMul - (1 << 14)) << 8;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000096
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 if (kTargetColor_Mode == fMode) {
98 mask = -1;
99 MAX = 255;
100 } else {
101 mask = 0;
102 MAX = 0;
103 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 for (int i = 0; i < count; i++) {
106 int d = color_dist32(dst[i], opR, opG, opB);
107 // now reverse d if we need to
108 d = MAX + (d ^ mask) - mask;
109 SkASSERT((unsigned)d <= 255);
reed@android.com370eeeb2010-03-12 19:23:27 +0000110 d = Accurate255To256(d);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000111
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 d = scale_dist_14(d, mul, sub);
113 SkASSERT(d <= 256);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 if (d > 0) {
116 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000117 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 if (0 == d) {
119 continue;
120 }
121 }
djsollen@google.com8ff1e512012-03-12 14:39:20 +0000122 dst[i] = SkFourByteInterp256(src[i], dst[i], d);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 }
124 }
125}
126
reed@google.com30da7452012-12-17 19:55:24 +0000127static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 SkASSERT(scale <= 32);
129 scale <<= 3;
130
131 return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
132 SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
133 SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
134}
135
136void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000137 const SkAlpha aa[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
139 unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
140 unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
141 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000142 uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143
144 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 if (kTargetColor_Mode == fMode) {
147 mask = -1;
148 MAX = 31;
149 } else {
150 mask = 0;
151 MAX = 0;
152 }
153
154 for (int i = 0; i < count; i++) {
155 int d = color_dist16(dst[i], opR, opG, opB);
156 // now reverse d if we need to
157 d = MAX + (d ^ mask) - mask;
158 SkASSERT((unsigned)d <= 31);
159 // convert from 0..31 to 0..32
160 d += d >> 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 d = scale_dist_14(d, mul, sub);
162 SkASSERT(d <= 32);
163
164 if (d > 0) {
165 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000166 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 if (0 == d) {
168 continue;
169 }
170 }
171 dst[i] = SkBlend3216(src[i], dst[i], d);
172 }
173 }
174}
175
176void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000177 const SkAlpha aa[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 unsigned opR = SkColorGetR(fOpColor) >> 4;
179 unsigned opG = SkColorGetG(fOpColor) >> 4;
180 unsigned opB = SkColorGetB(fOpColor) >> 4;
181 uint32_t mul = fDistMul;
reed@android.com0db5a7f2009-11-09 16:01:36 +0000182 uint32_t sub = (fDistMul - (1 << 14)) << 4;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000183
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 int MAX, mask;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000185
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 if (kTargetColor_Mode == fMode) {
187 mask = -1;
188 MAX = 15;
189 } else {
190 mask = 0;
191 MAX = 0;
192 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000193
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 for (int i = 0; i < count; i++) {
195 int d = color_dist4444(dst[i], opR, opG, opB);
196 // now reverse d if we need to
197 d = MAX + (d ^ mask) - mask;
198 SkASSERT((unsigned)d <= 15);
reed@android.com0db5a7f2009-11-09 16:01:36 +0000199 // convert from 0..15 to 0..16
200 d += d >> 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 d = scale_dist_14(d, mul, sub);
202 SkASSERT(d <= 16);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 if (d > 0) {
205 if (NULL != aa) {
reed@android.com370eeeb2010-03-12 19:23:27 +0000206 d = SkAlphaMul(d, Accurate255To256(*aa++));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 if (0 == d) {
208 continue;
209 }
210 }
211 dst[i] = SkBlend4444(SkPixel32ToPixel4444(src[i]), dst[i], d);
212 }
213 }
214}
215
reed@google.com30da7452012-12-17 19:55:24 +0000216void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
217 const SkAlpha aa[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 // override in subclass
219}