blob: 08f760d2054d5ccec46f56da2d4494394a71c368 [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
9#include "SkXfermode.h"
commit-bot@chromium.orgc524e982014-04-09 15:43:46 +000010#include "SkXfermode_opts_SSE2.h"
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +000011#include "SkXfermode_proccoeff.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkColorPriv.h"
commit-bot@chromium.org97de3572014-05-29 20:13:22 +000013#include "SkLazyPtr.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000014#include "SkMathPriv.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000015#include "SkReadBuffer.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000016#include "SkString.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000017#include "SkUtilsArm.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000018#include "SkWriteBuffer.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000019
20#if !SK_ARM_NEON_IS_NONE
21#include "SkXfermode_opts_arm_neon.h"
22#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
24#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
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
reed@android.com8a1c16f2008-12-17 15:59:43 +000070///////////////////////////////////////////////////////////////////////////////
71
reed@android.com8a1c16f2008-12-17 15:59:43 +000072// kClear_Mode, //!< [0, 0]
73static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
74 return 0;
75}
76
77// kSrc_Mode, //!< [Sa, Sc]
78static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
79 return src;
80}
81
82// kDst_Mode, //!< [Da, Dc]
83static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
84 return dst;
85}
86
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000087// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000088static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000089#if 0
90 // this is the old, more-correct way, but it doesn't guarantee that dst==255
91 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000093#else
94 // this is slightly faster, but more importantly guarantees that dst==255
95 // will always stay opaque
96 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
97#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000098}
99
reed@android.com1116fb22009-03-03 20:31:12 +0000100// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000102 // this is the reverse of srcover, just flipping src and dst
103 // see srcover's comment about the 256 for opaqueness guarantees
104 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
107// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
108static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
109 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
110}
111
112// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
113static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
114 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
115}
116
117// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
118static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
119 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
120}
121
122// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
123static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
124 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
125}
126
127// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
128static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
129 unsigned sa = SkGetPackedA32(src);
130 unsigned da = SkGetPackedA32(dst);
131 unsigned isa = 255 - sa;
132
133 return SkPackARGB32(da,
134 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
135 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
136 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
137 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
138 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
139 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
140}
141
142// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
143static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
144 unsigned sa = SkGetPackedA32(src);
145 unsigned da = SkGetPackedA32(dst);
146 unsigned ida = 255 - da;
147
148 return SkPackARGB32(sa,
149 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
150 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
151 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
152 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
153 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
154 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
155}
156
157// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
158static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
159 unsigned sa = SkGetPackedA32(src);
160 unsigned da = SkGetPackedA32(dst);
161 unsigned isa = 255 - sa;
162 unsigned ida = 255 - da;
163
164 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
165 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
166 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
167 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
168 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
169 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
170 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
171}
172
reed@android.coma0f5d152009-06-22 17:38:10 +0000173///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
reed@android.coma0f5d152009-06-22 17:38:10 +0000175// kPlus_Mode
176static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000177 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000178 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
179 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
180 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000181 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182}
183
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000184// kModulate_Mode
185static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
187 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
188 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
189 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
190 return SkPackARGB32(a, r, g, b);
191}
192
reed@android.coma0f5d152009-06-22 17:38:10 +0000193static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 return a + b - SkAlphaMulAlpha(a, b);
195}
reed@google.com25cfa692013-02-04 20:06:00 +0000196
197// kMultiply_Mode
198// B(Cb, Cs) = Cb x Cs
199// multiply uses its own version of blendfunc_byte because sa and da are not needed
200static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
201 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
202}
203
204static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
205 int sa = SkGetPackedA32(src);
206 int da = SkGetPackedA32(dst);
207 int a = srcover_byte(sa, da);
208 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
209 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
210 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
211 return SkPackARGB32(a, r, g, b);
212}
213
214// kScreen_Mode
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000216 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
217 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
218 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
219 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 return SkPackARGB32(a, r, g, b);
221}
222
reed@android.coma0f5d152009-06-22 17:38:10 +0000223// kOverlay_Mode
224static inline int overlay_byte(int sc, int dc, int sa, int da) {
225 int tmp = sc * (255 - da) + dc * (255 - sa);
226 int rc;
227 if (2 * dc <= da) {
228 rc = 2 * sc * dc;
229 } else {
230 rc = sa * da - 2 * (da - dc) * (sa - sc);
231 }
232 return clamp_div255round(rc + tmp);
233}
234static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
235 int sa = SkGetPackedA32(src);
236 int da = SkGetPackedA32(dst);
237 int a = srcover_byte(sa, da);
238 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
239 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
240 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
241 return SkPackARGB32(a, r, g, b);
242}
243
244// kDarken_Mode
245static inline int darken_byte(int sc, int dc, int sa, int da) {
246 int sd = sc * da;
247 int ds = dc * sa;
248 if (sd < ds) {
249 // srcover
250 return sc + dc - SkDiv255Round(ds);
251 } else {
252 // dstover
253 return dc + sc - SkDiv255Round(sd);
254 }
255}
256static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
257 int sa = SkGetPackedA32(src);
258 int da = SkGetPackedA32(dst);
259 int a = srcover_byte(sa, da);
260 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
261 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
262 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
263 return SkPackARGB32(a, r, g, b);
264}
265
266// kLighten_Mode
267static inline int lighten_byte(int sc, int dc, int sa, int da) {
268 int sd = sc * da;
269 int ds = dc * sa;
270 if (sd > ds) {
271 // srcover
272 return sc + dc - SkDiv255Round(ds);
273 } else {
274 // dstover
275 return dc + sc - SkDiv255Round(sd);
276 }
277}
278static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
279 int sa = SkGetPackedA32(src);
280 int da = SkGetPackedA32(dst);
281 int a = srcover_byte(sa, da);
282 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
283 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
284 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
285 return SkPackARGB32(a, r, g, b);
286}
287
288// kColorDodge_Mode
289static inline int colordodge_byte(int sc, int dc, int sa, int da) {
290 int diff = sa - sc;
291 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000292 if (0 == dc) {
293 return SkAlphaMulAlpha(sc, 255 - da);
294 } else if (0 == diff) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000295 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000296 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000297 diff = dc * sa / diff;
298 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000299 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000300 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000301}
302static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000303 int sa = SkGetPackedA32(src);
304 int da = SkGetPackedA32(dst);
305 int a = srcover_byte(sa, da);
306 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
307 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
308 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.coma0f5d152009-06-22 17:38:10 +0000309 return SkPackARGB32(a, r, g, b);
310}
311
312// kColorBurn_Mode
313static inline int colorburn_byte(int sc, int dc, int sa, int da) {
314 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000315 if (dc == da) {
316 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000317 } else if (0 == sc) {
318 return SkAlphaMulAlpha(dc, 255 - sa);
319 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000320 int tmp = (da - dc) * sa / sc;
321 rc = sa * (da - ((da < tmp) ? da : tmp))
322 + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000323 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000324 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000325}
326static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000327 int sa = SkGetPackedA32(src);
328 int da = SkGetPackedA32(dst);
329 int a = srcover_byte(sa, da);
330 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
331 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
332 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
333 return SkPackARGB32(a, r, g, b);
334}
335
336// kHardLight_Mode
337static inline int hardlight_byte(int sc, int dc, int sa, int da) {
338 int rc;
339 if (2 * sc <= sa) {
340 rc = 2 * sc * dc;
341 } else {
342 rc = sa * da - 2 * (da - dc) * (sa - sc);
343 }
344 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
345}
346static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
347 int sa = SkGetPackedA32(src);
348 int da = SkGetPackedA32(dst);
349 int a = srcover_byte(sa, da);
350 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
351 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
352 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
353 return SkPackARGB32(a, r, g, b);
354}
355
356// returns 255 * sqrt(n/255)
357static U8CPU sqrt_unit_byte(U8CPU n) {
358 return SkSqrtBits(n, 15+4);
359}
360
361// kSoftLight_Mode
362static inline int softlight_byte(int sc, int dc, int sa, int da) {
363 int m = da ? dc * 256 / da : 0;
364 int rc;
365 if (2 * sc <= sa) {
366 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
367 } else if (4 * dc <= da) {
368 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
369 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
370 } else {
371 int tmp = sqrt_unit_byte(m) - m;
372 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
373 }
374 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
375}
376static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
377 int sa = SkGetPackedA32(src);
378 int da = SkGetPackedA32(dst);
379 int a = srcover_byte(sa, da);
380 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
381 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
382 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
383 return SkPackARGB32(a, r, g, b);
384}
385
386// kDifference_Mode
387static inline int difference_byte(int sc, int dc, int sa, int da) {
388 int tmp = SkMin32(sc * da, dc * sa);
389 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
390}
391static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
392 int sa = SkGetPackedA32(src);
393 int da = SkGetPackedA32(dst);
394 int a = srcover_byte(sa, da);
395 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
396 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
397 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
398 return SkPackARGB32(a, r, g, b);
399}
400
401// kExclusion_Mode
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000402static inline int exclusion_byte(int sc, int dc, int, int) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000403 // this equations is wacky, wait for SVG to confirm it
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000404 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
405
406 // The above equation can be simplified as follows
407 int r = 255*(sc + dc) - 2 * sc * dc;
reed@android.coma0f5d152009-06-22 17:38:10 +0000408 return clamp_div255round(r);
409}
410static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
411 int sa = SkGetPackedA32(src);
412 int da = SkGetPackedA32(dst);
413 int a = srcover_byte(sa, da);
414 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
415 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
416 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000417 return SkPackARGB32(a, r, g, b);
418}
419
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000420// The CSS compositing spec introduces the following formulas:
421// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
422// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
423// while PDF and CG uses the one from Rec. Rec. 601
424// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
425static inline int Lum(int r, int g, int b)
426{
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000427 return SkDiv255Round(r * 77 + g * 150 + b * 28);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000428}
429
430static inline int min2(int a, int b) { return a < b ? a : b; }
431static inline int max2(int a, int b) { return a > b ? a : b; }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000432#define minimum(a, b, c) min2(min2(a, b), c)
433#define maximum(a, b, c) max2(max2(a, b), c)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000434
435static inline int Sat(int r, int g, int b) {
436 return maximum(r, g, b) - minimum(r, g, b);
437}
438
439static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
reed@google.com3c1ea3a2013-03-07 15:31:58 +0000440 if(*Cmax > *Cmin) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000441 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000442 *Cmax = s;
443 } else {
444 *Cmax = 0;
445 *Cmid = 0;
446 }
447
448 *Cmin = 0;
449}
450
451static inline void SetSat(int* r, int* g, int* b, int s) {
452 if(*r <= *g) {
453 if(*g <= *b) {
454 setSaturationComponents(r, g, b, s);
455 } else if(*r <= *b) {
456 setSaturationComponents(r, b, g, s);
457 } else {
458 setSaturationComponents(b, r, g, s);
459 }
460 } else if(*r <= *b) {
461 setSaturationComponents(g, r, b, s);
462 } else if(*g <= *b) {
463 setSaturationComponents(g, b, r, s);
464 } else {
465 setSaturationComponents(b, g, r, s);
466 }
467}
468
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000469static inline void clipColor(int* r, int* g, int* b, int a) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000470 int L = Lum(*r, *g, *b);
471 int n = minimum(*r, *g, *b);
472 int x = maximum(*r, *g, *b);
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000473 int denom;
474 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
475 *r = L + SkMulDiv(*r - L, L, denom);
476 *g = L + SkMulDiv(*g - L, L, denom);
477 *b = L + SkMulDiv(*b - L, L, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000478 }
479
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000480 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
481 int numer = a - L;
482 *r = L + SkMulDiv(*r - L, numer, denom);
483 *g = L + SkMulDiv(*g - L, numer, denom);
484 *b = L + SkMulDiv(*b - L, numer, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000485 }
486}
487
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000488static inline void SetLum(int* r, int* g, int* b, int a, int l) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000489 int d = l - Lum(*r, *g, *b);
490 *r += d;
491 *g += d;
492 *b += d;
493
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000494 clipColor(r, g, b, a);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000495}
496
497// non-separable blend modes are done in non-premultiplied alpha
498#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000499 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000500
501// kHue_Mode
502// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
503// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
504static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
505 int sr = SkGetPackedR32(src);
506 int sg = SkGetPackedG32(src);
507 int sb = SkGetPackedB32(src);
508 int sa = SkGetPackedA32(src);
509
510 int dr = SkGetPackedR32(dst);
511 int dg = SkGetPackedG32(dst);
512 int db = SkGetPackedB32(dst);
513 int da = SkGetPackedA32(dst);
514 int Sr, Sg, Sb;
515
516 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000517 Sr = sr * sa;
518 Sg = sg * sa;
519 Sb = sb * sa;
520 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
521 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000522 } else {
523 Sr = 0;
524 Sg = 0;
525 Sb = 0;
526 }
527
528 int a = srcover_byte(sa, da);
529 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
530 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
531 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
532 return SkPackARGB32(a, r, g, b);
533}
534
535// kSaturation_Mode
536// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000537// Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000538static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
539 int sr = SkGetPackedR32(src);
540 int sg = SkGetPackedG32(src);
541 int sb = SkGetPackedB32(src);
542 int sa = SkGetPackedA32(src);
543
544 int dr = SkGetPackedR32(dst);
545 int dg = SkGetPackedG32(dst);
546 int db = SkGetPackedB32(dst);
547 int da = SkGetPackedA32(dst);
548 int Dr, Dg, Db;
549
550 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000551 Dr = dr * sa;
552 Dg = dg * sa;
553 Db = db * sa;
554 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
555 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000556 } else {
557 Dr = 0;
558 Dg = 0;
559 Db = 0;
560 }
561
562 int a = srcover_byte(sa, da);
563 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
564 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
565 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
566 return SkPackARGB32(a, r, g, b);
567}
568
569// kColor_Mode
570// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000571// Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000572static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
573 int sr = SkGetPackedR32(src);
574 int sg = SkGetPackedG32(src);
575 int sb = SkGetPackedB32(src);
576 int sa = SkGetPackedA32(src);
577
578 int dr = SkGetPackedR32(dst);
579 int dg = SkGetPackedG32(dst);
580 int db = SkGetPackedB32(dst);
581 int da = SkGetPackedA32(dst);
582 int Sr, Sg, Sb;
583
584 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000585 Sr = sr * da;
586 Sg = sg * da;
587 Sb = sb * da;
588 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000589 } else {
590 Sr = 0;
591 Sg = 0;
592 Sb = 0;
593 }
594
595 int a = srcover_byte(sa, da);
596 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
597 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
598 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
599 return SkPackARGB32(a, r, g, b);
600}
601
602// kLuminosity_Mode
603// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000604// Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000605static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
606 int sr = SkGetPackedR32(src);
607 int sg = SkGetPackedG32(src);
608 int sb = SkGetPackedB32(src);
609 int sa = SkGetPackedA32(src);
610
611 int dr = SkGetPackedR32(dst);
612 int dg = SkGetPackedG32(dst);
613 int db = SkGetPackedB32(dst);
614 int da = SkGetPackedA32(dst);
615 int Dr, Dg, Db;
616
617 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000618 Dr = dr * sa;
619 Dg = dg * sa;
620 Db = db * sa;
621 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000622 } else {
623 Dr = 0;
624 Dg = 0;
625 Db = 0;
626 }
627
628 int a = srcover_byte(sa, da);
629 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
630 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
631 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
632 return SkPackARGB32(a, r, g, b);
633}
634
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000635const ProcCoeff gProcCoeffs[] = {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000636 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
637 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
638 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
639 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
640 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
641 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
642 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
643 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
644 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
645 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
646 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
647 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
648
reed@google.com521e34e2011-04-12 18:55:21 +0000649 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000650 { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
bsalomon@google.comb0091b82013-04-15 15:16:47 +0000651 { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000652 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
653 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
654 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
655 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
656 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
657 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
658 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
659 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
660 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed@google.com25cfa692013-02-04 20:06:00 +0000661 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000662 { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
663 { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
664 { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
665 { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000666};
667
668///////////////////////////////////////////////////////////////////////////////
669
reed@google.com30da7452012-12-17 19:55:24 +0000670bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000671 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000672}
673
joshualittb0a8a372014-09-23 09:50:21 -0700674bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrTexture*) const {
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000675 return false;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000676}
677
egdaniel378092f2014-12-03 10:40:13 -0800678bool SkXfermode::asXPFactory(GrXPFactory**) const {
679 return false;
680}
681
682
683#if SK_SUPPORT_GPU
684#include "effects/GrPorterDuffXferProcessor.h"
685
egdaniel58136162015-01-20 10:19:22 -0800686bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000687 if (NULL == xfermode) {
egdaniel58136162015-01-20 10:19:22 -0800688 if (xpf) {
689 *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode);
690 }
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000691 return true;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000692 } else {
egdaniel58136162015-01-20 10:19:22 -0800693 return xfermode->asXPFactory(xpf);
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000694 }
695}
egdaniel378092f2014-12-03 10:40:13 -0800696#else
egdaniel58136162015-01-20 10:19:22 -0800697bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
egdaniel378092f2014-12-03 10:40:13 -0800698 return false;
699}
700#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000701
reed@google.com30da7452012-12-17 19:55:24 +0000702SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000703 // no-op. subclasses should override this
704 return dst;
705}
706
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000707void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
708 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000709 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000710 SkASSERT(dst && src && count >= 0);
711
712 if (NULL == aa) {
713 for (int i = count - 1; i >= 0; --i) {
714 dst[i] = this->xferColor(src[i], dst[i]);
715 }
716 } else {
717 for (int i = count - 1; i >= 0; --i) {
718 unsigned a = aa[i];
719 if (0 != a) {
720 SkPMColor dstC = dst[i];
721 SkPMColor C = this->xferColor(src[i], dstC);
722 if (0xFF != a) {
723 C = SkFourByteInterp(C, dstC, a);
724 }
725 dst[i] = C;
726 }
727 }
728 }
729}
730
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000731void SkXfermode::xfer16(uint16_t* dst,
732 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000733 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000734 SkASSERT(dst && src && count >= 0);
735
736 if (NULL == aa) {
737 for (int i = count - 1; i >= 0; --i) {
738 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
739 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
740 }
741 } else {
742 for (int i = count - 1; i >= 0; --i) {
743 unsigned a = aa[i];
744 if (0 != a) {
745 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
746 SkPMColor C = this->xferColor(src[i], dstC);
747 if (0xFF != a) {
748 C = SkFourByteInterp(C, dstC, a);
749 }
750 dst[i] = SkPixel32ToPixel16_ToU16(C);
751 }
752 }
753 }
754}
755
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000756void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000757 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000758 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000759 SkASSERT(dst && src && count >= 0);
760
761 if (NULL == aa) {
762 for (int i = count - 1; i >= 0; --i) {
763 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
764 dst[i] = SkToU8(SkGetPackedA32(res));
765 }
766 } else {
767 for (int i = count - 1; i >= 0; --i) {
768 unsigned a = aa[i];
769 if (0 != a) {
770 SkAlpha dstA = dst[i];
771 unsigned A = SkGetPackedA32(this->xferColor(src[i],
772 (SkPMColor)(dstA << SK_A32_SHIFT)));
773 if (0xFF != a) {
774 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
775 }
776 dst[i] = SkToU8(A);
777 }
778 }
779 }
780}
781
egdanieldcfb7cf2015-01-22 06:52:29 -0800782bool SkXfermode::supportsCoverageAsAlpha() const {
783 return false;
784}
785
786bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
787 return false;
788}
789
vandebo@chromium.org48543272011-02-08 19:28:07 +0000790///////////////////////////////////////////////////////////////////////////////
791///////////////////////////////////////////////////////////////////////////////
792
reed9fa60da2014-08-21 07:59:51 -0700793SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
794 uint32_t mode32 = buffer.read32();
senorblanco0f7197b2014-09-24 11:09:38 -0700795 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
reed9fa60da2014-08-21 07:59:51 -0700796 return NULL;
797 }
798 return SkXfermode::Create((SkXfermode::Mode)mode32);
799}
800
801void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
802 buffer.write32(fMode);
803}
reed@google.com52314f82013-11-21 21:05:06 +0000804
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000805bool SkProcCoeffXfermode::asMode(Mode* mode) const {
806 if (mode) {
807 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000808 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000809 return true;
810}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +0000811
egdanieldcfb7cf2015-01-22 06:52:29 -0800812bool SkProcCoeffXfermode::supportsCoverageAsAlpha() const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000813 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +0000814 return false;
815 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000816
egdanieldcfb7cf2015-01-22 06:52:29 -0800817 switch (fDstCoeff) {
818 case SkXfermode::kOne_Coeff:
819 case SkXfermode::kISA_Coeff:
820 case SkXfermode::kISC_Coeff:
821 return true;
822 default:
823 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000824 }
egdanieldcfb7cf2015-01-22 06:52:29 -0800825}
826
827bool SkProcCoeffXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
828 if (CANNOT_USE_COEFF == fSrcCoeff) {
829 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000830 }
egdanieldcfb7cf2015-01-22 06:52:29 -0800831
832 if (SkXfermode::kDA_Coeff == fSrcCoeff || SkXfermode::kDC_Coeff == fSrcCoeff ||
833 SkXfermode::kIDA_Coeff == fSrcCoeff || SkXfermode::kIDC_Coeff == fSrcCoeff) {
834 return false;
835 }
836
837 switch (fDstCoeff) {
838 case SkXfermode::kZero_Coeff:
839 return true;
840 case SkXfermode::kISA_Coeff:
841 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
842 case SkXfermode::kSA_Coeff:
843 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType ||
844 SkXfermode::kTransparentAlpha_SrcColorOpacity == opacityType;
845 case SkXfermode::kSC_Coeff:
846 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType;
847 default:
848 return false;
849 }
850
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000851}
852
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000853void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
854 const SkPMColor* SK_RESTRICT src, int count,
855 const SkAlpha* SK_RESTRICT aa) const {
856 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000857
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000858 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000859
bsalomon49f085d2014-09-05 13:34:00 -0700860 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000861 if (NULL == aa) {
862 for (int i = count - 1; i >= 0; --i) {
863 dst[i] = proc(src[i], dst[i]);
864 }
865 } else {
866 for (int i = count - 1; i >= 0; --i) {
867 unsigned a = aa[i];
868 if (0 != a) {
869 SkPMColor dstC = dst[i];
870 SkPMColor C = proc(src[i], dstC);
871 if (a != 0xFF) {
872 C = SkFourByteInterp(C, dstC, a);
873 }
874 dst[i] = C;
875 }
876 }
877 }
878 }
879}
880
881void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
882 const SkPMColor* SK_RESTRICT src, int count,
883 const SkAlpha* SK_RESTRICT aa) const {
884 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000885
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000886 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000887
bsalomon49f085d2014-09-05 13:34:00 -0700888 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000889 if (NULL == aa) {
890 for (int i = count - 1; i >= 0; --i) {
891 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
892 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
893 }
894 } else {
895 for (int i = count - 1; i >= 0; --i) {
896 unsigned a = aa[i];
897 if (0 != a) {
898 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
899 SkPMColor C = proc(src[i], dstC);
900 if (0xFF != a) {
901 C = SkFourByteInterp(C, dstC, a);
902 }
903 dst[i] = SkPixel32ToPixel16_ToU16(C);
904 }
905 }
906 }
907 }
908}
909
910void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
911 const SkPMColor* SK_RESTRICT src, int count,
912 const SkAlpha* SK_RESTRICT aa) const {
913 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000914
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000915 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000916
bsalomon49f085d2014-09-05 13:34:00 -0700917 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000918 if (NULL == aa) {
919 for (int i = count - 1; i >= 0; --i) {
920 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
921 dst[i] = SkToU8(SkGetPackedA32(res));
922 }
923 } else {
924 for (int i = count - 1; i >= 0; --i) {
925 unsigned a = aa[i];
926 if (0 != a) {
927 SkAlpha dstA = dst[i];
928 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
929 unsigned A = SkGetPackedA32(res);
930 if (0xFF != a) {
931 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
932 }
933 dst[i] = SkToU8(A);
934 }
935 }
936 }
937 }
938}
939
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000940#if SK_SUPPORT_GPU
egdaniel0063a9b2015-01-15 10:52:32 -0800941#include "effects/GrCustomXfermode.h"
942
joshualittb0a8a372014-09-23 09:50:21 -0700943bool SkProcCoeffXfermode::asFragmentProcessor(GrFragmentProcessor** fp,
944 GrTexture* background) const {
egdaniel0063a9b2015-01-15 10:52:32 -0800945 if (GrCustomXfermode::IsSupportedMode(fMode)) {
joshualittb0a8a372014-09-23 09:50:21 -0700946 if (fp) {
egdaniel0063a9b2015-01-15 10:52:32 -0800947 *fp = GrCustomXfermode::CreateFP(fMode, background);
joshualittb0a8a372014-09-23 09:50:21 -0700948 SkASSERT(*fp);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000949 }
950 return true;
951 }
952 return false;
953}
egdaniel54f0e9d2015-01-16 06:29:47 -0800954
955bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {
egdaniel58136162015-01-20 10:19:22 -0800956 if (CANNOT_USE_COEFF != fSrcCoeff) {
957 if (xp) {
958 *xp = GrPorterDuffXPFactory::Create(fMode);
959 SkASSERT(*xp);
960 }
961 return true;
962 }
963
egdaniel54f0e9d2015-01-16 06:29:47 -0800964 if (GrCustomXfermode::IsSupportedMode(fMode)) {
965 if (xp) {
966 *xp = GrCustomXfermode::CreateXPFactory(fMode);
967 SkASSERT(*xp);
968 }
969 return true;
970 }
971 return false;
972}
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000973#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000974
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +0000975const char* SkXfermode::ModeName(Mode mode) {
976 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
977 const char* gModeStrings[] = {
978 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
979 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
980 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
981 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
982 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
983 };
984 return gModeStrings[mode];
985 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
986}
987
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000988#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000989void SkProcCoeffXfermode::toString(SkString* str) const {
990 str->append("SkProcCoeffXfermode: ");
991
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000992 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +0000993 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000994
995 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +0000996 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000997 };
998
999 str->append(" src: ");
1000 if (CANNOT_USE_COEFF == fSrcCoeff) {
1001 str->append("can't use");
1002 } else {
1003 str->append(gCoeffStrings[fSrcCoeff]);
1004 }
1005
1006 str->append(" dst: ");
1007 if (CANNOT_USE_COEFF == fDstCoeff) {
1008 str->append("can't use");
1009 } else {
1010 str->append(gCoeffStrings[fDstCoeff]);
1011 }
1012}
1013#endif
1014
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015///////////////////////////////////////////////////////////////////////////////
1016
1017class SkClearXfermode : public SkProcCoeffXfermode {
1018public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001019 static SkClearXfermode* Create(const ProcCoeff& rec) {
1020 return SkNEW_ARGS(SkClearXfermode, (rec));
1021 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022
mtklein72c9faa2015-01-09 10:06:39 -08001023 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1024 void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001026 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001027
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001029 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001030
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001031 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032};
1033
reed@google.com86ab6c62011-11-28 15:26:14 +00001034void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1035 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001036 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001037 SkASSERT(dst && count >= 0);
1038
1039 if (NULL == aa) {
1040 memset(dst, 0, count << 2);
1041 } else {
1042 for (int i = count - 1; i >= 0; --i) {
1043 unsigned a = aa[i];
1044 if (0xFF == a) {
1045 dst[i] = 0;
1046 } else if (a != 0) {
1047 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1048 }
1049 }
1050 }
1051}
1052void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1053 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001054 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001055 SkASSERT(dst && count >= 0);
1056
1057 if (NULL == aa) {
1058 memset(dst, 0, count);
1059 } else {
1060 for (int i = count - 1; i >= 0; --i) {
1061 unsigned a = aa[i];
1062 if (0xFF == a) {
1063 dst[i] = 0;
1064 } else if (0 != a) {
1065 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1066 }
1067 }
1068 }
1069}
1070
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001071#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001072void SkClearXfermode::toString(SkString* str) const {
1073 this->INHERITED::toString(str);
1074}
1075#endif
1076
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077///////////////////////////////////////////////////////////////////////////////
1078
1079class SkSrcXfermode : public SkProcCoeffXfermode {
1080public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001081 static SkSrcXfermode* Create(const ProcCoeff& rec) {
1082 return SkNEW_ARGS(SkSrcXfermode, (rec));
1083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084
mtklein72c9faa2015-01-09 10:06:39 -08001085 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1086 void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001088 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001089
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001091 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001092 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093};
1094
reed@google.com86ab6c62011-11-28 15:26:14 +00001095void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1096 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001097 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001098 SkASSERT(dst && src && count >= 0);
1099
1100 if (NULL == aa) {
1101 memcpy(dst, src, count << 2);
1102 } else {
1103 for (int i = count - 1; i >= 0; --i) {
1104 unsigned a = aa[i];
1105 if (a == 0xFF) {
1106 dst[i] = src[i];
1107 } else if (a != 0) {
1108 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1109 }
1110 }
1111 }
1112}
1113
1114void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1115 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001116 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001117 SkASSERT(dst && src && count >= 0);
1118
1119 if (NULL == aa) {
1120 for (int i = count - 1; i >= 0; --i) {
1121 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1122 }
1123 } else {
1124 for (int i = count - 1; i >= 0; --i) {
1125 unsigned a = aa[i];
1126 if (0 != a) {
1127 unsigned srcA = SkGetPackedA32(src[i]);
1128 if (a == 0xFF) {
1129 dst[i] = SkToU8(srcA);
1130 } else {
1131 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1132 }
1133 }
1134 }
1135 }
1136}
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001137#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001138void SkSrcXfermode::toString(SkString* str) const {
1139 this->INHERITED::toString(str);
1140}
1141#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001142
reed@google.com30da7452012-12-17 19:55:24 +00001143///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001144
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145class SkDstInXfermode : public SkProcCoeffXfermode {
1146public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001147 static SkDstInXfermode* Create(const ProcCoeff& rec) {
1148 return SkNEW_ARGS(SkDstInXfermode, (rec));
1149 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001150
mtklein72c9faa2015-01-09 10:06:39 -08001151 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001152
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001153 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001154
1155private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001156 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001157
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 typedef SkProcCoeffXfermode INHERITED;
1159};
1160
reed@google.com86ab6c62011-11-28 15:26:14 +00001161void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1162 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001163 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001164 SkASSERT(dst && src);
1165
1166 if (count <= 0) {
1167 return;
1168 }
bsalomon49f085d2014-09-05 13:34:00 -07001169 if (aa) {
reed@google.com86ab6c62011-11-28 15:26:14 +00001170 return this->INHERITED::xfer32(dst, src, count, aa);
1171 }
1172
1173 do {
1174 unsigned a = SkGetPackedA32(*src);
1175 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1176 dst++;
1177 src++;
1178 } while (--count != 0);
1179}
1180
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001181#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001182void SkDstInXfermode::toString(SkString* str) const {
1183 this->INHERITED::toString(str);
1184}
1185#endif
1186
reed@google.com30da7452012-12-17 19:55:24 +00001187///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001188
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189class SkDstOutXfermode : public SkProcCoeffXfermode {
1190public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001191 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
1192 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1193 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001194
mtklein72c9faa2015-01-09 10:06:39 -08001195 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001196
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001197 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001198
1199private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001200 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001201
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202 typedef SkProcCoeffXfermode INHERITED;
1203};
1204
reed@google.com86ab6c62011-11-28 15:26:14 +00001205void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1206 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001207 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001208 SkASSERT(dst && src);
1209
1210 if (count <= 0) {
1211 return;
1212 }
bsalomon49f085d2014-09-05 13:34:00 -07001213 if (aa) {
reed@google.com86ab6c62011-11-28 15:26:14 +00001214 return this->INHERITED::xfer32(dst, src, count, aa);
1215 }
1216
1217 do {
1218 unsigned a = SkGetPackedA32(*src);
1219 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1220 dst++;
1221 src++;
1222 } while (--count != 0);
1223}
1224
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001225#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001226void SkDstOutXfermode::toString(SkString* str) const {
1227 this->INHERITED::toString(str);
1228}
1229#endif
1230
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231///////////////////////////////////////////////////////////////////////////////
1232
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001233extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec, SkXfermode::Mode mode);
commit-bot@chromium.orgd6118642013-12-06 11:32:27 +00001234extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001235
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001236// Technically, can't be static and passed as a template parameter. So we use anonymous namespace.
1237namespace {
1238SkXfermode* create_mode(int iMode) {
1239 SkXfermode::Mode mode = (SkXfermode::Mode)iMode;
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001240
1241 ProcCoeff rec = gProcCoeffs[mode];
1242 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
1243 if (pp != NULL) {
1244 rec.fProc = pp;
1245 }
1246
1247 SkXfermode* xfer = NULL;
1248 // check if we have a platform optim for that
1249 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
1250 if (xfm != NULL) {
1251 xfer = xfm;
1252 } else {
1253 // All modes can in theory be represented by the ProcCoeff rec, since
1254 // it contains function ptrs. However, a few modes are both simple and
1255 // commonly used, so we call those out for their own subclasses here.
1256 switch (mode) {
1257 case SkXfermode::kClear_Mode:
1258 xfer = SkClearXfermode::Create(rec);
1259 break;
1260 case SkXfermode::kSrc_Mode:
1261 xfer = SkSrcXfermode::Create(rec);
1262 break;
1263 case SkXfermode::kSrcOver_Mode:
1264 SkASSERT(false); // should not land here
1265 break;
1266 case SkXfermode::kDstIn_Mode:
1267 xfer = SkDstInXfermode::Create(rec);
1268 break;
1269 case SkXfermode::kDstOut_Mode:
1270 xfer = SkDstOutXfermode::Create(rec);
1271 break;
1272 default:
1273 // no special-case, just rely in the rec and its function-ptrs
reed9fa60da2014-08-21 07:59:51 -07001274 xfer = SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001275 break;
1276 }
1277 }
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001278 return xfer;
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001279}
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001280} // namespace
1281
mtklein148ec592014-10-13 13:17:56 -07001282SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, SkXfermode::kLastMode + 1, create_mode);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001283
reed@android.coma0f5d152009-06-22 17:38:10 +00001284SkXfermode* SkXfermode::Create(Mode mode) {
1285 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001287 if ((unsigned)mode >= kModeCount) {
1288 // report error
1289 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001291
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001292 // Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcover
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001293 // so we can just return NULL from the factory.
1294 if (kSrcOver_Mode == mode) {
1295 return NULL;
1296 }
1297
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001298 return SkSafeRef(cached[mode]);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
reed@google.com43c50c82011-04-14 15:50:52 +00001301SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1302 SkXfermodeProc proc = NULL;
1303 if ((unsigned)mode < kModeCount) {
1304 proc = gProcCoeffs[mode].fProc;
1305 }
1306 return proc;
1307}
1308
1309bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1310 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001311
reed@google.com43c50c82011-04-14 15:50:52 +00001312 if ((unsigned)mode >= (unsigned)kModeCount) {
1313 // illegal mode parameter
1314 return false;
1315 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001316
reed@google.com43c50c82011-04-14 15:50:52 +00001317 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001318
reed@google.com43c50c82011-04-14 15:50:52 +00001319 if (CANNOT_USE_COEFF == rec.fSC) {
1320 return false;
1321 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001322
reed@google.com43c50c82011-04-14 15:50:52 +00001323 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1324 if (src) {
1325 *src = rec.fSC;
1326 }
1327 if (dst) {
1328 *dst = rec.fDC;
1329 }
1330 return true;
1331}
1332
reed@google.com30da7452012-12-17 19:55:24 +00001333bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 if (NULL == xfer) {
1335 if (mode) {
1336 *mode = kSrcOver_Mode;
1337 }
1338 return true;
1339 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001340 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
reed@google.com30da7452012-12-17 19:55:24 +00001343bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001344 // if xfer==null then the mode is srcover
1345 Mode m = kSrcOver_Mode;
1346 if (xfer && !xfer->asMode(&m)) {
1347 return false;
1348 }
1349 return mode == m;
1350}
1351
egdanieldcfb7cf2015-01-22 06:52:29 -08001352bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) {
1353 // if xfer is NULL we treat it as srcOver which always supports coverageAsAlpha
1354 if (!xfer) {
1355 return true;
1356 }
1357
1358 return xfer->supportsCoverageAsAlpha();
1359}
1360
1361bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) {
1362 // if xfer is NULL we treat it as srcOver which is opaque if our src is opaque
1363 if (!xfer) {
1364 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
1365 }
1366
1367 return xfer->isOpaque(opacityType);
1368}
1369
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370///////////////////////////////////////////////////////////////////////////////
1371//////////// 16bit xfermode procs
1372
1373#ifdef SK_DEBUG
1374static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1375static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1376#endif
1377
1378static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1379 SkASSERT(require_255(src));
1380 return SkPixel32ToPixel16(src);
1381}
1382
1383static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1384 return dst;
1385}
1386
1387static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1388 SkASSERT(require_0(src));
1389 return dst;
1390}
1391
1392static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1393 SkASSERT(require_255(src));
1394 return SkPixel32ToPixel16(src);
1395}
1396
1397static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1398 SkASSERT(require_0(src));
1399 return dst;
1400}
1401
1402static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1403 SkASSERT(require_255(src));
1404 return dst;
1405}
1406
1407static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1408 SkASSERT(require_255(src));
1409 return SkPixel32ToPixel16(src);
1410}
1411
1412static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1413 SkASSERT(require_255(src));
1414 return dst;
1415}
1416
1417static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1418 SkASSERT(require_0(src));
1419 return dst;
1420}
1421
1422static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1423 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001424
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425 return SkPackRGB16(
1426 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1427 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1428 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1429}
1430
1431static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1432 SkASSERT(require_0(src));
1433 return dst;
1434}
1435
1436static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1437 SkASSERT(require_255(src));
1438 return SkPixel32ToPixel16(src);
1439}
1440
1441static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1442 SkASSERT(require_255(src));
1443 return dst;
1444}
1445
1446/*********
1447 darken and lighten boil down to this.
1448
1449 darken = (1 - Sa) * Dc + min(Sc, Dc)
1450 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1451
1452 if (Sa == 0) these become
1453 darken = Dc + min(0, Dc) = 0
1454 lighten = Dc + max(0, Dc) = Dc
1455
1456 if (Sa == 1) these become
1457 darken = min(Sc, Dc)
1458 lighten = max(Sc, Dc)
1459*/
1460
1461static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1462 SkASSERT(require_0(src));
1463 return 0;
1464}
1465
1466static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1467 SkASSERT(require_255(src));
1468 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1469 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1470 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1471 return SkPackRGB16(r, g, b);
1472}
1473
1474static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1475 SkASSERT(require_0(src));
1476 return dst;
1477}
1478
1479static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1480 SkASSERT(require_255(src));
1481 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1482 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1483 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1484 return SkPackRGB16(r, g, b);
1485}
1486
1487struct Proc16Rec {
1488 SkXfermodeProc16 fProc16_0;
1489 SkXfermodeProc16 fProc16_255;
1490 SkXfermodeProc16 fProc16_General;
1491};
1492
reed@android.coma0f5d152009-06-22 17:38:10 +00001493static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 { NULL, NULL, NULL }, // CLEAR
1495 { NULL, src_modeproc16_255, NULL },
1496 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1497 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1498 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1499 { NULL, srcin_modeproc16_255, NULL },
1500 { NULL, dstin_modeproc16_255, NULL },
1501 { NULL, NULL, NULL },// SRC_OUT
1502 { dstout_modeproc16_0, NULL, NULL },
1503 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1504 { NULL, dstatop_modeproc16_255, NULL },
1505 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001506
1507 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00001508 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00001509 { NULL, NULL, NULL }, // screen
1510 { NULL, NULL, NULL }, // overlay
1511 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1512 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1513 { NULL, NULL, NULL }, // colordodge
1514 { NULL, NULL, NULL }, // colorburn
1515 { NULL, NULL, NULL }, // hardlight
1516 { NULL, NULL, NULL }, // softlight
1517 { NULL, NULL, NULL }, // difference
1518 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00001519 { NULL, NULL, NULL }, // multiply
1520 { NULL, NULL, NULL }, // hue
1521 { NULL, NULL, NULL }, // saturation
1522 { NULL, NULL, NULL }, // color
1523 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524};
1525
reed@android.coma0f5d152009-06-22 17:38:10 +00001526SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001528 if ((unsigned)mode < kModeCount) {
1529 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530 unsigned a = SkColorGetA(srcColor);
1531
1532 if (0 == a) {
1533 proc16 = rec.fProc16_0;
1534 } else if (255 == a) {
1535 proc16 = rec.fProc16_255;
1536 } else {
1537 proc16 = rec.fProc16_General;
1538 }
1539 }
1540 return proc16;
1541}
1542
caryclark@google.comd26147a2011-12-15 14:16:43 +00001543SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1544 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
caryclark@google.comd26147a2011-12-15 14:16:43 +00001545SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END