blob: 32a544c2af3f02914199035af32dcb31174d1ed0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkXfermode.h"
commit-bot@chromium.orgc524e982014-04-09 15:43:46 +000011#include "SkXfermode_opts_SSE2.h"
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +000012#include "SkXfermode_proccoeff.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkColorPriv.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000014#include "SkMathPriv.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000015#include "SkOnce.h"
16#include "SkReadBuffer.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000017#include "SkString.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000018#include "SkUtilsArm.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000019#include "SkWriteBuffer.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000020
21#if !SK_ARM_NEON_IS_NONE
22#include "SkXfermode_opts_arm_neon.h"
23#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
25#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
26
reed@android.comfc25abd2009-01-15 14:38:33 +000027#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000028// idea for higher precision blends in xfer procs (and slightly faster)
29// see DstATop as a probable caller
30static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
31 SkASSERT(a <= 255);
32 SkASSERT(b <= 255);
33 SkASSERT(c <= 255);
34 SkASSERT(d <= 255);
35 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
36 unsigned result = (prod + (prod >> 8)) >> 8;
37 SkASSERT(result <= 255);
38 return result;
39}
reed@android.comfc25abd2009-01-15 14:38:33 +000040#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000041
deanm@chromium.orgda946992009-07-03 12:54:24 +000042static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000043 SkASSERT(a <= 255);
44 SkASSERT(b <= 255);
45 unsigned sum = a + b;
46 if (sum > 255) {
47 sum = 255;
48 }
49 return sum;
50}
51
deanm@chromium.orgda946992009-07-03 12:54:24 +000052static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000053 if (n < 0) {
54 n = 0;
55 } else if (n > 255) {
56 n = 255;
57 }
58 return n;
59}
60
deanm@chromium.orgda946992009-07-03 12:54:24 +000061static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000062 if (prod <= 0) {
63 return 0;
64 } else if (prod >= 255*255) {
65 return 255;
66 } else {
67 return SkDiv255Round(prod);
68 }
69}
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071///////////////////////////////////////////////////////////////////////////////
72
reed@android.com8a1c16f2008-12-17 15:59:43 +000073// kClear_Mode, //!< [0, 0]
74static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
75 return 0;
76}
77
78// kSrc_Mode, //!< [Sa, Sc]
79static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
80 return src;
81}
82
83// kDst_Mode, //!< [Da, Dc]
84static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
85 return dst;
86}
87
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000088// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000089static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000090#if 0
91 // this is the old, more-correct way, but it doesn't guarantee that dst==255
92 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000094#else
95 // this is slightly faster, but more importantly guarantees that dst==255
96 // will always stay opaque
97 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
98#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000099}
100
reed@android.com1116fb22009-03-03 20:31:12 +0000101// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000103 // this is the reverse of srcover, just flipping src and dst
104 // see srcover's comment about the 256 for opaqueness guarantees
105 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
107
108// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
109static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
110 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
111}
112
113// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
114static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
115 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
116}
117
118// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
119static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
120 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
121}
122
123// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
124static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
125 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
126}
127
128// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
129static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
130 unsigned sa = SkGetPackedA32(src);
131 unsigned da = SkGetPackedA32(dst);
132 unsigned isa = 255 - sa;
133
134 return SkPackARGB32(da,
135 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
136 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
137 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
138 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
139 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
140 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
141}
142
143// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
144static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
145 unsigned sa = SkGetPackedA32(src);
146 unsigned da = SkGetPackedA32(dst);
147 unsigned ida = 255 - da;
148
149 return SkPackARGB32(sa,
150 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
151 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
152 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
153 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
154 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
155 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
156}
157
158// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
159static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
160 unsigned sa = SkGetPackedA32(src);
161 unsigned da = SkGetPackedA32(dst);
162 unsigned isa = 255 - sa;
163 unsigned ida = 255 - da;
164
165 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
166 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
167 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
168 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
169 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
170 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
171 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
172}
173
reed@android.coma0f5d152009-06-22 17:38:10 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
reed@android.coma0f5d152009-06-22 17:38:10 +0000176// kPlus_Mode
177static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000178 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000179 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
180 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
181 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000182 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000185// kModulate_Mode
186static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
188 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
189 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
190 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
191 return SkPackARGB32(a, r, g, b);
192}
193
reed@android.coma0f5d152009-06-22 17:38:10 +0000194static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 return a + b - SkAlphaMulAlpha(a, b);
196}
reed@google.com25cfa692013-02-04 20:06:00 +0000197
198// kMultiply_Mode
199// B(Cb, Cs) = Cb x Cs
200// multiply uses its own version of blendfunc_byte because sa and da are not needed
201static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
202 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
203}
204
205static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
206 int sa = SkGetPackedA32(src);
207 int da = SkGetPackedA32(dst);
208 int a = srcover_byte(sa, da);
209 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
210 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
211 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
212 return SkPackARGB32(a, r, g, b);
213}
214
215// kScreen_Mode
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000217 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
218 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
219 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
220 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 return SkPackARGB32(a, r, g, b);
222}
223
reed@android.coma0f5d152009-06-22 17:38:10 +0000224// kOverlay_Mode
225static inline int overlay_byte(int sc, int dc, int sa, int da) {
226 int tmp = sc * (255 - da) + dc * (255 - sa);
227 int rc;
228 if (2 * dc <= da) {
229 rc = 2 * sc * dc;
230 } else {
231 rc = sa * da - 2 * (da - dc) * (sa - sc);
232 }
233 return clamp_div255round(rc + tmp);
234}
235static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
236 int sa = SkGetPackedA32(src);
237 int da = SkGetPackedA32(dst);
238 int a = srcover_byte(sa, da);
239 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
240 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
241 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
242 return SkPackARGB32(a, r, g, b);
243}
244
245// kDarken_Mode
246static inline int darken_byte(int sc, int dc, int sa, int da) {
247 int sd = sc * da;
248 int ds = dc * sa;
249 if (sd < ds) {
250 // srcover
251 return sc + dc - SkDiv255Round(ds);
252 } else {
253 // dstover
254 return dc + sc - SkDiv255Round(sd);
255 }
256}
257static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
258 int sa = SkGetPackedA32(src);
259 int da = SkGetPackedA32(dst);
260 int a = srcover_byte(sa, da);
261 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
262 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
263 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
264 return SkPackARGB32(a, r, g, b);
265}
266
267// kLighten_Mode
268static inline int lighten_byte(int sc, int dc, int sa, int da) {
269 int sd = sc * da;
270 int ds = dc * sa;
271 if (sd > ds) {
272 // srcover
273 return sc + dc - SkDiv255Round(ds);
274 } else {
275 // dstover
276 return dc + sc - SkDiv255Round(sd);
277 }
278}
279static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
280 int sa = SkGetPackedA32(src);
281 int da = SkGetPackedA32(dst);
282 int a = srcover_byte(sa, da);
283 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
284 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
285 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
286 return SkPackARGB32(a, r, g, b);
287}
288
289// kColorDodge_Mode
290static inline int colordodge_byte(int sc, int dc, int sa, int da) {
291 int diff = sa - sc;
292 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000293 if (0 == dc) {
294 return SkAlphaMulAlpha(sc, 255 - da);
295 } else if (0 == diff) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000296 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000297 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000298 diff = dc * sa / diff;
299 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000300 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000301 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000302}
303static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000304 int sa = SkGetPackedA32(src);
305 int da = SkGetPackedA32(dst);
306 int a = srcover_byte(sa, da);
307 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
308 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
309 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.coma0f5d152009-06-22 17:38:10 +0000310 return SkPackARGB32(a, r, g, b);
311}
312
313// kColorBurn_Mode
314static inline int colorburn_byte(int sc, int dc, int sa, int da) {
315 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000316 if (dc == da) {
317 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000318 } else if (0 == sc) {
319 return SkAlphaMulAlpha(dc, 255 - sa);
320 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000321 int tmp = (da - dc) * sa / sc;
322 rc = sa * (da - ((da < tmp) ? da : tmp))
323 + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000324 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000325 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000326}
327static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000328 int sa = SkGetPackedA32(src);
329 int da = SkGetPackedA32(dst);
330 int a = srcover_byte(sa, da);
331 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
332 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
333 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
334 return SkPackARGB32(a, r, g, b);
335}
336
337// kHardLight_Mode
338static inline int hardlight_byte(int sc, int dc, int sa, int da) {
339 int rc;
340 if (2 * sc <= sa) {
341 rc = 2 * sc * dc;
342 } else {
343 rc = sa * da - 2 * (da - dc) * (sa - sc);
344 }
345 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
346}
347static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
348 int sa = SkGetPackedA32(src);
349 int da = SkGetPackedA32(dst);
350 int a = srcover_byte(sa, da);
351 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
352 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
353 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
354 return SkPackARGB32(a, r, g, b);
355}
356
357// returns 255 * sqrt(n/255)
358static U8CPU sqrt_unit_byte(U8CPU n) {
359 return SkSqrtBits(n, 15+4);
360}
361
362// kSoftLight_Mode
363static inline int softlight_byte(int sc, int dc, int sa, int da) {
364 int m = da ? dc * 256 / da : 0;
365 int rc;
366 if (2 * sc <= sa) {
367 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
368 } else if (4 * dc <= da) {
369 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
370 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
371 } else {
372 int tmp = sqrt_unit_byte(m) - m;
373 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
374 }
375 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
376}
377static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
378 int sa = SkGetPackedA32(src);
379 int da = SkGetPackedA32(dst);
380 int a = srcover_byte(sa, da);
381 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
382 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
383 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
384 return SkPackARGB32(a, r, g, b);
385}
386
387// kDifference_Mode
388static inline int difference_byte(int sc, int dc, int sa, int da) {
389 int tmp = SkMin32(sc * da, dc * sa);
390 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
391}
392static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
393 int sa = SkGetPackedA32(src);
394 int da = SkGetPackedA32(dst);
395 int a = srcover_byte(sa, da);
396 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
397 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
398 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
399 return SkPackARGB32(a, r, g, b);
400}
401
402// kExclusion_Mode
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000403static inline int exclusion_byte(int sc, int dc, int, int) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000404 // this equations is wacky, wait for SVG to confirm it
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000405 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
406
407 // The above equation can be simplified as follows
408 int r = 255*(sc + dc) - 2 * sc * dc;
reed@android.coma0f5d152009-06-22 17:38:10 +0000409 return clamp_div255round(r);
410}
411static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
412 int sa = SkGetPackedA32(src);
413 int da = SkGetPackedA32(dst);
414 int a = srcover_byte(sa, da);
415 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
416 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
417 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000418 return SkPackARGB32(a, r, g, b);
419}
420
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000421// The CSS compositing spec introduces the following formulas:
422// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
423// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
424// while PDF and CG uses the one from Rec. Rec. 601
425// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
426static inline int Lum(int r, int g, int b)
427{
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000428 return SkDiv255Round(r * 77 + g * 150 + b * 28);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000429}
430
431static inline int min2(int a, int b) { return a < b ? a : b; }
432static inline int max2(int a, int b) { return a > b ? a : b; }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000433#define minimum(a, b, c) min2(min2(a, b), c)
434#define maximum(a, b, c) max2(max2(a, b), c)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000435
436static inline int Sat(int r, int g, int b) {
437 return maximum(r, g, b) - minimum(r, g, b);
438}
439
440static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
reed@google.com3c1ea3a2013-03-07 15:31:58 +0000441 if(*Cmax > *Cmin) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000442 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000443 *Cmax = s;
444 } else {
445 *Cmax = 0;
446 *Cmid = 0;
447 }
448
449 *Cmin = 0;
450}
451
452static inline void SetSat(int* r, int* g, int* b, int s) {
453 if(*r <= *g) {
454 if(*g <= *b) {
455 setSaturationComponents(r, g, b, s);
456 } else if(*r <= *b) {
457 setSaturationComponents(r, b, g, s);
458 } else {
459 setSaturationComponents(b, r, g, s);
460 }
461 } else if(*r <= *b) {
462 setSaturationComponents(g, r, b, s);
463 } else if(*g <= *b) {
464 setSaturationComponents(g, b, r, s);
465 } else {
466 setSaturationComponents(b, g, r, s);
467 }
468}
469
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000470static inline void clipColor(int* r, int* g, int* b, int a) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000471 int L = Lum(*r, *g, *b);
472 int n = minimum(*r, *g, *b);
473 int x = maximum(*r, *g, *b);
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000474 int denom;
475 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
476 *r = L + SkMulDiv(*r - L, L, denom);
477 *g = L + SkMulDiv(*g - L, L, denom);
478 *b = L + SkMulDiv(*b - L, L, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000479 }
480
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000481 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
482 int numer = a - L;
483 *r = L + SkMulDiv(*r - L, numer, denom);
484 *g = L + SkMulDiv(*g - L, numer, denom);
485 *b = L + SkMulDiv(*b - L, numer, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000486 }
487}
488
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000489static inline void SetLum(int* r, int* g, int* b, int a, int l) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000490 int d = l - Lum(*r, *g, *b);
491 *r += d;
492 *g += d;
493 *b += d;
494
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000495 clipColor(r, g, b, a);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000496}
497
498// non-separable blend modes are done in non-premultiplied alpha
499#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000500 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000501
502// kHue_Mode
503// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
504// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
505static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
506 int sr = SkGetPackedR32(src);
507 int sg = SkGetPackedG32(src);
508 int sb = SkGetPackedB32(src);
509 int sa = SkGetPackedA32(src);
510
511 int dr = SkGetPackedR32(dst);
512 int dg = SkGetPackedG32(dst);
513 int db = SkGetPackedB32(dst);
514 int da = SkGetPackedA32(dst);
515 int Sr, Sg, Sb;
516
517 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000518 Sr = sr * sa;
519 Sg = sg * sa;
520 Sb = sb * sa;
521 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
522 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000523 } else {
524 Sr = 0;
525 Sg = 0;
526 Sb = 0;
527 }
528
529 int a = srcover_byte(sa, da);
530 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
531 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
532 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
533 return SkPackARGB32(a, r, g, b);
534}
535
536// kSaturation_Mode
537// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000538// 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 +0000539static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
540 int sr = SkGetPackedR32(src);
541 int sg = SkGetPackedG32(src);
542 int sb = SkGetPackedB32(src);
543 int sa = SkGetPackedA32(src);
544
545 int dr = SkGetPackedR32(dst);
546 int dg = SkGetPackedG32(dst);
547 int db = SkGetPackedB32(dst);
548 int da = SkGetPackedA32(dst);
549 int Dr, Dg, Db;
550
551 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000552 Dr = dr * sa;
553 Dg = dg * sa;
554 Db = db * sa;
555 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
556 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000557 } else {
558 Dr = 0;
559 Dg = 0;
560 Db = 0;
561 }
562
563 int a = srcover_byte(sa, da);
564 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
565 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
566 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
567 return SkPackARGB32(a, r, g, b);
568}
569
570// kColor_Mode
571// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000572// 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 +0000573static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
574 int sr = SkGetPackedR32(src);
575 int sg = SkGetPackedG32(src);
576 int sb = SkGetPackedB32(src);
577 int sa = SkGetPackedA32(src);
578
579 int dr = SkGetPackedR32(dst);
580 int dg = SkGetPackedG32(dst);
581 int db = SkGetPackedB32(dst);
582 int da = SkGetPackedA32(dst);
583 int Sr, Sg, Sb;
584
585 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000586 Sr = sr * da;
587 Sg = sg * da;
588 Sb = sb * da;
589 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000590 } else {
591 Sr = 0;
592 Sg = 0;
593 Sb = 0;
594 }
595
596 int a = srcover_byte(sa, da);
597 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
598 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
599 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
600 return SkPackARGB32(a, r, g, b);
601}
602
603// kLuminosity_Mode
604// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000605// 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 +0000606static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
607 int sr = SkGetPackedR32(src);
608 int sg = SkGetPackedG32(src);
609 int sb = SkGetPackedB32(src);
610 int sa = SkGetPackedA32(src);
611
612 int dr = SkGetPackedR32(dst);
613 int dg = SkGetPackedG32(dst);
614 int db = SkGetPackedB32(dst);
615 int da = SkGetPackedA32(dst);
616 int Dr, Dg, Db;
617
618 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000619 Dr = dr * sa;
620 Dg = dg * sa;
621 Db = db * sa;
622 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000623 } else {
624 Dr = 0;
625 Dg = 0;
626 Db = 0;
627 }
628
629 int a = srcover_byte(sa, da);
630 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
631 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
632 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
633 return SkPackARGB32(a, r, g, b);
634}
635
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000636const ProcCoeff gProcCoeffs[] = {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000637 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
638 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
639 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
640 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
641 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
642 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
643 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
644 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
645 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
646 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
647 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
648 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
649
reed@google.com521e34e2011-04-12 18:55:21 +0000650 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000651 { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
bsalomon@google.comb0091b82013-04-15 15:16:47 +0000652 { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000653 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
654 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
655 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
656 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
657 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
658 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
659 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
660 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
661 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed@google.com25cfa692013-02-04 20:06:00 +0000662 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000663 { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
664 { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
665 { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
666 { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000667};
668
669///////////////////////////////////////////////////////////////////////////////
670
reed@google.com30da7452012-12-17 19:55:24 +0000671bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000672 return false;
673}
674
reed@google.com30da7452012-12-17 19:55:24 +0000675bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000676 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000677}
678
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000679bool SkXfermode::asNewEffect(GrEffectRef** effect, GrTexture* background) const {
680 return false;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000681}
682
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000683bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000684 GrEffectRef** effect,
685 Coeff* src,
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000686 Coeff* dst,
687 GrTexture* background) {
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000688 if (NULL == xfermode) {
689 return ModeAsCoeff(kSrcOver_Mode, src, dst);
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000690 } else if (xfermode->asCoeff(src, dst)) {
691 return true;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000692 } else {
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +0000693 return xfermode->asNewEffect(effect, background);
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000694 }
695}
696
reed@google.com30da7452012-12-17 19:55:24 +0000697SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000698 // no-op. subclasses should override this
699 return dst;
700}
701
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000702void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
703 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000704 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000705 SkASSERT(dst && src && count >= 0);
706
707 if (NULL == aa) {
708 for (int i = count - 1; i >= 0; --i) {
709 dst[i] = this->xferColor(src[i], dst[i]);
710 }
711 } else {
712 for (int i = count - 1; i >= 0; --i) {
713 unsigned a = aa[i];
714 if (0 != a) {
715 SkPMColor dstC = dst[i];
716 SkPMColor C = this->xferColor(src[i], dstC);
717 if (0xFF != a) {
718 C = SkFourByteInterp(C, dstC, a);
719 }
720 dst[i] = C;
721 }
722 }
723 }
724}
725
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000726void SkXfermode::xfer16(uint16_t* dst,
727 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000728 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000729 SkASSERT(dst && src && count >= 0);
730
731 if (NULL == aa) {
732 for (int i = count - 1; i >= 0; --i) {
733 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
734 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
735 }
736 } else {
737 for (int i = count - 1; i >= 0; --i) {
738 unsigned a = aa[i];
739 if (0 != a) {
740 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
741 SkPMColor C = this->xferColor(src[i], dstC);
742 if (0xFF != a) {
743 C = SkFourByteInterp(C, dstC, a);
744 }
745 dst[i] = SkPixel32ToPixel16_ToU16(C);
746 }
747 }
748 }
749}
750
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000751void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000752 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000753 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000754 SkASSERT(dst && src && count >= 0);
755
756 if (NULL == aa) {
757 for (int i = count - 1; i >= 0; --i) {
758 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
759 dst[i] = SkToU8(SkGetPackedA32(res));
760 }
761 } else {
762 for (int i = count - 1; i >= 0; --i) {
763 unsigned a = aa[i];
764 if (0 != a) {
765 SkAlpha dstA = dst[i];
766 unsigned A = SkGetPackedA32(this->xferColor(src[i],
767 (SkPMColor)(dstA << SK_A32_SHIFT)));
768 if (0xFF != a) {
769 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
770 }
771 dst[i] = SkToU8(A);
772 }
773 }
774 }
775}
776
777///////////////////////////////////////////////////////////////////////////////
778
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000779void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
780 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000781 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000782 SkASSERT(dst && src && count >= 0);
783
784 SkXfermodeProc proc = fProc;
785
786 if (NULL != proc) {
787 if (NULL == aa) {
788 for (int i = count - 1; i >= 0; --i) {
789 dst[i] = proc(src[i], dst[i]);
790 }
791 } else {
792 for (int i = count - 1; i >= 0; --i) {
793 unsigned a = aa[i];
794 if (0 != a) {
795 SkPMColor dstC = dst[i];
796 SkPMColor C = proc(src[i], dstC);
797 if (a != 0xFF) {
798 C = SkFourByteInterp(C, dstC, a);
799 }
800 dst[i] = C;
801 }
802 }
803 }
804 }
805}
806
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000807void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
808 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000809 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000810 SkASSERT(dst && src && count >= 0);
811
812 SkXfermodeProc proc = fProc;
813
814 if (NULL != proc) {
815 if (NULL == aa) {
816 for (int i = count - 1; i >= 0; --i) {
817 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
818 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
819 }
820 } else {
821 for (int i = count - 1; i >= 0; --i) {
822 unsigned a = aa[i];
823 if (0 != a) {
824 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
825 SkPMColor C = proc(src[i], dstC);
826 if (0xFF != a) {
827 C = SkFourByteInterp(C, dstC, a);
828 }
829 dst[i] = SkPixel32ToPixel16_ToU16(C);
830 }
831 }
832 }
833 }
834}
835
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000836void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
837 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000838 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000839 SkASSERT(dst && src && count >= 0);
840
841 SkXfermodeProc proc = fProc;
842
843 if (NULL != proc) {
844 if (NULL == aa) {
845 for (int i = count - 1; i >= 0; --i) {
846 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
847 dst[i] = SkToU8(SkGetPackedA32(res));
848 }
849 } else {
850 for (int i = count - 1; i >= 0; --i) {
851 unsigned a = aa[i];
852 if (0 != a) {
853 SkAlpha dstA = dst[i];
854 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
855 unsigned A = SkGetPackedA32(res);
856 if (0xFF != a) {
857 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
858 }
859 dst[i] = SkToU8(A);
860 }
861 }
862 }
863 }
864}
865
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000866SkProcXfermode::SkProcXfermode(SkReadBuffer& buffer)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000867 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000868 fProc = NULL;
869 if (!buffer.isCrossProcess()) {
870 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
871 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000872}
873
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000874void SkProcXfermode::flatten(SkWriteBuffer& buffer) const {
djsollen@google.com54924242012-03-29 15:18:04 +0000875 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000876 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000877 buffer.writeFunctionPtr((void*)fProc);
878 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000879}
880
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000881#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000882void SkProcXfermode::toString(SkString* str) const {
883 str->appendf("SkProcXfermode: %p", fProc);
884}
885#endif
886
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000887//////////////////////////////////////////////////////////////////////////////
888
889#if SK_SUPPORT_GPU
890
891#include "GrEffect.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000892#include "GrCoordTransform.h"
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000893#include "GrEffectUnitTest.h"
894#include "GrTBackendEffectFactory.h"
895#include "gl/GrGLEffect.h"
896
897/**
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000898 * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000899 */
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000900class XferEffect : public GrEffect {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000901public:
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000902 static bool IsSupportedMode(SkXfermode::Mode mode) {
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000903 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000904 }
905
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000906 static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000907 if (!IsSupportedMode(mode)) {
908 return NULL;
909 } else {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000910 AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000911 return CreateEffectRef(effect);
912 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000913 }
914
915 virtual void getConstantColorComponents(GrColor* color,
916 uint32_t* validFlags) const SK_OVERRIDE {
917 *validFlags = 0;
918 }
919
920 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000921 return GrTBackendEffectFactory<XferEffect>::getInstance();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000922 }
923
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000924 static const char* Name() { return "XferEffect"; }
925
926 SkXfermode::Mode mode() const { return fMode; }
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000927 const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000928
929 class GLEffect : public GrGLEffect {
930 public:
931 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
bsalomon@google.com77af6802013-10-02 13:04:56 +0000932 : GrGLEffect(factory) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000933 }
934 virtual void emitCode(GrGLShaderBuilder* builder,
935 const GrDrawEffect& drawEffect,
936 EffectKey key,
937 const char* outputColor,
938 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000939 const TransformedCoordsArray& coords,
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000940 const TextureSamplerArray& samplers) SK_OVERRIDE {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000941 SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
942 const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
943 const char* dstColor;
944 if (backgroundTex) {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000945 dstColor = "bgColor";
946 builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
bsalomon@google.com77af6802013-10-02 13:04:56 +0000947 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000948 builder->fsCodeAppendf(";\n");
949 } else {
950 dstColor = builder->dstColor();
951 }
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000952 SkASSERT(NULL != dstColor);
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000953
954 // We don't try to optimize for this case at all
bsalomon@google.comb79d8652013-03-29 20:30:50 +0000955 if (NULL == inputColor) {
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000956 builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000957 inputColor = "ones";
958 }
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000959 builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
960
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000961 // These all perform src-over on the alpha channel.
962 builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
963 outputColor, inputColor, inputColor, dstColor);
964
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000965 switch (mode) {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000966 case SkXfermode::kOverlay_Mode:
967 // Overlay is Hard-Light with the src and dst reversed
968 HardLight(builder, outputColor, dstColor, inputColor);
969 break;
970 case SkXfermode::kDarken_Mode:
971 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
972 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
973 outputColor,
974 inputColor, dstColor, inputColor,
975 dstColor, inputColor, dstColor);
976 break;
977 case SkXfermode::kLighten_Mode:
978 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
979 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
980 outputColor,
981 inputColor, dstColor, inputColor,
982 dstColor, inputColor, dstColor);
983 break;
984 case SkXfermode::kColorDodge_Mode:
985 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
986 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
987 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
988 break;
989 case SkXfermode::kColorBurn_Mode:
990 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
991 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
992 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
993 break;
994 case SkXfermode::kHardLight_Mode:
995 HardLight(builder, outputColor, inputColor, dstColor);
996 break;
997 case SkXfermode::kSoftLight_Mode:
998 builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
999 builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
1000 builder->fsCodeAppendf("\t\t} else {\n");
1001 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
1002 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
1003 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
1004 builder->fsCodeAppendf("\t\t}\n");
1005 break;
1006 case SkXfermode::kDifference_Mode:
1007 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
skia.committer@gmail.com64b682c2013-04-20 07:01:07 +00001008 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001009 outputColor, inputColor, dstColor, inputColor, dstColor,
1010 dstColor, inputColor);
1011 break;
1012 case SkXfermode::kExclusion_Mode:
1013 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
1014 "2.0 * %s.rgb * %s.rgb;\n",
1015 outputColor, dstColor, inputColor, dstColor, inputColor);
1016 break;
1017 case SkXfermode::kMultiply_Mode:
1018 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
1019 "(1.0 - %s.a) * %s.rgb + "
1020 "%s.rgb * %s.rgb;\n",
1021 outputColor, inputColor, dstColor, dstColor, inputColor,
1022 inputColor, dstColor);
1023 break;
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001024 case SkXfermode::kHue_Mode: {
1025 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
1026 SkString setSat, setLum;
1027 AddSatFunction(builder, &setSat);
1028 AddLumFunction(builder, &setLum);
1029 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
1030 dstColor, inputColor);
1031 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
1032 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
1033 dstColor);
1034 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1035 outputColor, inputColor, dstColor, dstColor, inputColor);
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001036 break;
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001037 }
1038 case SkXfermode::kSaturation_Mode: {
1039 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
1040 SkString setSat, setLum;
1041 AddSatFunction(builder, &setSat);
1042 AddLumFunction(builder, &setLum);
1043 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
1044 dstColor, inputColor);
1045 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
1046 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
1047 dstColor);
1048 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1049 outputColor, inputColor, dstColor, dstColor, inputColor);
1050 break;
1051 }
1052 case SkXfermode::kColor_Mode: {
1053 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
1054 SkString setLum;
1055 AddLumFunction(builder, &setLum);
1056 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
1057 inputColor, dstColor);
1058 builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
1059 outputColor, setLum.c_str(), dstColor, inputColor);
1060 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1061 outputColor, inputColor, dstColor, dstColor, inputColor);
1062 break;
1063 }
1064 case SkXfermode::kLuminosity_Mode: {
1065 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
1066 SkString setLum;
1067 AddLumFunction(builder, &setLum);
1068 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
1069 inputColor, dstColor);
1070 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
1071 outputColor, setLum.c_str(), dstColor, inputColor);
1072 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1073 outputColor, inputColor, dstColor, dstColor, inputColor);
1074 break;
1075 }
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001076 default:
1077 GrCrash("Unknown XferEffect mode.");
1078 break;
bsalomon@google.comb79d8652013-03-29 20:30:50 +00001079 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001080 }
1081
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001082 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
commit-bot@chromium.org372a9c32014-04-07 17:13:10 +00001083 // The background may come from the dst or from a texture.
1084 int numTextures = (*drawEffect.effect())->numTextures();
1085 SkASSERT(numTextures <= 1);
1086 return (drawEffect.castEffect<XferEffect>().mode() << 1) | numTextures;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001087 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001088
1089 private:
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001090 static void HardLight(GrGLShaderBuilder* builder,
1091 const char* final,
1092 const char* src,
1093 const char* dst) {
commit-bot@chromium.orga0d91382013-04-29 17:40:33 +00001094 static const char kComponents[] = {'r', 'g', 'b'};
1095 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
1096 char component = kComponents[i];
1097 builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
1098 builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
1099 builder->fsCodeAppend("\t\t} else {\n");
1100 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
1101 final, component, src, dst, dst, dst, component, src, src, component);
1102 builder->fsCodeAppend("\t\t}\n");
1103 }
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001104 builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
1105 final, src, dst, dst, src);
1106 }
1107
1108 // Does one component of color-dodge
1109 static void ColorDodgeComponent(GrGLShaderBuilder* builder,
1110 const char* final,
1111 const char* src,
1112 const char* dst,
1113 const char component) {
1114 builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
bsalomon@google.com58eb1af2013-04-19 16:20:20 +00001115 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001116 final, component, src, component, dst);
1117 builder->fsCodeAppend("\t\t} else {\n");
1118 builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
bsalomon@google.com07fa3ab2013-04-19 17:21:49 +00001119 builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001120 builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1121 final, component, src, dst, src, component, dst, dst, component,
1122 src);
1123 builder->fsCodeAppend("\t\t\t} else {\n");
1124 builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
1125 dst, dst, component, src);
1126 builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1127 final, component, src, src, component, dst, dst, component, src);
1128 builder->fsCodeAppend("\t\t\t}\n");
1129 builder->fsCodeAppend("\t\t}\n");
1130 }
1131
1132 // Does one component of color-burn
1133 static void ColorBurnComponent(GrGLShaderBuilder* builder,
1134 const char* final,
1135 const char* src,
1136 const char* dst,
1137 const char component) {
1138 builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
1139 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1140 final, component, src, dst, src, component, dst, dst, component,
1141 src);
1142 builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
1143 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
1144 final, component, dst, component, src);
1145 builder->fsCodeAppend("\t\t} else {\n");
1146 builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
1147 dst, dst, dst, component, src, src, component);
1148 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1149 final, component, src, src, component, dst, dst, component, src);
1150 builder->fsCodeAppend("\t\t}\n");
1151 }
1152
1153 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
1154 static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
1155 const char* final,
1156 const char* src,
1157 const char* dst,
1158 const char component) {
1159 // if (2S < Sa)
1160 builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
1161 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
bsalomon@google.com68567792013-04-19 18:10:50 +00001162 builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001163 final, component, dst, component, dst, component, src, src,
1164 component, dst, dst, src, component, dst, component, src, src,
1165 component);
1166 // else if (4D < Da)
1167 builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
1168 dst, component, dst);
1169 builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
1170 dst, component, dst, component);
1171 builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
1172 builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
1173 builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
1174 // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
bsalomon@google.com68567792013-04-19 18:10:50 +00001175 builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001176 final, component, src, component, src, component, dst, component,
1177 src, src, component, dst, src, src, component, src, src,
1178 component);
1179 builder->fsCodeAppendf("\t\t\t} else {\n");
1180 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
bsalomon@google.com68567792013-04-19 18:10:50 +00001181 builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001182 final, component, dst, dst, component, src, src, component, dst,
1183 src, component, dst, component, src, src, component, src,
1184 component);
1185 builder->fsCodeAppendf("\t\t\t}\n");
1186 }
1187
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001188 // Adds a function that takes two colors and an alpha as input. It produces a color with the
1189 // hue and saturation of the first color, the luminosity of the second color, and the input
1190 // alpha. It has this signature:
1191 // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
1192 static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
1193 // Emit a helper that gets the luminance of a color.
1194 SkString getFunction;
1195 GrGLShaderVar getLumArgs[] = {
1196 GrGLShaderVar("color", kVec3f_GrSLType),
1197 };
1198 SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001199 builder->fsEmitFunction(kFloat_GrSLType,
1200 "luminance",
1201 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
1202 getLumBody.c_str(),
1203 &getFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001204
1205 // Emit the set luminance function.
1206 GrGLShaderVar setLumArgs[] = {
1207 GrGLShaderVar("hueSat", kVec3f_GrSLType),
1208 GrGLShaderVar("alpha", kFloat_GrSLType),
1209 GrGLShaderVar("lumColor", kVec3f_GrSLType),
1210 };
1211 SkString setLumBody;
1212 setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
1213 setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
1214 setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
1215 setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
1216 "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
1217 "\tif (minComp < 0.0) {\n"
1218 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
1219 "\t}\n"
1220 "\tif (maxComp > alpha) {\n"
1221 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
1222 "\t}\n"
1223 "\treturn outColor;\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001224 builder->fsEmitFunction(kVec3f_GrSLType,
1225 "set_luminance",
1226 SK_ARRAY_COUNT(setLumArgs), setLumArgs,
1227 setLumBody.c_str(),
1228 setLumFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001229 }
1230
1231 // Adds a function that creates a color with the hue and luminosity of one input color and
1232 // the saturation of another color. It will have this signature:
1233 // float set_saturation(vec3 hueLumColor, vec3 satColor)
1234 static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
1235 // Emit a helper that gets the saturation of a color
1236 SkString getFunction;
1237 GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
1238 SkString getSatBody;
1239 getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
1240 "min(min(color.r, color.g), color.b);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001241 builder->fsEmitFunction(kFloat_GrSLType,
1242 "saturation",
1243 SK_ARRAY_COUNT(getSatArgs), getSatArgs,
1244 getSatBody.c_str(),
1245 &getFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001246
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001247 // Emit a helper that sets the saturation given sorted input channels. This used
1248 // to use inout params for min, mid, and max components but that seems to cause
1249 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
1250 // adjusted min, mid, and max inputs, respectively.
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001251 SkString helperFunction;
1252 GrGLShaderVar helperArgs[] = {
1253 GrGLShaderVar("minComp", kFloat_GrSLType),
1254 GrGLShaderVar("midComp", kFloat_GrSLType),
1255 GrGLShaderVar("maxComp", kFloat_GrSLType),
1256 GrGLShaderVar("sat", kFloat_GrSLType),
1257 };
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001258 static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
1259 "\t\tvec3 result;\n"
1260 "\t\tresult.r = 0.0;\n"
1261 "\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
1262 "\t\tresult.b = sat;\n"
1263 "\t\treturn result;\n"
1264 "\t} else {\n"
1265 "\t\treturn vec3(0, 0, 0);\n"
1266 "\t}\n";
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001267 builder->fsEmitFunction(kVec3f_GrSLType,
1268 "set_saturation_helper",
1269 SK_ARRAY_COUNT(helperArgs), helperArgs,
1270 kHelperBody,
1271 &helperFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001272
1273 GrGLShaderVar setSatArgs[] = {
1274 GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
1275 GrGLShaderVar("satColor", kVec3f_GrSLType),
1276 };
1277 const char* helpFunc = helperFunction.c_str();
1278 SkString setSatBody;
1279 setSatBody.appendf("\tfloat sat = %s(satColor);\n"
1280 "\tif (hueLumColor.r <= hueLumColor.g) {\n"
1281 "\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001282 "\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001283 "\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001284 "\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001285 "\t\t} else {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001286 "\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001287 "\t\t}\n"
1288 "\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001289 "\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001290 "\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001291 "\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001292 "\t} else {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001293 "\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001294 "\t}\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001295 "\treturn hueLumColor;\n",
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001296 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
1297 helpFunc, helpFunc);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001298 builder->fsEmitFunction(kVec3f_GrSLType,
1299 "set_saturation",
1300 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
1301 setSatBody.c_str(),
1302 setSatFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001303
1304 }
1305
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001306 typedef GrGLEffect INHERITED;
1307 };
1308
1309 GR_DECLARE_EFFECT_TEST;
1310
1311private:
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001312 XferEffect(SkXfermode::Mode mode, GrTexture* background)
1313 : fMode(mode) {
1314 if (background) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001315 fBackgroundTransform.reset(kLocal_GrCoordSet, background);
1316 this->addCoordTransform(&fBackgroundTransform);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001317 fBackgroundAccess.reset(background);
1318 this->addTextureAccess(&fBackgroundAccess);
1319 } else {
1320 this->setWillReadDstColor();
1321 }
1322 }
1323 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
1324 const XferEffect& s = CastEffect<XferEffect>(other);
1325 return fMode == s.fMode &&
1326 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
1327 }
skia.committer@gmail.com64b682c2013-04-20 07:01:07 +00001328
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001329 SkXfermode::Mode fMode;
bsalomon@google.com77af6802013-10-02 13:04:56 +00001330 GrCoordTransform fBackgroundTransform;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001331 GrTextureAccess fBackgroundAccess;
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001332
1333 typedef GrEffect INHERITED;
1334};
1335
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001336GR_DEFINE_EFFECT_TEST(XferEffect);
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001337GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001338 GrContext*,
1339 const GrDrawTargetCaps&,
1340 GrTexture*[]) {
commit-bot@chromium.orga0d91382013-04-29 17:40:33 +00001341 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001342
commit-bot@chromium.orgccecbbb2013-10-24 13:33:32 +00001343 AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001344 return CreateEffectRef(gEffect);
1345}
1346
1347#endif
1348
vandebo@chromium.org48543272011-02-08 19:28:07 +00001349///////////////////////////////////////////////////////////////////////////////
1350///////////////////////////////////////////////////////////////////////////////
1351
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001352SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
reed@google.com52314f82013-11-21 21:05:06 +00001353 uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
1354 if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
1355 // out of range, just set to something harmless
1356 mode32 = SkXfermode::kSrcOut_Mode;
1357 }
1358 fMode = (SkXfermode::Mode)mode32;
skia.committer@gmail.comf61ebc02013-11-22 07:02:24 +00001359
reed@google.com52314f82013-11-21 21:05:06 +00001360 const ProcCoeff& rec = gProcCoeffs[fMode];
1361 // these may be valid, or may be CANNOT_USE_COEFF
1362 fSrcCoeff = rec.fSC;
1363 fDstCoeff = rec.fDC;
1364 // now update our function-ptr in the super class
1365 this->INHERITED::setProc(rec.fProc);
1366}
1367
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001368bool SkProcCoeffXfermode::asMode(Mode* mode) const {
1369 if (mode) {
1370 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001371 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001372 return true;
1373}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +00001374
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001375bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
1376 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +00001377 return false;
1378 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001379
1380 if (sc) {
1381 *sc = fSrcCoeff;
1382 }
1383 if (dc) {
1384 *dc = fDstCoeff;
1385 }
1386 return true;
1387}
1388
1389#if SK_SUPPORT_GPU
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +00001390bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
1391 GrTexture* background) const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001392 if (XferEffect::IsSupportedMode(fMode)) {
1393 if (NULL != effect) {
1394 *effect = XferEffect::Create(fMode, background);
1395 SkASSERT(NULL != *effect);
1396 }
1397 return true;
1398 }
1399 return false;
1400}
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001401#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001402
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001403void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001404 this->INHERITED::flatten(buffer);
1405 buffer.write32(fMode);
1406}
vandebo@chromium.org48543272011-02-08 19:28:07 +00001407
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001408const char* SkXfermode::ModeName(Mode mode) {
1409 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1410 const char* gModeStrings[] = {
1411 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1412 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1413 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1414 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1415 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1416 };
1417 return gModeStrings[mode];
1418 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
1419}
1420
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001421#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001422void SkProcCoeffXfermode::toString(SkString* str) const {
1423 str->append("SkProcCoeffXfermode: ");
1424
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001425 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001426 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001427
1428 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001429 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001430 };
1431
1432 str->append(" src: ");
1433 if (CANNOT_USE_COEFF == fSrcCoeff) {
1434 str->append("can't use");
1435 } else {
1436 str->append(gCoeffStrings[fSrcCoeff]);
1437 }
1438
1439 str->append(" dst: ");
1440 if (CANNOT_USE_COEFF == fDstCoeff) {
1441 str->append("can't use");
1442 } else {
1443 str->append(gCoeffStrings[fDstCoeff]);
1444 }
1445}
1446#endif
1447
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448///////////////////////////////////////////////////////////////////////////////
1449
1450class SkClearXfermode : public SkProcCoeffXfermode {
1451public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001452 static SkClearXfermode* Create(const ProcCoeff& rec) {
1453 return SkNEW_ARGS(SkClearXfermode, (rec));
1454 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455
reed@google.com30da7452012-12-17 19:55:24 +00001456 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1457 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001458
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001459 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001460 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001461
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001463 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001464 SkClearXfermode(SkReadBuffer& buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001466
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001467 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468};
1469
reed@google.com86ab6c62011-11-28 15:26:14 +00001470void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1471 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001472 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001473 SkASSERT(dst && count >= 0);
1474
1475 if (NULL == aa) {
1476 memset(dst, 0, count << 2);
1477 } else {
1478 for (int i = count - 1; i >= 0; --i) {
1479 unsigned a = aa[i];
1480 if (0xFF == a) {
1481 dst[i] = 0;
1482 } else if (a != 0) {
1483 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1484 }
1485 }
1486 }
1487}
1488void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1489 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001490 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001491 SkASSERT(dst && count >= 0);
1492
1493 if (NULL == aa) {
1494 memset(dst, 0, count);
1495 } else {
1496 for (int i = count - 1; i >= 0; --i) {
1497 unsigned a = aa[i];
1498 if (0xFF == a) {
1499 dst[i] = 0;
1500 } else if (0 != a) {
1501 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1502 }
1503 }
1504 }
1505}
1506
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001507#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001508void SkClearXfermode::toString(SkString* str) const {
1509 this->INHERITED::toString(str);
1510}
1511#endif
1512
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513///////////////////////////////////////////////////////////////////////////////
1514
1515class SkSrcXfermode : public SkProcCoeffXfermode {
1516public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001517 static SkSrcXfermode* Create(const ProcCoeff& rec) {
1518 return SkNEW_ARGS(SkSrcXfermode, (rec));
1519 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520
reed@google.com30da7452012-12-17 19:55:24 +00001521 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1522 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001524 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001525 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001526
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001528 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001529 SkSrcXfermode(SkReadBuffer& buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001531
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001532 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533};
1534
reed@google.com86ab6c62011-11-28 15:26:14 +00001535void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1536 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001537 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001538 SkASSERT(dst && src && count >= 0);
1539
1540 if (NULL == aa) {
1541 memcpy(dst, src, count << 2);
1542 } else {
1543 for (int i = count - 1; i >= 0; --i) {
1544 unsigned a = aa[i];
1545 if (a == 0xFF) {
1546 dst[i] = src[i];
1547 } else if (a != 0) {
1548 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1549 }
1550 }
1551 }
1552}
1553
1554void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1555 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001556 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001557 SkASSERT(dst && src && count >= 0);
1558
1559 if (NULL == aa) {
1560 for (int i = count - 1; i >= 0; --i) {
1561 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1562 }
1563 } else {
1564 for (int i = count - 1; i >= 0; --i) {
1565 unsigned a = aa[i];
1566 if (0 != a) {
1567 unsigned srcA = SkGetPackedA32(src[i]);
1568 if (a == 0xFF) {
1569 dst[i] = SkToU8(srcA);
1570 } else {
1571 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1572 }
1573 }
1574 }
1575 }
1576}
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001577#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001578void SkSrcXfermode::toString(SkString* str) const {
1579 this->INHERITED::toString(str);
1580}
1581#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001582
reed@google.com30da7452012-12-17 19:55:24 +00001583///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001584
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585class SkDstInXfermode : public SkProcCoeffXfermode {
1586public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001587 static SkDstInXfermode* Create(const ProcCoeff& rec) {
1588 return SkNEW_ARGS(SkDstInXfermode, (rec));
1589 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001590
reed@google.com30da7452012-12-17 19:55:24 +00001591 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001592
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001593 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001594 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001595
1596private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001597 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001598 SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001599
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 typedef SkProcCoeffXfermode INHERITED;
1601};
1602
reed@google.com86ab6c62011-11-28 15:26:14 +00001603void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1604 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001605 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001606 SkASSERT(dst && src);
1607
1608 if (count <= 0) {
1609 return;
1610 }
1611 if (NULL != aa) {
1612 return this->INHERITED::xfer32(dst, src, count, aa);
1613 }
1614
1615 do {
1616 unsigned a = SkGetPackedA32(*src);
1617 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1618 dst++;
1619 src++;
1620 } while (--count != 0);
1621}
1622
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001623#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001624void SkDstInXfermode::toString(SkString* str) const {
1625 this->INHERITED::toString(str);
1626}
1627#endif
1628
reed@google.com30da7452012-12-17 19:55:24 +00001629///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001630
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631class SkDstOutXfermode : public SkProcCoeffXfermode {
1632public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001633 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
1634 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1635 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001636
reed@google.com30da7452012-12-17 19:55:24 +00001637 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001638
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001639 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001640 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001641
1642private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001643 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001644 SkDstOutXfermode(SkReadBuffer& buffer)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001645 : INHERITED(buffer) {}
1646
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647 typedef SkProcCoeffXfermode INHERITED;
1648};
1649
reed@google.com86ab6c62011-11-28 15:26:14 +00001650void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1651 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001652 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001653 SkASSERT(dst && src);
1654
1655 if (count <= 0) {
1656 return;
1657 }
1658 if (NULL != aa) {
1659 return this->INHERITED::xfer32(dst, src, count, aa);
1660 }
1661
1662 do {
1663 unsigned a = SkGetPackedA32(*src);
1664 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1665 dst++;
1666 src++;
1667 } while (--count != 0);
1668}
1669
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001670#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001671void SkDstOutXfermode::toString(SkString* str) const {
1672 this->INHERITED::toString(str);
1673}
1674#endif
1675
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676///////////////////////////////////////////////////////////////////////////////
1677
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001678SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001679static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1]; // All NULL to start.
1680static bool gXfermodeCached[SK_ARRAY_COUNT(gCachedXfermodes)]; // All false to start.
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001681
1682void SkXfermode::Term() {
1683 SkAutoMutexAcquire ac(gCachedXfermodesMutex);
1684
1685 for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
1686 SkSafeUnref(gCachedXfermodes[i]);
1687 gCachedXfermodes[i] = NULL;
1688 }
1689}
1690
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001691extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
1692 SkXfermode::Mode mode);
commit-bot@chromium.orgd6118642013-12-06 11:32:27 +00001693extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001694
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001695
1696static void create_mode(SkXfermode::Mode mode) {
1697 SkASSERT(NULL == gCachedXfermodes[mode]);
1698
1699 ProcCoeff rec = gProcCoeffs[mode];
1700 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
1701 if (pp != NULL) {
1702 rec.fProc = pp;
1703 }
1704
1705 SkXfermode* xfer = NULL;
1706 // check if we have a platform optim for that
1707 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
1708 if (xfm != NULL) {
1709 xfer = xfm;
1710 } else {
1711 // All modes can in theory be represented by the ProcCoeff rec, since
1712 // it contains function ptrs. However, a few modes are both simple and
1713 // commonly used, so we call those out for their own subclasses here.
1714 switch (mode) {
1715 case SkXfermode::kClear_Mode:
1716 xfer = SkClearXfermode::Create(rec);
1717 break;
1718 case SkXfermode::kSrc_Mode:
1719 xfer = SkSrcXfermode::Create(rec);
1720 break;
1721 case SkXfermode::kSrcOver_Mode:
1722 SkASSERT(false); // should not land here
1723 break;
1724 case SkXfermode::kDstIn_Mode:
1725 xfer = SkDstInXfermode::Create(rec);
1726 break;
1727 case SkXfermode::kDstOut_Mode:
1728 xfer = SkDstOutXfermode::Create(rec);
1729 break;
1730 default:
1731 // no special-case, just rely in the rec and its function-ptrs
1732 xfer = SkProcCoeffXfermode::Create(rec, mode);
1733 break;
1734 }
1735 }
1736 gCachedXfermodes[mode] = xfer;
1737}
1738
reed@android.coma0f5d152009-06-22 17:38:10 +00001739SkXfermode* SkXfermode::Create(Mode mode) {
1740 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001741 SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001743 if ((unsigned)mode >= kModeCount) {
1744 // report error
1745 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001747
1748 // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
1749 // so we can just return NULL from the factory.
1750 if (kSrcOver_Mode == mode) {
1751 return NULL;
1752 }
1753
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001754 SkOnce(&gXfermodeCached[mode], &gCachedXfermodesMutex, create_mode, mode);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001755 SkXfermode* xfer = gCachedXfermodes[mode];
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001756 SkASSERT(xfer != NULL);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001757 return SkSafeRef(xfer);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001758}
1759
reed@google.com43c50c82011-04-14 15:50:52 +00001760SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1761 SkXfermodeProc proc = NULL;
1762 if ((unsigned)mode < kModeCount) {
1763 proc = gProcCoeffs[mode].fProc;
1764 }
1765 return proc;
1766}
1767
1768bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1769 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001770
reed@google.com43c50c82011-04-14 15:50:52 +00001771 if ((unsigned)mode >= (unsigned)kModeCount) {
1772 // illegal mode parameter
1773 return false;
1774 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001775
reed@google.com43c50c82011-04-14 15:50:52 +00001776 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001777
reed@google.com43c50c82011-04-14 15:50:52 +00001778 if (CANNOT_USE_COEFF == rec.fSC) {
1779 return false;
1780 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001781
reed@google.com43c50c82011-04-14 15:50:52 +00001782 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1783 if (src) {
1784 *src = rec.fSC;
1785 }
1786 if (dst) {
1787 *dst = rec.fDC;
1788 }
1789 return true;
1790}
1791
reed@google.com30da7452012-12-17 19:55:24 +00001792bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793 if (NULL == xfer) {
1794 if (mode) {
1795 *mode = kSrcOver_Mode;
1796 }
1797 return true;
1798 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001799 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800}
1801
reed@google.com30da7452012-12-17 19:55:24 +00001802bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001803 if (NULL == xfer) {
1804 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001805 }
reed@google.com43c50c82011-04-14 15:50:52 +00001806 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807}
1808
reed@google.com30da7452012-12-17 19:55:24 +00001809bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001810 // if xfer==null then the mode is srcover
1811 Mode m = kSrcOver_Mode;
1812 if (xfer && !xfer->asMode(&m)) {
1813 return false;
1814 }
1815 return mode == m;
1816}
1817
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818///////////////////////////////////////////////////////////////////////////////
1819//////////// 16bit xfermode procs
1820
1821#ifdef SK_DEBUG
1822static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1823static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1824#endif
1825
1826static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1827 SkASSERT(require_255(src));
1828 return SkPixel32ToPixel16(src);
1829}
1830
1831static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1832 return dst;
1833}
1834
1835static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1836 SkASSERT(require_0(src));
1837 return dst;
1838}
1839
1840static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1841 SkASSERT(require_255(src));
1842 return SkPixel32ToPixel16(src);
1843}
1844
1845static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1846 SkASSERT(require_0(src));
1847 return dst;
1848}
1849
1850static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1851 SkASSERT(require_255(src));
1852 return dst;
1853}
1854
1855static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1856 SkASSERT(require_255(src));
1857 return SkPixel32ToPixel16(src);
1858}
1859
1860static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1861 SkASSERT(require_255(src));
1862 return dst;
1863}
1864
1865static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1866 SkASSERT(require_0(src));
1867 return dst;
1868}
1869
1870static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1871 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001872
reed@android.com8a1c16f2008-12-17 15:59:43 +00001873 return SkPackRGB16(
1874 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1875 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1876 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1877}
1878
1879static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1880 SkASSERT(require_0(src));
1881 return dst;
1882}
1883
1884static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1885 SkASSERT(require_255(src));
1886 return SkPixel32ToPixel16(src);
1887}
1888
1889static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1890 SkASSERT(require_255(src));
1891 return dst;
1892}
1893
1894/*********
1895 darken and lighten boil down to this.
1896
1897 darken = (1 - Sa) * Dc + min(Sc, Dc)
1898 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1899
1900 if (Sa == 0) these become
1901 darken = Dc + min(0, Dc) = 0
1902 lighten = Dc + max(0, Dc) = Dc
1903
1904 if (Sa == 1) these become
1905 darken = min(Sc, Dc)
1906 lighten = max(Sc, Dc)
1907*/
1908
1909static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1910 SkASSERT(require_0(src));
1911 return 0;
1912}
1913
1914static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1915 SkASSERT(require_255(src));
1916 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1917 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1918 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1919 return SkPackRGB16(r, g, b);
1920}
1921
1922static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1923 SkASSERT(require_0(src));
1924 return dst;
1925}
1926
1927static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1928 SkASSERT(require_255(src));
1929 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1930 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1931 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1932 return SkPackRGB16(r, g, b);
1933}
1934
1935struct Proc16Rec {
1936 SkXfermodeProc16 fProc16_0;
1937 SkXfermodeProc16 fProc16_255;
1938 SkXfermodeProc16 fProc16_General;
1939};
1940
reed@android.coma0f5d152009-06-22 17:38:10 +00001941static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001942 { NULL, NULL, NULL }, // CLEAR
1943 { NULL, src_modeproc16_255, NULL },
1944 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1945 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1946 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1947 { NULL, srcin_modeproc16_255, NULL },
1948 { NULL, dstin_modeproc16_255, NULL },
1949 { NULL, NULL, NULL },// SRC_OUT
1950 { dstout_modeproc16_0, NULL, NULL },
1951 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1952 { NULL, dstatop_modeproc16_255, NULL },
1953 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001954
1955 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00001956 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00001957 { NULL, NULL, NULL }, // screen
1958 { NULL, NULL, NULL }, // overlay
1959 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1960 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1961 { NULL, NULL, NULL }, // colordodge
1962 { NULL, NULL, NULL }, // colorburn
1963 { NULL, NULL, NULL }, // hardlight
1964 { NULL, NULL, NULL }, // softlight
1965 { NULL, NULL, NULL }, // difference
1966 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00001967 { NULL, NULL, NULL }, // multiply
1968 { NULL, NULL, NULL }, // hue
1969 { NULL, NULL, NULL }, // saturation
1970 { NULL, NULL, NULL }, // color
1971 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972};
1973
reed@android.coma0f5d152009-06-22 17:38:10 +00001974SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001976 if ((unsigned)mode < kModeCount) {
1977 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001978 unsigned a = SkColorGetA(srcColor);
1979
1980 if (0 == a) {
1981 proc16 = rec.fProc16_0;
1982 } else if (255 == a) {
1983 proc16 = rec.fProc16_255;
1984 } else {
1985 proc16 = rec.fProc16_General;
1986 }
1987 }
1988 return proc16;
1989}
1990
caryclark@google.comd26147a2011-12-15 14:16:43 +00001991SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1992 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1993 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1994 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1995 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1996 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +00001997#if !SK_ARM_NEON_IS_NONE
1998 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
1999#endif
commit-bot@chromium.orge424c1d2014-04-11 12:52:44 +00002000#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
commit-bot@chromium.orgc524e982014-04-09 15:43:46 +00002001 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSSE2ProcCoeffXfermode)
commit-bot@chromium.org4460e752014-04-09 16:50:55 +00002002#endif
caryclark@google.comd26147a2011-12-15 14:16:43 +00002003SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END