blob: fb1726808fe55a39e3adb3a6aabc1b44cbd0bdb4 [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///////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000778#ifdef SK_SUPPORT_LEGACY_PROCXFERMODE
vandebo@chromium.org48543272011-02-08 19:28:07 +0000779
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000780void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
781 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000782 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000783 SkASSERT(dst && src && count >= 0);
784
785 SkXfermodeProc proc = fProc;
786
787 if (NULL != proc) {
788 if (NULL == aa) {
789 for (int i = count - 1; i >= 0; --i) {
790 dst[i] = proc(src[i], dst[i]);
791 }
792 } else {
793 for (int i = count - 1; i >= 0; --i) {
794 unsigned a = aa[i];
795 if (0 != a) {
796 SkPMColor dstC = dst[i];
797 SkPMColor C = proc(src[i], dstC);
798 if (a != 0xFF) {
799 C = SkFourByteInterp(C, dstC, a);
800 }
801 dst[i] = C;
802 }
803 }
804 }
805 }
806}
807
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000808void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
809 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000810 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000811 SkASSERT(dst && src && count >= 0);
812
813 SkXfermodeProc proc = fProc;
814
815 if (NULL != proc) {
816 if (NULL == aa) {
817 for (int i = count - 1; i >= 0; --i) {
818 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
819 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
820 }
821 } else {
822 for (int i = count - 1; i >= 0; --i) {
823 unsigned a = aa[i];
824 if (0 != a) {
825 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
826 SkPMColor C = proc(src[i], dstC);
827 if (0xFF != a) {
828 C = SkFourByteInterp(C, dstC, a);
829 }
830 dst[i] = SkPixel32ToPixel16_ToU16(C);
831 }
832 }
833 }
834 }
835}
836
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000837void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
838 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000839 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000840 SkASSERT(dst && src && count >= 0);
841
842 SkXfermodeProc proc = fProc;
843
844 if (NULL != proc) {
845 if (NULL == aa) {
846 for (int i = count - 1; i >= 0; --i) {
847 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
848 dst[i] = SkToU8(SkGetPackedA32(res));
849 }
850 } else {
851 for (int i = count - 1; i >= 0; --i) {
852 unsigned a = aa[i];
853 if (0 != a) {
854 SkAlpha dstA = dst[i];
855 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
856 unsigned A = SkGetPackedA32(res);
857 if (0xFF != a) {
858 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
859 }
860 dst[i] = SkToU8(A);
861 }
862 }
863 }
864 }
865}
866
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000867SkProcXfermode::SkProcXfermode(SkReadBuffer& buffer)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000868 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000869 fProc = NULL;
870 if (!buffer.isCrossProcess()) {
871 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
872 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000873}
874
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000875void SkProcXfermode::flatten(SkWriteBuffer& buffer) const {
djsollen@google.com54924242012-03-29 15:18:04 +0000876 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000877 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000878 buffer.writeFunctionPtr((void*)fProc);
879 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000880}
881
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000882#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000883void SkProcXfermode::toString(SkString* str) const {
884 str->appendf("SkProcXfermode: %p", fProc);
885}
886#endif
887
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000888#endif
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000889//////////////////////////////////////////////////////////////////////////////
890
891#if SK_SUPPORT_GPU
892
893#include "GrEffect.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000894#include "GrCoordTransform.h"
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000895#include "GrEffectUnitTest.h"
896#include "GrTBackendEffectFactory.h"
897#include "gl/GrGLEffect.h"
898
899/**
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000900 * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000901 */
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000902class XferEffect : public GrEffect {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000903public:
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000904 static bool IsSupportedMode(SkXfermode::Mode mode) {
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000905 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000906 }
907
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000908 static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000909 if (!IsSupportedMode(mode)) {
910 return NULL;
911 } else {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000912 AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000913 return CreateEffectRef(effect);
914 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000915 }
916
917 virtual void getConstantColorComponents(GrColor* color,
918 uint32_t* validFlags) const SK_OVERRIDE {
919 *validFlags = 0;
920 }
921
922 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000923 return GrTBackendEffectFactory<XferEffect>::getInstance();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000924 }
925
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000926 static const char* Name() { return "XferEffect"; }
927
928 SkXfermode::Mode mode() const { return fMode; }
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000929 const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000930
931 class GLEffect : public GrGLEffect {
932 public:
933 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
bsalomon@google.com77af6802013-10-02 13:04:56 +0000934 : GrGLEffect(factory) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000935 }
936 virtual void emitCode(GrGLShaderBuilder* builder,
937 const GrDrawEffect& drawEffect,
938 EffectKey key,
939 const char* outputColor,
940 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000941 const TransformedCoordsArray& coords,
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000942 const TextureSamplerArray& samplers) SK_OVERRIDE {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000943 SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
944 const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
945 const char* dstColor;
946 if (backgroundTex) {
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000947 dstColor = "bgColor";
948 builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
bsalomon@google.com77af6802013-10-02 13:04:56 +0000949 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +0000950 builder->fsCodeAppendf(";\n");
951 } else {
952 dstColor = builder->dstColor();
953 }
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000954 SkASSERT(NULL != dstColor);
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000955
956 // We don't try to optimize for this case at all
bsalomon@google.comb79d8652013-03-29 20:30:50 +0000957 if (NULL == inputColor) {
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000958 builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000959 inputColor = "ones";
960 }
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000961 builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
962
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000963 // These all perform src-over on the alpha channel.
964 builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
965 outputColor, inputColor, inputColor, dstColor);
966
bsalomon@google.com77cf4602013-04-22 21:05:48 +0000967 switch (mode) {
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000968 case SkXfermode::kOverlay_Mode:
969 // Overlay is Hard-Light with the src and dst reversed
970 HardLight(builder, outputColor, dstColor, inputColor);
971 break;
972 case SkXfermode::kDarken_Mode:
973 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
974 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
975 outputColor,
976 inputColor, dstColor, inputColor,
977 dstColor, inputColor, dstColor);
978 break;
979 case SkXfermode::kLighten_Mode:
980 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
981 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
982 outputColor,
983 inputColor, dstColor, inputColor,
984 dstColor, inputColor, dstColor);
985 break;
986 case SkXfermode::kColorDodge_Mode:
987 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
988 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
989 ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
990 break;
991 case SkXfermode::kColorBurn_Mode:
992 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
993 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
994 ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
995 break;
996 case SkXfermode::kHardLight_Mode:
997 HardLight(builder, outputColor, inputColor, dstColor);
998 break;
999 case SkXfermode::kSoftLight_Mode:
1000 builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
1001 builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
1002 builder->fsCodeAppendf("\t\t} else {\n");
1003 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
1004 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
1005 SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
1006 builder->fsCodeAppendf("\t\t}\n");
1007 break;
1008 case SkXfermode::kDifference_Mode:
1009 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
skia.committer@gmail.com64b682c2013-04-20 07:01:07 +00001010 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001011 outputColor, inputColor, dstColor, inputColor, dstColor,
1012 dstColor, inputColor);
1013 break;
1014 case SkXfermode::kExclusion_Mode:
1015 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
1016 "2.0 * %s.rgb * %s.rgb;\n",
1017 outputColor, dstColor, inputColor, dstColor, inputColor);
1018 break;
1019 case SkXfermode::kMultiply_Mode:
1020 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
1021 "(1.0 - %s.a) * %s.rgb + "
1022 "%s.rgb * %s.rgb;\n",
1023 outputColor, inputColor, dstColor, dstColor, inputColor,
1024 inputColor, dstColor);
1025 break;
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001026 case SkXfermode::kHue_Mode: {
1027 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
1028 SkString setSat, setLum;
1029 AddSatFunction(builder, &setSat);
1030 AddLumFunction(builder, &setLum);
1031 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
1032 dstColor, inputColor);
1033 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
1034 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
1035 dstColor);
1036 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1037 outputColor, inputColor, dstColor, dstColor, inputColor);
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001038 break;
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001039 }
1040 case SkXfermode::kSaturation_Mode: {
1041 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
1042 SkString setSat, setLum;
1043 AddSatFunction(builder, &setSat);
1044 AddLumFunction(builder, &setLum);
1045 builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
1046 dstColor, inputColor);
1047 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
1048 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
1049 dstColor);
1050 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1051 outputColor, inputColor, dstColor, dstColor, inputColor);
1052 break;
1053 }
1054 case SkXfermode::kColor_Mode: {
1055 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
1056 SkString setLum;
1057 AddLumFunction(builder, &setLum);
1058 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
1059 inputColor, dstColor);
1060 builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
1061 outputColor, setLum.c_str(), dstColor, inputColor);
1062 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1063 outputColor, inputColor, dstColor, dstColor, inputColor);
1064 break;
1065 }
1066 case SkXfermode::kLuminosity_Mode: {
1067 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
1068 SkString setLum;
1069 AddLumFunction(builder, &setLum);
1070 builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
1071 inputColor, dstColor);
1072 builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
1073 outputColor, setLum.c_str(), dstColor, inputColor);
1074 builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
1075 outputColor, inputColor, dstColor, dstColor, inputColor);
1076 break;
1077 }
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001078 default:
1079 GrCrash("Unknown XferEffect mode.");
1080 break;
bsalomon@google.comb79d8652013-03-29 20:30:50 +00001081 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001082 }
1083
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001084 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
commit-bot@chromium.org372a9c32014-04-07 17:13:10 +00001085 // The background may come from the dst or from a texture.
1086 int numTextures = (*drawEffect.effect())->numTextures();
1087 SkASSERT(numTextures <= 1);
1088 return (drawEffect.castEffect<XferEffect>().mode() << 1) | numTextures;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001089 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001090
1091 private:
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001092 static void HardLight(GrGLShaderBuilder* builder,
1093 const char* final,
1094 const char* src,
1095 const char* dst) {
commit-bot@chromium.orga0d91382013-04-29 17:40:33 +00001096 static const char kComponents[] = {'r', 'g', 'b'};
1097 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
1098 char component = kComponents[i];
1099 builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
1100 builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
1101 builder->fsCodeAppend("\t\t} else {\n");
1102 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
1103 final, component, src, dst, dst, dst, component, src, src, component);
1104 builder->fsCodeAppend("\t\t}\n");
1105 }
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001106 builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
1107 final, src, dst, dst, src);
1108 }
1109
1110 // Does one component of color-dodge
1111 static void ColorDodgeComponent(GrGLShaderBuilder* builder,
1112 const char* final,
1113 const char* src,
1114 const char* dst,
1115 const char component) {
1116 builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
bsalomon@google.com58eb1af2013-04-19 16:20:20 +00001117 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001118 final, component, src, component, dst);
1119 builder->fsCodeAppend("\t\t} else {\n");
1120 builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
bsalomon@google.com07fa3ab2013-04-19 17:21:49 +00001121 builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001122 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",
1123 final, component, src, dst, src, component, dst, dst, component,
1124 src);
1125 builder->fsCodeAppend("\t\t\t} else {\n");
1126 builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
1127 dst, dst, component, src);
1128 builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1129 final, component, src, src, component, dst, dst, component, src);
1130 builder->fsCodeAppend("\t\t\t}\n");
1131 builder->fsCodeAppend("\t\t}\n");
1132 }
1133
1134 // Does one component of color-burn
1135 static void ColorBurnComponent(GrGLShaderBuilder* builder,
1136 const char* final,
1137 const char* src,
1138 const char* dst,
1139 const char component) {
1140 builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
1141 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1142 final, component, src, dst, src, component, dst, dst, component,
1143 src);
1144 builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
1145 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
1146 final, component, dst, component, src);
1147 builder->fsCodeAppend("\t\t} else {\n");
1148 builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
1149 dst, dst, dst, component, src, src, component);
1150 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1151 final, component, src, src, component, dst, dst, component, src);
1152 builder->fsCodeAppend("\t\t}\n");
1153 }
1154
1155 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
1156 static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
1157 const char* final,
1158 const char* src,
1159 const char* dst,
1160 const char component) {
1161 // if (2S < Sa)
1162 builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
1163 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
bsalomon@google.com68567792013-04-19 18:10:50 +00001164 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 +00001165 final, component, dst, component, dst, component, src, src,
1166 component, dst, dst, src, component, dst, component, src, src,
1167 component);
1168 // else if (4D < Da)
1169 builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
1170 dst, component, dst);
1171 builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
1172 dst, component, dst, component);
1173 builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
1174 builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
1175 builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
1176 // (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 +00001177 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 +00001178 final, component, src, component, src, component, dst, component,
1179 src, src, component, dst, src, src, component, src, src,
1180 component);
1181 builder->fsCodeAppendf("\t\t\t} else {\n");
1182 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
bsalomon@google.com68567792013-04-19 18:10:50 +00001183 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 +00001184 final, component, dst, dst, component, src, src, component, dst,
1185 src, component, dst, component, src, src, component, src,
1186 component);
1187 builder->fsCodeAppendf("\t\t\t}\n");
1188 }
1189
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001190 // Adds a function that takes two colors and an alpha as input. It produces a color with the
1191 // hue and saturation of the first color, the luminosity of the second color, and the input
1192 // alpha. It has this signature:
1193 // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
1194 static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
1195 // Emit a helper that gets the luminance of a color.
1196 SkString getFunction;
1197 GrGLShaderVar getLumArgs[] = {
1198 GrGLShaderVar("color", kVec3f_GrSLType),
1199 };
1200 SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001201 builder->fsEmitFunction(kFloat_GrSLType,
1202 "luminance",
1203 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
1204 getLumBody.c_str(),
1205 &getFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001206
1207 // Emit the set luminance function.
1208 GrGLShaderVar setLumArgs[] = {
1209 GrGLShaderVar("hueSat", kVec3f_GrSLType),
1210 GrGLShaderVar("alpha", kFloat_GrSLType),
1211 GrGLShaderVar("lumColor", kVec3f_GrSLType),
1212 };
1213 SkString setLumBody;
1214 setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
1215 setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
1216 setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
1217 setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
1218 "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
1219 "\tif (minComp < 0.0) {\n"
1220 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
1221 "\t}\n"
1222 "\tif (maxComp > alpha) {\n"
1223 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
1224 "\t}\n"
1225 "\treturn outColor;\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001226 builder->fsEmitFunction(kVec3f_GrSLType,
1227 "set_luminance",
1228 SK_ARRAY_COUNT(setLumArgs), setLumArgs,
1229 setLumBody.c_str(),
1230 setLumFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001231 }
1232
1233 // Adds a function that creates a color with the hue and luminosity of one input color and
1234 // the saturation of another color. It will have this signature:
1235 // float set_saturation(vec3 hueLumColor, vec3 satColor)
1236 static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
1237 // Emit a helper that gets the saturation of a color
1238 SkString getFunction;
1239 GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
1240 SkString getSatBody;
1241 getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
1242 "min(min(color.r, color.g), color.b);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001243 builder->fsEmitFunction(kFloat_GrSLType,
1244 "saturation",
1245 SK_ARRAY_COUNT(getSatArgs), getSatArgs,
1246 getSatBody.c_str(),
1247 &getFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001248
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001249 // Emit a helper that sets the saturation given sorted input channels. This used
1250 // to use inout params for min, mid, and max components but that seems to cause
1251 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
1252 // adjusted min, mid, and max inputs, respectively.
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001253 SkString helperFunction;
1254 GrGLShaderVar helperArgs[] = {
1255 GrGLShaderVar("minComp", kFloat_GrSLType),
1256 GrGLShaderVar("midComp", kFloat_GrSLType),
1257 GrGLShaderVar("maxComp", kFloat_GrSLType),
1258 GrGLShaderVar("sat", kFloat_GrSLType),
1259 };
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001260 static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
1261 "\t\tvec3 result;\n"
1262 "\t\tresult.r = 0.0;\n"
1263 "\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
1264 "\t\tresult.b = sat;\n"
1265 "\t\treturn result;\n"
1266 "\t} else {\n"
1267 "\t\treturn vec3(0, 0, 0);\n"
1268 "\t}\n";
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001269 builder->fsEmitFunction(kVec3f_GrSLType,
1270 "set_saturation_helper",
1271 SK_ARRAY_COUNT(helperArgs), helperArgs,
1272 kHelperBody,
1273 &helperFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001274
1275 GrGLShaderVar setSatArgs[] = {
1276 GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
1277 GrGLShaderVar("satColor", kVec3f_GrSLType),
1278 };
1279 const char* helpFunc = helperFunction.c_str();
1280 SkString setSatBody;
1281 setSatBody.appendf("\tfloat sat = %s(satColor);\n"
1282 "\tif (hueLumColor.r <= hueLumColor.g) {\n"
1283 "\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001284 "\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001285 "\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001286 "\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001287 "\t\t} else {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001288 "\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001289 "\t\t}\n"
1290 "\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001291 "\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001292 "\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001293 "\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001294 "\t} else {\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001295 "\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001296 "\t}\n"
commit-bot@chromium.orgc718b352013-04-29 17:36:14 +00001297 "\treturn hueLumColor;\n",
commit-bot@chromium.org18c41ac2013-04-25 00:40:41 +00001298 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
1299 helpFunc, helpFunc);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001300 builder->fsEmitFunction(kVec3f_GrSLType,
1301 "set_saturation",
1302 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
1303 setSatBody.c_str(),
1304 setSatFunction);
bsalomon@google.com77cf4602013-04-22 21:05:48 +00001305
1306 }
1307
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001308 typedef GrGLEffect INHERITED;
1309 };
1310
1311 GR_DECLARE_EFFECT_TEST;
1312
1313private:
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001314 XferEffect(SkXfermode::Mode mode, GrTexture* background)
1315 : fMode(mode) {
1316 if (background) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001317 fBackgroundTransform.reset(kLocal_GrCoordSet, background);
1318 this->addCoordTransform(&fBackgroundTransform);
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001319 fBackgroundAccess.reset(background);
1320 this->addTextureAccess(&fBackgroundAccess);
1321 } else {
1322 this->setWillReadDstColor();
1323 }
1324 }
1325 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
1326 const XferEffect& s = CastEffect<XferEffect>(other);
1327 return fMode == s.fMode &&
1328 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
1329 }
skia.committer@gmail.com64b682c2013-04-20 07:01:07 +00001330
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001331 SkXfermode::Mode fMode;
bsalomon@google.com77af6802013-10-02 13:04:56 +00001332 GrCoordTransform fBackgroundTransform;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +00001333 GrTextureAccess fBackgroundAccess;
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001334
1335 typedef GrEffect INHERITED;
1336};
1337
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001338GR_DEFINE_EFFECT_TEST(XferEffect);
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001339GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
bsalomon@google.com8da9bc72013-04-19 15:03:21 +00001340 GrContext*,
1341 const GrDrawTargetCaps&,
1342 GrTexture*[]) {
commit-bot@chromium.orga0d91382013-04-29 17:40:33 +00001343 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
skia.committer@gmail.com2cf444f2013-04-26 07:00:58 +00001344
commit-bot@chromium.orgccecbbb2013-10-24 13:33:32 +00001345 AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001346 return CreateEffectRef(gEffect);
1347}
1348
1349#endif
1350
vandebo@chromium.org48543272011-02-08 19:28:07 +00001351///////////////////////////////////////////////////////////////////////////////
1352///////////////////////////////////////////////////////////////////////////////
1353
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001354SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
reed@google.com52314f82013-11-21 21:05:06 +00001355 uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
1356 if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
1357 // out of range, just set to something harmless
1358 mode32 = SkXfermode::kSrcOut_Mode;
1359 }
1360 fMode = (SkXfermode::Mode)mode32;
skia.committer@gmail.comf61ebc02013-11-22 07:02:24 +00001361
reed@google.com52314f82013-11-21 21:05:06 +00001362 const ProcCoeff& rec = gProcCoeffs[fMode];
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001363 fProc = rec.fProc;
reed@google.com52314f82013-11-21 21:05:06 +00001364 // these may be valid, or may be CANNOT_USE_COEFF
1365 fSrcCoeff = rec.fSC;
1366 fDstCoeff = rec.fDC;
reed@google.com52314f82013-11-21 21:05:06 +00001367}
1368
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001369bool SkProcCoeffXfermode::asMode(Mode* mode) const {
1370 if (mode) {
1371 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001372 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001373 return true;
1374}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +00001375
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001376bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
1377 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +00001378 return false;
1379 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001380
1381 if (sc) {
1382 *sc = fSrcCoeff;
1383 }
1384 if (dc) {
1385 *dc = fDstCoeff;
1386 }
1387 return true;
1388}
1389
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001390void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1391 const SkPMColor* SK_RESTRICT src, int count,
1392 const SkAlpha* SK_RESTRICT aa) const {
1393 SkASSERT(dst && src && count >= 0);
1394
1395 SkXfermodeProc proc = fProc;
1396
1397 if (NULL != proc) {
1398 if (NULL == aa) {
1399 for (int i = count - 1; i >= 0; --i) {
1400 dst[i] = proc(src[i], dst[i]);
1401 }
1402 } else {
1403 for (int i = count - 1; i >= 0; --i) {
1404 unsigned a = aa[i];
1405 if (0 != a) {
1406 SkPMColor dstC = dst[i];
1407 SkPMColor C = proc(src[i], dstC);
1408 if (a != 0xFF) {
1409 C = SkFourByteInterp(C, dstC, a);
1410 }
1411 dst[i] = C;
1412 }
1413 }
1414 }
1415 }
1416}
1417
1418void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
1419 const SkPMColor* SK_RESTRICT src, int count,
1420 const SkAlpha* SK_RESTRICT aa) const {
1421 SkASSERT(dst && src && count >= 0);
1422
1423 SkXfermodeProc proc = fProc;
1424
1425 if (NULL != proc) {
1426 if (NULL == aa) {
1427 for (int i = count - 1; i >= 0; --i) {
1428 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1429 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
1430 }
1431 } else {
1432 for (int i = count - 1; i >= 0; --i) {
1433 unsigned a = aa[i];
1434 if (0 != a) {
1435 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1436 SkPMColor C = proc(src[i], dstC);
1437 if (0xFF != a) {
1438 C = SkFourByteInterp(C, dstC, a);
1439 }
1440 dst[i] = SkPixel32ToPixel16_ToU16(C);
1441 }
1442 }
1443 }
1444 }
1445}
1446
1447void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1448 const SkPMColor* SK_RESTRICT src, int count,
1449 const SkAlpha* SK_RESTRICT aa) const {
1450 SkASSERT(dst && src && count >= 0);
1451
1452 SkXfermodeProc proc = fProc;
1453
1454 if (NULL != proc) {
1455 if (NULL == aa) {
1456 for (int i = count - 1; i >= 0; --i) {
1457 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
1458 dst[i] = SkToU8(SkGetPackedA32(res));
1459 }
1460 } else {
1461 for (int i = count - 1; i >= 0; --i) {
1462 unsigned a = aa[i];
1463 if (0 != a) {
1464 SkAlpha dstA = dst[i];
1465 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
1466 unsigned A = SkGetPackedA32(res);
1467 if (0xFF != a) {
1468 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1469 }
1470 dst[i] = SkToU8(A);
1471 }
1472 }
1473 }
1474 }
1475}
1476
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001477#if SK_SUPPORT_GPU
senorblanco@chromium.org1a6382f2013-10-23 18:41:36 +00001478bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
1479 GrTexture* background) const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001480 if (XferEffect::IsSupportedMode(fMode)) {
1481 if (NULL != effect) {
1482 *effect = XferEffect::Create(fMode, background);
1483 SkASSERT(NULL != *effect);
1484 }
1485 return true;
1486 }
1487 return false;
1488}
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001489#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001490
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001491void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001492 this->INHERITED::flatten(buffer);
1493 buffer.write32(fMode);
1494}
vandebo@chromium.org48543272011-02-08 19:28:07 +00001495
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001496const char* SkXfermode::ModeName(Mode mode) {
1497 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1498 const char* gModeStrings[] = {
1499 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1500 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1501 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1502 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1503 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1504 };
1505 return gModeStrings[mode];
1506 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
1507}
1508
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001509#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001510void SkProcCoeffXfermode::toString(SkString* str) const {
1511 str->append("SkProcCoeffXfermode: ");
1512
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001513 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001514 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001515
1516 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001517 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001518 };
1519
1520 str->append(" src: ");
1521 if (CANNOT_USE_COEFF == fSrcCoeff) {
1522 str->append("can't use");
1523 } else {
1524 str->append(gCoeffStrings[fSrcCoeff]);
1525 }
1526
1527 str->append(" dst: ");
1528 if (CANNOT_USE_COEFF == fDstCoeff) {
1529 str->append("can't use");
1530 } else {
1531 str->append(gCoeffStrings[fDstCoeff]);
1532 }
1533}
1534#endif
1535
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536///////////////////////////////////////////////////////////////////////////////
1537
1538class SkClearXfermode : public SkProcCoeffXfermode {
1539public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001540 static SkClearXfermode* Create(const ProcCoeff& rec) {
1541 return SkNEW_ARGS(SkClearXfermode, (rec));
1542 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543
reed@google.com30da7452012-12-17 19:55:24 +00001544 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1545 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001546
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001547 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001548 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001549
reed@android.com8a1c16f2008-12-17 15:59:43 +00001550private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001551 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001552 SkClearXfermode(SkReadBuffer& buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001554
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001555 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556};
1557
reed@google.com86ab6c62011-11-28 15:26:14 +00001558void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1559 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001560 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001561 SkASSERT(dst && count >= 0);
1562
1563 if (NULL == aa) {
1564 memset(dst, 0, count << 2);
1565 } else {
1566 for (int i = count - 1; i >= 0; --i) {
1567 unsigned a = aa[i];
1568 if (0xFF == a) {
1569 dst[i] = 0;
1570 } else if (a != 0) {
1571 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1572 }
1573 }
1574 }
1575}
1576void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1577 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001578 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001579 SkASSERT(dst && count >= 0);
1580
1581 if (NULL == aa) {
1582 memset(dst, 0, count);
1583 } else {
1584 for (int i = count - 1; i >= 0; --i) {
1585 unsigned a = aa[i];
1586 if (0xFF == a) {
1587 dst[i] = 0;
1588 } else if (0 != a) {
1589 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1590 }
1591 }
1592 }
1593}
1594
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001595#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001596void SkClearXfermode::toString(SkString* str) const {
1597 this->INHERITED::toString(str);
1598}
1599#endif
1600
reed@android.com8a1c16f2008-12-17 15:59:43 +00001601///////////////////////////////////////////////////////////////////////////////
1602
1603class SkSrcXfermode : public SkProcCoeffXfermode {
1604public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001605 static SkSrcXfermode* Create(const ProcCoeff& rec) {
1606 return SkNEW_ARGS(SkSrcXfermode, (rec));
1607 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608
reed@google.com30da7452012-12-17 19:55:24 +00001609 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1610 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001612 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001613 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001614
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001616 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001617 SkSrcXfermode(SkReadBuffer& buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001618 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001619
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001620 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621};
1622
reed@google.com86ab6c62011-11-28 15:26:14 +00001623void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1624 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001625 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001626 SkASSERT(dst && src && count >= 0);
1627
1628 if (NULL == aa) {
1629 memcpy(dst, src, count << 2);
1630 } else {
1631 for (int i = count - 1; i >= 0; --i) {
1632 unsigned a = aa[i];
1633 if (a == 0xFF) {
1634 dst[i] = src[i];
1635 } else if (a != 0) {
1636 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1637 }
1638 }
1639 }
1640}
1641
1642void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1643 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001644 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001645 SkASSERT(dst && src && count >= 0);
1646
1647 if (NULL == aa) {
1648 for (int i = count - 1; i >= 0; --i) {
1649 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1650 }
1651 } else {
1652 for (int i = count - 1; i >= 0; --i) {
1653 unsigned a = aa[i];
1654 if (0 != a) {
1655 unsigned srcA = SkGetPackedA32(src[i]);
1656 if (a == 0xFF) {
1657 dst[i] = SkToU8(srcA);
1658 } else {
1659 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1660 }
1661 }
1662 }
1663 }
1664}
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001665#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001666void SkSrcXfermode::toString(SkString* str) const {
1667 this->INHERITED::toString(str);
1668}
1669#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001670
reed@google.com30da7452012-12-17 19:55:24 +00001671///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001672
reed@android.com8a1c16f2008-12-17 15:59:43 +00001673class SkDstInXfermode : public SkProcCoeffXfermode {
1674public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001675 static SkDstInXfermode* Create(const ProcCoeff& rec) {
1676 return SkNEW_ARGS(SkDstInXfermode, (rec));
1677 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001678
reed@google.com30da7452012-12-17 19:55:24 +00001679 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001680
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001681 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001682 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001683
1684private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001685 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001686 SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001687
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688 typedef SkProcCoeffXfermode INHERITED;
1689};
1690
reed@google.com86ab6c62011-11-28 15:26:14 +00001691void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1692 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001693 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001694 SkASSERT(dst && src);
1695
1696 if (count <= 0) {
1697 return;
1698 }
1699 if (NULL != aa) {
1700 return this->INHERITED::xfer32(dst, src, count, aa);
1701 }
1702
1703 do {
1704 unsigned a = SkGetPackedA32(*src);
1705 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1706 dst++;
1707 src++;
1708 } while (--count != 0);
1709}
1710
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001711#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001712void SkDstInXfermode::toString(SkString* str) const {
1713 this->INHERITED::toString(str);
1714}
1715#endif
1716
reed@google.com30da7452012-12-17 19:55:24 +00001717///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001718
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719class SkDstOutXfermode : public SkProcCoeffXfermode {
1720public:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001721 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
1722 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1723 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001724
reed@google.com30da7452012-12-17 19:55:24 +00001725 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001726
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001727 SK_TO_STRING_OVERRIDE()
djsollen@google.comba28d032012-03-26 17:57:35 +00001728 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001729
1730private:
commit-bot@chromium.org0a2bf902014-02-20 20:40:19 +00001731 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001732 SkDstOutXfermode(SkReadBuffer& buffer)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001733 : INHERITED(buffer) {}
1734
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735 typedef SkProcCoeffXfermode INHERITED;
1736};
1737
reed@google.com86ab6c62011-11-28 15:26:14 +00001738void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1739 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001740 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001741 SkASSERT(dst && src);
1742
1743 if (count <= 0) {
1744 return;
1745 }
1746 if (NULL != aa) {
1747 return this->INHERITED::xfer32(dst, src, count, aa);
1748 }
1749
1750 do {
1751 unsigned a = SkGetPackedA32(*src);
1752 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1753 dst++;
1754 src++;
1755 } while (--count != 0);
1756}
1757
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001758#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001759void SkDstOutXfermode::toString(SkString* str) const {
1760 this->INHERITED::toString(str);
1761}
1762#endif
1763
reed@android.com8a1c16f2008-12-17 15:59:43 +00001764///////////////////////////////////////////////////////////////////////////////
1765
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001766SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001767static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1]; // All NULL to start.
1768static bool gXfermodeCached[SK_ARRAY_COUNT(gCachedXfermodes)]; // All false to start.
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001769
1770void SkXfermode::Term() {
1771 SkAutoMutexAcquire ac(gCachedXfermodesMutex);
1772
1773 for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
1774 SkSafeUnref(gCachedXfermodes[i]);
1775 gCachedXfermodes[i] = NULL;
1776 }
1777}
1778
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001779extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
1780 SkXfermode::Mode mode);
commit-bot@chromium.orgd6118642013-12-06 11:32:27 +00001781extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001782
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001783
1784static void create_mode(SkXfermode::Mode mode) {
1785 SkASSERT(NULL == gCachedXfermodes[mode]);
1786
1787 ProcCoeff rec = gProcCoeffs[mode];
1788 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
1789 if (pp != NULL) {
1790 rec.fProc = pp;
1791 }
1792
1793 SkXfermode* xfer = NULL;
1794 // check if we have a platform optim for that
1795 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
1796 if (xfm != NULL) {
1797 xfer = xfm;
1798 } else {
1799 // All modes can in theory be represented by the ProcCoeff rec, since
1800 // it contains function ptrs. However, a few modes are both simple and
1801 // commonly used, so we call those out for their own subclasses here.
1802 switch (mode) {
1803 case SkXfermode::kClear_Mode:
1804 xfer = SkClearXfermode::Create(rec);
1805 break;
1806 case SkXfermode::kSrc_Mode:
1807 xfer = SkSrcXfermode::Create(rec);
1808 break;
1809 case SkXfermode::kSrcOver_Mode:
1810 SkASSERT(false); // should not land here
1811 break;
1812 case SkXfermode::kDstIn_Mode:
1813 xfer = SkDstInXfermode::Create(rec);
1814 break;
1815 case SkXfermode::kDstOut_Mode:
1816 xfer = SkDstOutXfermode::Create(rec);
1817 break;
1818 default:
1819 // no special-case, just rely in the rec and its function-ptrs
1820 xfer = SkProcCoeffXfermode::Create(rec, mode);
1821 break;
1822 }
1823 }
1824 gCachedXfermodes[mode] = xfer;
1825}
1826
reed@android.coma0f5d152009-06-22 17:38:10 +00001827SkXfermode* SkXfermode::Create(Mode mode) {
1828 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001829 SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001830
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001831 if ((unsigned)mode >= kModeCount) {
1832 // report error
1833 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001835
1836 // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
1837 // so we can just return NULL from the factory.
1838 if (kSrcOver_Mode == mode) {
1839 return NULL;
1840 }
1841
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001842 SkOnce(&gXfermodeCached[mode], &gCachedXfermodesMutex, create_mode, mode);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001843 SkXfermode* xfer = gCachedXfermodes[mode];
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001844 SkASSERT(xfer != NULL);
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001845 return SkSafeRef(xfer);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846}
1847
reed@google.com43c50c82011-04-14 15:50:52 +00001848SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1849 SkXfermodeProc proc = NULL;
1850 if ((unsigned)mode < kModeCount) {
1851 proc = gProcCoeffs[mode].fProc;
1852 }
1853 return proc;
1854}
1855
1856bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1857 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001858
reed@google.com43c50c82011-04-14 15:50:52 +00001859 if ((unsigned)mode >= (unsigned)kModeCount) {
1860 // illegal mode parameter
1861 return false;
1862 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001863
reed@google.com43c50c82011-04-14 15:50:52 +00001864 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001865
reed@google.com43c50c82011-04-14 15:50:52 +00001866 if (CANNOT_USE_COEFF == rec.fSC) {
1867 return false;
1868 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001869
reed@google.com43c50c82011-04-14 15:50:52 +00001870 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1871 if (src) {
1872 *src = rec.fSC;
1873 }
1874 if (dst) {
1875 *dst = rec.fDC;
1876 }
1877 return true;
1878}
1879
reed@google.com30da7452012-12-17 19:55:24 +00001880bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001881 if (NULL == xfer) {
1882 if (mode) {
1883 *mode = kSrcOver_Mode;
1884 }
1885 return true;
1886 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001887 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001888}
1889
reed@google.com30da7452012-12-17 19:55:24 +00001890bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001891 if (NULL == xfer) {
1892 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001893 }
reed@google.com43c50c82011-04-14 15:50:52 +00001894 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001895}
1896
reed@google.com30da7452012-12-17 19:55:24 +00001897bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001898 // if xfer==null then the mode is srcover
1899 Mode m = kSrcOver_Mode;
1900 if (xfer && !xfer->asMode(&m)) {
1901 return false;
1902 }
1903 return mode == m;
1904}
1905
reed@android.com8a1c16f2008-12-17 15:59:43 +00001906///////////////////////////////////////////////////////////////////////////////
1907//////////// 16bit xfermode procs
1908
1909#ifdef SK_DEBUG
1910static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1911static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1912#endif
1913
1914static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1915 SkASSERT(require_255(src));
1916 return SkPixel32ToPixel16(src);
1917}
1918
1919static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1920 return dst;
1921}
1922
1923static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1924 SkASSERT(require_0(src));
1925 return dst;
1926}
1927
1928static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1929 SkASSERT(require_255(src));
1930 return SkPixel32ToPixel16(src);
1931}
1932
1933static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1934 SkASSERT(require_0(src));
1935 return dst;
1936}
1937
1938static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1939 SkASSERT(require_255(src));
1940 return dst;
1941}
1942
1943static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1944 SkASSERT(require_255(src));
1945 return SkPixel32ToPixel16(src);
1946}
1947
1948static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1949 SkASSERT(require_255(src));
1950 return dst;
1951}
1952
1953static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1954 SkASSERT(require_0(src));
1955 return dst;
1956}
1957
1958static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1959 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001960
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961 return SkPackRGB16(
1962 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1963 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1964 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1965}
1966
1967static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1968 SkASSERT(require_0(src));
1969 return dst;
1970}
1971
1972static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1973 SkASSERT(require_255(src));
1974 return SkPixel32ToPixel16(src);
1975}
1976
1977static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1978 SkASSERT(require_255(src));
1979 return dst;
1980}
1981
1982/*********
1983 darken and lighten boil down to this.
1984
1985 darken = (1 - Sa) * Dc + min(Sc, Dc)
1986 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1987
1988 if (Sa == 0) these become
1989 darken = Dc + min(0, Dc) = 0
1990 lighten = Dc + max(0, Dc) = Dc
1991
1992 if (Sa == 1) these become
1993 darken = min(Sc, Dc)
1994 lighten = max(Sc, Dc)
1995*/
1996
1997static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1998 SkASSERT(require_0(src));
1999 return 0;
2000}
2001
2002static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
2003 SkASSERT(require_255(src));
2004 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
2005 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
2006 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
2007 return SkPackRGB16(r, g, b);
2008}
2009
2010static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
2011 SkASSERT(require_0(src));
2012 return dst;
2013}
2014
2015static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
2016 SkASSERT(require_255(src));
2017 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
2018 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
2019 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
2020 return SkPackRGB16(r, g, b);
2021}
2022
2023struct Proc16Rec {
2024 SkXfermodeProc16 fProc16_0;
2025 SkXfermodeProc16 fProc16_255;
2026 SkXfermodeProc16 fProc16_General;
2027};
2028
reed@android.coma0f5d152009-06-22 17:38:10 +00002029static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 { NULL, NULL, NULL }, // CLEAR
2031 { NULL, src_modeproc16_255, NULL },
2032 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
2033 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
2034 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
2035 { NULL, srcin_modeproc16_255, NULL },
2036 { NULL, dstin_modeproc16_255, NULL },
2037 { NULL, NULL, NULL },// SRC_OUT
2038 { dstout_modeproc16_0, NULL, NULL },
2039 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
2040 { NULL, dstatop_modeproc16_255, NULL },
2041 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00002042
2043 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00002044 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00002045 { NULL, NULL, NULL }, // screen
2046 { NULL, NULL, NULL }, // overlay
2047 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
2048 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
2049 { NULL, NULL, NULL }, // colordodge
2050 { NULL, NULL, NULL }, // colorburn
2051 { NULL, NULL, NULL }, // hardlight
2052 { NULL, NULL, NULL }, // softlight
2053 { NULL, NULL, NULL }, // difference
2054 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00002055 { NULL, NULL, NULL }, // multiply
2056 { NULL, NULL, NULL }, // hue
2057 { NULL, NULL, NULL }, // saturation
2058 { NULL, NULL, NULL }, // color
2059 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060};
2061
reed@android.coma0f5d152009-06-22 17:38:10 +00002062SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00002064 if ((unsigned)mode < kModeCount) {
2065 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 unsigned a = SkColorGetA(srcColor);
2067
2068 if (0 == a) {
2069 proc16 = rec.fProc16_0;
2070 } else if (255 == a) {
2071 proc16 = rec.fProc16_255;
2072 } else {
2073 proc16 = rec.fProc16_General;
2074 }
2075 }
2076 return proc16;
2077}
2078
caryclark@google.comd26147a2011-12-15 14:16:43 +00002079SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
2080 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
2081 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
2082 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
2083 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
2084 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +00002085#if !SK_ARM_NEON_IS_NONE
2086 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
2087#endif
commit-bot@chromium.orge424c1d2014-04-11 12:52:44 +00002088#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
commit-bot@chromium.orgc524e982014-04-09 15:43:46 +00002089 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSSE2ProcCoeffXfermode)
commit-bot@chromium.org4460e752014-04-09 16:50:55 +00002090#endif
caryclark@google.comd26147a2011-12-15 14:16:43 +00002091SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END