blob: 7a25c6e18b5a5f730443ba0c3a3a05c48df537a0 [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"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000015SK_DEFINE_INST_COUNT(SkXfermode)
16
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
18
reed@android.comfc25abd2009-01-15 14:38:33 +000019#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000020// idea for higher precision blends in xfer procs (and slightly faster)
21// see DstATop as a probable caller
22static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
23 SkASSERT(a <= 255);
24 SkASSERT(b <= 255);
25 SkASSERT(c <= 255);
26 SkASSERT(d <= 255);
27 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
28 unsigned result = (prod + (prod >> 8)) >> 8;
29 SkASSERT(result <= 255);
30 return result;
31}
reed@android.comfc25abd2009-01-15 14:38:33 +000032#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
deanm@chromium.orgda946992009-07-03 12:54:24 +000034static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000035 SkASSERT(a <= 255);
36 SkASSERT(b <= 255);
37 unsigned sum = a + b;
38 if (sum > 255) {
39 sum = 255;
40 }
41 return sum;
42}
43
deanm@chromium.orgda946992009-07-03 12:54:24 +000044static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000045 if (n < 0) {
46 n = 0;
47 } else if (n > 255) {
48 n = 255;
49 }
50 return n;
51}
52
deanm@chromium.orgda946992009-07-03 12:54:24 +000053static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000054 if (prod <= 0) {
55 return 0;
56 } else if (prod >= 255*255) {
57 return 255;
58 } else {
59 return SkDiv255Round(prod);
60 }
61}
62
deanm@chromium.orgda946992009-07-03 12:54:24 +000063static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000064 if (value > max) {
65 value = max;
66 }
67 return value;
68}
69
reed@android.com8a1c16f2008-12-17 15:59:43 +000070///////////////////////////////////////////////////////////////////////////////
71
reed@android.com8a1c16f2008-12-17 15:59:43 +000072// kClear_Mode, //!< [0, 0]
73static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
74 return 0;
75}
76
77// kSrc_Mode, //!< [Sa, Sc]
78static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
79 return src;
80}
81
82// kDst_Mode, //!< [Da, Dc]
83static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
84 return dst;
85}
86
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000087// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000088static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000089#if 0
90 // this is the old, more-correct way, but it doesn't guarantee that dst==255
91 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000093#else
94 // this is slightly faster, but more importantly guarantees that dst==255
95 // will always stay opaque
96 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
97#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000098}
99
reed@android.com1116fb22009-03-03 20:31:12 +0000100// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000102 // this is the reverse of srcover, just flipping src and dst
103 // see srcover's comment about the 256 for opaqueness guarantees
104 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
107// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
108static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
109 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
110}
111
112// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
113static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
114 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
115}
116
117// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
118static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
119 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
120}
121
122// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
123static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
124 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
125}
126
127// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
128static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
129 unsigned sa = SkGetPackedA32(src);
130 unsigned da = SkGetPackedA32(dst);
131 unsigned isa = 255 - sa;
132
133 return SkPackARGB32(da,
134 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
135 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
136 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
137 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
138 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
139 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
140}
141
142// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
143static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
144 unsigned sa = SkGetPackedA32(src);
145 unsigned da = SkGetPackedA32(dst);
146 unsigned ida = 255 - da;
147
148 return SkPackARGB32(sa,
149 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
150 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
151 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
152 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
153 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
154 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
155}
156
157// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
158static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
159 unsigned sa = SkGetPackedA32(src);
160 unsigned da = SkGetPackedA32(dst);
161 unsigned isa = 255 - sa;
162 unsigned ida = 255 - da;
163
164 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
165 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
166 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
167 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
168 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
169 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
170 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
171}
172
reed@android.coma0f5d152009-06-22 17:38:10 +0000173///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
reed@android.coma0f5d152009-06-22 17:38:10 +0000175// kPlus_Mode
176static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000177 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000178 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
179 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
180 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000181 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182}
183
reed@android.coma0f5d152009-06-22 17:38:10 +0000184// kMultiply_Mode
185static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
187 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
188 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
189 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
190 return SkPackARGB32(a, r, g, b);
191}
192
reed@android.coma0f5d152009-06-22 17:38:10 +0000193// kScreen_Mode
194static 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@android.com8a1c16f2008-12-17 15:59:43 +0000197static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000198 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
199 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
200 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
201 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 return SkPackARGB32(a, r, g, b);
203}
204
reed@android.coma0f5d152009-06-22 17:38:10 +0000205// kOverlay_Mode
206static inline int overlay_byte(int sc, int dc, int sa, int da) {
207 int tmp = sc * (255 - da) + dc * (255 - sa);
208 int rc;
209 if (2 * dc <= da) {
210 rc = 2 * sc * dc;
211 } else {
212 rc = sa * da - 2 * (da - dc) * (sa - sc);
213 }
214 return clamp_div255round(rc + tmp);
215}
216static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
217 int sa = SkGetPackedA32(src);
218 int da = SkGetPackedA32(dst);
219 int a = srcover_byte(sa, da);
220 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
221 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
222 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
223 return SkPackARGB32(a, r, g, b);
224}
225
226// kDarken_Mode
227static inline int darken_byte(int sc, int dc, int sa, int da) {
228 int sd = sc * da;
229 int ds = dc * sa;
230 if (sd < ds) {
231 // srcover
232 return sc + dc - SkDiv255Round(ds);
233 } else {
234 // dstover
235 return dc + sc - SkDiv255Round(sd);
236 }
237}
238static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
239 int sa = SkGetPackedA32(src);
240 int da = SkGetPackedA32(dst);
241 int a = srcover_byte(sa, da);
242 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
243 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
244 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
245 return SkPackARGB32(a, r, g, b);
246}
247
248// kLighten_Mode
249static inline int lighten_byte(int sc, int dc, int sa, int da) {
250 int sd = sc * da;
251 int ds = dc * sa;
252 if (sd > ds) {
253 // srcover
254 return sc + dc - SkDiv255Round(ds);
255 } else {
256 // dstover
257 return dc + sc - SkDiv255Round(sd);
258 }
259}
260static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
261 int sa = SkGetPackedA32(src);
262 int da = SkGetPackedA32(dst);
263 int a = srcover_byte(sa, da);
264 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
265 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
266 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
267 return SkPackARGB32(a, r, g, b);
268}
269
270// kColorDodge_Mode
271static inline int colordodge_byte(int sc, int dc, int sa, int da) {
272 int diff = sa - sc;
273 int rc;
274 if (0 == diff) {
275 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
276 rc = SkDiv255Round(rc);
277 } else {
278 int tmp = (dc * sa << 15) / (da * diff);
279 rc = SkDiv255Round(sa * da) * tmp >> 15;
280 // don't clamp here, since we'll do it in our modeproc
281 }
282 return rc;
283}
284static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
285 // added to avoid div-by-zero in colordodge_byte
286 if (0 == dst) {
287 return src;
288 }
289
290 int sa = SkGetPackedA32(src);
291 int da = SkGetPackedA32(dst);
292 int a = srcover_byte(sa, da);
293 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
294 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
295 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
296 r = clamp_max(r, a);
297 g = clamp_max(g, a);
298 b = clamp_max(b, a);
299 return SkPackARGB32(a, r, g, b);
300}
301
302// kColorBurn_Mode
303static inline int colorburn_byte(int sc, int dc, int sa, int da) {
304 int rc;
305 if (dc == da && 0 == sc) {
306 rc = sa * da + dc * (255 - sa);
307 } else if (0 == sc) {
308 return SkAlphaMulAlpha(dc, 255 - sa);
309 } else {
310 int tmp = (sa * (da - dc) * 256) / (sc * da);
311 if (tmp > 256) {
312 tmp = 256;
313 }
314 int tmp2 = sa * da;
315 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
316 }
317 return SkDiv255Round(rc);
318}
319static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
320 // added to avoid div-by-zero in colorburn_byte
321 if (0 == dst) {
322 return src;
323 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000324
reed@android.coma0f5d152009-06-22 17:38:10 +0000325 int sa = SkGetPackedA32(src);
326 int da = SkGetPackedA32(dst);
327 int a = srcover_byte(sa, da);
328 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
329 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
330 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
331 return SkPackARGB32(a, r, g, b);
332}
333
334// kHardLight_Mode
335static inline int hardlight_byte(int sc, int dc, int sa, int da) {
336 int rc;
337 if (2 * sc <= sa) {
338 rc = 2 * sc * dc;
339 } else {
340 rc = sa * da - 2 * (da - dc) * (sa - sc);
341 }
342 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
343}
344static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
345 int sa = SkGetPackedA32(src);
346 int da = SkGetPackedA32(dst);
347 int a = srcover_byte(sa, da);
348 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
349 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
350 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
351 return SkPackARGB32(a, r, g, b);
352}
353
354// returns 255 * sqrt(n/255)
355static U8CPU sqrt_unit_byte(U8CPU n) {
356 return SkSqrtBits(n, 15+4);
357}
358
359// kSoftLight_Mode
360static inline int softlight_byte(int sc, int dc, int sa, int da) {
361 int m = da ? dc * 256 / da : 0;
362 int rc;
363 if (2 * sc <= sa) {
364 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
365 } else if (4 * dc <= da) {
366 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
367 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
368 } else {
369 int tmp = sqrt_unit_byte(m) - m;
370 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
371 }
372 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
373}
374static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
375 int sa = SkGetPackedA32(src);
376 int da = SkGetPackedA32(dst);
377 int a = srcover_byte(sa, da);
378 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
379 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
380 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
381 return SkPackARGB32(a, r, g, b);
382}
383
384// kDifference_Mode
385static inline int difference_byte(int sc, int dc, int sa, int da) {
386 int tmp = SkMin32(sc * da, dc * sa);
387 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
388}
389static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
390 int sa = SkGetPackedA32(src);
391 int da = SkGetPackedA32(dst);
392 int a = srcover_byte(sa, da);
393 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
394 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
395 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
396 return SkPackARGB32(a, r, g, b);
397}
398
399// kExclusion_Mode
400static inline int exclusion_byte(int sc, int dc, int sa, int da) {
401 // this equations is wacky, wait for SVG to confirm it
402 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
403 return clamp_div255round(r);
404}
405static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
406 int sa = SkGetPackedA32(src);
407 int da = SkGetPackedA32(dst);
408 int a = srcover_byte(sa, da);
409 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
410 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
411 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000412 return SkPackARGB32(a, r, g, b);
413}
414
vandebo@chromium.org48543272011-02-08 19:28:07 +0000415struct ProcCoeff {
416 SkXfermodeProc fProc;
417 SkXfermode::Coeff fSC;
418 SkXfermode::Coeff fDC;
419};
420
421#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
422
423static const ProcCoeff gProcCoeffs[] = {
424 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
425 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
426 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
427 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
428 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
429 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
430 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
431 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
432 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
433 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
434 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
435 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
436
reed@google.com521e34e2011-04-12 18:55:21 +0000437 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
438 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000439 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
440 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
441 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
442 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
443 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
444 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
445 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
446 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
447 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
448 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
449};
450
451///////////////////////////////////////////////////////////////////////////////
452
reed@google.com30da7452012-12-17 19:55:24 +0000453bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000454 return false;
455}
456
reed@google.com30da7452012-12-17 19:55:24 +0000457bool SkXfermode::asMode(Mode* mode) const {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000458 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000459}
460
reed@google.com30da7452012-12-17 19:55:24 +0000461SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
vandebo@chromium.org48543272011-02-08 19:28:07 +0000462 // no-op. subclasses should override this
463 return dst;
464}
465
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000466void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
467 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000468 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000469 SkASSERT(dst && src && count >= 0);
470
471 if (NULL == aa) {
472 for (int i = count - 1; i >= 0; --i) {
473 dst[i] = this->xferColor(src[i], dst[i]);
474 }
475 } else {
476 for (int i = count - 1; i >= 0; --i) {
477 unsigned a = aa[i];
478 if (0 != a) {
479 SkPMColor dstC = dst[i];
480 SkPMColor C = this->xferColor(src[i], dstC);
481 if (0xFF != a) {
482 C = SkFourByteInterp(C, dstC, a);
483 }
484 dst[i] = C;
485 }
486 }
487 }
488}
489
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000490void SkXfermode::xfer16(uint16_t* dst,
491 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000492 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000493 SkASSERT(dst && src && count >= 0);
494
495 if (NULL == aa) {
496 for (int i = count - 1; i >= 0; --i) {
497 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
498 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
499 }
500 } else {
501 for (int i = count - 1; i >= 0; --i) {
502 unsigned a = aa[i];
503 if (0 != a) {
504 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
505 SkPMColor C = this->xferColor(src[i], dstC);
506 if (0xFF != a) {
507 C = SkFourByteInterp(C, dstC, a);
508 }
509 dst[i] = SkPixel32ToPixel16_ToU16(C);
510 }
511 }
512 }
513}
514
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000515void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
516 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000517 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000518 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000519
vandebo@chromium.org48543272011-02-08 19:28:07 +0000520 if (NULL == aa) {
521 for (int i = count - 1; i >= 0; --i) {
522 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
523 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
524 }
525 } else {
526 for (int i = count - 1; i >= 0; --i) {
527 unsigned a = aa[i];
528 if (0 != a) {
529 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
530 SkPMColor C = this->xferColor(src[i], dstC);
531 if (0xFF != a) {
532 C = SkFourByteInterp(C, dstC, a);
533 }
534 dst[i] = SkPixel32ToPixel4444(C);
535 }
536 }
537 }
538}
539
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000540void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000541 const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +0000542 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000543 SkASSERT(dst && src && count >= 0);
544
545 if (NULL == aa) {
546 for (int i = count - 1; i >= 0; --i) {
547 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
548 dst[i] = SkToU8(SkGetPackedA32(res));
549 }
550 } else {
551 for (int i = count - 1; i >= 0; --i) {
552 unsigned a = aa[i];
553 if (0 != a) {
554 SkAlpha dstA = dst[i];
555 unsigned A = SkGetPackedA32(this->xferColor(src[i],
556 (SkPMColor)(dstA << SK_A32_SHIFT)));
557 if (0xFF != a) {
558 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
559 }
560 dst[i] = SkToU8(A);
561 }
562 }
563 }
564}
565
566///////////////////////////////////////////////////////////////////////////////
567
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000568void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
569 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000570 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000571 SkASSERT(dst && src && count >= 0);
572
573 SkXfermodeProc proc = fProc;
574
575 if (NULL != proc) {
576 if (NULL == aa) {
577 for (int i = count - 1; i >= 0; --i) {
578 dst[i] = proc(src[i], dst[i]);
579 }
580 } else {
581 for (int i = count - 1; i >= 0; --i) {
582 unsigned a = aa[i];
583 if (0 != a) {
584 SkPMColor dstC = dst[i];
585 SkPMColor C = proc(src[i], dstC);
586 if (a != 0xFF) {
587 C = SkFourByteInterp(C, dstC, a);
588 }
589 dst[i] = C;
590 }
591 }
592 }
593 }
594}
595
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000596void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
597 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000598 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000599 SkASSERT(dst && src && count >= 0);
600
601 SkXfermodeProc proc = fProc;
602
603 if (NULL != proc) {
604 if (NULL == aa) {
605 for (int i = count - 1; i >= 0; --i) {
606 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
607 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
608 }
609 } else {
610 for (int i = count - 1; i >= 0; --i) {
611 unsigned a = aa[i];
612 if (0 != a) {
613 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
614 SkPMColor C = proc(src[i], dstC);
615 if (0xFF != a) {
616 C = SkFourByteInterp(C, dstC, a);
617 }
618 dst[i] = SkPixel32ToPixel16_ToU16(C);
619 }
620 }
621 }
622 }
623}
624
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000625void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
626 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000627 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000628 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000629
vandebo@chromium.org48543272011-02-08 19:28:07 +0000630 SkXfermodeProc proc = fProc;
631
632 if (NULL != proc) {
633 if (NULL == aa) {
634 for (int i = count - 1; i >= 0; --i) {
635 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
636 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
637 }
638 } else {
639 for (int i = count - 1; i >= 0; --i) {
640 unsigned a = aa[i];
641 if (0 != a) {
642 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
643 SkPMColor C = proc(src[i], dstC);
644 if (0xFF != a) {
645 C = SkFourByteInterp(C, dstC, a);
646 }
647 dst[i] = SkPixel32ToPixel4444(C);
648 }
649 }
650 }
651 }
652}
653
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000654void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
655 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000656 const SkAlpha* SK_RESTRICT aa) const {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000657 SkASSERT(dst && src && count >= 0);
658
659 SkXfermodeProc proc = fProc;
660
661 if (NULL != proc) {
662 if (NULL == aa) {
663 for (int i = count - 1; i >= 0; --i) {
664 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
665 dst[i] = SkToU8(SkGetPackedA32(res));
666 }
667 } else {
668 for (int i = count - 1; i >= 0; --i) {
669 unsigned a = aa[i];
670 if (0 != a) {
671 SkAlpha dstA = dst[i];
672 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
673 unsigned A = SkGetPackedA32(res);
674 if (0xFF != a) {
675 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
676 }
677 dst[i] = SkToU8(A);
678 }
679 }
680 }
681 }
682}
683
684SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
685 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000686 fProc = NULL;
687 if (!buffer.isCrossProcess()) {
688 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
689 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000690}
691
djsollen@google.com54924242012-03-29 15:18:04 +0000692void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
693 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000694 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000695 buffer.writeFunctionPtr((void*)fProc);
696 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000697}
698
vandebo@chromium.org48543272011-02-08 19:28:07 +0000699///////////////////////////////////////////////////////////////////////////////
700///////////////////////////////////////////////////////////////////////////////
701
702class SkProcCoeffXfermode : public SkProcXfermode {
703public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000704 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
705 : INHERITED(rec.fProc) {
706 fMode = mode;
707 // these may be valid, or may be CANNOT_USE_COEFF
708 fSrcCoeff = rec.fSC;
709 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000710 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000711
reed@google.com30da7452012-12-17 19:55:24 +0000712 virtual bool asMode(Mode* mode) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000713 if (mode) {
714 *mode = fMode;
715 }
716 return true;
717 }
718
reed@google.com30da7452012-12-17 19:55:24 +0000719 virtual bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000720 if (CANNOT_USE_COEFF == fSrcCoeff) {
721 return false;
722 }
723
vandebo@chromium.org48543272011-02-08 19:28:07 +0000724 if (sc) {
725 *sc = fSrcCoeff;
726 }
727 if (dc) {
728 *dc = fDstCoeff;
729 }
730 return true;
731 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000732
djsollen@google.comba28d032012-03-26 17:57:35 +0000733 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000734
vandebo@chromium.org48543272011-02-08 19:28:07 +0000735protected:
djsollen@google.com54924242012-03-29 15:18:04 +0000736 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000737 fMode = (SkXfermode::Mode)buffer.read32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000738
739 const ProcCoeff& rec = gProcCoeffs[fMode];
740 // these may be valid, or may be CANNOT_USE_COEFF
741 fSrcCoeff = rec.fSC;
742 fDstCoeff = rec.fDC;
743 // now update our function-ptr in the super class
744 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000745 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000746
djsollen@google.com54924242012-03-29 15:18:04 +0000747 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
748 this->INHERITED::flatten(buffer);
749 buffer.write32(fMode);
750 }
751
vandebo@chromium.org48543272011-02-08 19:28:07 +0000752private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000753 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000754 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000755
vandebo@chromium.org48543272011-02-08 19:28:07 +0000756
757 typedef SkProcXfermode INHERITED;
758};
759
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760///////////////////////////////////////////////////////////////////////////////
761
762class SkClearXfermode : public SkProcCoeffXfermode {
763public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000764 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765
reed@google.com30da7452012-12-17 19:55:24 +0000766 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
767 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768
djsollen@google.comba28d032012-03-26 17:57:35 +0000769 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771private:
772 SkClearXfermode(SkFlattenableReadBuffer& buffer)
773 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000774
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775};
776
reed@google.com86ab6c62011-11-28 15:26:14 +0000777void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
778 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000779 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000780 SkASSERT(dst && count >= 0);
781
782 if (NULL == aa) {
783 memset(dst, 0, count << 2);
784 } else {
785 for (int i = count - 1; i >= 0; --i) {
786 unsigned a = aa[i];
787 if (0xFF == a) {
788 dst[i] = 0;
789 } else if (a != 0) {
790 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
791 }
792 }
793 }
794}
795void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
796 const SkPMColor* SK_RESTRICT, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000797 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000798 SkASSERT(dst && count >= 0);
799
800 if (NULL == aa) {
801 memset(dst, 0, count);
802 } else {
803 for (int i = count - 1; i >= 0; --i) {
804 unsigned a = aa[i];
805 if (0xFF == a) {
806 dst[i] = 0;
807 } else if (0 != a) {
808 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
809 }
810 }
811 }
812}
813
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814///////////////////////////////////////////////////////////////////////////////
815
816class SkSrcXfermode : public SkProcCoeffXfermode {
817public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000818 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819
reed@google.com30da7452012-12-17 19:55:24 +0000820 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
821 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822
djsollen@google.comba28d032012-03-26 17:57:35 +0000823 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825private:
826 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
827 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000828
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829};
830
reed@google.com86ab6c62011-11-28 15:26:14 +0000831void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
832 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000833 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000834 SkASSERT(dst && src && count >= 0);
835
836 if (NULL == aa) {
837 memcpy(dst, src, count << 2);
838 } else {
839 for (int i = count - 1; i >= 0; --i) {
840 unsigned a = aa[i];
841 if (a == 0xFF) {
842 dst[i] = src[i];
843 } else if (a != 0) {
844 dst[i] = SkFourByteInterp(src[i], dst[i], a);
845 }
846 }
847 }
848}
849
850void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
851 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000852 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000853 SkASSERT(dst && src && count >= 0);
854
855 if (NULL == aa) {
856 for (int i = count - 1; i >= 0; --i) {
857 dst[i] = SkToU8(SkGetPackedA32(src[i]));
858 }
859 } else {
860 for (int i = count - 1; i >= 0; --i) {
861 unsigned a = aa[i];
862 if (0 != a) {
863 unsigned srcA = SkGetPackedA32(src[i]);
864 if (a == 0xFF) {
865 dst[i] = SkToU8(srcA);
866 } else {
867 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
868 }
869 }
870 }
871 }
872}
873
reed@google.com30da7452012-12-17 19:55:24 +0000874///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +0000875
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876class SkDstInXfermode : public SkProcCoeffXfermode {
877public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000878 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000879
reed@google.com30da7452012-12-17 19:55:24 +0000880 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000881
djsollen@google.comba28d032012-03-26 17:57:35 +0000882 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000883
884private:
885 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
886
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887 typedef SkProcCoeffXfermode INHERITED;
888};
889
reed@google.com86ab6c62011-11-28 15:26:14 +0000890void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
891 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000892 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000893 SkASSERT(dst && src);
894
895 if (count <= 0) {
896 return;
897 }
898 if (NULL != aa) {
899 return this->INHERITED::xfer32(dst, src, count, aa);
900 }
901
902 do {
903 unsigned a = SkGetPackedA32(*src);
904 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
905 dst++;
906 src++;
907 } while (--count != 0);
908}
909
reed@google.com30da7452012-12-17 19:55:24 +0000910///////////////////////////////////////////////////////////////////////////////
reed@google.com86ab6c62011-11-28 15:26:14 +0000911
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912class SkDstOutXfermode : public SkProcCoeffXfermode {
913public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000914 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000915
reed@google.com30da7452012-12-17 19:55:24 +0000916 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000917
djsollen@google.comba28d032012-03-26 17:57:35 +0000918 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000919
920private:
921 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
922 : INHERITED(buffer) {}
923
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924 typedef SkProcCoeffXfermode INHERITED;
925};
926
reed@google.com86ab6c62011-11-28 15:26:14 +0000927void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
928 const SkPMColor* SK_RESTRICT src, int count,
reed@google.com30da7452012-12-17 19:55:24 +0000929 const SkAlpha* SK_RESTRICT aa) const {
reed@google.com86ab6c62011-11-28 15:26:14 +0000930 SkASSERT(dst && src);
931
932 if (count <= 0) {
933 return;
934 }
935 if (NULL != aa) {
936 return this->INHERITED::xfer32(dst, src, count, aa);
937 }
938
939 do {
940 unsigned a = SkGetPackedA32(*src);
941 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
942 dst++;
943 src++;
944 } while (--count != 0);
945}
946
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947///////////////////////////////////////////////////////////////////////////////
948
reed@android.coma0f5d152009-06-22 17:38:10 +0000949SkXfermode* SkXfermode::Create(Mode mode) {
950 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
951 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952
reed@google.comc0d4aa22011-04-13 21:12:04 +0000953 const ProcCoeff& rec = gProcCoeffs[mode];
954
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 switch (mode) {
956 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000957 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000959 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 case kSrcOver_Mode:
961 return NULL;
962 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000963 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000965 return SkNEW_ARGS(SkDstOutXfermode, (rec));
966 default:
967 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 }
969}
970
reed@google.com43c50c82011-04-14 15:50:52 +0000971SkXfermodeProc SkXfermode::GetProc(Mode mode) {
972 SkXfermodeProc proc = NULL;
973 if ((unsigned)mode < kModeCount) {
974 proc = gProcCoeffs[mode].fProc;
975 }
976 return proc;
977}
978
979bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
980 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000981
reed@google.com43c50c82011-04-14 15:50:52 +0000982 if ((unsigned)mode >= (unsigned)kModeCount) {
983 // illegal mode parameter
984 return false;
985 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000986
reed@google.com43c50c82011-04-14 15:50:52 +0000987 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000988
reed@google.com43c50c82011-04-14 15:50:52 +0000989 if (CANNOT_USE_COEFF == rec.fSC) {
990 return false;
991 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000992
reed@google.com43c50c82011-04-14 15:50:52 +0000993 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
994 if (src) {
995 *src = rec.fSC;
996 }
997 if (dst) {
998 *dst = rec.fDC;
999 }
1000 return true;
1001}
1002
reed@google.com30da7452012-12-17 19:55:24 +00001003bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 if (NULL == xfer) {
1005 if (mode) {
1006 *mode = kSrcOver_Mode;
1007 }
1008 return true;
1009 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001010 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011}
1012
reed@google.com30da7452012-12-17 19:55:24 +00001013bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
reed@google.com43c50c82011-04-14 15:50:52 +00001014 if (NULL == xfer) {
1015 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016 }
reed@google.com43c50c82011-04-14 15:50:52 +00001017 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018}
1019
reed@google.com30da7452012-12-17 19:55:24 +00001020bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001021 // if xfer==null then the mode is srcover
1022 Mode m = kSrcOver_Mode;
1023 if (xfer && !xfer->asMode(&m)) {
1024 return false;
1025 }
1026 return mode == m;
1027}
1028
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029///////////////////////////////////////////////////////////////////////////////
1030//////////// 16bit xfermode procs
1031
1032#ifdef SK_DEBUG
1033static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1034static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1035#endif
1036
1037static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1038 SkASSERT(require_255(src));
1039 return SkPixel32ToPixel16(src);
1040}
1041
1042static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1043 return dst;
1044}
1045
1046static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1047 SkASSERT(require_0(src));
1048 return dst;
1049}
1050
1051static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1052 SkASSERT(require_255(src));
1053 return SkPixel32ToPixel16(src);
1054}
1055
1056static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1057 SkASSERT(require_0(src));
1058 return dst;
1059}
1060
1061static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1062 SkASSERT(require_255(src));
1063 return dst;
1064}
1065
1066static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1067 SkASSERT(require_255(src));
1068 return SkPixel32ToPixel16(src);
1069}
1070
1071static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1072 SkASSERT(require_255(src));
1073 return dst;
1074}
1075
1076static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1077 SkASSERT(require_0(src));
1078 return dst;
1079}
1080
1081static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1082 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001083
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 return SkPackRGB16(
1085 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1086 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1087 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1088}
1089
1090static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1091 SkASSERT(require_0(src));
1092 return dst;
1093}
1094
1095static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1096 SkASSERT(require_255(src));
1097 return SkPixel32ToPixel16(src);
1098}
1099
1100static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1101 SkASSERT(require_255(src));
1102 return dst;
1103}
1104
1105/*********
1106 darken and lighten boil down to this.
1107
1108 darken = (1 - Sa) * Dc + min(Sc, Dc)
1109 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1110
1111 if (Sa == 0) these become
1112 darken = Dc + min(0, Dc) = 0
1113 lighten = Dc + max(0, Dc) = Dc
1114
1115 if (Sa == 1) these become
1116 darken = min(Sc, Dc)
1117 lighten = max(Sc, Dc)
1118*/
1119
1120static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1121 SkASSERT(require_0(src));
1122 return 0;
1123}
1124
1125static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1126 SkASSERT(require_255(src));
1127 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1128 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1129 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1130 return SkPackRGB16(r, g, b);
1131}
1132
1133static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1134 SkASSERT(require_0(src));
1135 return dst;
1136}
1137
1138static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1139 SkASSERT(require_255(src));
1140 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1141 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1142 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1143 return SkPackRGB16(r, g, b);
1144}
1145
1146struct Proc16Rec {
1147 SkXfermodeProc16 fProc16_0;
1148 SkXfermodeProc16 fProc16_255;
1149 SkXfermodeProc16 fProc16_General;
1150};
1151
reed@android.coma0f5d152009-06-22 17:38:10 +00001152static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153 { NULL, NULL, NULL }, // CLEAR
1154 { NULL, src_modeproc16_255, NULL },
1155 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1156 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1157 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1158 { NULL, srcin_modeproc16_255, NULL },
1159 { NULL, dstin_modeproc16_255, NULL },
1160 { NULL, NULL, NULL },// SRC_OUT
1161 { dstout_modeproc16_0, NULL, NULL },
1162 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1163 { NULL, dstatop_modeproc16_255, NULL },
1164 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001165
1166 { NULL, NULL, NULL }, // plus
1167 { NULL, NULL, NULL }, // multiply
1168 { NULL, NULL, NULL }, // screen
1169 { NULL, NULL, NULL }, // overlay
1170 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1171 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1172 { NULL, NULL, NULL }, // colordodge
1173 { NULL, NULL, NULL }, // colorburn
1174 { NULL, NULL, NULL }, // hardlight
1175 { NULL, NULL, NULL }, // softlight
1176 { NULL, NULL, NULL }, // difference
1177 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178};
1179
reed@android.coma0f5d152009-06-22 17:38:10 +00001180SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001182 if ((unsigned)mode < kModeCount) {
1183 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 unsigned a = SkColorGetA(srcColor);
1185
1186 if (0 == a) {
1187 proc16 = rec.fProc16_0;
1188 } else if (255 == a) {
1189 proc16 = rec.fProc16_255;
1190 } else {
1191 proc16 = rec.fProc16_General;
1192 }
1193 }
1194 return proc16;
1195}
1196
caryclark@google.comd26147a2011-12-15 14:16:43 +00001197SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1198 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1199 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1200 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1201 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1202 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1203SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END