blob: ac1ebcccb02c8e3530e3f062684acb5c04a000c5 [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::asCoeff(Coeff* src, Coeff* dst) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000671 return false;
672}
673
reed@google.com30da7452012-12-17 19:55:24 +0000674bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000675 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000676}
677
joshualittb0a8a372014-09-23 09:50:21 -0700678bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrTexture*) const {
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000679 return false;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000680}
681
egdaniel378092f2014-12-03 10:40:13 -0800682bool SkXfermode::asXPFactory(GrXPFactory**) const {
683 return false;
684}
685
686
687#if SK_SUPPORT_GPU
688#include "effects/GrPorterDuffXferProcessor.h"
689
egdaniel58136162015-01-20 10:19:22 -0800690bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000691 if (NULL == xfermode) {
egdaniel58136162015-01-20 10:19:22 -0800692 if (xpf) {
693 *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode);
694 }
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000695 return true;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000696 } else {
egdaniel58136162015-01-20 10:19:22 -0800697 return xfermode->asXPFactory(xpf);
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000698 }
699}
egdaniel378092f2014-12-03 10:40:13 -0800700#else
egdaniel58136162015-01-20 10:19:22 -0800701bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
egdaniel378092f2014-12-03 10:40:13 -0800702 return false;
703}
704#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000705
reed@google.com30da7452012-12-17 19:55:24 +0000706SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000707 // no-op. subclasses should override this
708 return dst;
709}
710
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000711void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
712 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000713 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000714 SkASSERT(dst && src && count >= 0);
715
716 if (NULL == aa) {
717 for (int i = count - 1; i >= 0; --i) {
718 dst[i] = this->xferColor(src[i], dst[i]);
719 }
720 } else {
721 for (int i = count - 1; i >= 0; --i) {
722 unsigned a = aa[i];
723 if (0 != a) {
724 SkPMColor dstC = dst[i];
725 SkPMColor C = this->xferColor(src[i], dstC);
726 if (0xFF != a) {
727 C = SkFourByteInterp(C, dstC, a);
728 }
729 dst[i] = C;
730 }
731 }
732 }
733}
734
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000735void SkXfermode::xfer16(uint16_t* dst,
736 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000737 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000738 SkASSERT(dst && src && count >= 0);
739
740 if (NULL == aa) {
741 for (int i = count - 1; i >= 0; --i) {
742 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
743 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
744 }
745 } else {
746 for (int i = count - 1; i >= 0; --i) {
747 unsigned a = aa[i];
748 if (0 != a) {
749 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
750 SkPMColor C = this->xferColor(src[i], dstC);
751 if (0xFF != a) {
752 C = SkFourByteInterp(C, dstC, a);
753 }
754 dst[i] = SkPixel32ToPixel16_ToU16(C);
755 }
756 }
757 }
758}
759
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000760void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000761 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000762 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000763 SkASSERT(dst && src && count >= 0);
764
765 if (NULL == aa) {
766 for (int i = count - 1; i >= 0; --i) {
767 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
768 dst[i] = SkToU8(SkGetPackedA32(res));
769 }
770 } else {
771 for (int i = count - 1; i >= 0; --i) {
772 unsigned a = aa[i];
773 if (0 != a) {
774 SkAlpha dstA = dst[i];
775 unsigned A = SkGetPackedA32(this->xferColor(src[i],
776 (SkPMColor)(dstA << SK_A32_SHIFT)));
777 if (0xFF != a) {
778 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
779 }
780 dst[i] = SkToU8(A);
781 }
782 }
783 }
784}
785
vandebo@chromium.org48543272011-02-08 19:28:07 +0000786///////////////////////////////////////////////////////////////////////////////
787///////////////////////////////////////////////////////////////////////////////
788
reed9fa60da2014-08-21 07:59:51 -0700789SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
790 uint32_t mode32 = buffer.read32();
senorblanco0f7197b2014-09-24 11:09:38 -0700791 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
reed9fa60da2014-08-21 07:59:51 -0700792 return NULL;
793 }
794 return SkXfermode::Create((SkXfermode::Mode)mode32);
795}
796
797void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
798 buffer.write32(fMode);
799}
reed@google.com52314f82013-11-21 21:05:06 +0000800
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000801bool SkProcCoeffXfermode::asMode(Mode* mode) const {
802 if (mode) {
803 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000804 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000805 return true;
806}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +0000807
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000808bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
809 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +0000810 return false;
811 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000812
813 if (sc) {
814 *sc = fSrcCoeff;
815 }
816 if (dc) {
817 *dc = fDstCoeff;
818 }
819 return true;
820}
821
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000822void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
823 const SkPMColor* SK_RESTRICT src, int count,
824 const SkAlpha* SK_RESTRICT aa) const {
825 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000826
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000827 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000828
bsalomon49f085d2014-09-05 13:34:00 -0700829 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000830 if (NULL == aa) {
831 for (int i = count - 1; i >= 0; --i) {
832 dst[i] = proc(src[i], dst[i]);
833 }
834 } else {
835 for (int i = count - 1; i >= 0; --i) {
836 unsigned a = aa[i];
837 if (0 != a) {
838 SkPMColor dstC = dst[i];
839 SkPMColor C = proc(src[i], dstC);
840 if (a != 0xFF) {
841 C = SkFourByteInterp(C, dstC, a);
842 }
843 dst[i] = C;
844 }
845 }
846 }
847 }
848}
849
850void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
851 const SkPMColor* SK_RESTRICT src, int count,
852 const SkAlpha* SK_RESTRICT aa) const {
853 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000854
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000855 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000856
bsalomon49f085d2014-09-05 13:34:00 -0700857 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000858 if (NULL == aa) {
859 for (int i = count - 1; i >= 0; --i) {
860 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
861 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
862 }
863 } else {
864 for (int i = count - 1; i >= 0; --i) {
865 unsigned a = aa[i];
866 if (0 != a) {
867 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
868 SkPMColor C = proc(src[i], dstC);
869 if (0xFF != a) {
870 C = SkFourByteInterp(C, dstC, a);
871 }
872 dst[i] = SkPixel32ToPixel16_ToU16(C);
873 }
874 }
875 }
876 }
877}
878
879void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
880 const SkPMColor* SK_RESTRICT src, int count,
881 const SkAlpha* SK_RESTRICT aa) const {
882 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000883
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000884 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000885
bsalomon49f085d2014-09-05 13:34:00 -0700886 if (proc) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000887 if (NULL == aa) {
888 for (int i = count - 1; i >= 0; --i) {
889 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
890 dst[i] = SkToU8(SkGetPackedA32(res));
891 }
892 } else {
893 for (int i = count - 1; i >= 0; --i) {
894 unsigned a = aa[i];
895 if (0 != a) {
896 SkAlpha dstA = dst[i];
897 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
898 unsigned A = SkGetPackedA32(res);
899 if (0xFF != a) {
900 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
901 }
902 dst[i] = SkToU8(A);
903 }
904 }
905 }
906 }
907}
908
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000909#if SK_SUPPORT_GPU
egdaniel0063a9b2015-01-15 10:52:32 -0800910#include "effects/GrCustomXfermode.h"
911
joshualittb0a8a372014-09-23 09:50:21 -0700912bool SkProcCoeffXfermode::asFragmentProcessor(GrFragmentProcessor** fp,
913 GrTexture* background) const {
egdaniel0063a9b2015-01-15 10:52:32 -0800914 if (GrCustomXfermode::IsSupportedMode(fMode)) {
joshualittb0a8a372014-09-23 09:50:21 -0700915 if (fp) {
egdaniel0063a9b2015-01-15 10:52:32 -0800916 *fp = GrCustomXfermode::CreateFP(fMode, background);
joshualittb0a8a372014-09-23 09:50:21 -0700917 SkASSERT(*fp);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000918 }
919 return true;
920 }
921 return false;
922}
egdaniel54f0e9d2015-01-16 06:29:47 -0800923
924bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {
egdaniel58136162015-01-20 10:19:22 -0800925 if (CANNOT_USE_COEFF != fSrcCoeff) {
926 if (xp) {
927 *xp = GrPorterDuffXPFactory::Create(fMode);
928 SkASSERT(*xp);
929 }
930 return true;
931 }
932
egdaniel54f0e9d2015-01-16 06:29:47 -0800933 if (GrCustomXfermode::IsSupportedMode(fMode)) {
934 if (xp) {
935 *xp = GrCustomXfermode::CreateXPFactory(fMode);
936 SkASSERT(*xp);
937 }
938 return true;
939 }
940 return false;
941}
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000942#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000943
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +0000944const char* SkXfermode::ModeName(Mode mode) {
945 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
946 const char* gModeStrings[] = {
947 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
948 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
949 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
950 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
951 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
952 };
953 return gModeStrings[mode];
954 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
955}
956
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000957#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000958void SkProcCoeffXfermode::toString(SkString* str) const {
959 str->append("SkProcCoeffXfermode: ");
960
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000961 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +0000962 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000963
964 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +0000965 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000966 };
967
968 str->append(" src: ");
969 if (CANNOT_USE_COEFF == fSrcCoeff) {
970 str->append("can't use");
971 } else {
972 str->append(gCoeffStrings[fSrcCoeff]);
973 }
974
975 str->append(" dst: ");
976 if (CANNOT_USE_COEFF == fDstCoeff) {
977 str->append("can't use");
978 } else {
979 str->append(gCoeffStrings[fDstCoeff]);
980 }
981}
982#endif
983
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984///////////////////////////////////////////////////////////////////////////////
985
986class SkClearXfermode : public SkProcCoeffXfermode {
987public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +0000988 static SkClearXfermode* Create(const ProcCoeff& rec) {
989 return SkNEW_ARGS(SkClearXfermode, (rec));
990 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991
mtklein72c9faa2015-01-09 10:06:39 -0800992 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
993 void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000995 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000996
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +0000998 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000999
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001000 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001};
1002
reed@google.com86ab6c62011-11-28 15:26:14 +00001003void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1004 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001005 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001006 SkASSERT(dst && count >= 0);
1007
1008 if (NULL == aa) {
1009 memset(dst, 0, count << 2);
1010 } else {
1011 for (int i = count - 1; i >= 0; --i) {
1012 unsigned a = aa[i];
1013 if (0xFF == a) {
1014 dst[i] = 0;
1015 } else if (a != 0) {
1016 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1017 }
1018 }
1019 }
1020}
1021void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1022 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001023 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001024 SkASSERT(dst && count >= 0);
1025
1026 if (NULL == aa) {
1027 memset(dst, 0, count);
1028 } else {
1029 for (int i = count - 1; i >= 0; --i) {
1030 unsigned a = aa[i];
1031 if (0xFF == a) {
1032 dst[i] = 0;
1033 } else if (0 != a) {
1034 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1035 }
1036 }
1037 }
1038}
1039
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001040#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001041void SkClearXfermode::toString(SkString* str) const {
1042 this->INHERITED::toString(str);
1043}
1044#endif
1045
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046///////////////////////////////////////////////////////////////////////////////
1047
1048class SkSrcXfermode : public SkProcCoeffXfermode {
1049public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001050 static SkSrcXfermode* Create(const ProcCoeff& rec) {
1051 return SkNEW_ARGS(SkSrcXfermode, (rec));
1052 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053
mtklein72c9faa2015-01-09 10:06:39 -08001054 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1055 void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001057 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001058
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001060 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001061 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062};
1063
reed@google.com86ab6c62011-11-28 15:26:14 +00001064void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1065 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001066 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001067 SkASSERT(dst && src && count >= 0);
1068
1069 if (NULL == aa) {
1070 memcpy(dst, src, count << 2);
1071 } else {
1072 for (int i = count - 1; i >= 0; --i) {
1073 unsigned a = aa[i];
1074 if (a == 0xFF) {
1075 dst[i] = src[i];
1076 } else if (a != 0) {
1077 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1078 }
1079 }
1080 }
1081}
1082
1083void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1084 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001085 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001086 SkASSERT(dst && src && count >= 0);
1087
1088 if (NULL == aa) {
1089 for (int i = count - 1; i >= 0; --i) {
1090 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1091 }
1092 } else {
1093 for (int i = count - 1; i >= 0; --i) {
1094 unsigned a = aa[i];
1095 if (0 != a) {
1096 unsigned srcA = SkGetPackedA32(src[i]);
1097 if (a == 0xFF) {
1098 dst[i] = SkToU8(srcA);
1099 } else {
1100 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1101 }
1102 }
1103 }
1104 }
1105}
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001106#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001107void SkSrcXfermode::toString(SkString* str) const {
1108 this->INHERITED::toString(str);
1109}
1110#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001111
reed@google.com30da7452012-12-17 19:55:24 +00001112///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001113
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114class SkDstInXfermode : public SkProcCoeffXfermode {
1115public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001116 static SkDstInXfermode* Create(const ProcCoeff& rec) {
1117 return SkNEW_ARGS(SkDstInXfermode, (rec));
1118 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001119
mtklein72c9faa2015-01-09 10:06:39 -08001120 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001121
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001122 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001123
1124private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001125 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001126
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127 typedef SkProcCoeffXfermode INHERITED;
1128};
1129
reed@google.com86ab6c62011-11-28 15:26:14 +00001130void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1131 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001132 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001133 SkASSERT(dst && src);
1134
1135 if (count <= 0) {
1136 return;
1137 }
bsalomon49f085d2014-09-05 13:34:00 -07001138 if (aa) {
reed@google.com86ab6c62011-11-28 15:26:14 +00001139 return this->INHERITED::xfer32(dst, src, count, aa);
1140 }
1141
1142 do {
1143 unsigned a = SkGetPackedA32(*src);
1144 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1145 dst++;
1146 src++;
1147 } while (--count != 0);
1148}
1149
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001150#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001151void SkDstInXfermode::toString(SkString* str) const {
1152 this->INHERITED::toString(str);
1153}
1154#endif
1155
reed@google.com30da7452012-12-17 19:55:24 +00001156///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001157
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158class SkDstOutXfermode : public SkProcCoeffXfermode {
1159public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001160 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
1161 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1162 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001163
mtklein72c9faa2015-01-09 10:06:39 -08001164 void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001165
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001166 SK_TO_STRING_OVERRIDE()
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001167
1168private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001169 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001170
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171 typedef SkProcCoeffXfermode INHERITED;
1172};
1173
reed@google.com86ab6c62011-11-28 15:26:14 +00001174void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1175 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001176 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001177 SkASSERT(dst && src);
1178
1179 if (count <= 0) {
1180 return;
1181 }
bsalomon49f085d2014-09-05 13:34:00 -07001182 if (aa) {
reed@google.com86ab6c62011-11-28 15:26:14 +00001183 return this->INHERITED::xfer32(dst, src, count, aa);
1184 }
1185
1186 do {
1187 unsigned a = SkGetPackedA32(*src);
1188 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1189 dst++;
1190 src++;
1191 } while (--count != 0);
1192}
1193
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001194#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001195void SkDstOutXfermode::toString(SkString* str) const {
1196 this->INHERITED::toString(str);
1197}
1198#endif
1199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200///////////////////////////////////////////////////////////////////////////////
1201
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001202extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec, SkXfermode::Mode mode);
commit-bot@chromium.orgd6118642013-12-06 11:32:27 +00001203extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001204
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001205// Technically, can't be static and passed as a template parameter. So we use anonymous namespace.
1206namespace {
1207SkXfermode* create_mode(int iMode) {
1208 SkXfermode::Mode mode = (SkXfermode::Mode)iMode;
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001209
1210 ProcCoeff rec = gProcCoeffs[mode];
1211 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
1212 if (pp != NULL) {
1213 rec.fProc = pp;
1214 }
1215
1216 SkXfermode* xfer = NULL;
1217 // check if we have a platform optim for that
1218 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
1219 if (xfm != NULL) {
1220 xfer = xfm;
1221 } else {
1222 // All modes can in theory be represented by the ProcCoeff rec, since
1223 // it contains function ptrs. However, a few modes are both simple and
1224 // commonly used, so we call those out for their own subclasses here.
1225 switch (mode) {
1226 case SkXfermode::kClear_Mode:
1227 xfer = SkClearXfermode::Create(rec);
1228 break;
1229 case SkXfermode::kSrc_Mode:
1230 xfer = SkSrcXfermode::Create(rec);
1231 break;
1232 case SkXfermode::kSrcOver_Mode:
1233 SkASSERT(false); // should not land here
1234 break;
1235 case SkXfermode::kDstIn_Mode:
1236 xfer = SkDstInXfermode::Create(rec);
1237 break;
1238 case SkXfermode::kDstOut_Mode:
1239 xfer = SkDstOutXfermode::Create(rec);
1240 break;
1241 default:
1242 // no special-case, just rely in the rec and its function-ptrs
reed9fa60da2014-08-21 07:59:51 -07001243 xfer = SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001244 break;
1245 }
1246 }
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001247 return xfer;
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001248}
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001249} // namespace
1250
mtklein148ec592014-10-13 13:17:56 -07001251SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, SkXfermode::kLastMode + 1, create_mode);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001252
reed@android.coma0f5d152009-06-22 17:38:10 +00001253SkXfermode* SkXfermode::Create(Mode mode) {
1254 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001256 if ((unsigned)mode >= kModeCount) {
1257 // report error
1258 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001260
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001261 // Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcover
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001262 // so we can just return NULL from the factory.
1263 if (kSrcOver_Mode == mode) {
1264 return NULL;
1265 }
1266
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00001267 return SkSafeRef(cached[mode]);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268}
1269
reed@google.com43c50c82011-04-14 15:50:52 +00001270SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1271 SkXfermodeProc proc = NULL;
1272 if ((unsigned)mode < kModeCount) {
1273 proc = gProcCoeffs[mode].fProc;
1274 }
1275 return proc;
1276}
1277
1278bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1279 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001280
reed@google.com43c50c82011-04-14 15:50:52 +00001281 if ((unsigned)mode >= (unsigned)kModeCount) {
1282 // illegal mode parameter
1283 return false;
1284 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001285
reed@google.com43c50c82011-04-14 15:50:52 +00001286 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001287
reed@google.com43c50c82011-04-14 15:50:52 +00001288 if (CANNOT_USE_COEFF == rec.fSC) {
1289 return false;
1290 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001291
reed@google.com43c50c82011-04-14 15:50:52 +00001292 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1293 if (src) {
1294 *src = rec.fSC;
1295 }
1296 if (dst) {
1297 *dst = rec.fDC;
1298 }
1299 return true;
1300}
1301
reed@google.com30da7452012-12-17 19:55:24 +00001302bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 if (NULL == xfer) {
1304 if (mode) {
1305 *mode = kSrcOver_Mode;
1306 }
1307 return true;
1308 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001309 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310}
1311
reed@google.com30da7452012-12-17 19:55:24 +00001312bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001313 if (NULL == xfer) {
1314 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 }
reed@google.com43c50c82011-04-14 15:50:52 +00001316 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
reed@google.com30da7452012-12-17 19:55:24 +00001319bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001320 // if xfer==null then the mode is srcover
1321 Mode m = kSrcOver_Mode;
1322 if (xfer && !xfer->asMode(&m)) {
1323 return false;
1324 }
1325 return mode == m;
1326}
1327
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328///////////////////////////////////////////////////////////////////////////////
1329//////////// 16bit xfermode procs
1330
1331#ifdef SK_DEBUG
1332static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1333static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1334#endif
1335
1336static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1337 SkASSERT(require_255(src));
1338 return SkPixel32ToPixel16(src);
1339}
1340
1341static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1342 return dst;
1343}
1344
1345static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1346 SkASSERT(require_0(src));
1347 return dst;
1348}
1349
1350static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1351 SkASSERT(require_255(src));
1352 return SkPixel32ToPixel16(src);
1353}
1354
1355static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1356 SkASSERT(require_0(src));
1357 return dst;
1358}
1359
1360static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1361 SkASSERT(require_255(src));
1362 return dst;
1363}
1364
1365static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1366 SkASSERT(require_255(src));
1367 return SkPixel32ToPixel16(src);
1368}
1369
1370static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1371 SkASSERT(require_255(src));
1372 return dst;
1373}
1374
1375static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1376 SkASSERT(require_0(src));
1377 return dst;
1378}
1379
1380static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1381 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001382
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 return SkPackRGB16(
1384 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1385 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1386 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1387}
1388
1389static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1390 SkASSERT(require_0(src));
1391 return dst;
1392}
1393
1394static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1395 SkASSERT(require_255(src));
1396 return SkPixel32ToPixel16(src);
1397}
1398
1399static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1400 SkASSERT(require_255(src));
1401 return dst;
1402}
1403
1404/*********
1405 darken and lighten boil down to this.
1406
1407 darken = (1 - Sa) * Dc + min(Sc, Dc)
1408 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1409
1410 if (Sa == 0) these become
1411 darken = Dc + min(0, Dc) = 0
1412 lighten = Dc + max(0, Dc) = Dc
1413
1414 if (Sa == 1) these become
1415 darken = min(Sc, Dc)
1416 lighten = max(Sc, Dc)
1417*/
1418
1419static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1420 SkASSERT(require_0(src));
1421 return 0;
1422}
1423
1424static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1425 SkASSERT(require_255(src));
1426 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1427 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1428 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1429 return SkPackRGB16(r, g, b);
1430}
1431
1432static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1433 SkASSERT(require_0(src));
1434 return dst;
1435}
1436
1437static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1438 SkASSERT(require_255(src));
1439 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1440 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1441 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1442 return SkPackRGB16(r, g, b);
1443}
1444
1445struct Proc16Rec {
1446 SkXfermodeProc16 fProc16_0;
1447 SkXfermodeProc16 fProc16_255;
1448 SkXfermodeProc16 fProc16_General;
1449};
1450
reed@android.coma0f5d152009-06-22 17:38:10 +00001451static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452 { NULL, NULL, NULL }, // CLEAR
1453 { NULL, src_modeproc16_255, NULL },
1454 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1455 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1456 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1457 { NULL, srcin_modeproc16_255, NULL },
1458 { NULL, dstin_modeproc16_255, NULL },
1459 { NULL, NULL, NULL },// SRC_OUT
1460 { dstout_modeproc16_0, NULL, NULL },
1461 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1462 { NULL, dstatop_modeproc16_255, NULL },
1463 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001464
1465 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00001466 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00001467 { NULL, NULL, NULL }, // screen
1468 { NULL, NULL, NULL }, // overlay
1469 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1470 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1471 { NULL, NULL, NULL }, // colordodge
1472 { NULL, NULL, NULL }, // colorburn
1473 { NULL, NULL, NULL }, // hardlight
1474 { NULL, NULL, NULL }, // softlight
1475 { NULL, NULL, NULL }, // difference
1476 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00001477 { NULL, NULL, NULL }, // multiply
1478 { NULL, NULL, NULL }, // hue
1479 { NULL, NULL, NULL }, // saturation
1480 { NULL, NULL, NULL }, // color
1481 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482};
1483
reed@android.coma0f5d152009-06-22 17:38:10 +00001484SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001486 if ((unsigned)mode < kModeCount) {
1487 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 unsigned a = SkColorGetA(srcColor);
1489
1490 if (0 == a) {
1491 proc16 = rec.fProc16_0;
1492 } else if (255 == a) {
1493 proc16 = rec.fProc16_255;
1494 } else {
1495 proc16 = rec.fProc16_General;
1496 }
1497 }
1498 return proc16;
1499}
1500
caryclark@google.comd26147a2011-12-15 14:16:43 +00001501SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1502 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
caryclark@google.comd26147a2011-12-15 14:16:43 +00001503SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END