blob: fdf179811f322c3394d2b2a1be7296823c2d5b3c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkXfermode.h"
11#include "SkColorPriv.h"
12
13#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
14
15static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha) {
16 unsigned scale = SkAlpha255To256(alpha);
17
18 unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
19 unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
20 unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
21 unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
22
23 return SkPackARGB32(a, r, g, b);
24}
25
reed@android.comfc25abd2009-01-15 14:38:33 +000026#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000027// idea for higher precision blends in xfer procs (and slightly faster)
28// see DstATop as a probable caller
29static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
30 SkASSERT(a <= 255);
31 SkASSERT(b <= 255);
32 SkASSERT(c <= 255);
33 SkASSERT(d <= 255);
34 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
35 unsigned result = (prod + (prod >> 8)) >> 8;
36 SkASSERT(result <= 255);
37 return result;
38}
reed@android.comfc25abd2009-01-15 14:38:33 +000039#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
deanm@chromium.orgda946992009-07-03 12:54:24 +000041static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000042 SkASSERT(a <= 255);
43 SkASSERT(b <= 255);
44 unsigned sum = a + b;
45 if (sum > 255) {
46 sum = 255;
47 }
48 return sum;
49}
50
deanm@chromium.orgda946992009-07-03 12:54:24 +000051static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000052 if (n < 0) {
53 n = 0;
54 } else if (n > 255) {
55 n = 255;
56 }
57 return n;
58}
59
deanm@chromium.orgda946992009-07-03 12:54:24 +000060static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000061 if (prod <= 0) {
62 return 0;
63 } else if (prod >= 255*255) {
64 return 255;
65 } else {
66 return SkDiv255Round(prod);
67 }
68}
69
deanm@chromium.orgda946992009-07-03 12:54:24 +000070static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000071 if (value > max) {
72 value = max;
73 }
74 return value;
75}
76
reed@android.com8a1c16f2008-12-17 15:59:43 +000077///////////////////////////////////////////////////////////////////////////////
78
reed@android.com8a1c16f2008-12-17 15:59:43 +000079// kClear_Mode, //!< [0, 0]
80static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
81 return 0;
82}
83
84// kSrc_Mode, //!< [Sa, Sc]
85static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
86 return src;
87}
88
89// kDst_Mode, //!< [Da, Dc]
90static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
91 return dst;
92}
93
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000094// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000095static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000096#if 0
97 // this is the old, more-correct way, but it doesn't guarantee that dst==255
98 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000100#else
101 // this is slightly faster, but more importantly guarantees that dst==255
102 // will always stay opaque
103 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
104#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
reed@android.com1116fb22009-03-03 20:31:12 +0000107// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000109 // this is the reverse of srcover, just flipping src and dst
110 // see srcover's comment about the 256 for opaqueness guarantees
111 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112}
113
114// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
115static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
116 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
117}
118
119// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
120static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
121 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
122}
123
124// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
125static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
126 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
127}
128
129// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
130static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
131 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
132}
133
134// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
135static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
136 unsigned sa = SkGetPackedA32(src);
137 unsigned da = SkGetPackedA32(dst);
138 unsigned isa = 255 - sa;
139
140 return SkPackARGB32(da,
141 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
142 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
143 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
144 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
145 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
146 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
147}
148
149// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
150static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
151 unsigned sa = SkGetPackedA32(src);
152 unsigned da = SkGetPackedA32(dst);
153 unsigned ida = 255 - da;
154
155 return SkPackARGB32(sa,
156 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
157 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
158 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
159 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
160 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
161 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
162}
163
164// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
165static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
166 unsigned sa = SkGetPackedA32(src);
167 unsigned da = SkGetPackedA32(dst);
168 unsigned isa = 255 - sa;
169 unsigned ida = 255 - da;
170
171 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
172 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
173 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
174 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
175 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
176 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
177 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
178}
179
reed@android.coma0f5d152009-06-22 17:38:10 +0000180///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181
reed@android.coma0f5d152009-06-22 17:38:10 +0000182// kPlus_Mode
183static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000184 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000185 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
186 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
187 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000188 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189}
190
reed@android.coma0f5d152009-06-22 17:38:10 +0000191// kMultiply_Mode
192static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
194 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
195 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
196 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
197 return SkPackARGB32(a, r, g, b);
198}
199
reed@android.coma0f5d152009-06-22 17:38:10 +0000200// kScreen_Mode
201static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 return a + b - SkAlphaMulAlpha(a, b);
203}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000205 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
206 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
207 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
208 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 return SkPackARGB32(a, r, g, b);
210}
211
reed@android.coma0f5d152009-06-22 17:38:10 +0000212// kOverlay_Mode
213static inline int overlay_byte(int sc, int dc, int sa, int da) {
214 int tmp = sc * (255 - da) + dc * (255 - sa);
215 int rc;
216 if (2 * dc <= da) {
217 rc = 2 * sc * dc;
218 } else {
219 rc = sa * da - 2 * (da - dc) * (sa - sc);
220 }
221 return clamp_div255round(rc + tmp);
222}
223static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
224 int sa = SkGetPackedA32(src);
225 int da = SkGetPackedA32(dst);
226 int a = srcover_byte(sa, da);
227 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
228 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
229 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
230 return SkPackARGB32(a, r, g, b);
231}
232
233// kDarken_Mode
234static inline int darken_byte(int sc, int dc, int sa, int da) {
235 int sd = sc * da;
236 int ds = dc * sa;
237 if (sd < ds) {
238 // srcover
239 return sc + dc - SkDiv255Round(ds);
240 } else {
241 // dstover
242 return dc + sc - SkDiv255Round(sd);
243 }
244}
245static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
246 int sa = SkGetPackedA32(src);
247 int da = SkGetPackedA32(dst);
248 int a = srcover_byte(sa, da);
249 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
250 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
251 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
252 return SkPackARGB32(a, r, g, b);
253}
254
255// kLighten_Mode
256static inline int lighten_byte(int sc, int dc, int sa, int da) {
257 int sd = sc * da;
258 int ds = dc * sa;
259 if (sd > ds) {
260 // srcover
261 return sc + dc - SkDiv255Round(ds);
262 } else {
263 // dstover
264 return dc + sc - SkDiv255Round(sd);
265 }
266}
267static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
268 int sa = SkGetPackedA32(src);
269 int da = SkGetPackedA32(dst);
270 int a = srcover_byte(sa, da);
271 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
272 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
273 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
274 return SkPackARGB32(a, r, g, b);
275}
276
277// kColorDodge_Mode
278static inline int colordodge_byte(int sc, int dc, int sa, int da) {
279 int diff = sa - sc;
280 int rc;
281 if (0 == diff) {
282 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
283 rc = SkDiv255Round(rc);
284 } else {
285 int tmp = (dc * sa << 15) / (da * diff);
286 rc = SkDiv255Round(sa * da) * tmp >> 15;
287 // don't clamp here, since we'll do it in our modeproc
288 }
289 return rc;
290}
291static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
292 // added to avoid div-by-zero in colordodge_byte
293 if (0 == dst) {
294 return src;
295 }
296
297 int sa = SkGetPackedA32(src);
298 int da = SkGetPackedA32(dst);
299 int a = srcover_byte(sa, da);
300 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
301 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
302 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
303 r = clamp_max(r, a);
304 g = clamp_max(g, a);
305 b = clamp_max(b, a);
306 return SkPackARGB32(a, r, g, b);
307}
308
309// kColorBurn_Mode
310static inline int colorburn_byte(int sc, int dc, int sa, int da) {
311 int rc;
312 if (dc == da && 0 == sc) {
313 rc = sa * da + dc * (255 - sa);
314 } else if (0 == sc) {
315 return SkAlphaMulAlpha(dc, 255 - sa);
316 } else {
317 int tmp = (sa * (da - dc) * 256) / (sc * da);
318 if (tmp > 256) {
319 tmp = 256;
320 }
321 int tmp2 = sa * da;
322 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
323 }
324 return SkDiv255Round(rc);
325}
326static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
327 // added to avoid div-by-zero in colorburn_byte
328 if (0 == dst) {
329 return src;
330 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000331
reed@android.coma0f5d152009-06-22 17:38:10 +0000332 int sa = SkGetPackedA32(src);
333 int da = SkGetPackedA32(dst);
334 int a = srcover_byte(sa, da);
335 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
336 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
337 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
338 return SkPackARGB32(a, r, g, b);
339}
340
341// kHardLight_Mode
342static inline int hardlight_byte(int sc, int dc, int sa, int da) {
343 int rc;
344 if (2 * sc <= sa) {
345 rc = 2 * sc * dc;
346 } else {
347 rc = sa * da - 2 * (da - dc) * (sa - sc);
348 }
349 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
350}
351static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
352 int sa = SkGetPackedA32(src);
353 int da = SkGetPackedA32(dst);
354 int a = srcover_byte(sa, da);
355 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
356 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
357 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
358 return SkPackARGB32(a, r, g, b);
359}
360
361// returns 255 * sqrt(n/255)
362static U8CPU sqrt_unit_byte(U8CPU n) {
363 return SkSqrtBits(n, 15+4);
364}
365
366// kSoftLight_Mode
367static inline int softlight_byte(int sc, int dc, int sa, int da) {
368 int m = da ? dc * 256 / da : 0;
369 int rc;
370 if (2 * sc <= sa) {
371 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
372 } else if (4 * dc <= da) {
373 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
374 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
375 } else {
376 int tmp = sqrt_unit_byte(m) - m;
377 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
378 }
379 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
380}
381static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
382 int sa = SkGetPackedA32(src);
383 int da = SkGetPackedA32(dst);
384 int a = srcover_byte(sa, da);
385 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
386 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
387 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
388 return SkPackARGB32(a, r, g, b);
389}
390
391// kDifference_Mode
392static inline int difference_byte(int sc, int dc, int sa, int da) {
393 int tmp = SkMin32(sc * da, dc * sa);
394 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
395}
396static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
397 int sa = SkGetPackedA32(src);
398 int da = SkGetPackedA32(dst);
399 int a = srcover_byte(sa, da);
400 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
401 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
402 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
403 return SkPackARGB32(a, r, g, b);
404}
405
406// kExclusion_Mode
407static inline int exclusion_byte(int sc, int dc, int sa, int da) {
408 // this equations is wacky, wait for SVG to confirm it
409 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
410 return clamp_div255round(r);
411}
412static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
413 int sa = SkGetPackedA32(src);
414 int da = SkGetPackedA32(dst);
415 int a = srcover_byte(sa, da);
416 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
417 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
418 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000419 return SkPackARGB32(a, r, g, b);
420}
421
vandebo@chromium.org48543272011-02-08 19:28:07 +0000422struct ProcCoeff {
423 SkXfermodeProc fProc;
424 SkXfermode::Coeff fSC;
425 SkXfermode::Coeff fDC;
426};
427
428#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
429
430static const ProcCoeff gProcCoeffs[] = {
431 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
432 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
433 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
434 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
435 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
436 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
437 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
438 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
439 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
440 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
441 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
442 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
443
reed@google.com521e34e2011-04-12 18:55:21 +0000444 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
445 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000446 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
447 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
448 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
449 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
450 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
451 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
452 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
453 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
454 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
455 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
456};
457
458///////////////////////////////////////////////////////////////////////////////
459
460bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
461 return false;
462}
463
464bool SkXfermode::asMode(Mode* mode) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000465 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000466}
467
468SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
469 // no-op. subclasses should override this
470 return dst;
471}
472
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000473void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
474 const SkPMColor* SK_RESTRICT src, int count,
475 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000476 SkASSERT(dst && src && count >= 0);
477
478 if (NULL == aa) {
479 for (int i = count - 1; i >= 0; --i) {
480 dst[i] = this->xferColor(src[i], dst[i]);
481 }
482 } else {
483 for (int i = count - 1; i >= 0; --i) {
484 unsigned a = aa[i];
485 if (0 != a) {
486 SkPMColor dstC = dst[i];
487 SkPMColor C = this->xferColor(src[i], dstC);
488 if (0xFF != a) {
489 C = SkFourByteInterp(C, dstC, a);
490 }
491 dst[i] = C;
492 }
493 }
494 }
495}
496
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000497void SkXfermode::xfer16(uint16_t* dst,
498 const SkPMColor* SK_RESTRICT src, int count,
499 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000500 SkASSERT(dst && src && count >= 0);
501
502 if (NULL == aa) {
503 for (int i = count - 1; i >= 0; --i) {
504 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
505 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
506 }
507 } else {
508 for (int i = count - 1; i >= 0; --i) {
509 unsigned a = aa[i];
510 if (0 != a) {
511 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
512 SkPMColor C = this->xferColor(src[i], dstC);
513 if (0xFF != a) {
514 C = SkFourByteInterp(C, dstC, a);
515 }
516 dst[i] = SkPixel32ToPixel16_ToU16(C);
517 }
518 }
519 }
520}
521
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000522void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
523 const SkPMColor* SK_RESTRICT src, int count,
524 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000525{
526 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000527
vandebo@chromium.org48543272011-02-08 19:28:07 +0000528 if (NULL == aa) {
529 for (int i = count - 1; i >= 0; --i) {
530 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
531 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
532 }
533 } else {
534 for (int i = count - 1; i >= 0; --i) {
535 unsigned a = aa[i];
536 if (0 != a) {
537 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
538 SkPMColor C = this->xferColor(src[i], dstC);
539 if (0xFF != a) {
540 C = SkFourByteInterp(C, dstC, a);
541 }
542 dst[i] = SkPixel32ToPixel4444(C);
543 }
544 }
545 }
546}
547
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000548void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000549 const SkPMColor src[], int count,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000550 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000551{
552 SkASSERT(dst && src && count >= 0);
553
554 if (NULL == aa) {
555 for (int i = count - 1; i >= 0; --i) {
556 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
557 dst[i] = SkToU8(SkGetPackedA32(res));
558 }
559 } else {
560 for (int i = count - 1; i >= 0; --i) {
561 unsigned a = aa[i];
562 if (0 != a) {
563 SkAlpha dstA = dst[i];
564 unsigned A = SkGetPackedA32(this->xferColor(src[i],
565 (SkPMColor)(dstA << SK_A32_SHIFT)));
566 if (0xFF != a) {
567 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
568 }
569 dst[i] = SkToU8(A);
570 }
571 }
572 }
573}
574
575///////////////////////////////////////////////////////////////////////////////
576
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000577void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
578 const SkPMColor* SK_RESTRICT src, int count,
579 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000580 SkASSERT(dst && src && count >= 0);
581
582 SkXfermodeProc proc = fProc;
583
584 if (NULL != proc) {
585 if (NULL == aa) {
586 for (int i = count - 1; i >= 0; --i) {
587 dst[i] = proc(src[i], dst[i]);
588 }
589 } else {
590 for (int i = count - 1; i >= 0; --i) {
591 unsigned a = aa[i];
592 if (0 != a) {
593 SkPMColor dstC = dst[i];
594 SkPMColor C = proc(src[i], dstC);
595 if (a != 0xFF) {
596 C = SkFourByteInterp(C, dstC, a);
597 }
598 dst[i] = C;
599 }
600 }
601 }
602 }
603}
604
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000605void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
606 const SkPMColor* SK_RESTRICT src, int count,
607 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000608 SkASSERT(dst && src && count >= 0);
609
610 SkXfermodeProc proc = fProc;
611
612 if (NULL != proc) {
613 if (NULL == aa) {
614 for (int i = count - 1; i >= 0; --i) {
615 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
616 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
617 }
618 } else {
619 for (int i = count - 1; i >= 0; --i) {
620 unsigned a = aa[i];
621 if (0 != a) {
622 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
623 SkPMColor C = proc(src[i], dstC);
624 if (0xFF != a) {
625 C = SkFourByteInterp(C, dstC, a);
626 }
627 dst[i] = SkPixel32ToPixel16_ToU16(C);
628 }
629 }
630 }
631 }
632}
633
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000634void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
635 const SkPMColor* SK_RESTRICT src, int count,
636 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000637 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000638
vandebo@chromium.org48543272011-02-08 19:28:07 +0000639 SkXfermodeProc proc = fProc;
640
641 if (NULL != proc) {
642 if (NULL == aa) {
643 for (int i = count - 1; i >= 0; --i) {
644 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
645 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
646 }
647 } else {
648 for (int i = count - 1; i >= 0; --i) {
649 unsigned a = aa[i];
650 if (0 != a) {
651 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
652 SkPMColor C = proc(src[i], dstC);
653 if (0xFF != a) {
654 C = SkFourByteInterp(C, dstC, a);
655 }
656 dst[i] = SkPixel32ToPixel4444(C);
657 }
658 }
659 }
660 }
661}
662
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000663void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
664 const SkPMColor* SK_RESTRICT src, int count,
665 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000666 SkASSERT(dst && src && count >= 0);
667
668 SkXfermodeProc proc = fProc;
669
670 if (NULL != proc) {
671 if (NULL == aa) {
672 for (int i = count - 1; i >= 0; --i) {
673 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
674 dst[i] = SkToU8(SkGetPackedA32(res));
675 }
676 } else {
677 for (int i = count - 1; i >= 0; --i) {
678 unsigned a = aa[i];
679 if (0 != a) {
680 SkAlpha dstA = dst[i];
681 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
682 unsigned A = SkGetPackedA32(res);
683 if (0xFF != a) {
684 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
685 }
686 dst[i] = SkToU8(A);
687 }
688 }
689 }
690 }
691}
692
693SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
694 : SkXfermode(buffer) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000695 // Might be a NULL if the Xfermode is recorded using the CrossProcess flag
vandebo@chromium.org48543272011-02-08 19:28:07 +0000696 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
697}
698
699void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000700 if (buffer.isCrossProcess()) {
701 // function pointer is only valid in the current process. Write a NULL
702 // so it can't be accidentally used
703 buffer.writeFunctionPtr(NULL);
704 } else {
705 buffer.writeFunctionPtr((void*)fProc);
706 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000707}
708
vandebo@chromium.org48543272011-02-08 19:28:07 +0000709///////////////////////////////////////////////////////////////////////////////
710///////////////////////////////////////////////////////////////////////////////
711
712class SkProcCoeffXfermode : public SkProcXfermode {
713public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000714 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
715 : INHERITED(rec.fProc) {
716 fMode = mode;
717 // these may be valid, or may be CANNOT_USE_COEFF
718 fSrcCoeff = rec.fSC;
719 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000720 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000721
722 virtual bool asMode(Mode* mode) {
723 if (mode) {
724 *mode = fMode;
725 }
726 return true;
727 }
728
vandebo@chromium.org48543272011-02-08 19:28:07 +0000729 virtual bool asCoeff(Coeff* sc, Coeff* dc) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000730 if (CANNOT_USE_COEFF == fSrcCoeff) {
731 return false;
732 }
733
vandebo@chromium.org48543272011-02-08 19:28:07 +0000734 if (sc) {
735 *sc = fSrcCoeff;
736 }
737 if (dc) {
738 *dc = fDstCoeff;
739 }
740 return true;
741 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000742
vandebo@chromium.org48543272011-02-08 19:28:07 +0000743 virtual Factory getFactory() { return CreateProc; }
744 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
745 this->INHERITED::flatten(buffer);
reed@google.comc0d4aa22011-04-13 21:12:04 +0000746 buffer.write32(fMode);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000747 }
748
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000749 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
750 return SkNEW_ARGS(SkProcCoeffXfermode, (buffer));
751 }
752
vandebo@chromium.org48543272011-02-08 19:28:07 +0000753protected:
754 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
755 : INHERITED(buffer) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000756 fMode = (SkXfermode::Mode)buffer.readU32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000757
758 const ProcCoeff& rec = gProcCoeffs[fMode];
759 // these may be valid, or may be CANNOT_USE_COEFF
760 fSrcCoeff = rec.fSC;
761 fDstCoeff = rec.fDC;
762 // now update our function-ptr in the super class
763 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000764 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000765
vandebo@chromium.org48543272011-02-08 19:28:07 +0000766private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000767 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000768 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000769
vandebo@chromium.org48543272011-02-08 19:28:07 +0000770
771 typedef SkProcXfermode INHERITED;
772};
773
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774///////////////////////////////////////////////////////////////////////////////
775
776class SkClearXfermode : public SkProcCoeffXfermode {
777public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000778 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779
reed@google.com86ab6c62011-11-28 15:26:14 +0000780 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
781 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
782 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000784 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
785 return SkNEW_ARGS(SkClearXfermode, (buffer));
786 }
787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788private:
789 SkClearXfermode(SkFlattenableReadBuffer& buffer)
790 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000791
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792};
793
reed@google.com86ab6c62011-11-28 15:26:14 +0000794void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
795 const SkPMColor* SK_RESTRICT, int count,
796 const SkAlpha* SK_RESTRICT aa) {
797 SkASSERT(dst && count >= 0);
798
799 if (NULL == aa) {
800 memset(dst, 0, count << 2);
801 } else {
802 for (int i = count - 1; i >= 0; --i) {
803 unsigned a = aa[i];
804 if (0xFF == a) {
805 dst[i] = 0;
806 } else if (a != 0) {
807 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
808 }
809 }
810 }
811}
812void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
813 const SkPMColor* SK_RESTRICT, int count,
814 const SkAlpha* SK_RESTRICT aa) {
815 SkASSERT(dst && count >= 0);
816
817 if (NULL == aa) {
818 memset(dst, 0, count);
819 } else {
820 for (int i = count - 1; i >= 0; --i) {
821 unsigned a = aa[i];
822 if (0xFF == a) {
823 dst[i] = 0;
824 } else if (0 != a) {
825 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
826 }
827 }
828 }
829}
830
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831///////////////////////////////////////////////////////////////////////////////
832
833class SkSrcXfermode : public SkProcCoeffXfermode {
834public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000835 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836
reed@google.com86ab6c62011-11-28 15:26:14 +0000837 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
838 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
839 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000841 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
842 return SkNEW_ARGS(SkSrcXfermode, (buffer));
843 }
844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845private:
846 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
847 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000848
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849};
850
reed@google.com86ab6c62011-11-28 15:26:14 +0000851void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
852 const SkPMColor* SK_RESTRICT src, int count,
853 const SkAlpha* SK_RESTRICT aa) {
854 SkASSERT(dst && src && count >= 0);
855
856 if (NULL == aa) {
857 memcpy(dst, src, count << 2);
858 } else {
859 for (int i = count - 1; i >= 0; --i) {
860 unsigned a = aa[i];
861 if (a == 0xFF) {
862 dst[i] = src[i];
863 } else if (a != 0) {
864 dst[i] = SkFourByteInterp(src[i], dst[i], a);
865 }
866 }
867 }
868}
869
870void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
871 const SkPMColor* SK_RESTRICT src, int count,
872 const SkAlpha* SK_RESTRICT aa) {
873 SkASSERT(dst && src && count >= 0);
874
875 if (NULL == aa) {
876 for (int i = count - 1; i >= 0; --i) {
877 dst[i] = SkToU8(SkGetPackedA32(src[i]));
878 }
879 } else {
880 for (int i = count - 1; i >= 0; --i) {
881 unsigned a = aa[i];
882 if (0 != a) {
883 unsigned srcA = SkGetPackedA32(src[i]);
884 if (a == 0xFF) {
885 dst[i] = SkToU8(srcA);
886 } else {
887 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
888 }
889 }
890 }
891 }
892}
893
894////////////////////////////////////////////////////////////////////////////////////
895
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896class SkDstInXfermode : public SkProcCoeffXfermode {
897public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000898 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000899
reed@google.com86ab6c62011-11-28 15:26:14 +0000900 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
901 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000902
reed@android.com8a1c16f2008-12-17 15:59:43 +0000903 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
904 return SkNEW_ARGS(SkDstInXfermode, (buffer));
905 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000906
907private:
908 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
909
reed@android.com8a1c16f2008-12-17 15:59:43 +0000910 typedef SkProcCoeffXfermode INHERITED;
911};
912
reed@google.com86ab6c62011-11-28 15:26:14 +0000913void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
914 const SkPMColor* SK_RESTRICT src, int count,
915 const SkAlpha* SK_RESTRICT aa) {
916 SkASSERT(dst && src);
917
918 if (count <= 0) {
919 return;
920 }
921 if (NULL != aa) {
922 return this->INHERITED::xfer32(dst, src, count, aa);
923 }
924
925 do {
926 unsigned a = SkGetPackedA32(*src);
927 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
928 dst++;
929 src++;
930 } while (--count != 0);
931}
932
933/////////////////////////////////////////////////////////////////////////////////////////
934
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935class SkDstOutXfermode : public SkProcCoeffXfermode {
936public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000937 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000938
reed@google.com86ab6c62011-11-28 15:26:14 +0000939 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
940 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000941
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
943 return SkNEW_ARGS(SkDstOutXfermode, (buffer));
944 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000945
946private:
947 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
948 : INHERITED(buffer) {}
949
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 typedef SkProcCoeffXfermode INHERITED;
951};
952
reed@google.com86ab6c62011-11-28 15:26:14 +0000953void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
954 const SkPMColor* SK_RESTRICT src, int count,
955 const SkAlpha* SK_RESTRICT aa) {
956 SkASSERT(dst && src);
957
958 if (count <= 0) {
959 return;
960 }
961 if (NULL != aa) {
962 return this->INHERITED::xfer32(dst, src, count, aa);
963 }
964
965 do {
966 unsigned a = SkGetPackedA32(*src);
967 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
968 dst++;
969 src++;
970 } while (--count != 0);
971}
972
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973///////////////////////////////////////////////////////////////////////////////
974
reed@android.coma0f5d152009-06-22 17:38:10 +0000975SkXfermode* SkXfermode::Create(Mode mode) {
976 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
977 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978
reed@google.comc0d4aa22011-04-13 21:12:04 +0000979 const ProcCoeff& rec = gProcCoeffs[mode];
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 switch (mode) {
982 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000983 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000985 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 case kSrcOver_Mode:
987 return NULL;
988 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000989 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000991 return SkNEW_ARGS(SkDstOutXfermode, (rec));
992 default:
993 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 }
995}
996
reed@google.com43c50c82011-04-14 15:50:52 +0000997SkXfermodeProc SkXfermode::GetProc(Mode mode) {
998 SkXfermodeProc proc = NULL;
999 if ((unsigned)mode < kModeCount) {
1000 proc = gProcCoeffs[mode].fProc;
1001 }
1002 return proc;
1003}
1004
1005bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1006 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001007
reed@google.com43c50c82011-04-14 15:50:52 +00001008 if ((unsigned)mode >= (unsigned)kModeCount) {
1009 // illegal mode parameter
1010 return false;
1011 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001012
reed@google.com43c50c82011-04-14 15:50:52 +00001013 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001014
reed@google.com43c50c82011-04-14 15:50:52 +00001015 if (CANNOT_USE_COEFF == rec.fSC) {
1016 return false;
1017 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001018
reed@google.com43c50c82011-04-14 15:50:52 +00001019 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1020 if (src) {
1021 *src = rec.fSC;
1022 }
1023 if (dst) {
1024 *dst = rec.fDC;
1025 }
1026 return true;
1027}
1028
1029bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030 if (NULL == xfer) {
1031 if (mode) {
1032 *mode = kSrcOver_Mode;
1033 }
1034 return true;
1035 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001036 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037}
1038
reed@google.com43c50c82011-04-14 15:50:52 +00001039bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
1040 if (NULL == xfer) {
1041 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 }
reed@google.com43c50c82011-04-14 15:50:52 +00001043 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044}
1045
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001046bool SkXfermode::IsMode(SkXfermode* xfer, Mode mode) {
1047 // if xfer==null then the mode is srcover
1048 Mode m = kSrcOver_Mode;
1049 if (xfer && !xfer->asMode(&m)) {
1050 return false;
1051 }
1052 return mode == m;
1053}
1054
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055///////////////////////////////////////////////////////////////////////////////
1056//////////// 16bit xfermode procs
1057
1058#ifdef SK_DEBUG
1059static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1060static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1061#endif
1062
1063static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1064 SkASSERT(require_255(src));
1065 return SkPixel32ToPixel16(src);
1066}
1067
1068static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1069 return dst;
1070}
1071
1072static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1073 SkASSERT(require_0(src));
1074 return dst;
1075}
1076
1077static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1078 SkASSERT(require_255(src));
1079 return SkPixel32ToPixel16(src);
1080}
1081
1082static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1083 SkASSERT(require_0(src));
1084 return dst;
1085}
1086
1087static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1088 SkASSERT(require_255(src));
1089 return dst;
1090}
1091
1092static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1093 SkASSERT(require_255(src));
1094 return SkPixel32ToPixel16(src);
1095}
1096
1097static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1098 SkASSERT(require_255(src));
1099 return dst;
1100}
1101
1102static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1103 SkASSERT(require_0(src));
1104 return dst;
1105}
1106
1107static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1108 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001109
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 return SkPackRGB16(
1111 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1112 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1113 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1114}
1115
1116static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1117 SkASSERT(require_0(src));
1118 return dst;
1119}
1120
1121static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1122 SkASSERT(require_255(src));
1123 return SkPixel32ToPixel16(src);
1124}
1125
1126static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1127 SkASSERT(require_255(src));
1128 return dst;
1129}
1130
1131/*********
1132 darken and lighten boil down to this.
1133
1134 darken = (1 - Sa) * Dc + min(Sc, Dc)
1135 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1136
1137 if (Sa == 0) these become
1138 darken = Dc + min(0, Dc) = 0
1139 lighten = Dc + max(0, Dc) = Dc
1140
1141 if (Sa == 1) these become
1142 darken = min(Sc, Dc)
1143 lighten = max(Sc, Dc)
1144*/
1145
1146static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1147 SkASSERT(require_0(src));
1148 return 0;
1149}
1150
1151static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1152 SkASSERT(require_255(src));
1153 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1154 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1155 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1156 return SkPackRGB16(r, g, b);
1157}
1158
1159static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1160 SkASSERT(require_0(src));
1161 return dst;
1162}
1163
1164static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1165 SkASSERT(require_255(src));
1166 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1167 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1168 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1169 return SkPackRGB16(r, g, b);
1170}
1171
1172struct Proc16Rec {
1173 SkXfermodeProc16 fProc16_0;
1174 SkXfermodeProc16 fProc16_255;
1175 SkXfermodeProc16 fProc16_General;
1176};
1177
reed@android.coma0f5d152009-06-22 17:38:10 +00001178static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179 { NULL, NULL, NULL }, // CLEAR
1180 { NULL, src_modeproc16_255, NULL },
1181 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1182 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1183 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1184 { NULL, srcin_modeproc16_255, NULL },
1185 { NULL, dstin_modeproc16_255, NULL },
1186 { NULL, NULL, NULL },// SRC_OUT
1187 { dstout_modeproc16_0, NULL, NULL },
1188 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1189 { NULL, dstatop_modeproc16_255, NULL },
1190 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001191
1192 { NULL, NULL, NULL }, // plus
1193 { NULL, NULL, NULL }, // multiply
1194 { NULL, NULL, NULL }, // screen
1195 { NULL, NULL, NULL }, // overlay
1196 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1197 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1198 { NULL, NULL, NULL }, // colordodge
1199 { NULL, NULL, NULL }, // colorburn
1200 { NULL, NULL, NULL }, // hardlight
1201 { NULL, NULL, NULL }, // softlight
1202 { NULL, NULL, NULL }, // difference
1203 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204};
1205
reed@android.coma0f5d152009-06-22 17:38:10 +00001206SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001208 if ((unsigned)mode < kModeCount) {
1209 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 unsigned a = SkColorGetA(srcColor);
1211
1212 if (0 == a) {
1213 proc16 = rec.fProc16_0;
1214 } else if (255 == a) {
1215 proc16 = rec.fProc16_255;
1216 } else {
1217 proc16 = rec.fProc16_General;
1218 }
1219 }
1220 return proc16;
1221}
1222
caryclark@google.comd26147a2011-12-15 14:16:43 +00001223SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1224 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1225 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1226 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1227 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1228 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1229SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END