blob: 7f8932770340e9630ecc5e68398bacb6f2023955 [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"
reeddd9ffea2016-02-18 12:39:14 -080017#include "SkPM4f.h"
commit-bot@chromium.orgcd7992b2013-10-17 16:29:34 +000018
reed@android.com8a1c16f2008-12-17 15:59:43 +000019#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
20
deanm@chromium.orgda946992009-07-03 12:54:24 +000021static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000022 SkASSERT(a <= 255);
23 SkASSERT(b <= 255);
24 unsigned sum = a + b;
25 if (sum > 255) {
26 sum = 255;
27 }
28 return sum;
29}
30
deanm@chromium.orgda946992009-07-03 12:54:24 +000031static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000032 if (n < 0) {
33 n = 0;
34 } else if (n > 255) {
35 n = 255;
36 }
37 return n;
38}
39
deanm@chromium.orgda946992009-07-03 12:54:24 +000040static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000041 if (prod <= 0) {
42 return 0;
43 } else if (prod >= 255*255) {
44 return 255;
45 } else {
46 return SkDiv255Round(prod);
47 }
48}
49
reed@android.com8a1c16f2008-12-17 15:59:43 +000050///////////////////////////////////////////////////////////////////////////////
reed31255652016-02-08 12:56:56 -080051#include "SkNx.h"
52
mtklein7c249e52016-02-21 10:54:19 -080053static Sk4f alpha(const Sk4f& color) { return Sk4f(color[3]); }
54static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color[3]); }
reed31255652016-02-08 12:56:56 -080055static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
56
reede7125322016-02-09 11:59:24 -080057static Sk4f color_alpha(const Sk4f& color, float newAlpha) {
mtklein7c249e52016-02-21 10:54:19 -080058 return Sk4f(color[0], color[1], color[2], newAlpha);
reede7125322016-02-09 11:59:24 -080059}
60static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) {
mtklein7c249e52016-02-21 10:54:19 -080061 return color_alpha(color, newAlpha[3]);
reede7125322016-02-09 11:59:24 -080062}
63
64static Sk4f set_argb(float a, float r, float g, float b) {
65 if (0 == SkPM4f::R) {
66 return Sk4f(r, g, b, a);
67 } else {
68 return Sk4f(b, g, r, a);
69 }
70}
71
reed31255652016-02-08 12:56:56 -080072static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
73static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; }
74static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
75static Sk4f srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; }
76static Sk4f dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; }
77static Sk4f srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); }
78static Sk4f dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); }
79static Sk4f srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); }
80static Sk4f dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); }
81static Sk4f srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); }
82static Sk4f dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); }
83static Sk4f xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);}
84static Sk4f plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); }
85static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; }
86static Sk4f screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; }
87
88static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
89 return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
90}
91
reede7125322016-02-09 11:59:24 -080092static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) {
93 Sk4f sa = alpha(s);
94 Sk4f da = alpha(d);
95 Sk4f two = Sk4f(2);
96 Sk4f rc = (two * d <= da).thenElse(two * s * d,
97 sa * da - two * (da - d) * (sa - s));
98 return s + d - s * da + color_alpha(rc - d * sa, 0);
reed31255652016-02-08 12:56:56 -080099}
100
reede7125322016-02-09 11:59:24 -0800101static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) {
102 return overlay_4f(d, s);
reed31255652016-02-08 12:56:56 -0800103}
104
reede7125322016-02-09 11:59:24 -0800105static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) {
106 Sk4f sa = alpha(s);
107 Sk4f da = alpha(d);
108 return s + d - Sk4f::Max(s * da, d * sa);
109}
110
111static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) {
112 Sk4f sa = alpha(s);
113 Sk4f da = alpha(d);
114 return s + d - Sk4f::Min(s * da, d * sa);
115}
116
117static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) {
118 Sk4f sa = alpha(s);
119 Sk4f da = alpha(d);
120 Sk4f isa = Sk4f(1) - sa;
121 Sk4f ida = Sk4f(1) - da;
122
123 Sk4f srcover = s + d * isa;
124 Sk4f dstover = d + s * ida;
125 Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa;
126
127 // Order matters here, preferring d==0 over s==sa.
128 auto colors = (d == Sk4f(0)).thenElse(dstover,
129 (s == sa).thenElse(srcover,
130 otherwise));
131 return color_alpha(colors, srcover);
132}
133
134static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) {
135 Sk4f sa = alpha(s);
136 Sk4f da = alpha(d);
137 Sk4f isa = Sk4f(1) - sa;
138 Sk4f ida = Sk4f(1) - da;
139
140 Sk4f srcover = s + d * isa;
141 Sk4f dstover = d + s * ida;
142 Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa;
143
144 // Order matters here, preferring d==da over s==0.
145 auto colors = (d == da).thenElse(dstover,
146 (s == Sk4f(0)).thenElse(srcover,
147 otherwise));
148 return color_alpha(colors, srcover);
149}
150
151static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) {
152 Sk4f sa = alpha(s);
153 Sk4f da = alpha(d);
154 Sk4f isa = Sk4f(1) - sa;
155 Sk4f ida = Sk4f(1) - da;
156
157 // Some common terms.
158 Sk4f m = (da > Sk4f(0)).thenElse(d / da, Sk4f(0));
159 Sk4f s2 = Sk4f(2) * s;
160 Sk4f m4 = Sk4f(4) * m;
161
162 // The logic forks three ways:
163 // 1. dark src?
164 // 2. light src, dark dst?
165 // 3. light src, light dst?
166 Sk4f darkSrc = d * (sa + (s2 - sa) * (Sk4f(1) - m)); // Used in case 1.
167 Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m; // Used in case 2.
168 Sk4f liteDst = m.sqrt() - m; // Used in case 3.
169 Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst,
170 liteDst); // Case 2 or 3?
171
172 return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3?
173 s + d * isa);
174}
175
176static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) {
177 Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s));
178 return s + d - min - color_alpha(min, 0);
179}
180
181static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) {
182 Sk4f product = s * d;
183 return s + d - product - color_alpha(product, 0);
184}
185
186////////////////////////////////////////////////////
187
188// The CSS compositing spec introduces the following formulas:
189// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
190// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
191// while PDF and CG uses the one from Rec. Rec. 601
192// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
193static inline float Lum(float r, float g, float b) {
194 return r * 0.2126f + g * 0.7152f + b * 0.0722f;
195}
196
197static inline float max(float a, float b, float c) {
198 return SkTMax(a, SkTMax(b, c));
199}
200
201static inline float min(float a, float b, float c) {
202 return SkTMin(a, SkTMin(b, c));
203}
204
205static inline float Sat(float r, float g, float b) {
206 return max(r, g, b) - min(r, g, b);
207}
208
209static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) {
210 if(*Cmax > *Cmin) {
211 *Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin);
212 *Cmax = s;
213 } else {
214 *Cmax = 0;
215 *Cmid = 0;
216 }
217 *Cmin = 0;
218}
219
220static inline void SetSat(float* r, float* g, float* b, float s) {
221 if(*r <= *g) {
222 if(*g <= *b) {
223 setSaturationComponents(r, g, b, s);
224 } else if(*r <= *b) {
225 setSaturationComponents(r, b, g, s);
226 } else {
227 setSaturationComponents(b, r, g, s);
228 }
229 } else if(*r <= *b) {
230 setSaturationComponents(g, r, b, s);
231 } else if(*g <= *b) {
232 setSaturationComponents(g, b, r, s);
233 } else {
234 setSaturationComponents(b, g, r, s);
235 }
236}
237
238static inline void clipColor(float* r, float* g, float* b, float a) {
239 float L = Lum(*r, *g, *b);
240 float n = min(*r, *g, *b);
241 float x = max(*r, *g, *b);
242 float denom;
243 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
244 float scale = L / denom;
245 *r = L + (*r - L) * scale;
246 *g = L + (*g - L) * scale;
247 *b = L + (*b - L) * scale;
248 }
249
250 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
251 float scale = (a - L) / denom;
252 *r = L + (*r - L) * scale;
253 *g = L + (*g - L) * scale;
254 *b = L + (*b - L) * scale;
255 }
256}
257
258static inline void SetLum(float* r, float* g, float* b, float a, float l) {
259 float d = l - Lum(*r, *g, *b);
260 *r += d;
261 *g += d;
262 *b += d;
263 clipColor(r, g, b, a);
264}
265
266static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) {
mtklein7c249e52016-02-21 10:54:19 -0800267 float sa = s[SkPM4f::A];
268 float sr = s[SkPM4f::R];
269 float sg = s[SkPM4f::G];
270 float sb = s[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800271
mtklein7c249e52016-02-21 10:54:19 -0800272 float da = d[SkPM4f::A];
273 float dr = d[SkPM4f::R];
274 float dg = d[SkPM4f::G];
275 float db = d[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800276
277 float Sr = sr;
278 float Sg = sg;
279 float Sb = sb;
280 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
281 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
282
283 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
284 sa + da - sa * da);
285}
286
287static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) {
mtklein7c249e52016-02-21 10:54:19 -0800288 float sa = s[SkPM4f::A];
289 float sr = s[SkPM4f::R];
290 float sg = s[SkPM4f::G];
291 float sb = s[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800292
mtklein7c249e52016-02-21 10:54:19 -0800293 float da = d[SkPM4f::A];
294 float dr = d[SkPM4f::R];
295 float dg = d[SkPM4f::G];
296 float db = d[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800297
298 float Dr = dr;
299 float Dg = dg;
300 float Db = db;
301 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
302 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
303
304 return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
305 sa + da - sa * da);
306}
307
308static Sk4f color_4f(const Sk4f& s, const Sk4f& d) {
mtklein7c249e52016-02-21 10:54:19 -0800309 float sa = s[SkPM4f::A];
310 float sr = s[SkPM4f::R];
311 float sg = s[SkPM4f::G];
312 float sb = s[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800313
mtklein7c249e52016-02-21 10:54:19 -0800314 float da = d[SkPM4f::A];
315 float dr = d[SkPM4f::R];
316 float dg = d[SkPM4f::G];
317 float db = d[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800318
319 float Sr = sr;
320 float Sg = sg;
321 float Sb = sb;
322 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
323
reed576af8f2016-02-17 18:02:49 -0800324 Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
325 sa + da - sa * da);
326 // Can return tiny negative values ...
327 return Sk4f::Max(res, Sk4f(0));
reede7125322016-02-09 11:59:24 -0800328}
329
330static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) {
mtklein7c249e52016-02-21 10:54:19 -0800331 float sa = s[SkPM4f::A];
332 float sr = s[SkPM4f::R];
333 float sg = s[SkPM4f::G];
334 float sb = s[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800335
mtklein7c249e52016-02-21 10:54:19 -0800336 float da = d[SkPM4f::A];
337 float dr = d[SkPM4f::R];
338 float dg = d[SkPM4f::G];
339 float db = d[SkPM4f::B];
reede7125322016-02-09 11:59:24 -0800340
341 float Dr = dr;
342 float Dg = dg;
343 float Db = db;
344 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
345
reed576af8f2016-02-17 18:02:49 -0800346 Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
347 sa + da - sa * da);
348 // Can return tiny negative values ...
349 return Sk4f::Max(res, Sk4f(0));
reed31255652016-02-08 12:56:56 -0800350}
351
352///////////////////////////////////////////////////////////////////////////////
353
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354// kClear_Mode, //!< [0, 0]
355static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
356 return 0;
357}
358
359// kSrc_Mode, //!< [Sa, Sc]
360static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
361 return src;
362}
363
364// kDst_Mode, //!< [Da, Dc]
365static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
366 return dst;
367}
368
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000369// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000371#if 0
372 // this is the old, more-correct way, but it doesn't guarantee that dst==255
373 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000375#else
376 // this is slightly faster, but more importantly guarantees that dst==255
377 // will always stay opaque
378 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
379#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380}
381
reed@android.com1116fb22009-03-03 20:31:12 +0000382// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000384 // this is the reverse of srcover, just flipping src and dst
385 // see srcover's comment about the 256 for opaqueness guarantees
386 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387}
388
389// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
390static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
391 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
392}
393
394// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
395static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
396 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
397}
398
399// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
400static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
401 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
402}
403
404// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
405static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
406 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
407}
408
409// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
410static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
411 unsigned sa = SkGetPackedA32(src);
412 unsigned da = SkGetPackedA32(dst);
413 unsigned isa = 255 - sa;
414
415 return SkPackARGB32(da,
416 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
417 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
418 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
419 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
420 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
421 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
422}
423
424// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
425static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
426 unsigned sa = SkGetPackedA32(src);
427 unsigned da = SkGetPackedA32(dst);
428 unsigned ida = 255 - da;
429
430 return SkPackARGB32(sa,
431 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
432 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
433 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
434 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
435 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
436 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
437}
438
439// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
440static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
441 unsigned sa = SkGetPackedA32(src);
442 unsigned da = SkGetPackedA32(dst);
443 unsigned isa = 255 - sa;
444 unsigned ida = 255 - da;
445
446 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
447 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
448 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
449 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
450 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
451 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
452 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
453}
454
reed@android.coma0f5d152009-06-22 17:38:10 +0000455///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
reed@android.coma0f5d152009-06-22 17:38:10 +0000457// kPlus_Mode
458static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000459 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000460 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
461 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
462 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000463 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464}
465
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000466// kModulate_Mode
467static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
469 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
470 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
471 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
472 return SkPackARGB32(a, r, g, b);
473}
474
reed@android.coma0f5d152009-06-22 17:38:10 +0000475static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 return a + b - SkAlphaMulAlpha(a, b);
477}
reed@google.com25cfa692013-02-04 20:06:00 +0000478
479// kMultiply_Mode
480// B(Cb, Cs) = Cb x Cs
481// multiply uses its own version of blendfunc_byte because sa and da are not needed
482static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
483 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
484}
485
486static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
487 int sa = SkGetPackedA32(src);
488 int da = SkGetPackedA32(dst);
489 int a = srcover_byte(sa, da);
490 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
491 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
492 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
493 return SkPackARGB32(a, r, g, b);
494}
495
496// kScreen_Mode
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000498 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
499 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
500 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
501 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 return SkPackARGB32(a, r, g, b);
503}
504
reed@android.coma0f5d152009-06-22 17:38:10 +0000505// kOverlay_Mode
506static inline int overlay_byte(int sc, int dc, int sa, int da) {
507 int tmp = sc * (255 - da) + dc * (255 - sa);
508 int rc;
509 if (2 * dc <= da) {
510 rc = 2 * sc * dc;
511 } else {
512 rc = sa * da - 2 * (da - dc) * (sa - sc);
513 }
514 return clamp_div255round(rc + tmp);
515}
516static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
517 int sa = SkGetPackedA32(src);
518 int da = SkGetPackedA32(dst);
519 int a = srcover_byte(sa, da);
520 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
521 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
522 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
523 return SkPackARGB32(a, r, g, b);
524}
525
526// kDarken_Mode
527static inline int darken_byte(int sc, int dc, int sa, int da) {
528 int sd = sc * da;
529 int ds = dc * sa;
530 if (sd < ds) {
531 // srcover
532 return sc + dc - SkDiv255Round(ds);
533 } else {
534 // dstover
535 return dc + sc - SkDiv255Round(sd);
536 }
537}
538static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
539 int sa = SkGetPackedA32(src);
540 int da = SkGetPackedA32(dst);
541 int a = srcover_byte(sa, da);
542 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
543 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
544 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
545 return SkPackARGB32(a, r, g, b);
546}
547
548// kLighten_Mode
549static inline int lighten_byte(int sc, int dc, int sa, int da) {
550 int sd = sc * da;
551 int ds = dc * sa;
552 if (sd > ds) {
553 // srcover
554 return sc + dc - SkDiv255Round(ds);
555 } else {
556 // dstover
557 return dc + sc - SkDiv255Round(sd);
558 }
559}
560static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
561 int sa = SkGetPackedA32(src);
562 int da = SkGetPackedA32(dst);
563 int a = srcover_byte(sa, da);
564 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
565 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
566 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
567 return SkPackARGB32(a, r, g, b);
568}
569
570// kColorDodge_Mode
571static inline int colordodge_byte(int sc, int dc, int sa, int da) {
572 int diff = sa - sc;
573 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000574 if (0 == dc) {
575 return SkAlphaMulAlpha(sc, 255 - da);
576 } else if (0 == diff) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000577 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000578 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000579 diff = dc * sa / diff;
580 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000581 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000582 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000583}
584static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000585 int sa = SkGetPackedA32(src);
586 int da = SkGetPackedA32(dst);
587 int a = srcover_byte(sa, da);
588 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
589 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
590 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.coma0f5d152009-06-22 17:38:10 +0000591 return SkPackARGB32(a, r, g, b);
592}
593
594// kColorBurn_Mode
595static inline int colorburn_byte(int sc, int dc, int sa, int da) {
596 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000597 if (dc == da) {
598 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000599 } else if (0 == sc) {
600 return SkAlphaMulAlpha(dc, 255 - sa);
601 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000602 int tmp = (da - dc) * sa / sc;
603 rc = sa * (da - ((da < tmp) ? da : tmp))
604 + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000605 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000606 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000607}
608static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000609 int sa = SkGetPackedA32(src);
610 int da = SkGetPackedA32(dst);
611 int a = srcover_byte(sa, da);
612 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
613 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
614 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
615 return SkPackARGB32(a, r, g, b);
616}
617
618// kHardLight_Mode
619static inline int hardlight_byte(int sc, int dc, int sa, int da) {
620 int rc;
621 if (2 * sc <= sa) {
622 rc = 2 * sc * dc;
623 } else {
624 rc = sa * da - 2 * (da - dc) * (sa - sc);
625 }
626 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
627}
628static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
629 int sa = SkGetPackedA32(src);
630 int da = SkGetPackedA32(dst);
631 int a = srcover_byte(sa, da);
632 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
633 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
634 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
635 return SkPackARGB32(a, r, g, b);
636}
637
638// returns 255 * sqrt(n/255)
639static U8CPU sqrt_unit_byte(U8CPU n) {
640 return SkSqrtBits(n, 15+4);
641}
642
643// kSoftLight_Mode
644static inline int softlight_byte(int sc, int dc, int sa, int da) {
645 int m = da ? dc * 256 / da : 0;
646 int rc;
647 if (2 * sc <= sa) {
648 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
649 } else if (4 * dc <= da) {
650 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
651 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
652 } else {
653 int tmp = sqrt_unit_byte(m) - m;
654 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
655 }
656 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
657}
658static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
659 int sa = SkGetPackedA32(src);
660 int da = SkGetPackedA32(dst);
661 int a = srcover_byte(sa, da);
662 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
663 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
664 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
665 return SkPackARGB32(a, r, g, b);
666}
667
668// kDifference_Mode
669static inline int difference_byte(int sc, int dc, int sa, int da) {
670 int tmp = SkMin32(sc * da, dc * sa);
671 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
672}
673static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
674 int sa = SkGetPackedA32(src);
675 int da = SkGetPackedA32(dst);
676 int a = srcover_byte(sa, da);
677 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
678 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
679 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
680 return SkPackARGB32(a, r, g, b);
681}
682
683// kExclusion_Mode
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000684static inline int exclusion_byte(int sc, int dc, int, int) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000685 // this equations is wacky, wait for SVG to confirm it
commit-bot@chromium.orge38e53b2013-07-15 12:20:36 +0000686 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
687
688 // The above equation can be simplified as follows
689 int r = 255*(sc + dc) - 2 * sc * dc;
reed@android.coma0f5d152009-06-22 17:38:10 +0000690 return clamp_div255round(r);
691}
692static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
693 int sa = SkGetPackedA32(src);
694 int da = SkGetPackedA32(dst);
695 int a = srcover_byte(sa, da);
696 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
697 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
698 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000699 return SkPackARGB32(a, r, g, b);
700}
701
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000702// The CSS compositing spec introduces the following formulas:
703// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
704// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
705// while PDF and CG uses the one from Rec. Rec. 601
706// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
707static inline int Lum(int r, int g, int b)
708{
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000709 return SkDiv255Round(r * 77 + g * 150 + b * 28);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000710}
711
712static inline int min2(int a, int b) { return a < b ? a : b; }
713static inline int max2(int a, int b) { return a > b ? a : b; }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000714#define minimum(a, b, c) min2(min2(a, b), c)
715#define maximum(a, b, c) max2(max2(a, b), c)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000716
717static inline int Sat(int r, int g, int b) {
718 return maximum(r, g, b) - minimum(r, g, b);
719}
720
721static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
reed@google.com3c1ea3a2013-03-07 15:31:58 +0000722 if(*Cmax > *Cmin) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000723 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000724 *Cmax = s;
725 } else {
726 *Cmax = 0;
727 *Cmid = 0;
728 }
729
730 *Cmin = 0;
731}
732
733static inline void SetSat(int* r, int* g, int* b, int s) {
734 if(*r <= *g) {
735 if(*g <= *b) {
736 setSaturationComponents(r, g, b, s);
737 } else if(*r <= *b) {
738 setSaturationComponents(r, b, g, s);
739 } else {
740 setSaturationComponents(b, r, g, s);
741 }
742 } else if(*r <= *b) {
743 setSaturationComponents(g, r, b, s);
744 } else if(*g <= *b) {
745 setSaturationComponents(g, b, r, s);
746 } else {
747 setSaturationComponents(b, g, r, s);
748 }
749}
750
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000751static inline void clipColor(int* r, int* g, int* b, int a) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000752 int L = Lum(*r, *g, *b);
753 int n = minimum(*r, *g, *b);
754 int x = maximum(*r, *g, *b);
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000755 int denom;
756 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
757 *r = L + SkMulDiv(*r - L, L, denom);
758 *g = L + SkMulDiv(*g - L, L, denom);
759 *b = L + SkMulDiv(*b - L, L, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000760 }
761
commit-bot@chromium.orgb85ebea2013-12-12 19:47:09 +0000762 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
763 int numer = a - L;
764 *r = L + SkMulDiv(*r - L, numer, denom);
765 *g = L + SkMulDiv(*g - L, numer, denom);
766 *b = L + SkMulDiv(*b - L, numer, denom);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000767 }
768}
769
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000770static inline void SetLum(int* r, int* g, int* b, int a, int l) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000771 int d = l - Lum(*r, *g, *b);
772 *r += d;
773 *g += d;
774 *b += d;
775
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000776 clipColor(r, g, b, a);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000777}
778
779// non-separable blend modes are done in non-premultiplied alpha
780#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000781 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000782
783// kHue_Mode
784// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
785// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
786static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
787 int sr = SkGetPackedR32(src);
788 int sg = SkGetPackedG32(src);
789 int sb = SkGetPackedB32(src);
790 int sa = SkGetPackedA32(src);
791
792 int dr = SkGetPackedR32(dst);
793 int dg = SkGetPackedG32(dst);
794 int db = SkGetPackedB32(dst);
795 int da = SkGetPackedA32(dst);
796 int Sr, Sg, Sb;
797
798 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000799 Sr = sr * sa;
800 Sg = sg * sa;
801 Sb = sb * sa;
802 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
803 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000804 } else {
805 Sr = 0;
806 Sg = 0;
807 Sb = 0;
808 }
809
810 int a = srcover_byte(sa, da);
811 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
812 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
813 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
814 return SkPackARGB32(a, r, g, b);
815}
816
817// kSaturation_Mode
818// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000819// 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 +0000820static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
821 int sr = SkGetPackedR32(src);
822 int sg = SkGetPackedG32(src);
823 int sb = SkGetPackedB32(src);
824 int sa = SkGetPackedA32(src);
825
826 int dr = SkGetPackedR32(dst);
827 int dg = SkGetPackedG32(dst);
828 int db = SkGetPackedB32(dst);
829 int da = SkGetPackedA32(dst);
830 int Dr, Dg, Db;
831
832 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000833 Dr = dr * sa;
834 Dg = dg * sa;
835 Db = db * sa;
836 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
837 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000838 } else {
839 Dr = 0;
840 Dg = 0;
841 Db = 0;
842 }
843
844 int a = srcover_byte(sa, da);
845 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
846 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
847 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
848 return SkPackARGB32(a, r, g, b);
849}
850
851// kColor_Mode
852// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000853// 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 +0000854static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
855 int sr = SkGetPackedR32(src);
856 int sg = SkGetPackedG32(src);
857 int sb = SkGetPackedB32(src);
858 int sa = SkGetPackedA32(src);
859
860 int dr = SkGetPackedR32(dst);
861 int dg = SkGetPackedG32(dst);
862 int db = SkGetPackedB32(dst);
863 int da = SkGetPackedA32(dst);
864 int Sr, Sg, Sb;
865
866 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000867 Sr = sr * da;
868 Sg = sg * da;
869 Sb = sb * da;
870 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000871 } else {
872 Sr = 0;
873 Sg = 0;
874 Sb = 0;
875 }
876
877 int a = srcover_byte(sa, da);
878 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
879 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
880 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
881 return SkPackARGB32(a, r, g, b);
882}
883
884// kLuminosity_Mode
885// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000886// 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 +0000887static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
888 int sr = SkGetPackedR32(src);
889 int sg = SkGetPackedG32(src);
890 int sb = SkGetPackedB32(src);
891 int sa = SkGetPackedA32(src);
892
893 int dr = SkGetPackedR32(dst);
894 int dg = SkGetPackedG32(dst);
895 int db = SkGetPackedB32(dst);
896 int da = SkGetPackedA32(dst);
897 int Dr, Dg, Db;
898
899 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000900 Dr = dr * sa;
901 Dg = dg * sa;
902 Db = db * sa;
903 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000904 } else {
905 Dr = 0;
906 Dg = 0;
907 Db = 0;
908 }
909
910 int a = srcover_byte(sa, da);
911 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
912 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
913 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
914 return SkPackARGB32(a, r, g, b);
915}
reede7125322016-02-09 11:59:24 -0800916
917///////////////////////////////////////////////////////////////////////////////////////////////////
918
919static SkPM4f as_pm4f(const Sk4f& x) {
920 SkPM4f pm4;
921 x.store(pm4.fVec);
922 return pm4;
923}
924
925static Sk4f as_4f(const SkPM4f& pm4) {
926 return Sk4f::Load(pm4.fVec);
927}
928
reed576af8f2016-02-17 18:02:49 -0800929static void assert_unit(const SkPM4f& r) {
reede7125322016-02-09 11:59:24 -0800930#ifdef SK_DEBUG
931 const float min = 0;
932 const float max = 1;
933 for (int i = 0; i < 4; ++i) {
934 SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max);
935 }
936#endif
reed576af8f2016-02-17 18:02:49 -0800937}
938
939template <Sk4f (blend)(const Sk4f&, const Sk4f&)> SkPM4f proc_4f(const SkPM4f& s, const SkPM4f& d) {
940 assert_unit(s);
941 assert_unit(d);
942 SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d)));
943 assert_unit(r);
reede7125322016-02-09 11:59:24 -0800944 return r;
reed31255652016-02-08 12:56:56 -0800945}
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000946
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +0000947const ProcCoeff gProcCoeffs[] = {
reed31255652016-02-08 12:56:56 -0800948 { clear_modeproc, proc_4f<clear_4f>, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
949 { src_modeproc, proc_4f<src_4f>, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
950 { dst_modeproc, proc_4f<dst_4f>, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
951 { srcover_modeproc, proc_4f<srcover_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
952 { dstover_modeproc, proc_4f<dstover_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
953 { srcin_modeproc, proc_4f<srcin_4f>, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
954 { dstin_modeproc, proc_4f<dstin_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
955 { srcout_modeproc, proc_4f<srcout_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
956 { dstout_modeproc, proc_4f<dstout_4f>, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
957 { srcatop_modeproc, proc_4f<srcatop_4f>, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
958 { dstatop_modeproc, proc_4f<dstatop_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
959 { xor_modeproc, proc_4f<xor_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000960
reed31255652016-02-08 12:56:56 -0800961 { plus_modeproc, proc_4f<plus_4f>, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
962 { modulate_modeproc, proc_4f<modulate_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
963 { screen_modeproc, proc_4f<screen_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
reede7125322016-02-09 11:59:24 -0800964 { overlay_modeproc, proc_4f<overlay_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
965 { darken_modeproc, proc_4f<darken_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
966 { lighten_modeproc, proc_4f<lighten_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
967 { colordodge_modeproc, proc_4f<colordodge_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
968 { colorburn_modeproc, proc_4f<colorburn_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
969 { hardlight_modeproc, proc_4f<hardlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
970 { softlight_modeproc, proc_4f<softlight_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
971 { difference_modeproc, proc_4f<difference_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
972 { exclusion_modeproc, proc_4f<exclusion_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed31255652016-02-08 12:56:56 -0800973 { multiply_modeproc, proc_4f<multiply_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reede7125322016-02-09 11:59:24 -0800974 { hue_modeproc, proc_4f<hue_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
975 { saturation_modeproc, proc_4f<saturation_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
976 { color_modeproc, proc_4f<color_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
977 { luminosity_modeproc, proc_4f<luminosity_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000978};
979
980///////////////////////////////////////////////////////////////////////////////
981
reed@google.com30da7452012-12-17 19:55:24 +0000982bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000983 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000984}
985
robertphillips4f037942016-02-09 05:09:27 -0800986#if SK_SUPPORT_GPU
987const GrFragmentProcessor* SkXfermode::getFragmentProcessorForImageFilter(
988 const GrFragmentProcessor*) const {
989 // This should never be called.
990 // TODO: make pure virtual in SkXfermode once Android update lands
991 SkASSERT(0);
992 return nullptr;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000993}
994
robertphillips4f037942016-02-09 05:09:27 -0800995GrXPFactory* SkXfermode::asXPFactory() const {
996 // This should never be called.
997 // TODO: make pure virtual in SkXfermode once Android update lands
998 SkASSERT(0);
999 return nullptr;
egdaniel378092f2014-12-03 10:40:13 -08001000}
robertphillips4f037942016-02-09 05:09:27 -08001001#endif
egdaniel378092f2014-12-03 10:40:13 -08001002
reed@google.com30da7452012-12-17 19:55:24 +00001003SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +00001004 // no-op. subclasses should override this
1005 return dst;
1006}
1007
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +00001008void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1009 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001010 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001011 SkASSERT(dst && src && count >= 0);
1012
halcanary96fcdcc2015-08-27 07:41:13 -07001013 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001014 for (int i = count - 1; i >= 0; --i) {
1015 dst[i] = this->xferColor(src[i], dst[i]);
1016 }
1017 } else {
1018 for (int i = count - 1; i >= 0; --i) {
1019 unsigned a = aa[i];
1020 if (0 != a) {
1021 SkPMColor dstC = dst[i];
1022 SkPMColor C = this->xferColor(src[i], dstC);
1023 if (0xFF != a) {
1024 C = SkFourByteInterp(C, dstC, a);
1025 }
1026 dst[i] = C;
1027 }
1028 }
1029 }
1030}
1031
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +00001032void SkXfermode::xfer16(uint16_t* dst,
1033 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001034 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001035 SkASSERT(dst && src && count >= 0);
1036
halcanary96fcdcc2015-08-27 07:41:13 -07001037 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001038 for (int i = count - 1; i >= 0; --i) {
1039 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1040 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
1041 }
1042 } else {
1043 for (int i = count - 1; i >= 0; --i) {
1044 unsigned a = aa[i];
1045 if (0 != a) {
1046 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1047 SkPMColor C = this->xferColor(src[i], dstC);
1048 if (0xFF != a) {
1049 C = SkFourByteInterp(C, dstC, a);
1050 }
1051 dst[i] = SkPixel32ToPixel16_ToU16(C);
1052 }
1053 }
1054 }
1055}
1056
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +00001057void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +00001058 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +00001059 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001060 SkASSERT(dst && src && count >= 0);
1061
halcanary96fcdcc2015-08-27 07:41:13 -07001062 if (nullptr == aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +00001063 for (int i = count - 1; i >= 0; --i) {
1064 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
1065 dst[i] = SkToU8(SkGetPackedA32(res));
1066 }
1067 } else {
1068 for (int i = count - 1; i >= 0; --i) {
1069 unsigned a = aa[i];
1070 if (0 != a) {
1071 SkAlpha dstA = dst[i];
1072 unsigned A = SkGetPackedA32(this->xferColor(src[i],
1073 (SkPMColor)(dstA << SK_A32_SHIFT)));
1074 if (0xFF != a) {
1075 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1076 }
1077 dst[i] = SkToU8(A);
1078 }
1079 }
1080 }
1081}
1082
egdanieldcfb7cf2015-01-22 06:52:29 -08001083bool SkXfermode::supportsCoverageAsAlpha() const {
1084 return false;
1085}
1086
1087bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
1088 return false;
1089}
1090
vandebo@chromium.org48543272011-02-08 19:28:07 +00001091///////////////////////////////////////////////////////////////////////////////
1092///////////////////////////////////////////////////////////////////////////////
1093
reed9fa60da2014-08-21 07:59:51 -07001094SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
1095 uint32_t mode32 = buffer.read32();
senorblanco0f7197b2014-09-24 11:09:38 -07001096 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
halcanary96fcdcc2015-08-27 07:41:13 -07001097 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001098 }
1099 return SkXfermode::Create((SkXfermode::Mode)mode32);
1100}
1101
1102void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
1103 buffer.write32(fMode);
1104}
reed@google.com52314f82013-11-21 21:05:06 +00001105
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001106bool SkProcCoeffXfermode::asMode(Mode* mode) const {
1107 if (mode) {
1108 *mode = fMode;
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001109 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001110 return true;
1111}
commit-bot@chromium.org84cc1eb2013-10-08 16:47:22 +00001112
egdanieldcfb7cf2015-01-22 06:52:29 -08001113bool SkProcCoeffXfermode::supportsCoverageAsAlpha() const {
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001114 if (CANNOT_USE_COEFF == fSrcCoeff) {
djsollen@google.com6f980c62013-10-08 16:59:53 +00001115 return false;
1116 }
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001117
egdanieldcfb7cf2015-01-22 06:52:29 -08001118 switch (fDstCoeff) {
1119 case SkXfermode::kOne_Coeff:
1120 case SkXfermode::kISA_Coeff:
1121 case SkXfermode::kISC_Coeff:
1122 return true;
1123 default:
1124 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001125 }
egdanieldcfb7cf2015-01-22 06:52:29 -08001126}
1127
1128bool SkProcCoeffXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
1129 if (CANNOT_USE_COEFF == fSrcCoeff) {
1130 return false;
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001131 }
mtklein3d626832015-04-03 07:05:20 -07001132
egdanieldcfb7cf2015-01-22 06:52:29 -08001133 if (SkXfermode::kDA_Coeff == fSrcCoeff || SkXfermode::kDC_Coeff == fSrcCoeff ||
1134 SkXfermode::kIDA_Coeff == fSrcCoeff || SkXfermode::kIDC_Coeff == fSrcCoeff) {
1135 return false;
1136 }
mtklein3d626832015-04-03 07:05:20 -07001137
egdanieldcfb7cf2015-01-22 06:52:29 -08001138 switch (fDstCoeff) {
1139 case SkXfermode::kZero_Coeff:
1140 return true;
1141 case SkXfermode::kISA_Coeff:
1142 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
1143 case SkXfermode::kSA_Coeff:
1144 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType ||
1145 SkXfermode::kTransparentAlpha_SrcColorOpacity == opacityType;
1146 case SkXfermode::kSC_Coeff:
1147 return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType;
1148 default:
1149 return false;
1150 }
1151
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001152}
1153
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001154void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1155 const SkPMColor* SK_RESTRICT src, int count,
1156 const SkAlpha* SK_RESTRICT aa) const {
1157 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001158
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001159 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001160
bsalomon49f085d2014-09-05 13:34:00 -07001161 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001162 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001163 for (int i = count - 1; i >= 0; --i) {
1164 dst[i] = proc(src[i], dst[i]);
1165 }
1166 } else {
1167 for (int i = count - 1; i >= 0; --i) {
1168 unsigned a = aa[i];
1169 if (0 != a) {
1170 SkPMColor dstC = dst[i];
1171 SkPMColor C = proc(src[i], dstC);
1172 if (a != 0xFF) {
1173 C = SkFourByteInterp(C, dstC, a);
1174 }
1175 dst[i] = C;
1176 }
1177 }
1178 }
1179 }
1180}
1181
1182void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
1183 const SkPMColor* SK_RESTRICT src, int count,
1184 const SkAlpha* SK_RESTRICT aa) const {
1185 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001186
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001187 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001188
bsalomon49f085d2014-09-05 13:34:00 -07001189 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001190 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001191 for (int i = count - 1; i >= 0; --i) {
1192 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1193 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
1194 }
1195 } else {
1196 for (int i = count - 1; i >= 0; --i) {
1197 unsigned a = aa[i];
1198 if (0 != a) {
1199 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1200 SkPMColor C = proc(src[i], dstC);
1201 if (0xFF != a) {
1202 C = SkFourByteInterp(C, dstC, a);
1203 }
1204 dst[i] = SkPixel32ToPixel16_ToU16(C);
1205 }
1206 }
1207 }
1208 }
1209}
1210
1211void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1212 const SkPMColor* SK_RESTRICT src, int count,
1213 const SkAlpha* SK_RESTRICT aa) const {
1214 SkASSERT(dst && src && count >= 0);
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001215
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001216 SkXfermodeProc proc = fProc;
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +00001217
bsalomon49f085d2014-09-05 13:34:00 -07001218 if (proc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001219 if (nullptr == aa) {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +00001220 for (int i = count - 1; i >= 0; --i) {
1221 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
1222 dst[i] = SkToU8(SkGetPackedA32(res));
1223 }
1224 } else {
1225 for (int i = count - 1; i >= 0; --i) {
1226 unsigned a = aa[i];
1227 if (0 != a) {
1228 SkAlpha dstA = dst[i];
1229 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
1230 unsigned A = SkGetPackedA32(res);
1231 if (0xFF != a) {
1232 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1233 }
1234 dst[i] = SkToU8(A);
1235 }
1236 }
1237 }
1238 }
1239}
1240
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001241#if SK_SUPPORT_GPU
egdaniel0063a9b2015-01-15 10:52:32 -08001242#include "effects/GrCustomXfermode.h"
egdanielc4b72722015-11-23 13:20:41 -08001243#include "effects/GrPorterDuffXferProcessor.h"
bsalomonae4738f2015-09-15 15:33:27 -07001244#include "effects/GrXfermodeFragmentProcessor.h"
egdaniel0063a9b2015-01-15 10:52:32 -08001245
robertphillips4f037942016-02-09 05:09:27 -08001246const GrFragmentProcessor* SkProcCoeffXfermode::getFragmentProcessorForImageFilter(
1247 const GrFragmentProcessor* dst) const {
1248 SkASSERT(dst);
1249 return GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode);
commit-bot@chromium.orgdf187c72013-10-09 14:39:46 +00001250}
egdaniel54f0e9d2015-01-16 06:29:47 -08001251
robertphillips4f037942016-02-09 05:09:27 -08001252GrXPFactory* SkProcCoeffXfermode::asXPFactory() const {
egdaniel58136162015-01-20 10:19:22 -08001253 if (CANNOT_USE_COEFF != fSrcCoeff) {
robertphillips4f037942016-02-09 05:09:27 -08001254 GrXPFactory* result = GrPorterDuffXPFactory::Create(fMode);
1255 SkASSERT(result);
1256 return result;
egdaniel58136162015-01-20 10:19:22 -08001257 }
1258
robertphillips4f037942016-02-09 05:09:27 -08001259 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
1260 return GrCustomXfermode::CreateXPFactory(fMode);
egdaniel54f0e9d2015-01-16 06:29:47 -08001261}
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001262#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001263
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001264const char* SkXfermode::ModeName(Mode mode) {
1265 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1266 const char* gModeStrings[] = {
1267 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1268 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1269 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1270 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1271 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1272 };
1273 return gModeStrings[mode];
bungeman99fe8222015-08-20 07:57:51 -07001274 static_assert(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, "mode_count");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001275}
1276
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001277#ifndef SK_IGNORE_TO_STRING
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001278void SkProcCoeffXfermode::toString(SkString* str) const {
1279 str->append("SkProcCoeffXfermode: ");
1280
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001281 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001282 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001283
1284 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001285 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001286 };
1287
1288 str->append(" src: ");
1289 if (CANNOT_USE_COEFF == fSrcCoeff) {
1290 str->append("can't use");
1291 } else {
1292 str->append(gCoeffStrings[fSrcCoeff]);
1293 }
1294
1295 str->append(" dst: ");
1296 if (CANNOT_USE_COEFF == fDstCoeff) {
1297 str->append("can't use");
1298 } else {
1299 str->append(gCoeffStrings[fDstCoeff]);
1300 }
1301}
1302#endif
1303
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304
mtklein6c59d802015-09-09 09:09:53 -07001305SK_DECLARE_STATIC_ONCE_PTR(SkXfermode, cached[SkXfermode::kLastMode + 1]);
commit-bot@chromium.org140950c2014-03-28 20:04:11 +00001306
reed@android.coma0f5d152009-06-22 17:38:10 +00001307SkXfermode* SkXfermode::Create(Mode mode) {
1308 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001310 if ((unsigned)mode >= kModeCount) {
1311 // report error
halcanary96fcdcc2015-08-27 07:41:13 -07001312 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 }
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001314
halcanary96fcdcc2015-08-27 07:41:13 -07001315 // Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as srcover
1316 // so we can just return nullptr from the factory.
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001317 if (kSrcOver_Mode == mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001318 return nullptr;
commit-bot@chromium.org86490572013-10-04 16:52:55 +00001319 }
1320
mtklein6c59d802015-09-09 09:09:53 -07001321 return SkSafeRef(cached[mode].get([=]{
1322 ProcCoeff rec = gProcCoeffs[mode];
1323 if (auto xfermode = SkOpts::create_xfermode(rec, mode)) {
1324 return xfermode;
1325 }
1326 return (SkXfermode*) new SkProcCoeffXfermode(rec, mode);
1327 }));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328}
1329
reed@google.com43c50c82011-04-14 15:50:52 +00001330SkXfermodeProc SkXfermode::GetProc(Mode mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001331 SkXfermodeProc proc = nullptr;
reed@google.com43c50c82011-04-14 15:50:52 +00001332 if ((unsigned)mode < kModeCount) {
1333 proc = gProcCoeffs[mode].fProc;
1334 }
1335 return proc;
1336}
1337
reed31255652016-02-08 12:56:56 -08001338SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) {
1339 SkXfermodeProc4f proc = nullptr;
1340 if ((unsigned)mode < kModeCount) {
1341 proc = gProcCoeffs[mode].fProc4f;
1342 }
1343 return proc;
1344}
1345
reed@google.com43c50c82011-04-14 15:50:52 +00001346bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1347 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001348
reed@google.com43c50c82011-04-14 15:50:52 +00001349 if ((unsigned)mode >= (unsigned)kModeCount) {
1350 // illegal mode parameter
1351 return false;
1352 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001353
reed@google.com43c50c82011-04-14 15:50:52 +00001354 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001355
reed@google.com43c50c82011-04-14 15:50:52 +00001356 if (CANNOT_USE_COEFF == rec.fSC) {
1357 return false;
1358 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001359
reed@google.com43c50c82011-04-14 15:50:52 +00001360 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1361 if (src) {
1362 *src = rec.fSC;
1363 }
1364 if (dst) {
1365 *dst = rec.fDC;
1366 }
1367 return true;
1368}
1369
reed@google.com30da7452012-12-17 19:55:24 +00001370bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
halcanary96fcdcc2015-08-27 07:41:13 -07001371 if (nullptr == xfer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372 if (mode) {
1373 *mode = kSrcOver_Mode;
1374 }
1375 return true;
1376 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001377 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378}
1379
reed@google.com30da7452012-12-17 19:55:24 +00001380bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001381 // if xfer==null then the mode is srcover
1382 Mode m = kSrcOver_Mode;
1383 if (xfer && !xfer->asMode(&m)) {
1384 return false;
1385 }
1386 return mode == m;
1387}
1388
egdanieldcfb7cf2015-01-22 06:52:29 -08001389bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) {
halcanary96fcdcc2015-08-27 07:41:13 -07001390 // if xfer is nullptr we treat it as srcOver which always supports coverageAsAlpha
egdanieldcfb7cf2015-01-22 06:52:29 -08001391 if (!xfer) {
1392 return true;
1393 }
1394
1395 return xfer->supportsCoverageAsAlpha();
1396}
1397
1398bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) {
halcanary96fcdcc2015-08-27 07:41:13 -07001399 // if xfer is nullptr we treat it as srcOver which is opaque if our src is opaque
egdanieldcfb7cf2015-01-22 06:52:29 -08001400 if (!xfer) {
1401 return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
1402 }
1403
1404 return xfer->isOpaque(opacityType);
1405}
1406
caryclark@google.comd26147a2011-12-15 14:16:43 +00001407SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1408 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
caryclark@google.comd26147a2011-12-15 14:16:43 +00001409SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END