blob: d1a0f7a76e97f4ee905788554ee6fdbb6e5c76a3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkXfermode.h"
11#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkFlattenableBuffers.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000013#include "SkMathPriv.h"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000014#include "SkString.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000016SK_DEFINE_INST_COUNT(SkXfermode)
17
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
19
reed@android.comfc25abd2009-01-15 14:38:33 +000020#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000021// idea for higher precision blends in xfer procs (and slightly faster)
22// see DstATop as a probable caller
23static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
24 SkASSERT(a <= 255);
25 SkASSERT(b <= 255);
26 SkASSERT(c <= 255);
27 SkASSERT(d <= 255);
28 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
29 unsigned result = (prod + (prod >> 8)) >> 8;
30 SkASSERT(result <= 255);
31 return result;
32}
reed@android.comfc25abd2009-01-15 14:38:33 +000033#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
deanm@chromium.orgda946992009-07-03 12:54:24 +000035static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000036 SkASSERT(a <= 255);
37 SkASSERT(b <= 255);
38 unsigned sum = a + b;
39 if (sum > 255) {
40 sum = 255;
41 }
42 return sum;
43}
44
deanm@chromium.orgda946992009-07-03 12:54:24 +000045static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000046 if (n < 0) {
47 n = 0;
48 } else if (n > 255) {
49 n = 255;
50 }
51 return n;
52}
53
deanm@chromium.orgda946992009-07-03 12:54:24 +000054static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000055 if (prod <= 0) {
56 return 0;
57 } else if (prod >= 255*255) {
58 return 255;
59 } else {
60 return SkDiv255Round(prod);
61 }
62}
63
deanm@chromium.orgda946992009-07-03 12:54:24 +000064static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000065 if (value > max) {
66 value = max;
67 }
68 return value;
69}
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071///////////////////////////////////////////////////////////////////////////////
72
reed@android.com8a1c16f2008-12-17 15:59:43 +000073// kClear_Mode, //!< [0, 0]
74static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
75 return 0;
76}
77
78// kSrc_Mode, //!< [Sa, Sc]
79static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
80 return src;
81}
82
83// kDst_Mode, //!< [Da, Dc]
84static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
85 return dst;
86}
87
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000088// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000089static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000090#if 0
91 // this is the old, more-correct way, but it doesn't guarantee that dst==255
92 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000094#else
95 // this is slightly faster, but more importantly guarantees that dst==255
96 // will always stay opaque
97 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
98#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000099}
100
reed@android.com1116fb22009-03-03 20:31:12 +0000101// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000103 // this is the reverse of srcover, just flipping src and dst
104 // see srcover's comment about the 256 for opaqueness guarantees
105 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
107
108// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
109static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
110 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
111}
112
113// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
114static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
115 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
116}
117
118// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
119static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
120 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
121}
122
123// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
124static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
125 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
126}
127
128// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
129static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
130 unsigned sa = SkGetPackedA32(src);
131 unsigned da = SkGetPackedA32(dst);
132 unsigned isa = 255 - sa;
133
134 return SkPackARGB32(da,
135 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
136 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
137 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
138 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
139 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
140 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
141}
142
143// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
144static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
145 unsigned sa = SkGetPackedA32(src);
146 unsigned da = SkGetPackedA32(dst);
147 unsigned ida = 255 - da;
148
149 return SkPackARGB32(sa,
150 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
151 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
152 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
153 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
154 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
155 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
156}
157
158// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
159static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
160 unsigned sa = SkGetPackedA32(src);
161 unsigned da = SkGetPackedA32(dst);
162 unsigned isa = 255 - sa;
163 unsigned ida = 255 - da;
164
165 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
166 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
167 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
168 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
169 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
170 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
171 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
172}
173
reed@android.coma0f5d152009-06-22 17:38:10 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
reed@android.coma0f5d152009-06-22 17:38:10 +0000176// kPlus_Mode
177static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000178 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000179 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
180 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
181 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000182 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000185// kModulate_Mode
186static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
188 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
189 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
190 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
191 return SkPackARGB32(a, r, g, b);
192}
193
reed@android.coma0f5d152009-06-22 17:38:10 +0000194static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 return a + b - SkAlphaMulAlpha(a, b);
196}
reed@google.com25cfa692013-02-04 20:06:00 +0000197
198// kMultiply_Mode
199// B(Cb, Cs) = Cb x Cs
200// multiply uses its own version of blendfunc_byte because sa and da are not needed
201static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
202 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
203}
204
205static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
206 int sa = SkGetPackedA32(src);
207 int da = SkGetPackedA32(dst);
208 int a = srcover_byte(sa, da);
209 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
210 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
211 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
212 return SkPackARGB32(a, r, g, b);
213}
214
215// kScreen_Mode
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000217 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
218 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
219 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
220 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 return SkPackARGB32(a, r, g, b);
222}
223
reed@android.coma0f5d152009-06-22 17:38:10 +0000224// kOverlay_Mode
225static inline int overlay_byte(int sc, int dc, int sa, int da) {
226 int tmp = sc * (255 - da) + dc * (255 - sa);
227 int rc;
228 if (2 * dc <= da) {
229 rc = 2 * sc * dc;
230 } else {
231 rc = sa * da - 2 * (da - dc) * (sa - sc);
232 }
233 return clamp_div255round(rc + tmp);
234}
235static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
236 int sa = SkGetPackedA32(src);
237 int da = SkGetPackedA32(dst);
238 int a = srcover_byte(sa, da);
239 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
240 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
241 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
242 return SkPackARGB32(a, r, g, b);
243}
244
245// kDarken_Mode
246static inline int darken_byte(int sc, int dc, int sa, int da) {
247 int sd = sc * da;
248 int ds = dc * sa;
249 if (sd < ds) {
250 // srcover
251 return sc + dc - SkDiv255Round(ds);
252 } else {
253 // dstover
254 return dc + sc - SkDiv255Round(sd);
255 }
256}
257static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
258 int sa = SkGetPackedA32(src);
259 int da = SkGetPackedA32(dst);
260 int a = srcover_byte(sa, da);
261 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
262 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
263 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
264 return SkPackARGB32(a, r, g, b);
265}
266
267// kLighten_Mode
268static inline int lighten_byte(int sc, int dc, int sa, int da) {
269 int sd = sc * da;
270 int ds = dc * sa;
271 if (sd > ds) {
272 // srcover
273 return sc + dc - SkDiv255Round(ds);
274 } else {
275 // dstover
276 return dc + sc - SkDiv255Round(sd);
277 }
278}
279static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
280 int sa = SkGetPackedA32(src);
281 int da = SkGetPackedA32(dst);
282 int a = srcover_byte(sa, da);
283 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
284 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
285 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
286 return SkPackARGB32(a, r, g, b);
287}
288
289// kColorDodge_Mode
290static inline int colordodge_byte(int sc, int dc, int sa, int da) {
291 int diff = sa - sc;
292 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000293 if (0 == dc) {
294 return SkAlphaMulAlpha(sc, 255 - da);
295 } else if (0 == diff) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000296 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000297 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000298 diff = dc * sa / diff;
299 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000300 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000301 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000302}
303static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000304 int sa = SkGetPackedA32(src);
305 int da = SkGetPackedA32(dst);
306 int a = srcover_byte(sa, da);
307 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
308 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
309 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.coma0f5d152009-06-22 17:38:10 +0000310 return SkPackARGB32(a, r, g, b);
311}
312
313// kColorBurn_Mode
314static inline int colorburn_byte(int sc, int dc, int sa, int da) {
315 int rc;
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000316 if (dc == da) {
317 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000318 } else if (0 == sc) {
319 return SkAlphaMulAlpha(dc, 255 - sa);
320 } else {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000321 int tmp = (da - dc) * sa / sc;
322 rc = sa * (da - ((da < tmp) ? da : tmp))
323 + sc * (255 - da) + dc * (255 - sa);
reed@android.coma0f5d152009-06-22 17:38:10 +0000324 }
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000325 return clamp_div255round(rc);
reed@android.coma0f5d152009-06-22 17:38:10 +0000326}
327static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000328 int sa = SkGetPackedA32(src);
329 int da = SkGetPackedA32(dst);
330 int a = srcover_byte(sa, da);
331 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
332 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
333 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
334 return SkPackARGB32(a, r, g, b);
335}
336
337// kHardLight_Mode
338static inline int hardlight_byte(int sc, int dc, int sa, int da) {
339 int rc;
340 if (2 * sc <= sa) {
341 rc = 2 * sc * dc;
342 } else {
343 rc = sa * da - 2 * (da - dc) * (sa - sc);
344 }
345 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
346}
347static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
348 int sa = SkGetPackedA32(src);
349 int da = SkGetPackedA32(dst);
350 int a = srcover_byte(sa, da);
351 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
352 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
353 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
354 return SkPackARGB32(a, r, g, b);
355}
356
357// returns 255 * sqrt(n/255)
358static U8CPU sqrt_unit_byte(U8CPU n) {
359 return SkSqrtBits(n, 15+4);
360}
361
362// kSoftLight_Mode
363static inline int softlight_byte(int sc, int dc, int sa, int da) {
364 int m = da ? dc * 256 / da : 0;
365 int rc;
366 if (2 * sc <= sa) {
367 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
368 } else if (4 * dc <= da) {
369 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
370 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
371 } else {
372 int tmp = sqrt_unit_byte(m) - m;
373 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
374 }
375 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
376}
377static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
378 int sa = SkGetPackedA32(src);
379 int da = SkGetPackedA32(dst);
380 int a = srcover_byte(sa, da);
381 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
382 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
383 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
384 return SkPackARGB32(a, r, g, b);
385}
386
387// kDifference_Mode
388static inline int difference_byte(int sc, int dc, int sa, int da) {
389 int tmp = SkMin32(sc * da, dc * sa);
390 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
391}
392static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
393 int sa = SkGetPackedA32(src);
394 int da = SkGetPackedA32(dst);
395 int a = srcover_byte(sa, da);
396 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
397 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
398 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
399 return SkPackARGB32(a, r, g, b);
400}
401
402// kExclusion_Mode
403static inline int exclusion_byte(int sc, int dc, int sa, int da) {
404 // this equations is wacky, wait for SVG to confirm it
405 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
406 return clamp_div255round(r);
407}
408static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
409 int sa = SkGetPackedA32(src);
410 int da = SkGetPackedA32(dst);
411 int a = srcover_byte(sa, da);
412 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
413 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
414 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000415 return SkPackARGB32(a, r, g, b);
416}
417
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000418// The CSS compositing spec introduces the following formulas:
419// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
420// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
421// while PDF and CG uses the one from Rec. Rec. 601
422// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
423static inline int Lum(int r, int g, int b)
424{
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000425 return SkDiv255Round(r * 77 + g * 150 + b * 28);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000426}
427
428static inline int min2(int a, int b) { return a < b ? a : b; }
429static inline int max2(int a, int b) { return a > b ? a : b; }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000430#define minimum(a, b, c) min2(min2(a, b), c)
431#define maximum(a, b, c) max2(max2(a, b), c)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000432
433static inline int Sat(int r, int g, int b) {
434 return maximum(r, g, b) - minimum(r, g, b);
435}
436
437static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
reed@google.com3c1ea3a2013-03-07 15:31:58 +0000438 if(*Cmax > *Cmin) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000439 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000440 *Cmax = s;
441 } else {
442 *Cmax = 0;
443 *Cmid = 0;
444 }
445
446 *Cmin = 0;
447}
448
449static inline void SetSat(int* r, int* g, int* b, int s) {
450 if(*r <= *g) {
451 if(*g <= *b) {
452 setSaturationComponents(r, g, b, s);
453 } else if(*r <= *b) {
454 setSaturationComponents(r, b, g, s);
455 } else {
456 setSaturationComponents(b, r, g, s);
457 }
458 } else if(*r <= *b) {
459 setSaturationComponents(g, r, b, s);
460 } else if(*g <= *b) {
461 setSaturationComponents(g, b, r, s);
462 } else {
463 setSaturationComponents(b, g, r, s);
464 }
465}
466
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000467static inline void clipColor(int* r, int* g, int* b, int a) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000468 int L = Lum(*r, *g, *b);
469 int n = minimum(*r, *g, *b);
470 int x = maximum(*r, *g, *b);
471 if(n < 0) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000472 *r = L + SkMulDiv(*r - L, L, L - n);
473 *g = L + SkMulDiv(*g - L, L, L - n);
474 *b = L + SkMulDiv(*b - L, L, L - n);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000475 }
476
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000477 if (x > a) {
478 *r = L + SkMulDiv(*r - L, a - L, x - L);
479 *g = L + SkMulDiv(*g - L, a - L, x - L);
480 *b = L + SkMulDiv(*b - L, a - L, x - L);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000481 }
482}
483
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000484static inline void SetLum(int* r, int* g, int* b, int a, int l) {
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000485 int d = l - Lum(*r, *g, *b);
486 *r += d;
487 *g += d;
488 *b += d;
489
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000490 clipColor(r, g, b, a);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000491}
492
493// non-separable blend modes are done in non-premultiplied alpha
494#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000495 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000496
497// kHue_Mode
498// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
499// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
500static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
501 int sr = SkGetPackedR32(src);
502 int sg = SkGetPackedG32(src);
503 int sb = SkGetPackedB32(src);
504 int sa = SkGetPackedA32(src);
505
506 int dr = SkGetPackedR32(dst);
507 int dg = SkGetPackedG32(dst);
508 int db = SkGetPackedB32(dst);
509 int da = SkGetPackedA32(dst);
510 int Sr, Sg, Sb;
511
512 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000513 Sr = sr * sa;
514 Sg = sg * sa;
515 Sb = sb * sa;
516 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
517 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000518 } else {
519 Sr = 0;
520 Sg = 0;
521 Sb = 0;
522 }
523
524 int a = srcover_byte(sa, da);
525 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
526 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
527 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
528 return SkPackARGB32(a, r, g, b);
529}
530
531// kSaturation_Mode
532// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000533// 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 +0000534static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
535 int sr = SkGetPackedR32(src);
536 int sg = SkGetPackedG32(src);
537 int sb = SkGetPackedB32(src);
538 int sa = SkGetPackedA32(src);
539
540 int dr = SkGetPackedR32(dst);
541 int dg = SkGetPackedG32(dst);
542 int db = SkGetPackedB32(dst);
543 int da = SkGetPackedA32(dst);
544 int Dr, Dg, Db;
545
546 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000547 Dr = dr * sa;
548 Dg = dg * sa;
549 Db = db * sa;
550 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
551 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000552 } else {
553 Dr = 0;
554 Dg = 0;
555 Db = 0;
556 }
557
558 int a = srcover_byte(sa, da);
559 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
560 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
561 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
562 return SkPackARGB32(a, r, g, b);
563}
564
565// kColor_Mode
566// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000567// 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 +0000568static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
569 int sr = SkGetPackedR32(src);
570 int sg = SkGetPackedG32(src);
571 int sb = SkGetPackedB32(src);
572 int sa = SkGetPackedA32(src);
573
574 int dr = SkGetPackedR32(dst);
575 int dg = SkGetPackedG32(dst);
576 int db = SkGetPackedB32(dst);
577 int da = SkGetPackedA32(dst);
578 int Sr, Sg, Sb;
579
580 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000581 Sr = sr * da;
582 Sg = sg * da;
583 Sb = sb * da;
584 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000585 } else {
586 Sr = 0;
587 Sg = 0;
588 Sb = 0;
589 }
590
591 int a = srcover_byte(sa, da);
592 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
593 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
594 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
595 return SkPackARGB32(a, r, g, b);
596}
597
598// kLuminosity_Mode
599// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000600// 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 +0000601static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
602 int sr = SkGetPackedR32(src);
603 int sg = SkGetPackedG32(src);
604 int sb = SkGetPackedB32(src);
605 int sa = SkGetPackedA32(src);
606
607 int dr = SkGetPackedR32(dst);
608 int dg = SkGetPackedG32(dst);
609 int db = SkGetPackedB32(dst);
610 int da = SkGetPackedA32(dst);
611 int Dr, Dg, Db;
612
613 if(sa && da) {
commit-bot@chromium.org311d4ea2013-03-21 12:40:08 +0000614 Dr = dr * sa;
615 Dg = dg * sa;
616 Db = db * sa;
617 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000618 } else {
619 Dr = 0;
620 Dg = 0;
621 Db = 0;
622 }
623
624 int a = srcover_byte(sa, da);
625 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
626 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
627 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
628 return SkPackARGB32(a, r, g, b);
629}
630
631
vandebo@chromium.org48543272011-02-08 19:28:07 +0000632struct ProcCoeff {
633 SkXfermodeProc fProc;
634 SkXfermode::Coeff fSC;
635 SkXfermode::Coeff fDC;
636};
637
638#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
639
640static const ProcCoeff gProcCoeffs[] = {
641 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
642 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
643 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
644 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
645 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
646 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
647 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
648 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
649 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
650 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
651 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
652 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
653
reed@google.com521e34e2011-04-12 18:55:21 +0000654 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000655 { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000656 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
657 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
658 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
659 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
660 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
661 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
662 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
663 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
664 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
665 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed@google.com25cfa692013-02-04 20:06:00 +0000666 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000667 { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
668 { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
669 { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
670 { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000671};
672
673///////////////////////////////////////////////////////////////////////////////
674
reed@google.com30da7452012-12-17 19:55:24 +0000675bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000676 return false;
677}
678
reed@google.com30da7452012-12-17 19:55:24 +0000679bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000680 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000681}
682
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000683bool SkXfermode::asNewEffectOrCoeff(GrContext*, GrEffectRef**, Coeff* src, Coeff* dst) const {
684 return this->asCoeff(src, dst);
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000685}
686
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000687bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
688 GrContext* context,
689 GrEffectRef** effect,
690 Coeff* src,
691 Coeff* dst) {
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000692 if (NULL == xfermode) {
693 return ModeAsCoeff(kSrcOver_Mode, src, dst);
694 } else {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000695 return xfermode->asNewEffectOrCoeff(context, effect, src, dst);
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000696 }
697}
698
reed@google.com30da7452012-12-17 19:55:24 +0000699SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000700 // no-op. subclasses should override this
701 return dst;
702}
703
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000704void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
705 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000706 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000707 SkASSERT(dst && src && count >= 0);
708
709 if (NULL == aa) {
710 for (int i = count - 1; i >= 0; --i) {
711 dst[i] = this->xferColor(src[i], dst[i]);
712 }
713 } else {
714 for (int i = count - 1; i >= 0; --i) {
715 unsigned a = aa[i];
716 if (0 != a) {
717 SkPMColor dstC = dst[i];
718 SkPMColor C = this->xferColor(src[i], dstC);
719 if (0xFF != a) {
720 C = SkFourByteInterp(C, dstC, a);
721 }
722 dst[i] = C;
723 }
724 }
725 }
726}
727
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000728void SkXfermode::xfer16(uint16_t* dst,
729 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000730 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000731 SkASSERT(dst && src && count >= 0);
732
733 if (NULL == aa) {
734 for (int i = count - 1; i >= 0; --i) {
735 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
736 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
737 }
738 } else {
739 for (int i = count - 1; i >= 0; --i) {
740 unsigned a = aa[i];
741 if (0 != a) {
742 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
743 SkPMColor C = this->xferColor(src[i], dstC);
744 if (0xFF != a) {
745 C = SkFourByteInterp(C, dstC, a);
746 }
747 dst[i] = SkPixel32ToPixel16_ToU16(C);
748 }
749 }
750 }
751}
752
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000753void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
754 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000755 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000756 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000757
vandebo@chromium.org48543272011-02-08 19:28:07 +0000758 if (NULL == aa) {
759 for (int i = count - 1; i >= 0; --i) {
760 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
761 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
762 }
763 } else {
764 for (int i = count - 1; i >= 0; --i) {
765 unsigned a = aa[i];
766 if (0 != a) {
767 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
768 SkPMColor C = this->xferColor(src[i], dstC);
769 if (0xFF != a) {
770 C = SkFourByteInterp(C, dstC, a);
771 }
772 dst[i] = SkPixel32ToPixel4444(C);
773 }
774 }
775 }
776}
777
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000778void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000779 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000780 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000781 SkASSERT(dst && src && count >= 0);
782
783 if (NULL == aa) {
784 for (int i = count - 1; i >= 0; --i) {
785 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
786 dst[i] = SkToU8(SkGetPackedA32(res));
787 }
788 } else {
789 for (int i = count - 1; i >= 0; --i) {
790 unsigned a = aa[i];
791 if (0 != a) {
792 SkAlpha dstA = dst[i];
793 unsigned A = SkGetPackedA32(this->xferColor(src[i],
794 (SkPMColor)(dstA << SK_A32_SHIFT)));
795 if (0xFF != a) {
796 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
797 }
798 dst[i] = SkToU8(A);
799 }
800 }
801 }
802}
803
804///////////////////////////////////////////////////////////////////////////////
805
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000806void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
807 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000808 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000809 SkASSERT(dst && src && count >= 0);
810
811 SkXfermodeProc proc = fProc;
812
813 if (NULL != proc) {
814 if (NULL == aa) {
815 for (int i = count - 1; i >= 0; --i) {
816 dst[i] = proc(src[i], dst[i]);
817 }
818 } else {
819 for (int i = count - 1; i >= 0; --i) {
820 unsigned a = aa[i];
821 if (0 != a) {
822 SkPMColor dstC = dst[i];
823 SkPMColor C = proc(src[i], dstC);
824 if (a != 0xFF) {
825 C = SkFourByteInterp(C, dstC, a);
826 }
827 dst[i] = C;
828 }
829 }
830 }
831 }
832}
833
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000834void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
835 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000836 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000837 SkASSERT(dst && src && count >= 0);
838
839 SkXfermodeProc proc = fProc;
840
841 if (NULL != proc) {
842 if (NULL == aa) {
843 for (int i = count - 1; i >= 0; --i) {
844 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
845 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
846 }
847 } else {
848 for (int i = count - 1; i >= 0; --i) {
849 unsigned a = aa[i];
850 if (0 != a) {
851 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
852 SkPMColor C = proc(src[i], dstC);
853 if (0xFF != a) {
854 C = SkFourByteInterp(C, dstC, a);
855 }
856 dst[i] = SkPixel32ToPixel16_ToU16(C);
857 }
858 }
859 }
860 }
861}
862
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000863void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
864 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000865 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000866 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000867
vandebo@chromium.org48543272011-02-08 19:28:07 +0000868 SkXfermodeProc proc = fProc;
869
870 if (NULL != proc) {
871 if (NULL == aa) {
872 for (int i = count - 1; i >= 0; --i) {
873 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
874 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
875 }
876 } else {
877 for (int i = count - 1; i >= 0; --i) {
878 unsigned a = aa[i];
879 if (0 != a) {
880 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
881 SkPMColor C = proc(src[i], dstC);
882 if (0xFF != a) {
883 C = SkFourByteInterp(C, dstC, a);
884 }
885 dst[i] = SkPixel32ToPixel4444(C);
886 }
887 }
888 }
889 }
890}
891
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000892void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
893 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000894 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000895 SkASSERT(dst && src && count >= 0);
896
897 SkXfermodeProc proc = fProc;
898
899 if (NULL != proc) {
900 if (NULL == aa) {
901 for (int i = count - 1; i >= 0; --i) {
902 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
903 dst[i] = SkToU8(SkGetPackedA32(res));
904 }
905 } else {
906 for (int i = count - 1; i >= 0; --i) {
907 unsigned a = aa[i];
908 if (0 != a) {
909 SkAlpha dstA = dst[i];
910 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
911 unsigned A = SkGetPackedA32(res);
912 if (0xFF != a) {
913 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
914 }
915 dst[i] = SkToU8(A);
916 }
917 }
918 }
919 }
920}
921
922SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
923 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000924 fProc = NULL;
925 if (!buffer.isCrossProcess()) {
926 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
927 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000928}
929
djsollen@google.com54924242012-03-29 15:18:04 +0000930void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
931 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000932 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000933 buffer.writeFunctionPtr((void*)fProc);
934 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000935}
936
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000937#ifdef SK_DEVELOPER
938void SkProcXfermode::toString(SkString* str) const {
939 str->appendf("SkProcXfermode: %p", fProc);
940}
941#endif
942
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000943//////////////////////////////////////////////////////////////////////////////
944
945#if SK_SUPPORT_GPU
946
947#include "GrEffect.h"
948#include "GrEffectUnitTest.h"
949#include "GrTBackendEffectFactory.h"
950#include "gl/GrGLEffect.h"
951
952/**
953 * GrEffect that implements the kDarken_Mode Xfermode. It requires access to the dst pixel color
954 * in the shader. TODO: Make this work for all non-Coeff SkXfermode::Mode values.
955 */
956class DarkenEffect : public GrEffect {
957public:
958 static GrEffectRef* Create() {
959 static AutoEffectUnref gEffect(SkNEW(DarkenEffect));
960 return CreateEffectRef(gEffect);
961 }
962
963 virtual void getConstantColorComponents(GrColor* color,
964 uint32_t* validFlags) const SK_OVERRIDE {
965 *validFlags = 0;
966 }
967
968 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
969 return GrTBackendEffectFactory<DarkenEffect>::getInstance();
970 }
971
972 static const char* Name() { return "XfermodeDarken"; }
973
974 class GLEffect : public GrGLEffect {
975 public:
976 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
977 : GrGLEffect(factory ) {
978 }
979 virtual void emitCode(GrGLShaderBuilder* builder,
980 const GrDrawEffect& drawEffect,
981 EffectKey key,
982 const char* outputColor,
983 const char* inputColor,
984 const TextureSamplerArray& samplers) SK_OVERRIDE {
985 const char* dstColorName = builder->dstColor();
986 GrAssert(NULL != dstColorName);
bsalomon@google.comb79d8652013-03-29 20:30:50 +0000987 if (NULL == inputColor) {
988 // the input color is solid white
989 builder->fsCodeAppendf("\t\t%s.a = 1.0;\n", outputColor);
990 builder->fsCodeAppendf("\t\t%s.rgb = vec3(1.0, 1.0, 1.0) - %s.aaa + %s.rgb;\n",
991 outputColor, dstColorName, dstColorName);
992 } else {
993 builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.a);\n",
994 outputColor, dstColorName, inputColor);
995 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb,"
996 " (1.0 - %s.a) * %s.rgb + %s.rgb);\n",
997 outputColor,
998 inputColor, dstColorName, inputColor,
999 dstColorName, inputColor, dstColorName);
1000 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001001 }
1002
1003 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
1004
1005 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
1006
1007 private:
1008 typedef GrGLEffect INHERITED;
1009 };
1010
1011 GR_DECLARE_EFFECT_TEST;
1012
1013private:
1014 DarkenEffect() { this->setWillReadDst(); }
1015 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { return true; }
1016
1017 typedef GrEffect INHERITED;
1018};
1019
1020GR_DEFINE_EFFECT_TEST(DarkenEffect);
1021GrEffectRef* DarkenEffect::TestCreate(SkMWCRandom*,
1022 GrContext*,
1023 const GrDrawTargetCaps&,
1024 GrTexture*[]) {
1025 static AutoEffectUnref gEffect(SkNEW(DarkenEffect));
1026 return CreateEffectRef(gEffect);
1027}
1028
1029#endif
1030
vandebo@chromium.org48543272011-02-08 19:28:07 +00001031///////////////////////////////////////////////////////////////////////////////
1032///////////////////////////////////////////////////////////////////////////////
1033
1034class SkProcCoeffXfermode : public SkProcXfermode {
1035public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001036 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
1037 : INHERITED(rec.fProc) {
1038 fMode = mode;
1039 // these may be valid, or may be CANNOT_USE_COEFF
1040 fSrcCoeff = rec.fSC;
1041 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +00001042 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001043
reed@google.com30da7452012-12-17 19:55:24 +00001044 virtual bool asMode(Mode* mode) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +00001045 if (mode) {
1046 *mode = fMode;
1047 }
1048 return true;
1049 }
1050
reed@google.com30da7452012-12-17 19:55:24 +00001051 virtual bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +00001052 if (CANNOT_USE_COEFF == fSrcCoeff) {
1053 return false;
1054 }
1055
vandebo@chromium.org48543272011-02-08 19:28:07 +00001056 if (sc) {
1057 *sc = fSrcCoeff;
1058 }
1059 if (dc) {
1060 *dc = fDstCoeff;
1061 }
1062 return true;
1063 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001064
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001065#if SK_SUPPORT_GPU
1066 virtual bool asNewEffectOrCoeff(GrContext*,
1067 GrEffectRef** effect,
1068 Coeff* src,
1069 Coeff* dst) const SK_OVERRIDE {
1070 if (this->asCoeff(src, dst)) {
1071 return true;
1072 }
1073 if (kDarken_Mode == fMode) {
1074 if (NULL != effect) {
1075 *effect = DarkenEffect::Create();
1076 }
1077 return true;
1078 }
1079 return false;
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001080 }
bsalomon@google.com26e18b52013-03-29 19:22:36 +00001081#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +00001082
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001083 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001084 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001085
vandebo@chromium.org48543272011-02-08 19:28:07 +00001086protected:
djsollen@google.com54924242012-03-29 15:18:04 +00001087 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00001088 fMode = (SkXfermode::Mode)buffer.read32();
reed@google.comc34d7cf2011-08-09 22:42:10 +00001089
1090 const ProcCoeff& rec = gProcCoeffs[fMode];
1091 // these may be valid, or may be CANNOT_USE_COEFF
1092 fSrcCoeff = rec.fSC;
1093 fDstCoeff = rec.fDC;
1094 // now update our function-ptr in the super class
1095 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +00001096 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001097
djsollen@google.com54924242012-03-29 15:18:04 +00001098 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
1099 this->INHERITED::flatten(buffer);
1100 buffer.write32(fMode);
1101 }
1102
vandebo@chromium.org48543272011-02-08 19:28:07 +00001103private:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001104 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +00001105 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001106
vandebo@chromium.org48543272011-02-08 19:28:07 +00001107 typedef SkProcXfermode INHERITED;
1108};
1109
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001110const char* SkXfermode::ModeName(Mode mode) {
1111 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1112 const char* gModeStrings[] = {
1113 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1114 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1115 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1116 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1117 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1118 };
1119 return gModeStrings[mode];
1120 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
1121}
1122
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001123#ifdef SK_DEVELOPER
1124void SkProcCoeffXfermode::toString(SkString* str) const {
1125 str->append("SkProcCoeffXfermode: ");
1126
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001127 str->append("mode: ");
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +00001128 str->append(ModeName(fMode));
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001129
1130 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001131 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001132 };
1133
1134 str->append(" src: ");
1135 if (CANNOT_USE_COEFF == fSrcCoeff) {
1136 str->append("can't use");
1137 } else {
1138 str->append(gCoeffStrings[fSrcCoeff]);
1139 }
1140
1141 str->append(" dst: ");
1142 if (CANNOT_USE_COEFF == fDstCoeff) {
1143 str->append("can't use");
1144 } else {
1145 str->append(gCoeffStrings[fDstCoeff]);
1146 }
1147}
1148#endif
1149
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150///////////////////////////////////////////////////////////////////////////////
1151
1152class SkClearXfermode : public SkProcCoeffXfermode {
1153public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001154 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155
reed@google.com30da7452012-12-17 19:55:24 +00001156 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1157 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001159 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001160 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001161
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162private:
1163 SkClearXfermode(SkFlattenableReadBuffer& buffer)
1164 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001165
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001166 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167};
1168
reed@google.com86ab6c62011-11-28 15:26:14 +00001169void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1170 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001171 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001172 SkASSERT(dst && count >= 0);
1173
1174 if (NULL == aa) {
1175 memset(dst, 0, count << 2);
1176 } else {
1177 for (int i = count - 1; i >= 0; --i) {
1178 unsigned a = aa[i];
1179 if (0xFF == a) {
1180 dst[i] = 0;
1181 } else if (a != 0) {
1182 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1183 }
1184 }
1185 }
1186}
1187void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1188 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001189 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001190 SkASSERT(dst && count >= 0);
1191
1192 if (NULL == aa) {
1193 memset(dst, 0, count);
1194 } else {
1195 for (int i = count - 1; i >= 0; --i) {
1196 unsigned a = aa[i];
1197 if (0xFF == a) {
1198 dst[i] = 0;
1199 } else if (0 != a) {
1200 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1201 }
1202 }
1203 }
1204}
1205
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001206#ifdef SK_DEVELOPER
1207void SkClearXfermode::toString(SkString* str) const {
1208 this->INHERITED::toString(str);
1209}
1210#endif
1211
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212///////////////////////////////////////////////////////////////////////////////
1213
1214class SkSrcXfermode : public SkProcCoeffXfermode {
1215public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001216 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217
reed@google.com30da7452012-12-17 19:55:24 +00001218 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1219 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001221 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001222 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001223
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224private:
1225 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
1226 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001227
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001228 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229};
1230
reed@google.com86ab6c62011-11-28 15:26:14 +00001231void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1232 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001233 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001234 SkASSERT(dst && src && count >= 0);
1235
1236 if (NULL == aa) {
1237 memcpy(dst, src, count << 2);
1238 } else {
1239 for (int i = count - 1; i >= 0; --i) {
1240 unsigned a = aa[i];
1241 if (a == 0xFF) {
1242 dst[i] = src[i];
1243 } else if (a != 0) {
1244 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1245 }
1246 }
1247 }
1248}
1249
1250void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1251 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001252 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001253 SkASSERT(dst && src && count >= 0);
1254
1255 if (NULL == aa) {
1256 for (int i = count - 1; i >= 0; --i) {
1257 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1258 }
1259 } else {
1260 for (int i = count - 1; i >= 0; --i) {
1261 unsigned a = aa[i];
1262 if (0 != a) {
1263 unsigned srcA = SkGetPackedA32(src[i]);
1264 if (a == 0xFF) {
1265 dst[i] = SkToU8(srcA);
1266 } else {
1267 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1268 }
1269 }
1270 }
1271 }
1272}
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001273#ifdef SK_DEVELOPER
1274void SkSrcXfermode::toString(SkString* str) const {
1275 this->INHERITED::toString(str);
1276}
1277#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001278
reed@google.com30da7452012-12-17 19:55:24 +00001279///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001280
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281class SkDstInXfermode : public SkProcCoeffXfermode {
1282public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001283 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001284
reed@google.com30da7452012-12-17 19:55:24 +00001285 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001286
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001287 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001288 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001289
1290private:
1291 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
1292
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 typedef SkProcCoeffXfermode INHERITED;
1294};
1295
reed@google.com86ab6c62011-11-28 15:26:14 +00001296void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1297 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001298 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001299 SkASSERT(dst && src);
1300
1301 if (count <= 0) {
1302 return;
1303 }
1304 if (NULL != aa) {
1305 return this->INHERITED::xfer32(dst, src, count, aa);
1306 }
1307
1308 do {
1309 unsigned a = SkGetPackedA32(*src);
1310 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1311 dst++;
1312 src++;
1313 } while (--count != 0);
1314}
1315
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001316#ifdef SK_DEVELOPER
1317void SkDstInXfermode::toString(SkString* str) const {
1318 this->INHERITED::toString(str);
1319}
1320#endif
1321
reed@google.com30da7452012-12-17 19:55:24 +00001322///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001323
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324class SkDstOutXfermode : public SkProcCoeffXfermode {
1325public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001326 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001327
reed@google.com30da7452012-12-17 19:55:24 +00001328 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001329
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001330 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001331 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001332
1333private:
1334 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
1335 : INHERITED(buffer) {}
1336
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 typedef SkProcCoeffXfermode INHERITED;
1338};
1339
reed@google.com86ab6c62011-11-28 15:26:14 +00001340void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1341 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001342 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001343 SkASSERT(dst && src);
1344
1345 if (count <= 0) {
1346 return;
1347 }
1348 if (NULL != aa) {
1349 return this->INHERITED::xfer32(dst, src, count, aa);
1350 }
1351
1352 do {
1353 unsigned a = SkGetPackedA32(*src);
1354 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1355 dst++;
1356 src++;
1357 } while (--count != 0);
1358}
1359
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001360#ifdef SK_DEVELOPER
1361void SkDstOutXfermode::toString(SkString* str) const {
1362 this->INHERITED::toString(str);
1363}
1364#endif
1365
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366///////////////////////////////////////////////////////////////////////////////
1367
reed@android.coma0f5d152009-06-22 17:38:10 +00001368SkXfermode* SkXfermode::Create(Mode mode) {
1369 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1370 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371
reed@google.comc0d4aa22011-04-13 21:12:04 +00001372 const ProcCoeff& rec = gProcCoeffs[mode];
1373
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374 switch (mode) {
1375 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001376 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001378 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379 case kSrcOver_Mode:
1380 return NULL;
1381 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001382 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001384 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1385 default:
1386 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001387 }
1388}
1389
reed@google.com43c50c82011-04-14 15:50:52 +00001390SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1391 SkXfermodeProc proc = NULL;
1392 if ((unsigned)mode < kModeCount) {
1393 proc = gProcCoeffs[mode].fProc;
1394 }
1395 return proc;
1396}
1397
1398bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1399 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001400
reed@google.com43c50c82011-04-14 15:50:52 +00001401 if ((unsigned)mode >= (unsigned)kModeCount) {
1402 // illegal mode parameter
1403 return false;
1404 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001405
reed@google.com43c50c82011-04-14 15:50:52 +00001406 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001407
reed@google.com43c50c82011-04-14 15:50:52 +00001408 if (CANNOT_USE_COEFF == rec.fSC) {
1409 return false;
1410 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001411
reed@google.com43c50c82011-04-14 15:50:52 +00001412 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1413 if (src) {
1414 *src = rec.fSC;
1415 }
1416 if (dst) {
1417 *dst = rec.fDC;
1418 }
1419 return true;
1420}
1421
reed@google.com30da7452012-12-17 19:55:24 +00001422bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 if (NULL == xfer) {
1424 if (mode) {
1425 *mode = kSrcOver_Mode;
1426 }
1427 return true;
1428 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001429 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
reed@google.com30da7452012-12-17 19:55:24 +00001432bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001433 if (NULL == xfer) {
1434 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435 }
reed@google.com43c50c82011-04-14 15:50:52 +00001436 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437}
1438
reed@google.com30da7452012-12-17 19:55:24 +00001439bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001440 // if xfer==null then the mode is srcover
1441 Mode m = kSrcOver_Mode;
1442 if (xfer && !xfer->asMode(&m)) {
1443 return false;
1444 }
1445 return mode == m;
1446}
1447
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448///////////////////////////////////////////////////////////////////////////////
1449//////////// 16bit xfermode procs
1450
1451#ifdef SK_DEBUG
1452static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1453static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1454#endif
1455
1456static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1457 SkASSERT(require_255(src));
1458 return SkPixel32ToPixel16(src);
1459}
1460
1461static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1462 return dst;
1463}
1464
1465static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1466 SkASSERT(require_0(src));
1467 return dst;
1468}
1469
1470static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1471 SkASSERT(require_255(src));
1472 return SkPixel32ToPixel16(src);
1473}
1474
1475static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1476 SkASSERT(require_0(src));
1477 return dst;
1478}
1479
1480static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1481 SkASSERT(require_255(src));
1482 return dst;
1483}
1484
1485static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1486 SkASSERT(require_255(src));
1487 return SkPixel32ToPixel16(src);
1488}
1489
1490static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1491 SkASSERT(require_255(src));
1492 return dst;
1493}
1494
1495static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1496 SkASSERT(require_0(src));
1497 return dst;
1498}
1499
1500static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1501 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001502
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 return SkPackRGB16(
1504 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1505 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1506 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1507}
1508
1509static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1510 SkASSERT(require_0(src));
1511 return dst;
1512}
1513
1514static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1515 SkASSERT(require_255(src));
1516 return SkPixel32ToPixel16(src);
1517}
1518
1519static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1520 SkASSERT(require_255(src));
1521 return dst;
1522}
1523
1524/*********
1525 darken and lighten boil down to this.
1526
1527 darken = (1 - Sa) * Dc + min(Sc, Dc)
1528 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1529
1530 if (Sa == 0) these become
1531 darken = Dc + min(0, Dc) = 0
1532 lighten = Dc + max(0, Dc) = Dc
1533
1534 if (Sa == 1) these become
1535 darken = min(Sc, Dc)
1536 lighten = max(Sc, Dc)
1537*/
1538
1539static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1540 SkASSERT(require_0(src));
1541 return 0;
1542}
1543
1544static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1545 SkASSERT(require_255(src));
1546 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1547 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1548 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1549 return SkPackRGB16(r, g, b);
1550}
1551
1552static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1553 SkASSERT(require_0(src));
1554 return dst;
1555}
1556
1557static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1558 SkASSERT(require_255(src));
1559 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1560 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1561 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1562 return SkPackRGB16(r, g, b);
1563}
1564
1565struct Proc16Rec {
1566 SkXfermodeProc16 fProc16_0;
1567 SkXfermodeProc16 fProc16_255;
1568 SkXfermodeProc16 fProc16_General;
1569};
1570
reed@android.coma0f5d152009-06-22 17:38:10 +00001571static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572 { NULL, NULL, NULL }, // CLEAR
1573 { NULL, src_modeproc16_255, NULL },
1574 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1575 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1576 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1577 { NULL, srcin_modeproc16_255, NULL },
1578 { NULL, dstin_modeproc16_255, NULL },
1579 { NULL, NULL, NULL },// SRC_OUT
1580 { dstout_modeproc16_0, NULL, NULL },
1581 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1582 { NULL, dstatop_modeproc16_255, NULL },
1583 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001584
1585 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00001586 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00001587 { NULL, NULL, NULL }, // screen
1588 { NULL, NULL, NULL }, // overlay
1589 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1590 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1591 { NULL, NULL, NULL }, // colordodge
1592 { NULL, NULL, NULL }, // colorburn
1593 { NULL, NULL, NULL }, // hardlight
1594 { NULL, NULL, NULL }, // softlight
1595 { NULL, NULL, NULL }, // difference
1596 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00001597 { NULL, NULL, NULL }, // multiply
1598 { NULL, NULL, NULL }, // hue
1599 { NULL, NULL, NULL }, // saturation
1600 { NULL, NULL, NULL }, // color
1601 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00001602};
1603
reed@android.coma0f5d152009-06-22 17:38:10 +00001604SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001605 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001606 if ((unsigned)mode < kModeCount) {
1607 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608 unsigned a = SkColorGetA(srcColor);
1609
1610 if (0 == a) {
1611 proc16 = rec.fProc16_0;
1612 } else if (255 == a) {
1613 proc16 = rec.fProc16_255;
1614 } else {
1615 proc16 = rec.fProc16_General;
1616 }
1617 }
1618 return proc16;
1619}
1620
caryclark@google.comd26147a2011-12-15 14:16:43 +00001621SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1622 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1624 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1625 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1626 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1627SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END