blob: 8c62bb7ad43cec4365aa7932268267cdbe0a4ee2 [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkFlattenableBuffers.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000013#include "SkMathPriv.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000014#include "SkString.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000016SK_DEFINE_INST_COUNT(SkXfermode)
17
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
19
reed@android.comfc25abd2009-01-15 14:38:33 +000020#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000021// idea for higher precision blends in xfer procs (and slightly faster)
22// see DstATop as a probable caller
23static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
24 SkASSERT(a <= 255);
25 SkASSERT(b <= 255);
26 SkASSERT(c <= 255);
27 SkASSERT(d <= 255);
28 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
29 unsigned result = (prod + (prod >> 8)) >> 8;
30 SkASSERT(result <= 255);
31 return result;
32}
reed@android.comfc25abd2009-01-15 14:38:33 +000033#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
deanm@chromium.orgda946992009-07-03 12:54:24 +000035static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000036 SkASSERT(a <= 255);
37 SkASSERT(b <= 255);
38 unsigned sum = a + b;
39 if (sum > 255) {
40 sum = 255;
41 }
42 return sum;
43}
44
deanm@chromium.orgda946992009-07-03 12:54:24 +000045static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000046 if (n < 0) {
47 n = 0;
48 } else if (n > 255) {
49 n = 255;
50 }
51 return n;
52}
53
deanm@chromium.orgda946992009-07-03 12:54:24 +000054static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000055 if (prod <= 0) {
56 return 0;
57 } else if (prod >= 255*255) {
58 return 255;
59 } else {
60 return SkDiv255Round(prod);
61 }
62}
63
deanm@chromium.orgda946992009-07-03 12:54:24 +000064static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000065 if (value > max) {
66 value = max;
67 }
68 return value;
69}
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071///////////////////////////////////////////////////////////////////////////////
72
reed@android.com8a1c16f2008-12-17 15:59:43 +000073// kClear_Mode, //!< [0, 0]
74static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
75 return 0;
76}
77
78// kSrc_Mode, //!< [Sa, Sc]
79static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
80 return src;
81}
82
83// kDst_Mode, //!< [Da, Dc]
84static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
85 return dst;
86}
87
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000088// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000089static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000090#if 0
91 // this is the old, more-correct way, but it doesn't guarantee that dst==255
92 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000094#else
95 // this is slightly faster, but more importantly guarantees that dst==255
96 // will always stay opaque
97 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
98#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000099}
100
reed@android.com1116fb22009-03-03 20:31:12 +0000101// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000103 // this is the reverse of srcover, just flipping src and dst
104 // see srcover's comment about the 256 for opaqueness guarantees
105 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
107
108// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
109static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
110 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
111}
112
113// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
114static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
115 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
116}
117
118// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
119static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
120 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
121}
122
123// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
124static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
125 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
126}
127
128// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
129static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
130 unsigned sa = SkGetPackedA32(src);
131 unsigned da = SkGetPackedA32(dst);
132 unsigned isa = 255 - sa;
133
134 return SkPackARGB32(da,
135 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
136 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
137 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
138 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
139 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
140 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
141}
142
143// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
144static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
145 unsigned sa = SkGetPackedA32(src);
146 unsigned da = SkGetPackedA32(dst);
147 unsigned ida = 255 - da;
148
149 return SkPackARGB32(sa,
150 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
151 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
152 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
153 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
154 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
155 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
156}
157
158// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
159static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
160 unsigned sa = SkGetPackedA32(src);
161 unsigned da = SkGetPackedA32(dst);
162 unsigned isa = 255 - sa;
163 unsigned ida = 255 - da;
164
165 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
166 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
167 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
168 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
169 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
170 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
171 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
172}
173
reed@android.coma0f5d152009-06-22 17:38:10 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
reed@android.coma0f5d152009-06-22 17:38:10 +0000176// kPlus_Mode
177static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000178 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000179 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
180 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
181 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000182 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
reed@android.coma0f5d152009-06-22 17:38:10 +0000185// kMultiply_Mode
186static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
188 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
189 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
190 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
191 return SkPackARGB32(a, r, g, b);
192}
193
reed@android.coma0f5d152009-06-22 17:38:10 +0000194// kScreen_Mode
195static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 return a + b - SkAlphaMulAlpha(a, b);
197}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000199 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
200 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
201 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
202 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 return SkPackARGB32(a, r, g, b);
204}
205
reed@android.coma0f5d152009-06-22 17:38:10 +0000206// kOverlay_Mode
207static inline int overlay_byte(int sc, int dc, int sa, int da) {
208 int tmp = sc * (255 - da) + dc * (255 - sa);
209 int rc;
210 if (2 * dc <= da) {
211 rc = 2 * sc * dc;
212 } else {
213 rc = sa * da - 2 * (da - dc) * (sa - sc);
214 }
215 return clamp_div255round(rc + tmp);
216}
217static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
218 int sa = SkGetPackedA32(src);
219 int da = SkGetPackedA32(dst);
220 int a = srcover_byte(sa, da);
221 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
222 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
223 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
224 return SkPackARGB32(a, r, g, b);
225}
226
227// kDarken_Mode
228static inline int darken_byte(int sc, int dc, int sa, int da) {
229 int sd = sc * da;
230 int ds = dc * sa;
231 if (sd < ds) {
232 // srcover
233 return sc + dc - SkDiv255Round(ds);
234 } else {
235 // dstover
236 return dc + sc - SkDiv255Round(sd);
237 }
238}
239static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
240 int sa = SkGetPackedA32(src);
241 int da = SkGetPackedA32(dst);
242 int a = srcover_byte(sa, da);
243 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
244 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
245 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
246 return SkPackARGB32(a, r, g, b);
247}
248
249// kLighten_Mode
250static inline int lighten_byte(int sc, int dc, int sa, int da) {
251 int sd = sc * da;
252 int ds = dc * sa;
253 if (sd > ds) {
254 // srcover
255 return sc + dc - SkDiv255Round(ds);
256 } else {
257 // dstover
258 return dc + sc - SkDiv255Round(sd);
259 }
260}
261static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
262 int sa = SkGetPackedA32(src);
263 int da = SkGetPackedA32(dst);
264 int a = srcover_byte(sa, da);
265 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
266 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
267 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
268 return SkPackARGB32(a, r, g, b);
269}
270
271// kColorDodge_Mode
272static inline int colordodge_byte(int sc, int dc, int sa, int da) {
273 int diff = sa - sc;
274 int rc;
275 if (0 == diff) {
276 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
277 rc = SkDiv255Round(rc);
278 } else {
279 int tmp = (dc * sa << 15) / (da * diff);
280 rc = SkDiv255Round(sa * da) * tmp >> 15;
281 // don't clamp here, since we'll do it in our modeproc
282 }
283 return rc;
284}
285static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
286 // added to avoid div-by-zero in colordodge_byte
287 if (0 == dst) {
288 return src;
289 }
290
291 int sa = SkGetPackedA32(src);
292 int da = SkGetPackedA32(dst);
293 int a = srcover_byte(sa, da);
294 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
295 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
296 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
297 r = clamp_max(r, a);
298 g = clamp_max(g, a);
299 b = clamp_max(b, a);
300 return SkPackARGB32(a, r, g, b);
301}
302
303// kColorBurn_Mode
304static inline int colorburn_byte(int sc, int dc, int sa, int da) {
305 int rc;
306 if (dc == da && 0 == sc) {
307 rc = sa * da + dc * (255 - sa);
308 } else if (0 == sc) {
309 return SkAlphaMulAlpha(dc, 255 - sa);
310 } else {
311 int tmp = (sa * (da - dc) * 256) / (sc * da);
312 if (tmp > 256) {
313 tmp = 256;
314 }
315 int tmp2 = sa * da;
316 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
317 }
318 return SkDiv255Round(rc);
319}
320static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
321 // added to avoid div-by-zero in colorburn_byte
322 if (0 == dst) {
323 return src;
324 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000325
reed@android.coma0f5d152009-06-22 17:38:10 +0000326 int sa = SkGetPackedA32(src);
327 int da = SkGetPackedA32(dst);
328 int a = srcover_byte(sa, da);
329 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
330 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
331 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
332 return SkPackARGB32(a, r, g, b);
333}
334
335// kHardLight_Mode
336static inline int hardlight_byte(int sc, int dc, int sa, int da) {
337 int rc;
338 if (2 * sc <= sa) {
339 rc = 2 * sc * dc;
340 } else {
341 rc = sa * da - 2 * (da - dc) * (sa - sc);
342 }
343 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
344}
345static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
346 int sa = SkGetPackedA32(src);
347 int da = SkGetPackedA32(dst);
348 int a = srcover_byte(sa, da);
349 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
350 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
351 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
352 return SkPackARGB32(a, r, g, b);
353}
354
355// returns 255 * sqrt(n/255)
356static U8CPU sqrt_unit_byte(U8CPU n) {
357 return SkSqrtBits(n, 15+4);
358}
359
360// kSoftLight_Mode
361static inline int softlight_byte(int sc, int dc, int sa, int da) {
362 int m = da ? dc * 256 / da : 0;
363 int rc;
364 if (2 * sc <= sa) {
365 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
366 } else if (4 * dc <= da) {
367 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
368 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
369 } else {
370 int tmp = sqrt_unit_byte(m) - m;
371 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
372 }
373 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
374}
375static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
376 int sa = SkGetPackedA32(src);
377 int da = SkGetPackedA32(dst);
378 int a = srcover_byte(sa, da);
379 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
380 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
381 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
382 return SkPackARGB32(a, r, g, b);
383}
384
385// kDifference_Mode
386static inline int difference_byte(int sc, int dc, int sa, int da) {
387 int tmp = SkMin32(sc * da, dc * sa);
388 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
389}
390static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
391 int sa = SkGetPackedA32(src);
392 int da = SkGetPackedA32(dst);
393 int a = srcover_byte(sa, da);
394 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
395 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
396 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
397 return SkPackARGB32(a, r, g, b);
398}
399
400// kExclusion_Mode
401static inline int exclusion_byte(int sc, int dc, int sa, int da) {
402 // this equations is wacky, wait for SVG to confirm it
403 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
404 return clamp_div255round(r);
405}
406static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
407 int sa = SkGetPackedA32(src);
408 int da = SkGetPackedA32(dst);
409 int a = srcover_byte(sa, da);
410 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
411 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
412 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000413 return SkPackARGB32(a, r, g, b);
414}
415
vandebo@chromium.org48543272011-02-08 19:28:07 +0000416struct ProcCoeff {
417 SkXfermodeProc fProc;
418 SkXfermode::Coeff fSC;
419 SkXfermode::Coeff fDC;
420};
421
422#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
423
424static const ProcCoeff gProcCoeffs[] = {
425 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
426 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
427 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
428 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
429 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
430 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
431 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
432 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
433 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
434 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
435 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
436 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
437
reed@google.com521e34e2011-04-12 18:55:21 +0000438 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
439 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000440 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
441 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
442 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
443 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
444 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
445 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
446 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
447 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
448 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
449 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
450};
451
452///////////////////////////////////////////////////////////////////////////////
453
reed@google.com30da7452012-12-17 19:55:24 +0000454bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000455 return false;
456}
457
reed@google.com30da7452012-12-17 19:55:24 +0000458bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000459 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000460}
461
reed@google.com30da7452012-12-17 19:55:24 +0000462SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000463 // no-op. subclasses should override this
464 return dst;
465}
466
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000467void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
468 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000469 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000470 SkASSERT(dst && src && count >= 0);
471
472 if (NULL == aa) {
473 for (int i = count - 1; i >= 0; --i) {
474 dst[i] = this->xferColor(src[i], dst[i]);
475 }
476 } else {
477 for (int i = count - 1; i >= 0; --i) {
478 unsigned a = aa[i];
479 if (0 != a) {
480 SkPMColor dstC = dst[i];
481 SkPMColor C = this->xferColor(src[i], dstC);
482 if (0xFF != a) {
483 C = SkFourByteInterp(C, dstC, a);
484 }
485 dst[i] = C;
486 }
487 }
488 }
489}
490
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000491void SkXfermode::xfer16(uint16_t* dst,
492 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000493 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000494 SkASSERT(dst && src && count >= 0);
495
496 if (NULL == aa) {
497 for (int i = count - 1; i >= 0; --i) {
498 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
499 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
500 }
501 } else {
502 for (int i = count - 1; i >= 0; --i) {
503 unsigned a = aa[i];
504 if (0 != a) {
505 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
506 SkPMColor C = this->xferColor(src[i], dstC);
507 if (0xFF != a) {
508 C = SkFourByteInterp(C, dstC, a);
509 }
510 dst[i] = SkPixel32ToPixel16_ToU16(C);
511 }
512 }
513 }
514}
515
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000516void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
517 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000518 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000519 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000520
vandebo@chromium.org48543272011-02-08 19:28:07 +0000521 if (NULL == aa) {
522 for (int i = count - 1; i >= 0; --i) {
523 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
524 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
525 }
526 } else {
527 for (int i = count - 1; i >= 0; --i) {
528 unsigned a = aa[i];
529 if (0 != a) {
530 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
531 SkPMColor C = this->xferColor(src[i], dstC);
532 if (0xFF != a) {
533 C = SkFourByteInterp(C, dstC, a);
534 }
535 dst[i] = SkPixel32ToPixel4444(C);
536 }
537 }
538 }
539}
540
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000541void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000542 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000543 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000544 SkASSERT(dst && src && count >= 0);
545
546 if (NULL == aa) {
547 for (int i = count - 1; i >= 0; --i) {
548 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
549 dst[i] = SkToU8(SkGetPackedA32(res));
550 }
551 } else {
552 for (int i = count - 1; i >= 0; --i) {
553 unsigned a = aa[i];
554 if (0 != a) {
555 SkAlpha dstA = dst[i];
556 unsigned A = SkGetPackedA32(this->xferColor(src[i],
557 (SkPMColor)(dstA << SK_A32_SHIFT)));
558 if (0xFF != a) {
559 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
560 }
561 dst[i] = SkToU8(A);
562 }
563 }
564 }
565}
566
567///////////////////////////////////////////////////////////////////////////////
568
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000569void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
570 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000571 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000572 SkASSERT(dst && src && count >= 0);
573
574 SkXfermodeProc proc = fProc;
575
576 if (NULL != proc) {
577 if (NULL == aa) {
578 for (int i = count - 1; i >= 0; --i) {
579 dst[i] = proc(src[i], dst[i]);
580 }
581 } else {
582 for (int i = count - 1; i >= 0; --i) {
583 unsigned a = aa[i];
584 if (0 != a) {
585 SkPMColor dstC = dst[i];
586 SkPMColor C = proc(src[i], dstC);
587 if (a != 0xFF) {
588 C = SkFourByteInterp(C, dstC, a);
589 }
590 dst[i] = C;
591 }
592 }
593 }
594 }
595}
596
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000597void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
598 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000599 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000600 SkASSERT(dst && src && count >= 0);
601
602 SkXfermodeProc proc = fProc;
603
604 if (NULL != proc) {
605 if (NULL == aa) {
606 for (int i = count - 1; i >= 0; --i) {
607 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
608 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
609 }
610 } else {
611 for (int i = count - 1; i >= 0; --i) {
612 unsigned a = aa[i];
613 if (0 != a) {
614 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
615 SkPMColor C = proc(src[i], dstC);
616 if (0xFF != a) {
617 C = SkFourByteInterp(C, dstC, a);
618 }
619 dst[i] = SkPixel32ToPixel16_ToU16(C);
620 }
621 }
622 }
623 }
624}
625
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000626void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
627 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000628 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000629 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000630
vandebo@chromium.org48543272011-02-08 19:28:07 +0000631 SkXfermodeProc proc = fProc;
632
633 if (NULL != proc) {
634 if (NULL == aa) {
635 for (int i = count - 1; i >= 0; --i) {
636 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
637 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
638 }
639 } else {
640 for (int i = count - 1; i >= 0; --i) {
641 unsigned a = aa[i];
642 if (0 != a) {
643 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
644 SkPMColor C = proc(src[i], dstC);
645 if (0xFF != a) {
646 C = SkFourByteInterp(C, dstC, a);
647 }
648 dst[i] = SkPixel32ToPixel4444(C);
649 }
650 }
651 }
652 }
653}
654
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000655void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
656 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000657 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000658 SkASSERT(dst && src && count >= 0);
659
660 SkXfermodeProc proc = fProc;
661
662 if (NULL != proc) {
663 if (NULL == aa) {
664 for (int i = count - 1; i >= 0; --i) {
665 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
666 dst[i] = SkToU8(SkGetPackedA32(res));
667 }
668 } else {
669 for (int i = count - 1; i >= 0; --i) {
670 unsigned a = aa[i];
671 if (0 != a) {
672 SkAlpha dstA = dst[i];
673 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
674 unsigned A = SkGetPackedA32(res);
675 if (0xFF != a) {
676 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
677 }
678 dst[i] = SkToU8(A);
679 }
680 }
681 }
682 }
683}
684
685SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
686 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000687 fProc = NULL;
688 if (!buffer.isCrossProcess()) {
689 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
690 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000691}
692
djsollen@google.com54924242012-03-29 15:18:04 +0000693void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
694 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000695 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000696 buffer.writeFunctionPtr((void*)fProc);
697 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000698}
699
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000700#ifdef SK_DEVELOPER
701void SkProcXfermode::toString(SkString* str) const {
702 str->appendf("SkProcXfermode: %p", fProc);
703}
704#endif
705
vandebo@chromium.org48543272011-02-08 19:28:07 +0000706///////////////////////////////////////////////////////////////////////////////
707///////////////////////////////////////////////////////////////////////////////
708
709class SkProcCoeffXfermode : public SkProcXfermode {
710public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000711 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
712 : INHERITED(rec.fProc) {
713 fMode = mode;
714 // these may be valid, or may be CANNOT_USE_COEFF
715 fSrcCoeff = rec.fSC;
716 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000717 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000718
reed@google.com30da7452012-12-17 19:55:24 +0000719 virtual bool asMode(Mode* mode) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000720 if (mode) {
721 *mode = fMode;
722 }
723 return true;
724 }
725
reed@google.com30da7452012-12-17 19:55:24 +0000726 virtual bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000727 if (CANNOT_USE_COEFF == fSrcCoeff) {
728 return false;
729 }
730
vandebo@chromium.org48543272011-02-08 19:28:07 +0000731 if (sc) {
732 *sc = fSrcCoeff;
733 }
734 if (dc) {
735 *dc = fDstCoeff;
736 }
737 return true;
738 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000739
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000740 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000741 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000742
vandebo@chromium.org48543272011-02-08 19:28:07 +0000743protected:
djsollen@google.com54924242012-03-29 15:18:04 +0000744 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000745 fMode = (SkXfermode::Mode)buffer.read32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000746
747 const ProcCoeff& rec = gProcCoeffs[fMode];
748 // these may be valid, or may be CANNOT_USE_COEFF
749 fSrcCoeff = rec.fSC;
750 fDstCoeff = rec.fDC;
751 // now update our function-ptr in the super class
752 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000753 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000754
djsollen@google.com54924242012-03-29 15:18:04 +0000755 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
756 this->INHERITED::flatten(buffer);
757 buffer.write32(fMode);
758 }
759
vandebo@chromium.org48543272011-02-08 19:28:07 +0000760private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000761 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000762 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000763
vandebo@chromium.org48543272011-02-08 19:28:07 +0000764 typedef SkProcXfermode INHERITED;
765};
766
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000767#ifdef SK_DEVELOPER
768void SkProcCoeffXfermode::toString(SkString* str) const {
769 str->append("SkProcCoeffXfermode: ");
770
771 const char *gModeStrings[kLastMode+1] = {
772 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
773 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
774 "Multiply", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
775 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion"
776 };
777
778 str->append("mode: ");
779 str->append(gModeStrings[fMode]);
780
781 static const char* gCoeffStrings[kCoeffCount] = {
782 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
783 };
784
785 str->append(" src: ");
786 if (CANNOT_USE_COEFF == fSrcCoeff) {
787 str->append("can't use");
788 } else {
789 str->append(gCoeffStrings[fSrcCoeff]);
790 }
791
792 str->append(" dst: ");
793 if (CANNOT_USE_COEFF == fDstCoeff) {
794 str->append("can't use");
795 } else {
796 str->append(gCoeffStrings[fDstCoeff]);
797 }
798}
799#endif
800
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801///////////////////////////////////////////////////////////////////////////////
802
803class SkClearXfermode : public SkProcCoeffXfermode {
804public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000805 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806
reed@google.com30da7452012-12-17 19:55:24 +0000807 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
808 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000810 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000811 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813private:
814 SkClearXfermode(SkFlattenableReadBuffer& buffer)
815 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000816
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000817 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818};
819
reed@google.com86ab6c62011-11-28 15:26:14 +0000820void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
821 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000822 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000823 SkASSERT(dst && count >= 0);
824
825 if (NULL == aa) {
826 memset(dst, 0, count << 2);
827 } else {
828 for (int i = count - 1; i >= 0; --i) {
829 unsigned a = aa[i];
830 if (0xFF == a) {
831 dst[i] = 0;
832 } else if (a != 0) {
833 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
834 }
835 }
836 }
837}
838void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
839 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000840 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000841 SkASSERT(dst && count >= 0);
842
843 if (NULL == aa) {
844 memset(dst, 0, count);
845 } else {
846 for (int i = count - 1; i >= 0; --i) {
847 unsigned a = aa[i];
848 if (0xFF == a) {
849 dst[i] = 0;
850 } else if (0 != a) {
851 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
852 }
853 }
854 }
855}
856
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000857#ifdef SK_DEVELOPER
858void SkClearXfermode::toString(SkString* str) const {
859 this->INHERITED::toString(str);
860}
861#endif
862
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863///////////////////////////////////////////////////////////////////////////////
864
865class SkSrcXfermode : public SkProcCoeffXfermode {
866public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000867 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868
reed@google.com30da7452012-12-17 19:55:24 +0000869 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
870 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000872 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000873 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000874
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875private:
876 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
877 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000878
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000879 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000880};
881
reed@google.com86ab6c62011-11-28 15:26:14 +0000882void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
883 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000884 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000885 SkASSERT(dst && src && count >= 0);
886
887 if (NULL == aa) {
888 memcpy(dst, src, count << 2);
889 } else {
890 for (int i = count - 1; i >= 0; --i) {
891 unsigned a = aa[i];
892 if (a == 0xFF) {
893 dst[i] = src[i];
894 } else if (a != 0) {
895 dst[i] = SkFourByteInterp(src[i], dst[i], a);
896 }
897 }
898 }
899}
900
901void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
902 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000903 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000904 SkASSERT(dst && src && count >= 0);
905
906 if (NULL == aa) {
907 for (int i = count - 1; i >= 0; --i) {
908 dst[i] = SkToU8(SkGetPackedA32(src[i]));
909 }
910 } else {
911 for (int i = count - 1; i >= 0; --i) {
912 unsigned a = aa[i];
913 if (0 != a) {
914 unsigned srcA = SkGetPackedA32(src[i]);
915 if (a == 0xFF) {
916 dst[i] = SkToU8(srcA);
917 } else {
918 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
919 }
920 }
921 }
922 }
923}
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000924#ifdef SK_DEVELOPER
925void SkSrcXfermode::toString(SkString* str) const {
926 this->INHERITED::toString(str);
927}
928#endif
reed@google.com86ab6c62011-11-28 15:26:14 +0000929
reed@google.com30da7452012-12-17 19:55:24 +0000930///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +0000931
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932class SkDstInXfermode : public SkProcCoeffXfermode {
933public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000934 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000935
reed@google.com30da7452012-12-17 19:55:24 +0000936 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000937
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000938 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000939 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000940
941private:
942 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
943
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944 typedef SkProcCoeffXfermode INHERITED;
945};
946
reed@google.com86ab6c62011-11-28 15:26:14 +0000947void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
948 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000949 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000950 SkASSERT(dst && src);
951
952 if (count <= 0) {
953 return;
954 }
955 if (NULL != aa) {
956 return this->INHERITED::xfer32(dst, src, count, aa);
957 }
958
959 do {
960 unsigned a = SkGetPackedA32(*src);
961 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
962 dst++;
963 src++;
964 } while (--count != 0);
965}
966
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000967#ifdef SK_DEVELOPER
968void SkDstInXfermode::toString(SkString* str) const {
969 this->INHERITED::toString(str);
970}
971#endif
972
reed@google.com30da7452012-12-17 19:55:24 +0000973///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +0000974
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975class SkDstOutXfermode : public SkProcCoeffXfermode {
976public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000977 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000978
reed@google.com30da7452012-12-17 19:55:24 +0000979 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000980
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000981 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000982 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000983
984private:
985 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
986 : INHERITED(buffer) {}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 typedef SkProcCoeffXfermode INHERITED;
989};
990
reed@google.com86ab6c62011-11-28 15:26:14 +0000991void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
992 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000993 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000994 SkASSERT(dst && src);
995
996 if (count <= 0) {
997 return;
998 }
999 if (NULL != aa) {
1000 return this->INHERITED::xfer32(dst, src, count, aa);
1001 }
1002
1003 do {
1004 unsigned a = SkGetPackedA32(*src);
1005 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1006 dst++;
1007 src++;
1008 } while (--count != 0);
1009}
1010
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001011#ifdef SK_DEVELOPER
1012void SkDstOutXfermode::toString(SkString* str) const {
1013 this->INHERITED::toString(str);
1014}
1015#endif
1016
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017///////////////////////////////////////////////////////////////////////////////
1018
reed@android.coma0f5d152009-06-22 17:38:10 +00001019SkXfermode* SkXfermode::Create(Mode mode) {
1020 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1021 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022
reed@google.comc0d4aa22011-04-13 21:12:04 +00001023 const ProcCoeff& rec = gProcCoeffs[mode];
1024
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025 switch (mode) {
1026 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001027 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001029 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030 case kSrcOver_Mode:
1031 return NULL;
1032 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001033 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001035 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1036 default:
1037 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038 }
1039}
1040
reed@google.com43c50c82011-04-14 15:50:52 +00001041SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1042 SkXfermodeProc proc = NULL;
1043 if ((unsigned)mode < kModeCount) {
1044 proc = gProcCoeffs[mode].fProc;
1045 }
1046 return proc;
1047}
1048
1049bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1050 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001051
reed@google.com43c50c82011-04-14 15:50:52 +00001052 if ((unsigned)mode >= (unsigned)kModeCount) {
1053 // illegal mode parameter
1054 return false;
1055 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001056
reed@google.com43c50c82011-04-14 15:50:52 +00001057 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001058
reed@google.com43c50c82011-04-14 15:50:52 +00001059 if (CANNOT_USE_COEFF == rec.fSC) {
1060 return false;
1061 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001062
reed@google.com43c50c82011-04-14 15:50:52 +00001063 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1064 if (src) {
1065 *src = rec.fSC;
1066 }
1067 if (dst) {
1068 *dst = rec.fDC;
1069 }
1070 return true;
1071}
1072
reed@google.com30da7452012-12-17 19:55:24 +00001073bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074 if (NULL == xfer) {
1075 if (mode) {
1076 *mode = kSrcOver_Mode;
1077 }
1078 return true;
1079 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001080 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081}
1082
reed@google.com30da7452012-12-17 19:55:24 +00001083bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001084 if (NULL == xfer) {
1085 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 }
reed@google.com43c50c82011-04-14 15:50:52 +00001087 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088}
1089
reed@google.com30da7452012-12-17 19:55:24 +00001090bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001091 // if xfer==null then the mode is srcover
1092 Mode m = kSrcOver_Mode;
1093 if (xfer && !xfer->asMode(&m)) {
1094 return false;
1095 }
1096 return mode == m;
1097}
1098
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099///////////////////////////////////////////////////////////////////////////////
1100//////////// 16bit xfermode procs
1101
1102#ifdef SK_DEBUG
1103static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1104static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1105#endif
1106
1107static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1108 SkASSERT(require_255(src));
1109 return SkPixel32ToPixel16(src);
1110}
1111
1112static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1113 return dst;
1114}
1115
1116static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1117 SkASSERT(require_0(src));
1118 return dst;
1119}
1120
1121static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1122 SkASSERT(require_255(src));
1123 return SkPixel32ToPixel16(src);
1124}
1125
1126static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1127 SkASSERT(require_0(src));
1128 return dst;
1129}
1130
1131static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1132 SkASSERT(require_255(src));
1133 return dst;
1134}
1135
1136static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1137 SkASSERT(require_255(src));
1138 return SkPixel32ToPixel16(src);
1139}
1140
1141static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1142 SkASSERT(require_255(src));
1143 return dst;
1144}
1145
1146static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1147 SkASSERT(require_0(src));
1148 return dst;
1149}
1150
1151static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1152 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001153
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154 return SkPackRGB16(
1155 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1156 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1157 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1158}
1159
1160static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1161 SkASSERT(require_0(src));
1162 return dst;
1163}
1164
1165static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1166 SkASSERT(require_255(src));
1167 return SkPixel32ToPixel16(src);
1168}
1169
1170static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1171 SkASSERT(require_255(src));
1172 return dst;
1173}
1174
1175/*********
1176 darken and lighten boil down to this.
1177
1178 darken = (1 - Sa) * Dc + min(Sc, Dc)
1179 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1180
1181 if (Sa == 0) these become
1182 darken = Dc + min(0, Dc) = 0
1183 lighten = Dc + max(0, Dc) = Dc
1184
1185 if (Sa == 1) these become
1186 darken = min(Sc, Dc)
1187 lighten = max(Sc, Dc)
1188*/
1189
1190static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1191 SkASSERT(require_0(src));
1192 return 0;
1193}
1194
1195static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1196 SkASSERT(require_255(src));
1197 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1198 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1199 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1200 return SkPackRGB16(r, g, b);
1201}
1202
1203static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1204 SkASSERT(require_0(src));
1205 return dst;
1206}
1207
1208static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1209 SkASSERT(require_255(src));
1210 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1211 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1212 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1213 return SkPackRGB16(r, g, b);
1214}
1215
1216struct Proc16Rec {
1217 SkXfermodeProc16 fProc16_0;
1218 SkXfermodeProc16 fProc16_255;
1219 SkXfermodeProc16 fProc16_General;
1220};
1221
reed@android.coma0f5d152009-06-22 17:38:10 +00001222static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 { NULL, NULL, NULL }, // CLEAR
1224 { NULL, src_modeproc16_255, NULL },
1225 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1226 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1227 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1228 { NULL, srcin_modeproc16_255, NULL },
1229 { NULL, dstin_modeproc16_255, NULL },
1230 { NULL, NULL, NULL },// SRC_OUT
1231 { dstout_modeproc16_0, NULL, NULL },
1232 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1233 { NULL, dstatop_modeproc16_255, NULL },
1234 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001235
1236 { NULL, NULL, NULL }, // plus
1237 { NULL, NULL, NULL }, // multiply
1238 { NULL, NULL, NULL }, // screen
1239 { NULL, NULL, NULL }, // overlay
1240 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1241 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1242 { NULL, NULL, NULL }, // colordodge
1243 { NULL, NULL, NULL }, // colorburn
1244 { NULL, NULL, NULL }, // hardlight
1245 { NULL, NULL, NULL }, // softlight
1246 { NULL, NULL, NULL }, // difference
1247 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248};
1249
reed@android.coma0f5d152009-06-22 17:38:10 +00001250SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001252 if ((unsigned)mode < kModeCount) {
1253 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001254 unsigned a = SkColorGetA(srcColor);
1255
1256 if (0 == a) {
1257 proc16 = rec.fProc16_0;
1258 } else if (255 == a) {
1259 proc16 = rec.fProc16_255;
1260 } else {
1261 proc16 = rec.fProc16_General;
1262 }
1263 }
1264 return proc16;
1265}
1266
caryclark@google.comd26147a2011-12-15 14:16:43 +00001267SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1268 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1269 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1270 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1271 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1272 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1273SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END