blob: 22881c6cfe94d63d3a5a5e6b3f95f9ad82a5481e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#include "SkXfermode.h"
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00009#include "SkXfermode_proccoeff.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkColorPriv.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000011#include "SkMathPriv.h"
mtklein6c59d802015-09-09 09:09:53 -070012#include "SkOncePtr.h"
mtklein490b6152015-07-31 11:50:27 -070013#include "SkOpts.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000014#include "SkReadBuffer.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000015#include "SkString.h"
commit-bot@chromium.org140950c2014-03-28 20:04:11 +000016#include "SkWriteBuffer.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000017
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
19
deanm@chromium.orgda946992009-07-03 12:54:24 +000020static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000021 SkASSERT(a <= 255);
22 SkASSERT(b <= 255);
23 unsigned sum = a + b;
24 if (sum > 255) {
25 sum = 255;
26 }
27 return sum;
28}
29
deanm@chromium.orgda946992009-07-03 12:54:24 +000030static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000031 if (n < 0) {
32 n = 0;
33 } else if (n > 255) {
34 n = 255;
35 }
36 return n;
37}
38
deanm@chromium.orgda946992009-07-03 12:54:24 +000039static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000040 if (prod <= 0) {
41 return 0;
42 } else if (prod >= 255*255) {
43 return 255;
44 } else {
45 return SkDiv255Round(prod);
46 }
47}
48
reed@android.com8a1c16f2008-12-17 15:59:43 +000049///////////////////////////////////////////////////////////////////////////////
reed31255652016-02-08 12:56:56 -080050#include "SkNx.h"
51
52static Sk4f alpha(const Sk4f& color) { return Sk4f(color.kth<3>()); }
53static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color.kth<3>()); }
54static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
55
reede7125322016-02-09 11:59:24 -080056static Sk4f color_alpha(const Sk4f& color, float newAlpha) {
57 return Sk4f(color.kth<0>(), color.kth<1>(), color.kth<2>(), newAlpha);
58}
59static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) {
60 return color_alpha(color, newAlpha.kth<3>());
61}
62
63static Sk4f set_argb(float a, float r, float g, float b) {
64 if (0 == SkPM4f::R) {
65 return Sk4f(r, g, b, a);
66 } else {
67 return Sk4f(b, g, r, a);
68 }
69}
70
reed31255652016-02-08 12:56:56 -080071static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
72static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; }
73static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
74static Sk4f srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; }
75static Sk4f dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; }
76static Sk4f srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); }
77static Sk4f dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); }
78static Sk4f srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); }
79static Sk4f dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); }
80static Sk4f srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); }
81static Sk4f dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); }
82static Sk4f xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);}
83static Sk4f plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); }
84static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; }
85static Sk4f screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; }
86
87static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
88 return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
89}
90
reede7125322016-02-09 11:59:24 -080091static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) {
92 Sk4f sa = alpha(s);
93 Sk4f da = alpha(d);
94 Sk4f two = Sk4f(2);
95 Sk4f rc = (two * d <= da).thenElse(two * s * d,
96 sa * da - two * (da - d) * (sa - s));
97 return s + d - s * da + color_alpha(rc - d * sa, 0);
reed31255652016-02-08 12:56:56 -080098}
99
reede7125322016-02-09 11:59:24 -0800100static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) {
101 return overlay_4f(d, s);
reed31255652016-02-08 12:56:56 -0800102}
103
reede7125322016-02-09 11:59:24 -0800104static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) {
105 Sk4f sa = alpha(s);
106 Sk4f da = alpha(d);
107 return s + d - Sk4f::Max(s * da, d * sa);
108}
109
110static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) {
111 Sk4f sa = alpha(s);
112 Sk4f da = alpha(d);
113 return s + d - Sk4f::Min(s * da, d * sa);
114}
115
116static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) {
117 Sk4f sa = alpha(s);
118 Sk4f da = alpha(d);
119 Sk4f isa = Sk4f(1) - sa;
120 Sk4f ida = Sk4f(1) - da;
121
122 Sk4f srcover = s + d * isa;
123 Sk4f dstover = d + s * ida;
124 Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa;
125
126 // Order matters here, preferring d==0 over s==sa.
127 auto colors = (d == Sk4f(0)).thenElse(dstover,
128 (s == sa).thenElse(srcover,
129 otherwise));
130 return color_alpha(colors, srcover);
131}
132
133static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) {
134 Sk4f sa = alpha(s);
135 Sk4f da = alpha(d);
136 Sk4f isa = Sk4f(1) - sa;
137 Sk4f ida = Sk4f(1) - da;
138
139 Sk4f srcover = s + d * isa;
140 Sk4f dstover = d + s * ida;
141 Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa;
142
143 // Order matters here, preferring d==da over s==0.
144 auto colors = (d == da).thenElse(dstover,
145 (s == Sk4f(0)).thenElse(srcover,
146 otherwise));
147 return color_alpha(colors, srcover);
148}
149
150static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) {
151 Sk4f sa = alpha(s);
152 Sk4f da = alpha(d);
153 Sk4f isa = Sk4f(1) - sa;
154 Sk4f ida = Sk4f(1) - da;
155
156 // Some common terms.
157 Sk4f m = (da > Sk4f(0)).thenElse(d / da, Sk4f(0));
158 Sk4f s2 = Sk4f(2) * s;
159 Sk4f m4 = Sk4f(4) * m;
160
161 // The logic forks three ways:
162 // 1. dark src?
163 // 2. light src, dark dst?
164 // 3. light src, light dst?
165 Sk4f darkSrc = d * (sa + (s2 - sa) * (Sk4f(1) - m)); // Used in case 1.
166 Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m; // Used in case 2.
167 Sk4f liteDst = m.sqrt() - m; // Used in case 3.
168 Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst,
169 liteDst); // Case 2 or 3?
170
171 return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3?
172 s + d * isa);
173}
174
175static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) {
176 Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s));
177 return s + d - min - color_alpha(min, 0);
178}
179
180static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) {
181 Sk4f product = s * d;
182 return s + d - product - color_alpha(product, 0);
183}
184
185////////////////////////////////////////////////////
186
187// The CSS compositing spec introduces the following formulas:
188// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
189// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
190// while PDF and CG uses the one from Rec. Rec. 601
191// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
192static inline float Lum(float r, float g, float b) {
193 return r * 0.2126f + g * 0.7152f + b * 0.0722f;
194}
195
196static inline float max(float a, float b, float c) {
197 return SkTMax(a, SkTMax(b, c));
198}
199
200static inline float min(float a, float b, float c) {
201 return SkTMin(a, SkTMin(b, c));
202}
203
204static inline float Sat(float r, float g, float b) {
205 return max(r, g, b) - min(r, g, b);
206}
207
208static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) {
209 if(*Cmax > *Cmin) {
210 *Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin);
211 *Cmax = s;
212 } else {
213 *Cmax = 0;
214 *Cmid = 0;
215 }
216 *Cmin = 0;
217}
218
219static inline void SetSat(float* r, float* g, float* b, float s) {
220 if(*r <= *g) {
221 if(*g <= *b) {
222 setSaturationComponents(r, g, b, s);
223 } else if(*r <= *b) {
224 setSaturationComponents(r, b, g, s);
225 } else {
226 setSaturationComponents(b, r, g, s);
227 }
228 } else if(*r <= *b) {
229 setSaturationComponents(g, r, b, s);
230 } else if(*g <= *b) {
231 setSaturationComponents(g, b, r, s);
232 } else {
233 setSaturationComponents(b, g, r, s);
234 }
235}
236
237static inline void clipColor(float* r, float* g, float* b, float a) {
238 float L = Lum(*r, *g, *b);
239 float n = min(*r, *g, *b);
240 float x = max(*r, *g, *b);
241 float denom;
242 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
243 float scale = L / denom;
244 *r = L + (*r - L) * scale;
245 *g = L + (*g - L) * scale;
246 *b = L + (*b - L) * scale;
247 }
248
249 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
250 float scale = (a - L) / denom;
251 *r = L + (*r - L) * scale;
252 *g = L + (*g - L) * scale;
253 *b = L + (*b - L) * scale;
254 }
255}
256
257static inline void SetLum(float* r, float* g, float* b, float a, float l) {
258 float d = l - Lum(*r, *g, *b);
259 *r += d;
260 *g += d;
261 *b += d;
262 clipColor(r, g, b, a);
263}
264
265static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) {
266 float sa = s.kth<SkPM4f::A>();
267 float sr = s.kth<SkPM4f::R>();
268 float sg = s.kth<SkPM4f::G>();
269 float sb = s.kth<SkPM4f::B>();
270
271 float da = d.kth<SkPM4f::A>();
272 float dr = d.kth<SkPM4f::R>();
273 float dg = d.kth<SkPM4f::G>();
274 float db = d.kth<SkPM4f::B>();
275
276 float Sr = sr;
277 float Sg = sg;
278 float Sb = sb;
279 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
280 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
281
282 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
283 sa + da - sa * da);
284}
285
286static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) {
287 float sa = s.kth<SkPM4f::A>();
288 float sr = s.kth<SkPM4f::R>();
289 float sg = s.kth<SkPM4f::G>();
290 float sb = s.kth<SkPM4f::B>();
291
292 float da = d.kth<SkPM4f::A>();
293 float dr = d.kth<SkPM4f::R>();
294 float dg = d.kth<SkPM4f::G>();
295 float db = d.kth<SkPM4f::B>();
296
297 float Dr = dr;
298 float Dg = dg;
299 float Db = db;
300 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
301 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
302
303 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
304 sa + da - sa * da);
305}
306
307static Sk4f color_4f(const Sk4f& s, const Sk4f& d) {
308 float sa = s.kth<SkPM4f::A>();
309 float sr = s.kth<SkPM4f::R>();
310 float sg = s.kth<SkPM4f::G>();
311 float sb = s.kth<SkPM4f::B>();
312
313 float da = d.kth<SkPM4f::A>();
314 float dr = d.kth<SkPM4f::R>();
315 float dg = d.kth<SkPM4f::G>();
316 float db = d.kth<SkPM4f::B>();
317
318 float Sr = sr;
319 float Sg = sg;
320 float Sb = sb;
321 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
322
323 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
324 sa + da - sa * da);
325}
326
327static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) {
328 float sa = s.kth<SkPM4f::A>();
329 float sr = s.kth<SkPM4f::R>();
330 float sg = s.kth<SkPM4f::G>();
331 float sb = s.kth<SkPM4f::B>();
332
333 float da = d.kth<SkPM4f::A>();
334 float dr = d.kth<SkPM4f::R>();
335 float dg = d.kth<SkPM4f::G>();
336 float db = d.kth<SkPM4f::B>();
337
338 float Dr = dr;
339 float Dg = dg;
340 float Db = db;
341 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
342
343 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
344 sa + da - sa * da);
reed31255652016-02-08 12:56:56 -0800345}
346
347///////////////////////////////////////////////////////////////////////////////
348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349// kClear_Mode, //!< [0, 0]
350static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
351 return 0;
352}
353
354// kSrc_Mode, //!< [Sa, Sc]
355static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
356 return src;
357}
358
359// kDst_Mode, //!< [Da, Dc]
360static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
361 return dst;
362}
363
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000364// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000366#if 0
367 // this is the old, more-correct way, but it doesn't guarantee that dst==255
368 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000370#else
371 // this is slightly faster, but more importantly guarantees that dst==255
372 // will always stay opaque
373 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
374#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375}
376
reed@android.com1116fb22009-03-03 20:31:12 +0000377// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000379 // this is the reverse of srcover, just flipping src and dst
380 // see srcover's comment about the 256 for opaqueness guarantees
381 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382}
383
384// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
385static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
386 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
387}
388
389// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
390static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
391 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
392}
393
394// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
395static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
396 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
397}
398
399// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
400static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
401 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
402}
403
404// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
405static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
406 unsigned sa = SkGetPackedA32(src);
407 unsigned da = SkGetPackedA32(dst);
408 unsigned isa = 255 - sa;
409
410 return SkPackARGB32(da,
411 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
412 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
413 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
414 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
415 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
416 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
417}
418
419// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
420static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
421 unsigned sa = SkGetPackedA32(src);
422 unsigned da = SkGetPackedA32(dst);
423 unsigned ida = 255 - da;
424
425 return SkPackARGB32(sa,
426 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
427 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
428 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
429 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
430 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
431 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
432}
433
434// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
435static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
436 unsigned sa = SkGetPackedA32(src);
437 unsigned da = SkGetPackedA32(dst);
438 unsigned isa = 255 - sa;
439 unsigned ida = 255 - da;
440
441 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
442 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
443 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
444 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
445 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
446 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
447 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
448}
449
reed@android.coma0f5d152009-06-22 17:38:10 +0000450///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451
reed@android.coma0f5d152009-06-22 17:38:10 +0000452// kPlus_Mode
453static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000454 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000455 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
456 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
457 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000458 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459}
460
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000461// kModulate_Mode
462static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
464 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
465 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
466 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
467 return SkPackARGB32(a, r, g, b);
468}
469
reed@android.coma0f5d152009-06-22 17:38:10 +0000470static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 return a + b - SkAlphaMulAlpha(a, b);
472}
reed@google.com25cfa692013-02-04 20:06:00 +0000473
474// kMultiply_Mode
475// B(Cb, Cs) = Cb x Cs
476// multiply uses its own version of blendfunc_byte because sa and da are not needed
477static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
478 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
479}
480
481static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
482 int sa = SkGetPackedA32(src);
483 int da = SkGetPackedA32(dst);
484 int a = srcover_byte(sa, da);
485 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
486 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
487 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
488 return SkPackARGB32(a, r, g, b);
489}
490
491// kScreen_Mode
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000493 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
494 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
495 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
496 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 return SkPackARGB32(a, r, g, b);
498}
499
reed@android.coma0f5d152009-06-22 17:38:10 +0000500// kOverlay_Mode
501static inline int overlay_byte(int sc, int dc, int sa, int da) {
502 int tmp = sc * (255 - da) + dc * (255 - sa);
503 int rc;
504 if (2 * dc <= da) {
505 rc = 2 * sc * dc;
506 } else {
507 rc = sa * da - 2 * (da - dc) * (sa - sc);
508 }
509 return clamp_div255round(rc + tmp);
510}
511static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
512 int sa = SkGetPackedA32(src);
513 int da = SkGetPackedA32(dst);
514 int a = srcover_byte(sa, da);
515 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
516 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
517 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
518 return SkPackARGB32(a, r, g, b);
519}
520
521// kDarken_Mode
522static inline int darken_byte(int sc, int dc, int sa, int da) {
523 int sd = sc * da;
524 int ds = dc * sa;
525 if (sd < ds) {
526 // srcover
527 return sc + dc - SkDiv255Round(ds);
528 } else {
529 // dstover
530 return dc + sc - SkDiv255Round(sd);
531 }
532}
533static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
534 int sa = SkGetPackedA32(src);
535 int da = SkGetPackedA32(dst);
536 int a = srcover_byte(sa, da);
537 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
538 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
539 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
540 return SkPackARGB32(a, r, g, b);
541}
542
543// kLighten_Mode
544static inline int lighten_byte(int sc, int dc, int sa, int da) {
545 int sd = sc * da;
546 int ds = dc * sa;
547 if (sd > ds) {
548 // srcover
549 return sc + dc - SkDiv255Round(ds);
550 } else {
551 // dstover
552 return dc + sc - SkDiv255Round(sd);
553 }
554}
555static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
556 int sa = SkGetPackedA32(src);
557 int da = SkGetPackedA32(dst);
558 int a = srcover_byte(sa, da);
559 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
560 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
561 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
562 return SkPackARGB32(a, r, g, b);
563}
564
565// kColorDodge_Mode
566static inline int colordodge_byte(int sc, int dc, int sa, int da) {
567 int diff = sa - sc;
568 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000569 if (0 == dc) {
570 return SkAlphaMulAlpha(sc, 255 - da);
571 } else if (0 == diff) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000572 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000573 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000574 diff = dc * sa / diff;
575 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000576 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000577 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000578}
579static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000580 int sa = SkGetPackedA32(src);
581 int da = SkGetPackedA32(dst);
582 int a = srcover_byte(sa, da);
583 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
584 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
585 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.coma0f5d152009-06-22 17:38:10 +0000586 return SkPackARGB32(a, r, g, b);
587}
588
589// kColorBurn_Mode
590static inline int colorburn_byte(int sc, int dc, int sa, int da) {
591 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000592 if (dc == da) {
593 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000594 } else if (0 == sc) {
595 return SkAlphaMulAlpha(dc, 255 - sa);
596 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000597 int tmp = (da - dc) * sa / sc;
598 rc = sa * (da - ((da < tmp) ? da : tmp))
599 + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000600 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000601 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000602}
603static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000604 int sa = SkGetPackedA32(src);
605 int da = SkGetPackedA32(dst);
606 int a = srcover_byte(sa, da);
607 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
608 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
609 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
610 return SkPackARGB32(a, r, g, b);
611}
612
613// kHardLight_Mode
614static inline int hardlight_byte(int sc, int dc, int sa, int da) {
615 int rc;
616 if (2 * sc <= sa) {
617 rc = 2 * sc * dc;
618 } else {
619 rc = sa * da - 2 * (da - dc) * (sa - sc);
620 }
621 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
622}
623static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
624 int sa = SkGetPackedA32(src);
625 int da = SkGetPackedA32(dst);
626 int a = srcover_byte(sa, da);
627 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
628 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
629 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
630 return SkPackARGB32(a, r, g, b);
631}
632
633// returns 255 * sqrt(n/255)
634static U8CPU sqrt_unit_byte(U8CPU n) {
635 return SkSqrtBits(n, 15+4);
636}
637
638// kSoftLight_Mode
639static inline int softlight_byte(int sc, int dc, int sa, int da) {
640 int m = da ? dc * 256 / da : 0;
641 int rc;
642 if (2 * sc <= sa) {
643 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
644 } else if (4 * dc <= da) {
645 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
646 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
647 } else {
648 int tmp = sqrt_unit_byte(m) - m;
649 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
650 }
651 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
652}
653static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
654 int sa = SkGetPackedA32(src);
655 int da = SkGetPackedA32(dst);
656 int a = srcover_byte(sa, da);
657 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
658 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
659 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
660 return SkPackARGB32(a, r, g, b);
661}
662
663// kDifference_Mode
664static inline int difference_byte(int sc, int dc, int sa, int da) {
665 int tmp = SkMin32(sc * da, dc * sa);
666 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
667}
668static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
669 int sa = SkGetPackedA32(src);
670 int da = SkGetPackedA32(dst);
671 int a = srcover_byte(sa, da);
672 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
673 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
674 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
675 return SkPackARGB32(a, r, g, b);
676}
677
678// kExclusion_Mode
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000679static inline int exclusion_byte(int sc, int dc, int, int) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000680 // this equations is wacky, wait for SVG to confirm it
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000681 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
682
683 // The above equation can be simplified as follows
684 int r = 255*(sc + dc) - 2 * sc * dc;
reed@android.coma0f5d152009-06-22 17:38:10 +0000685 return clamp_div255round(r);
686}
687static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
688 int sa = SkGetPackedA32(src);
689 int da = SkGetPackedA32(dst);
690 int a = srcover_byte(sa, da);
691 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
692 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
693 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000694 return SkPackARGB32(a, r, g, b);
695}
696
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000697// The CSS compositing spec introduces the following formulas:
698// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
699// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
700// while PDF and CG uses the one from Rec. Rec. 601
701// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
702static inline int Lum(int r, int g, int b)
703{
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000704 return SkDiv255Round(r * 77 + g * 150 + b * 28);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000705}
706
707static inline int min2(int a, int b) { return a < b ? a : b; }
708static inline int max2(int a, int b) { return a > b ? a : b; }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000709#define minimum(a, b, c) min2(min2(a, b), c)
710#define maximum(a, b, c) max2(max2(a, b), c)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000711
712static inline int Sat(int r, int g, int b) {
713 return maximum(r, g, b) - minimum(r, g, b);
714}
715
716static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
reed@google.com3c1ea3a2013-03-07 15:31:58 +0000717 if(*Cmax > *Cmin) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000718 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000719 *Cmax = s;
720 } else {
721 *Cmax = 0;
722 *Cmid = 0;
723 }
724
725 *Cmin = 0;
726}
727
728static inline void SetSat(int* r, int* g, int* b, int s) {
729 if(*r <= *g) {
730 if(*g <= *b) {
731 setSaturationComponents(r, g, b, s);
732 } else if(*r <= *b) {
733 setSaturationComponents(r, b, g, s);
734 } else {
735 setSaturationComponents(b, r, g, s);
736 }
737 } else if(*r <= *b) {
738 setSaturationComponents(g, r, b, s);
739 } else if(*g <= *b) {
740 setSaturationComponents(g, b, r, s);
741 } else {
742 setSaturationComponents(b, g, r, s);
743 }
744}
745
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000746static inline void clipColor(int* r, int* g, int* b, int a) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000747 int L = Lum(*r, *g, *b);
748 int n = minimum(*r, *g, *b);
749 int x = maximum(*r, *g, *b);
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000750 int denom;
751 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
752 *r = L + SkMulDiv(*r - L, L, denom);
753 *g = L + SkMulDiv(*g - L, L, denom);
754 *b = L + SkMulDiv(*b - L, L, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000755 }
756
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000757 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
758 int numer = a - L;
759 *r = L + SkMulDiv(*r - L, numer, denom);
760 *g = L + SkMulDiv(*g - L, numer, denom);
761 *b = L + SkMulDiv(*b - L, numer, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000762 }
763}
764
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000765static inline void SetLum(int* r, int* g, int* b, int a, int l) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000766 int d = l - Lum(*r, *g, *b);
767 *r += d;
768 *g += d;
769 *b += d;
770
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000771 clipColor(r, g, b, a);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000772}
773
774// non-separable blend modes are done in non-premultiplied alpha
775#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000776 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000777
778// kHue_Mode
779// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
780// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
781static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
782 int sr = SkGetPackedR32(src);
783 int sg = SkGetPackedG32(src);
784 int sb = SkGetPackedB32(src);
785 int sa = SkGetPackedA32(src);
786
787 int dr = SkGetPackedR32(dst);
788 int dg = SkGetPackedG32(dst);
789 int db = SkGetPackedB32(dst);
790 int da = SkGetPackedA32(dst);
791 int Sr, Sg, Sb;
792
793 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000794 Sr = sr * sa;
795 Sg = sg * sa;
796 Sb = sb * sa;
797 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
798 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000799 } else {
800 Sr = 0;
801 Sg = 0;
802 Sb = 0;
803 }
804
805 int a = srcover_byte(sa, da);
806 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
807 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
808 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
809 return SkPackARGB32(a, r, g, b);
810}
811
812// kSaturation_Mode
813// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000814// 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 +0000815static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
816 int sr = SkGetPackedR32(src);
817 int sg = SkGetPackedG32(src);
818 int sb = SkGetPackedB32(src);
819 int sa = SkGetPackedA32(src);
820
821 int dr = SkGetPackedR32(dst);
822 int dg = SkGetPackedG32(dst);
823 int db = SkGetPackedB32(dst);
824 int da = SkGetPackedA32(dst);
825 int Dr, Dg, Db;
826
827 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000828 Dr = dr * sa;
829 Dg = dg * sa;
830 Db = db * sa;
831 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
832 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000833 } else {
834 Dr = 0;
835 Dg = 0;
836 Db = 0;
837 }
838
839 int a = srcover_byte(sa, da);
840 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
841 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
842 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
843 return SkPackARGB32(a, r, g, b);
844}
845
846// kColor_Mode
847// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000848// 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 +0000849static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
850 int sr = SkGetPackedR32(src);
851 int sg = SkGetPackedG32(src);
852 int sb = SkGetPackedB32(src);
853 int sa = SkGetPackedA32(src);
854
855 int dr = SkGetPackedR32(dst);
856 int dg = SkGetPackedG32(dst);
857 int db = SkGetPackedB32(dst);
858 int da = SkGetPackedA32(dst);
859 int Sr, Sg, Sb;
860
861 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000862 Sr = sr * da;
863 Sg = sg * da;
864 Sb = sb * da;
865 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000866 } else {
867 Sr = 0;
868 Sg = 0;
869 Sb = 0;
870 }
871
872 int a = srcover_byte(sa, da);
873 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
874 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
875 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
876 return SkPackARGB32(a, r, g, b);
877}
878
879// kLuminosity_Mode
880// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000881// 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 +0000882static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
883 int sr = SkGetPackedR32(src);
884 int sg = SkGetPackedG32(src);
885 int sb = SkGetPackedB32(src);
886 int sa = SkGetPackedA32(src);
887
888 int dr = SkGetPackedR32(dst);
889 int dg = SkGetPackedG32(dst);
890 int db = SkGetPackedB32(dst);
891 int da = SkGetPackedA32(dst);
892 int Dr, Dg, Db;
893
894 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000895 Dr = dr * sa;
896 Dg = dg * sa;
897 Db = db * sa;
898 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000899 } else {
900 Dr = 0;
901 Dg = 0;
902 Db = 0;
903 }
904
905 int a = srcover_byte(sa, da);
906 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
907 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
908 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
909 return SkPackARGB32(a, r, g, b);
910}
reede7125322016-02-09 11:59:24 -0800911
912///////////////////////////////////////////////////////////////////////////////////////////////////
913
914static SkPM4f as_pm4f(const Sk4f& x) {
915 SkPM4f pm4;
916 x.store(pm4.fVec);
917 return pm4;
918}
919
920static Sk4f as_4f(const SkPM4f& pm4) {
921 return Sk4f::Load(pm4.fVec);
922}
923
924template <Sk4f (blend)(const Sk4f&, const Sk4f&)> SkPM4f proc_4f(const SkPM4f& s, const SkPM4f& d) {
925 SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d)));
926#ifdef SK_DEBUG
927 const float min = 0;
928 const float max = 1;
929 for (int i = 0; i < 4; ++i) {
930 SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max);
931 }
932#endif
933 return r;
reed31255652016-02-08 12:56:56 -0800934}
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000935
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000936const ProcCoeff gProcCoeffs[] = {
reed31255652016-02-08 12:56:56 -0800937 { clear_modeproc, proc_4f<clear_4f>, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
938 { src_modeproc, proc_4f<src_4f>, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
939 { dst_modeproc, proc_4f<dst_4f>, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
940 { srcover_modeproc, proc_4f<srcover_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
941 { dstover_modeproc, proc_4f<dstover_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
942 { srcin_modeproc, proc_4f<srcin_4f>, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
943 { dstin_modeproc, proc_4f<dstin_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
944 { srcout_modeproc, proc_4f<srcout_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
945 { dstout_modeproc, proc_4f<dstout_4f>, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
946 { srcatop_modeproc, proc_4f<srcatop_4f>, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
947 { dstatop_modeproc, proc_4f<dstatop_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
948 { xor_modeproc, proc_4f<xor_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000949
reed31255652016-02-08 12:56:56 -0800950 { plus_modeproc, proc_4f<plus_4f>, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
951 { modulate_modeproc, proc_4f<modulate_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
952 { screen_modeproc, proc_4f<screen_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
reede7125322016-02-09 11:59:24 -0800953 { overlay_modeproc, proc_4f<overlay_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
954 { darken_modeproc, proc_4f<darken_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
955 { lighten_modeproc, proc_4f<lighten_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
956 { colordodge_modeproc, proc_4f<colordodge_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
957 { colorburn_modeproc, proc_4f<colorburn_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
958 { hardlight_modeproc, proc_4f<hardlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
959 { softlight_modeproc, proc_4f<softlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
960 { difference_modeproc, proc_4f<difference_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
961 { exclusion_modeproc, proc_4f<exclusion_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed31255652016-02-08 12:56:56 -0800962 { multiply_modeproc, proc_4f<multiply_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reede7125322016-02-09 11:59:24 -0800963 { hue_modeproc, proc_4f<hue_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
964 { saturation_modeproc, proc_4f<saturation_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
965 { color_modeproc, proc_4f<color_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
966 { luminosity_modeproc, proc_4f<luminosity_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000967};
968
969///////////////////////////////////////////////////////////////////////////////
970
reed@google.com30da7452012-12-17 19:55:24 +0000971bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000972 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000973}
974
robertphillips4f037942016-02-09 05:09:27 -0800975#if SK_SUPPORT_GPU
976const GrFragmentProcessor* SkXfermode::getFragmentProcessorForImageFilter(
977 const GrFragmentProcessor*) const {
978 // This should never be called.
979 // TODO: make pure virtual in SkXfermode once Android update lands
980 SkASSERT(0);
981 return nullptr;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000982}
983
robertphillips4f037942016-02-09 05:09:27 -0800984GrXPFactory* SkXfermode::asXPFactory() const {
985 // This should never be called.
986 // TODO: make pure virtual in SkXfermode once Android update lands
987 SkASSERT(0);
988 return nullptr;
egdaniel378092f2014-12-03 10:40:13 -0800989}
robertphillips4f037942016-02-09 05:09:27 -0800990#endif
egdaniel378092f2014-12-03 10:40:13 -0800991
reed@google.com30da7452012-12-17 19:55:24 +0000992SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000993 // no-op. subclasses should override this
994 return dst;
995}
996
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000997void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
998 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000999 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001000 SkASSERT(dst && src && count >= 0);
1001
halcanary96fcdcc2015-08-27 07:41:13 -07001002 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001003 for (int i = count - 1; i >= 0; --i) {
1004 dst[i] = this->xferColor(src[i], dst[i]);
1005 }
1006 } else {
1007 for (int i = count - 1; i >= 0; --i) {
1008 unsigned a = aa[i];
1009 if (0 != a) {
1010 SkPMColor dstC = dst[i];
1011 SkPMColor C = this->xferColor(src[i], dstC);
1012 if (0xFF != a) {
1013 C = SkFourByteInterp(C, dstC, a);
1014 }
1015 dst[i] = C;
1016 }
1017 }
1018 }
1019}
1020
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +00001021void SkXfermode::xfer16(uint16_t* dst,
1022 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001023 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001024 SkASSERT(dst && src && count >= 0);
1025
halcanary96fcdcc2015-08-27 07:41:13 -07001026 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001027 for (int i = count - 1; i >= 0; --i) {
1028 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1029 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
1030 }
1031 } else {
1032 for (int i = count - 1; i >= 0; --i) {
1033 unsigned a = aa[i];
1034 if (0 != a) {
1035 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1036 SkPMColor C = this->xferColor(src[i], dstC);
1037 if (0xFF != a) {
1038 C = SkFourByteInterp(C, dstC, a);
1039 }
1040 dst[i] = SkPixel32ToPixel16_ToU16(C);
1041 }
1042 }
1043 }
1044}
1045
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +00001046void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +00001047 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +00001048 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001049 SkASSERT(dst && src && count >= 0);
1050
halcanary96fcdcc2015-08-27 07:41:13 -07001051 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001052 for (int i = count - 1; i >= 0; --i) {
1053 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
1054 dst[i] = SkToU8(SkGetPackedA32(res));
1055 }
1056 } else {
1057 for (int i = count - 1; i >= 0; --i) {
1058 unsigned a = aa[i];
1059 if (0 != a) {
1060 SkAlpha dstA = dst[i];
1061 unsigned A = SkGetPackedA32(this->xferColor(src[i],
1062 (SkPMColor)(dstA << SK_A32_SHIFT)));
1063 if (0xFF != a) {
1064 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1065 }
1066 dst[i] = SkToU8(A);
1067 }
1068 }
1069 }
1070}
1071
egdanieldcfb7cf2015-01-22 06:52:29 -08001072bool SkXfermode::supportsCoverageAsAlpha() const {
1073 return false;
1074}
1075
1076bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
1077 return false;
1078}
1079
vandebo@chromium.org48543272011-02-08 19:28:07 +00001080///////////////////////////////////////////////////////////////////////////////
1081///////////////////////////////////////////////////////////////////////////////
1082
reed9fa60da2014-08-21 07:59:51 -07001083SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
1084 uint32_t mode32 = buffer.read32();
senorblanco0f7197b2014-09-24 11:09:38 -07001085 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
halcanary96fcdcc2015-08-27 07:41:13 -07001086 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001087 }
1088 return SkXfermode::Create((SkXfermode::Mode)mode32);
1089}
1090
1091void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
1092 buffer.write32(fMode);
1093}
reed@google.com52314f82013-11-21 21:05:06 +00001094
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001095bool SkProcCoeffXfermode::asMode(Mode* mode) const {
1096 if (mode) {
1097 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001098 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001099 return true;
1100}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +00001101
egdanieldcfb7cf2015-01-22 06:52:29 -08001102bool SkProcCoeffXfermode::supportsCoverageAsAlpha() const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001103 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +00001104 return false;
1105 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001106
egdanieldcfb7cf2015-01-22 06:52:29 -08001107 switch (fDstCoeff) {
1108 case SkXfermode::kOne_Coeff:
1109 case SkXfermode::kISA_Coeff:
1110 case SkXfermode::kISC_Coeff:
1111 return true;
1112 default:
1113 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001114 }
egdanieldcfb7cf2015-01-22 06:52:29 -08001115}
1116
1117bool SkProcCoeffXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
1118 if (CANNOT_USE_COEFF == fSrcCoeff) {
1119 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001120 }
mtklein3d626832015-04-03 07:05:20 -07001121
egdanieldcfb7cf2015-01-22 06:52:29 -08001122 if (SkXfermode::kDA_Coeff == fSrcCoeff || SkXfermode::kDC_Coeff == fSrcCoeff ||
1123 SkXfermode::kIDA_Coeff == fSrcCoeff || SkXfermode::kIDC_Coeff == fSrcCoeff) {
1124 return false;
1125 }
mtklein3d626832015-04-03 07:05:20 -07001126
egdanieldcfb7cf2015-01-22 06:52:29 -08001127 switch (fDstCoeff) {
1128 case SkXfermode::kZero_Coeff:
1129 return true;
1130 case SkXfermode::kISA_Coeff:
1131 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
1132 case SkXfermode::kSA_Coeff:
1133 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType ||
1134 SkXfermode::kTransparentAlpha_SrcColorOpacity == opacityType;
1135 case SkXfermode::kSC_Coeff:
1136 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType;
1137 default:
1138 return false;
1139 }
1140
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001141}
1142
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001143void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1144 const SkPMColor* SK_RESTRICT src, int count,
1145 const SkAlpha* SK_RESTRICT aa) const {
1146 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001147
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001148 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001149
bsalomon49f085d2014-09-05 13:34:00 -07001150 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001151 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001152 for (int i = count - 1; i >= 0; --i) {
1153 dst[i] = proc(src[i], dst[i]);
1154 }
1155 } else {
1156 for (int i = count - 1; i >= 0; --i) {
1157 unsigned a = aa[i];
1158 if (0 != a) {
1159 SkPMColor dstC = dst[i];
1160 SkPMColor C = proc(src[i], dstC);
1161 if (a != 0xFF) {
1162 C = SkFourByteInterp(C, dstC, a);
1163 }
1164 dst[i] = C;
1165 }
1166 }
1167 }
1168 }
1169}
1170
1171void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
1172 const SkPMColor* SK_RESTRICT src, int count,
1173 const SkAlpha* SK_RESTRICT aa) const {
1174 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001175
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001176 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001177
bsalomon49f085d2014-09-05 13:34:00 -07001178 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001179 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001180 for (int i = count - 1; i >= 0; --i) {
1181 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1182 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
1183 }
1184 } else {
1185 for (int i = count - 1; i >= 0; --i) {
1186 unsigned a = aa[i];
1187 if (0 != a) {
1188 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1189 SkPMColor C = proc(src[i], dstC);
1190 if (0xFF != a) {
1191 C = SkFourByteInterp(C, dstC, a);
1192 }
1193 dst[i] = SkPixel32ToPixel16_ToU16(C);
1194 }
1195 }
1196 }
1197 }
1198}
1199
1200void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1201 const SkPMColor* SK_RESTRICT src, int count,
1202 const SkAlpha* SK_RESTRICT aa) const {
1203 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001204
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001205 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001206
bsalomon49f085d2014-09-05 13:34:00 -07001207 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001208 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001209 for (int i = count - 1; i >= 0; --i) {
1210 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
1211 dst[i] = SkToU8(SkGetPackedA32(res));
1212 }
1213 } else {
1214 for (int i = count - 1; i >= 0; --i) {
1215 unsigned a = aa[i];
1216 if (0 != a) {
1217 SkAlpha dstA = dst[i];
1218 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
1219 unsigned A = SkGetPackedA32(res);
1220 if (0xFF != a) {
1221 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1222 }
1223 dst[i] = SkToU8(A);
1224 }
1225 }
1226 }
1227 }
1228}
1229
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001230#if SK_SUPPORT_GPU
egdaniel0063a9b2015-01-15 10:52:32 -08001231#include "effects/GrCustomXfermode.h"
egdanielc4b72722015-11-23 13:20:41 -08001232#include "effects/GrPorterDuffXferProcessor.h"
bsalomonae4738f2015-09-15 15:33:27 -07001233#include "effects/GrXfermodeFragmentProcessor.h"
egdaniel0063a9b2015-01-15 10:52:32 -08001234
robertphillips4f037942016-02-09 05:09:27 -08001235const GrFragmentProcessor* SkProcCoeffXfermode::getFragmentProcessorForImageFilter(
1236 const GrFragmentProcessor* dst) const {
1237 SkASSERT(dst);
1238 return GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001239}
egdaniel54f0e9d2015-01-16 06:29:47 -08001240
robertphillips4f037942016-02-09 05:09:27 -08001241GrXPFactory* SkProcCoeffXfermode::asXPFactory() const {
egdaniel58136162015-01-20 10:19:22 -08001242 if (CANNOT_USE_COEFF != fSrcCoeff) {
robertphillips4f037942016-02-09 05:09:27 -08001243 GrXPFactory* result = GrPorterDuffXPFactory::Create(fMode);
1244 SkASSERT(result);
1245 return result;
egdaniel58136162015-01-20 10:19:22 -08001246 }
1247
robertphillips4f037942016-02-09 05:09:27 -08001248 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
1249 return GrCustomXfermode::CreateXPFactory(fMode);
egdaniel54f0e9d2015-01-16 06:29:47 -08001250}
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001251#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001252
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001253const char* SkXfermode::ModeName(Mode mode) {
1254 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1255 const char* gModeStrings[] = {
1256 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1257 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1258 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1259 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1260 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1261 };
1262 return gModeStrings[mode];
bungeman99fe8222015-08-20 07:57:51 -07001263 static_assert(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, "mode_count");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001264}
1265
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001266#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001267void SkProcCoeffXfermode::toString(SkString* str) const {
1268 str->append("SkProcCoeffXfermode: ");
1269
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001270 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001271 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001272
1273 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001274 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001275 };
1276
1277 str->append(" src: ");
1278 if (CANNOT_USE_COEFF == fSrcCoeff) {
1279 str->append("can't use");
1280 } else {
1281 str->append(gCoeffStrings[fSrcCoeff]);
1282 }
1283
1284 str->append(" dst: ");
1285 if (CANNOT_USE_COEFF == fDstCoeff) {
1286 str->append("can't use");
1287 } else {
1288 str->append(gCoeffStrings[fDstCoeff]);
1289 }
1290}
1291#endif
1292
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293
mtklein6c59d802015-09-09 09:09:53 -07001294SK_DECLARE_STATIC_ONCE_PTR(SkXfermode, cached[SkXfermode::kLastMode + 1]);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001295
reed@android.coma0f5d152009-06-22 17:38:10 +00001296SkXfermode* SkXfermode::Create(Mode mode) {
1297 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001299 if ((unsigned)mode >= kModeCount) {
1300 // report error
halcanary96fcdcc2015-08-27 07:41:13 -07001301 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001303
halcanary96fcdcc2015-08-27 07:41:13 -07001304 // Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as srcover
1305 // so we can just return nullptr from the factory.
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001306 if (kSrcOver_Mode == mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001307 return nullptr;
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001308 }
1309
mtklein6c59d802015-09-09 09:09:53 -07001310 return SkSafeRef(cached[mode].get([=]{
1311 ProcCoeff rec = gProcCoeffs[mode];
1312 if (auto xfermode = SkOpts::create_xfermode(rec, mode)) {
1313 return xfermode;
1314 }
1315 return (SkXfermode*) new SkProcCoeffXfermode(rec, mode);
1316 }));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
reed@google.com43c50c82011-04-14 15:50:52 +00001319SkXfermodeProc SkXfermode::GetProc(Mode mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001320 SkXfermodeProc proc = nullptr;
reed@google.com43c50c82011-04-14 15:50:52 +00001321 if ((unsigned)mode < kModeCount) {
1322 proc = gProcCoeffs[mode].fProc;
1323 }
1324 return proc;
1325}
1326
reed31255652016-02-08 12:56:56 -08001327SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) {
1328 SkXfermodeProc4f proc = nullptr;
1329 if ((unsigned)mode < kModeCount) {
1330 proc = gProcCoeffs[mode].fProc4f;
1331 }
1332 return proc;
1333}
1334
reed@google.com43c50c82011-04-14 15:50:52 +00001335bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1336 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001337
reed@google.com43c50c82011-04-14 15:50:52 +00001338 if ((unsigned)mode >= (unsigned)kModeCount) {
1339 // illegal mode parameter
1340 return false;
1341 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001342
reed@google.com43c50c82011-04-14 15:50:52 +00001343 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001344
reed@google.com43c50c82011-04-14 15:50:52 +00001345 if (CANNOT_USE_COEFF == rec.fSC) {
1346 return false;
1347 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001348
reed@google.com43c50c82011-04-14 15:50:52 +00001349 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1350 if (src) {
1351 *src = rec.fSC;
1352 }
1353 if (dst) {
1354 *dst = rec.fDC;
1355 }
1356 return true;
1357}
1358
reed@google.com30da7452012-12-17 19:55:24 +00001359bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001360 if (nullptr == xfer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361 if (mode) {
1362 *mode = kSrcOver_Mode;
1363 }
1364 return true;
1365 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001366 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367}
1368
reed@google.com30da7452012-12-17 19:55:24 +00001369bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001370 // if xfer==null then the mode is srcover
1371 Mode m = kSrcOver_Mode;
1372 if (xfer && !xfer->asMode(&m)) {
1373 return false;
1374 }
1375 return mode == m;
1376}
1377
egdanieldcfb7cf2015-01-22 06:52:29 -08001378bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) {
halcanary96fcdcc2015-08-27 07:41:13 -07001379 // if xfer is nullptr we treat it as srcOver which always supports coverageAsAlpha
egdanieldcfb7cf2015-01-22 06:52:29 -08001380 if (!xfer) {
1381 return true;
1382 }
1383
1384 return xfer->supportsCoverageAsAlpha();
1385}
1386
1387bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) {
halcanary96fcdcc2015-08-27 07:41:13 -07001388 // if xfer is nullptr we treat it as srcOver which is opaque if our src is opaque
egdanieldcfb7cf2015-01-22 06:52:29 -08001389 if (!xfer) {
1390 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
1391 }
1392
1393 return xfer->isOpaque(opacityType);
1394}
1395
caryclark@google.comd26147a2011-12-15 14:16:43 +00001396SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1397 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
caryclark@google.comd26147a2011-12-15 14:16:43 +00001398SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END