blob: de18c26fd12392ca1fc3168c4b695b7bd48f4e63 [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
reed@google.com30da7452012-12-17 19:55:24 +0000683SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000684 // no-op. subclasses should override this
685 return dst;
686}
687
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000688void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
689 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000690 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000691 SkASSERT(dst && src && count >= 0);
692
693 if (NULL == aa) {
694 for (int i = count - 1; i >= 0; --i) {
695 dst[i] = this->xferColor(src[i], dst[i]);
696 }
697 } else {
698 for (int i = count - 1; i >= 0; --i) {
699 unsigned a = aa[i];
700 if (0 != a) {
701 SkPMColor dstC = dst[i];
702 SkPMColor C = this->xferColor(src[i], dstC);
703 if (0xFF != a) {
704 C = SkFourByteInterp(C, dstC, a);
705 }
706 dst[i] = C;
707 }
708 }
709 }
710}
711
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000712void SkXfermode::xfer16(uint16_t* dst,
713 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000714 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000715 SkASSERT(dst && src && count >= 0);
716
717 if (NULL == aa) {
718 for (int i = count - 1; i >= 0; --i) {
719 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
720 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
721 }
722 } else {
723 for (int i = count - 1; i >= 0; --i) {
724 unsigned a = aa[i];
725 if (0 != a) {
726 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
727 SkPMColor C = this->xferColor(src[i], dstC);
728 if (0xFF != a) {
729 C = SkFourByteInterp(C, dstC, a);
730 }
731 dst[i] = SkPixel32ToPixel16_ToU16(C);
732 }
733 }
734 }
735}
736
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000737void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
738 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000739 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000740 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000741
vandebo@chromium.org48543272011-02-08 19:28:07 +0000742 if (NULL == aa) {
743 for (int i = count - 1; i >= 0; --i) {
744 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
745 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
746 }
747 } else {
748 for (int i = count - 1; i >= 0; --i) {
749 unsigned a = aa[i];
750 if (0 != a) {
751 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
752 SkPMColor C = this->xferColor(src[i], dstC);
753 if (0xFF != a) {
754 C = SkFourByteInterp(C, dstC, a);
755 }
756 dst[i] = SkPixel32ToPixel4444(C);
757 }
758 }
759 }
760}
761
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000762void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000763 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000764 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000765 SkASSERT(dst && src && count >= 0);
766
767 if (NULL == aa) {
768 for (int i = count - 1; i >= 0; --i) {
769 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
770 dst[i] = SkToU8(SkGetPackedA32(res));
771 }
772 } else {
773 for (int i = count - 1; i >= 0; --i) {
774 unsigned a = aa[i];
775 if (0 != a) {
776 SkAlpha dstA = dst[i];
777 unsigned A = SkGetPackedA32(this->xferColor(src[i],
778 (SkPMColor)(dstA << SK_A32_SHIFT)));
779 if (0xFF != a) {
780 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
781 }
782 dst[i] = SkToU8(A);
783 }
784 }
785 }
786}
787
788///////////////////////////////////////////////////////////////////////////////
789
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000790void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
791 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000792 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000793 SkASSERT(dst && src && count >= 0);
794
795 SkXfermodeProc proc = fProc;
796
797 if (NULL != proc) {
798 if (NULL == aa) {
799 for (int i = count - 1; i >= 0; --i) {
800 dst[i] = proc(src[i], dst[i]);
801 }
802 } else {
803 for (int i = count - 1; i >= 0; --i) {
804 unsigned a = aa[i];
805 if (0 != a) {
806 SkPMColor dstC = dst[i];
807 SkPMColor C = proc(src[i], dstC);
808 if (a != 0xFF) {
809 C = SkFourByteInterp(C, dstC, a);
810 }
811 dst[i] = C;
812 }
813 }
814 }
815 }
816}
817
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000818void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
819 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000820 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000821 SkASSERT(dst && src && count >= 0);
822
823 SkXfermodeProc proc = fProc;
824
825 if (NULL != proc) {
826 if (NULL == aa) {
827 for (int i = count - 1; i >= 0; --i) {
828 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
829 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
830 }
831 } else {
832 for (int i = count - 1; i >= 0; --i) {
833 unsigned a = aa[i];
834 if (0 != a) {
835 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
836 SkPMColor C = proc(src[i], dstC);
837 if (0xFF != a) {
838 C = SkFourByteInterp(C, dstC, a);
839 }
840 dst[i] = SkPixel32ToPixel16_ToU16(C);
841 }
842 }
843 }
844 }
845}
846
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000847void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
848 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000849 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000850 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000851
vandebo@chromium.org48543272011-02-08 19:28:07 +0000852 SkXfermodeProc proc = fProc;
853
854 if (NULL != proc) {
855 if (NULL == aa) {
856 for (int i = count - 1; i >= 0; --i) {
857 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
858 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
859 }
860 } else {
861 for (int i = count - 1; i >= 0; --i) {
862 unsigned a = aa[i];
863 if (0 != a) {
864 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
865 SkPMColor C = proc(src[i], dstC);
866 if (0xFF != a) {
867 C = SkFourByteInterp(C, dstC, a);
868 }
869 dst[i] = SkPixel32ToPixel4444(C);
870 }
871 }
872 }
873 }
874}
875
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000876void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
877 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000878 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000879 SkASSERT(dst && src && count >= 0);
880
881 SkXfermodeProc proc = fProc;
882
883 if (NULL != proc) {
884 if (NULL == aa) {
885 for (int i = count - 1; i >= 0; --i) {
886 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
887 dst[i] = SkToU8(SkGetPackedA32(res));
888 }
889 } else {
890 for (int i = count - 1; i >= 0; --i) {
891 unsigned a = aa[i];
892 if (0 != a) {
893 SkAlpha dstA = dst[i];
894 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
895 unsigned A = SkGetPackedA32(res);
896 if (0xFF != a) {
897 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
898 }
899 dst[i] = SkToU8(A);
900 }
901 }
902 }
903 }
904}
905
906SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
907 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000908 fProc = NULL;
909 if (!buffer.isCrossProcess()) {
910 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
911 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000912}
913
djsollen@google.com54924242012-03-29 15:18:04 +0000914void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
915 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000916 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000917 buffer.writeFunctionPtr((void*)fProc);
918 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000919}
920
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000921#ifdef SK_DEVELOPER
922void SkProcXfermode::toString(SkString* str) const {
923 str->appendf("SkProcXfermode: %p", fProc);
924}
925#endif
926
vandebo@chromium.org48543272011-02-08 19:28:07 +0000927///////////////////////////////////////////////////////////////////////////////
928///////////////////////////////////////////////////////////////////////////////
929
930class SkProcCoeffXfermode : public SkProcXfermode {
931public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000932 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
933 : INHERITED(rec.fProc) {
934 fMode = mode;
935 // these may be valid, or may be CANNOT_USE_COEFF
936 fSrcCoeff = rec.fSC;
937 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000938 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000939
reed@google.com30da7452012-12-17 19:55:24 +0000940 virtual bool asMode(Mode* mode) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000941 if (mode) {
942 *mode = fMode;
943 }
944 return true;
945 }
946
reed@google.com30da7452012-12-17 19:55:24 +0000947 virtual bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000948 if (CANNOT_USE_COEFF == fSrcCoeff) {
949 return false;
950 }
951
vandebo@chromium.org48543272011-02-08 19:28:07 +0000952 if (sc) {
953 *sc = fSrcCoeff;
954 }
955 if (dc) {
956 *dc = fDstCoeff;
957 }
958 return true;
959 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000960
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000961 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +0000962 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000963
vandebo@chromium.org48543272011-02-08 19:28:07 +0000964protected:
djsollen@google.com54924242012-03-29 15:18:04 +0000965 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000966 fMode = (SkXfermode::Mode)buffer.read32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000967
968 const ProcCoeff& rec = gProcCoeffs[fMode];
969 // these may be valid, or may be CANNOT_USE_COEFF
970 fSrcCoeff = rec.fSC;
971 fDstCoeff = rec.fDC;
972 // now update our function-ptr in the super class
973 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000974 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000975
djsollen@google.com54924242012-03-29 15:18:04 +0000976 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
977 this->INHERITED::flatten(buffer);
978 buffer.write32(fMode);
979 }
980
vandebo@chromium.org48543272011-02-08 19:28:07 +0000981private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000982 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000983 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000984
vandebo@chromium.org48543272011-02-08 19:28:07 +0000985 typedef SkProcXfermode INHERITED;
986};
987
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000988#ifdef SK_DEVELOPER
989void SkProcCoeffXfermode::toString(SkString* str) const {
990 str->append("SkProcCoeffXfermode: ");
991
992 const char *gModeStrings[kLastMode+1] = {
993 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
994 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
reed@google.com8d3cd7a2013-01-30 21:36:11 +0000995 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
robertphillips@google.comb83b6b42013-01-22 14:32:09 +0000996 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion"
997 };
998
999 str->append("mode: ");
1000 str->append(gModeStrings[fMode]);
1001
1002 static const char* gCoeffStrings[kCoeffCount] = {
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001003 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001004 };
1005
1006 str->append(" src: ");
1007 if (CANNOT_USE_COEFF == fSrcCoeff) {
1008 str->append("can't use");
1009 } else {
1010 str->append(gCoeffStrings[fSrcCoeff]);
1011 }
1012
1013 str->append(" dst: ");
1014 if (CANNOT_USE_COEFF == fDstCoeff) {
1015 str->append("can't use");
1016 } else {
1017 str->append(gCoeffStrings[fDstCoeff]);
1018 }
1019}
1020#endif
1021
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022///////////////////////////////////////////////////////////////////////////////
1023
1024class SkClearXfermode : public SkProcCoeffXfermode {
1025public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001026 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027
reed@google.com30da7452012-12-17 19:55:24 +00001028 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1029 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001031 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001032 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001033
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034private:
1035 SkClearXfermode(SkFlattenableReadBuffer& buffer)
1036 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001037
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001038 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039};
1040
reed@google.com86ab6c62011-11-28 15:26:14 +00001041void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1042 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001043 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001044 SkASSERT(dst && count >= 0);
1045
1046 if (NULL == aa) {
1047 memset(dst, 0, count << 2);
1048 } else {
1049 for (int i = count - 1; i >= 0; --i) {
1050 unsigned a = aa[i];
1051 if (0xFF == a) {
1052 dst[i] = 0;
1053 } else if (a != 0) {
1054 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1055 }
1056 }
1057 }
1058}
1059void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1060 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001061 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001062 SkASSERT(dst && count >= 0);
1063
1064 if (NULL == aa) {
1065 memset(dst, 0, count);
1066 } else {
1067 for (int i = count - 1; i >= 0; --i) {
1068 unsigned a = aa[i];
1069 if (0xFF == a) {
1070 dst[i] = 0;
1071 } else if (0 != a) {
1072 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1073 }
1074 }
1075 }
1076}
1077
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001078#ifdef SK_DEVELOPER
1079void SkClearXfermode::toString(SkString* str) const {
1080 this->INHERITED::toString(str);
1081}
1082#endif
1083
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084///////////////////////////////////////////////////////////////////////////////
1085
1086class SkSrcXfermode : public SkProcCoeffXfermode {
1087public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001088 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089
reed@google.com30da7452012-12-17 19:55:24 +00001090 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1091 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001093 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001094 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001095
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096private:
1097 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
1098 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001099
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001100 typedef SkProcCoeffXfermode INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101};
1102
reed@google.com86ab6c62011-11-28 15:26:14 +00001103void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1104 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001105 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001106 SkASSERT(dst && src && count >= 0);
1107
1108 if (NULL == aa) {
1109 memcpy(dst, src, count << 2);
1110 } else {
1111 for (int i = count - 1; i >= 0; --i) {
1112 unsigned a = aa[i];
1113 if (a == 0xFF) {
1114 dst[i] = src[i];
1115 } else if (a != 0) {
1116 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1117 }
1118 }
1119 }
1120}
1121
1122void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1123 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001124 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001125 SkASSERT(dst && src && count >= 0);
1126
1127 if (NULL == aa) {
1128 for (int i = count - 1; i >= 0; --i) {
1129 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1130 }
1131 } else {
1132 for (int i = count - 1; i >= 0; --i) {
1133 unsigned a = aa[i];
1134 if (0 != a) {
1135 unsigned srcA = SkGetPackedA32(src[i]);
1136 if (a == 0xFF) {
1137 dst[i] = SkToU8(srcA);
1138 } else {
1139 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1140 }
1141 }
1142 }
1143 }
1144}
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001145#ifdef SK_DEVELOPER
1146void SkSrcXfermode::toString(SkString* str) const {
1147 this->INHERITED::toString(str);
1148}
1149#endif
reed@google.com86ab6c62011-11-28 15:26:14 +00001150
reed@google.com30da7452012-12-17 19:55:24 +00001151///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001152
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153class SkDstInXfermode : public SkProcCoeffXfermode {
1154public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001155 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001156
reed@google.com30da7452012-12-17 19:55:24 +00001157 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +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(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001161
1162private:
1163 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
1164
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165 typedef SkProcCoeffXfermode INHERITED;
1166};
1167
reed@google.com86ab6c62011-11-28 15:26:14 +00001168void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1169 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001170 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001171 SkASSERT(dst && src);
1172
1173 if (count <= 0) {
1174 return;
1175 }
1176 if (NULL != aa) {
1177 return this->INHERITED::xfer32(dst, src, count, aa);
1178 }
1179
1180 do {
1181 unsigned a = SkGetPackedA32(*src);
1182 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1183 dst++;
1184 src++;
1185 } while (--count != 0);
1186}
1187
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001188#ifdef SK_DEVELOPER
1189void SkDstInXfermode::toString(SkString* str) const {
1190 this->INHERITED::toString(str);
1191}
1192#endif
1193
reed@google.com30da7452012-12-17 19:55:24 +00001194///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +00001195
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196class SkDstOutXfermode : public SkProcCoeffXfermode {
1197public:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001198 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001199
reed@google.com30da7452012-12-17 19:55:24 +00001200 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001201
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001202 SK_DEVELOPER_TO_STRING()
djsollen@google.comba28d032012-03-26 17:57:35 +00001203 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001204
1205private:
1206 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
1207 : INHERITED(buffer) {}
1208
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 typedef SkProcCoeffXfermode INHERITED;
1210};
1211
reed@google.com86ab6c62011-11-28 15:26:14 +00001212void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1213 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +00001214 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +00001215 SkASSERT(dst && src);
1216
1217 if (count <= 0) {
1218 return;
1219 }
1220 if (NULL != aa) {
1221 return this->INHERITED::xfer32(dst, src, count, aa);
1222 }
1223
1224 do {
1225 unsigned a = SkGetPackedA32(*src);
1226 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1227 dst++;
1228 src++;
1229 } while (--count != 0);
1230}
1231
robertphillips@google.comb83b6b42013-01-22 14:32:09 +00001232#ifdef SK_DEVELOPER
1233void SkDstOutXfermode::toString(SkString* str) const {
1234 this->INHERITED::toString(str);
1235}
1236#endif
1237
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238///////////////////////////////////////////////////////////////////////////////
1239
reed@android.coma0f5d152009-06-22 17:38:10 +00001240SkXfermode* SkXfermode::Create(Mode mode) {
1241 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1242 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243
reed@google.comc0d4aa22011-04-13 21:12:04 +00001244 const ProcCoeff& rec = gProcCoeffs[mode];
1245
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 switch (mode) {
1247 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001248 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001250 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 case kSrcOver_Mode:
1252 return NULL;
1253 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001254 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +00001256 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1257 default:
1258 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259 }
1260}
1261
reed@google.com43c50c82011-04-14 15:50:52 +00001262SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1263 SkXfermodeProc proc = NULL;
1264 if ((unsigned)mode < kModeCount) {
1265 proc = gProcCoeffs[mode].fProc;
1266 }
1267 return proc;
1268}
1269
1270bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1271 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001272
reed@google.com43c50c82011-04-14 15:50:52 +00001273 if ((unsigned)mode >= (unsigned)kModeCount) {
1274 // illegal mode parameter
1275 return false;
1276 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001277
reed@google.com43c50c82011-04-14 15:50:52 +00001278 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001279
reed@google.com43c50c82011-04-14 15:50:52 +00001280 if (CANNOT_USE_COEFF == rec.fSC) {
1281 return false;
1282 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001283
reed@google.com43c50c82011-04-14 15:50:52 +00001284 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1285 if (src) {
1286 *src = rec.fSC;
1287 }
1288 if (dst) {
1289 *dst = rec.fDC;
1290 }
1291 return true;
1292}
1293
reed@google.com30da7452012-12-17 19:55:24 +00001294bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 if (NULL == xfer) {
1296 if (mode) {
1297 *mode = kSrcOver_Mode;
1298 }
1299 return true;
1300 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001301 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302}
1303
reed@google.com30da7452012-12-17 19:55:24 +00001304bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001305 if (NULL == xfer) {
1306 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 }
reed@google.com43c50c82011-04-14 15:50:52 +00001308 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309}
1310
reed@google.com30da7452012-12-17 19:55:24 +00001311bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001312 // if xfer==null then the mode is srcover
1313 Mode m = kSrcOver_Mode;
1314 if (xfer && !xfer->asMode(&m)) {
1315 return false;
1316 }
1317 return mode == m;
1318}
1319
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320///////////////////////////////////////////////////////////////////////////////
1321//////////// 16bit xfermode procs
1322
1323#ifdef SK_DEBUG
1324static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1325static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1326#endif
1327
1328static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1329 SkASSERT(require_255(src));
1330 return SkPixel32ToPixel16(src);
1331}
1332
1333static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1334 return dst;
1335}
1336
1337static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1338 SkASSERT(require_0(src));
1339 return dst;
1340}
1341
1342static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1343 SkASSERT(require_255(src));
1344 return SkPixel32ToPixel16(src);
1345}
1346
1347static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1348 SkASSERT(require_0(src));
1349 return dst;
1350}
1351
1352static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1353 SkASSERT(require_255(src));
1354 return dst;
1355}
1356
1357static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1358 SkASSERT(require_255(src));
1359 return SkPixel32ToPixel16(src);
1360}
1361
1362static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1363 SkASSERT(require_255(src));
1364 return dst;
1365}
1366
1367static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1368 SkASSERT(require_0(src));
1369 return dst;
1370}
1371
1372static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1373 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001374
reed@android.com8a1c16f2008-12-17 15:59:43 +00001375 return SkPackRGB16(
1376 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1377 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1378 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1379}
1380
1381static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1382 SkASSERT(require_0(src));
1383 return dst;
1384}
1385
1386static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1387 SkASSERT(require_255(src));
1388 return SkPixel32ToPixel16(src);
1389}
1390
1391static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1392 SkASSERT(require_255(src));
1393 return dst;
1394}
1395
1396/*********
1397 darken and lighten boil down to this.
1398
1399 darken = (1 - Sa) * Dc + min(Sc, Dc)
1400 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1401
1402 if (Sa == 0) these become
1403 darken = Dc + min(0, Dc) = 0
1404 lighten = Dc + max(0, Dc) = Dc
1405
1406 if (Sa == 1) these become
1407 darken = min(Sc, Dc)
1408 lighten = max(Sc, Dc)
1409*/
1410
1411static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1412 SkASSERT(require_0(src));
1413 return 0;
1414}
1415
1416static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1417 SkASSERT(require_255(src));
1418 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1419 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1420 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1421 return SkPackRGB16(r, g, b);
1422}
1423
1424static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1425 SkASSERT(require_0(src));
1426 return dst;
1427}
1428
1429static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1430 SkASSERT(require_255(src));
1431 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1432 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1433 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1434 return SkPackRGB16(r, g, b);
1435}
1436
1437struct Proc16Rec {
1438 SkXfermodeProc16 fProc16_0;
1439 SkXfermodeProc16 fProc16_255;
1440 SkXfermodeProc16 fProc16_General;
1441};
1442
reed@android.coma0f5d152009-06-22 17:38:10 +00001443static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444 { NULL, NULL, NULL }, // CLEAR
1445 { NULL, src_modeproc16_255, NULL },
1446 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1447 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1448 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1449 { NULL, srcin_modeproc16_255, NULL },
1450 { NULL, dstin_modeproc16_255, NULL },
1451 { NULL, NULL, NULL },// SRC_OUT
1452 { dstout_modeproc16_0, NULL, NULL },
1453 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1454 { NULL, dstatop_modeproc16_255, NULL },
1455 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001456
1457 { NULL, NULL, NULL }, // plus
reed@google.com8d3cd7a2013-01-30 21:36:11 +00001458 { NULL, NULL, NULL }, // modulate
reed@android.coma0f5d152009-06-22 17:38:10 +00001459 { NULL, NULL, NULL }, // screen
1460 { NULL, NULL, NULL }, // overlay
1461 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1462 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1463 { NULL, NULL, NULL }, // colordodge
1464 { NULL, NULL, NULL }, // colorburn
1465 { NULL, NULL, NULL }, // hardlight
1466 { NULL, NULL, NULL }, // softlight
1467 { NULL, NULL, NULL }, // difference
1468 { NULL, NULL, NULL }, // exclusion
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +00001469 { NULL, NULL, NULL }, // multiply
1470 { NULL, NULL, NULL }, // hue
1471 { NULL, NULL, NULL }, // saturation
1472 { NULL, NULL, NULL }, // color
1473 { NULL, NULL, NULL }, // luminosity
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474};
1475
reed@android.coma0f5d152009-06-22 17:38:10 +00001476SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001478 if ((unsigned)mode < kModeCount) {
1479 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 unsigned a = SkColorGetA(srcColor);
1481
1482 if (0 == a) {
1483 proc16 = rec.fProc16_0;
1484 } else if (255 == a) {
1485 proc16 = rec.fProc16_255;
1486 } else {
1487 proc16 = rec.fProc16_General;
1488 }
1489 }
1490 return proc16;
1491}
1492
caryclark@google.comd26147a2011-12-15 14:16:43 +00001493SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1494 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1495 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1496 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1497 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1498 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1499SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END