blob: bb9dc793266e7ad194001d264bcd947a93186d3b [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"
12
13#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
14
reed@android.comfc25abd2009-01-15 14:38:33 +000015#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000016// idea for higher precision blends in xfer procs (and slightly faster)
17// see DstATop as a probable caller
18static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
19 SkASSERT(a <= 255);
20 SkASSERT(b <= 255);
21 SkASSERT(c <= 255);
22 SkASSERT(d <= 255);
23 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
24 unsigned result = (prod + (prod >> 8)) >> 8;
25 SkASSERT(result <= 255);
26 return result;
27}
reed@android.comfc25abd2009-01-15 14:38:33 +000028#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
deanm@chromium.orgda946992009-07-03 12:54:24 +000030static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000031 SkASSERT(a <= 255);
32 SkASSERT(b <= 255);
33 unsigned sum = a + b;
34 if (sum > 255) {
35 sum = 255;
36 }
37 return sum;
38}
39
deanm@chromium.orgda946992009-07-03 12:54:24 +000040static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000041 if (n < 0) {
42 n = 0;
43 } else if (n > 255) {
44 n = 255;
45 }
46 return n;
47}
48
deanm@chromium.orgda946992009-07-03 12:54:24 +000049static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000050 if (prod <= 0) {
51 return 0;
52 } else if (prod >= 255*255) {
53 return 255;
54 } else {
55 return SkDiv255Round(prod);
56 }
57}
58
deanm@chromium.orgda946992009-07-03 12:54:24 +000059static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000060 if (value > max) {
61 value = max;
62 }
63 return value;
64}
65
reed@android.com8a1c16f2008-12-17 15:59:43 +000066///////////////////////////////////////////////////////////////////////////////
67
reed@android.com8a1c16f2008-12-17 15:59:43 +000068// kClear_Mode, //!< [0, 0]
69static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
70 return 0;
71}
72
73// kSrc_Mode, //!< [Sa, Sc]
74static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
75 return src;
76}
77
78// kDst_Mode, //!< [Da, Dc]
79static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
80 return dst;
81}
82
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000083// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000084static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000085#if 0
86 // this is the old, more-correct way, but it doesn't guarantee that dst==255
87 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +000089#else
90 // this is slightly faster, but more importantly guarantees that dst==255
91 // will always stay opaque
92 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
93#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000094}
95
reed@android.com1116fb22009-03-03 20:31:12 +000096// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000097static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000098 // this is the reverse of srcover, just flipping src and dst
99 // see srcover's comment about the 256 for opaqueness guarantees
100 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101}
102
103// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
104static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
105 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
106}
107
108// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
109static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
110 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
111}
112
113// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
114static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
115 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
116}
117
118// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
119static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
120 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
121}
122
123// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
124static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
125 unsigned sa = SkGetPackedA32(src);
126 unsigned da = SkGetPackedA32(dst);
127 unsigned isa = 255 - sa;
128
129 return SkPackARGB32(da,
130 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
131 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
132 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
133 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
134 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
135 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
136}
137
138// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
139static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
140 unsigned sa = SkGetPackedA32(src);
141 unsigned da = SkGetPackedA32(dst);
142 unsigned ida = 255 - da;
143
144 return SkPackARGB32(sa,
145 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
146 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
147 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
148 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
149 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
150 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
151}
152
153// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
154static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
155 unsigned sa = SkGetPackedA32(src);
156 unsigned da = SkGetPackedA32(dst);
157 unsigned isa = 255 - sa;
158 unsigned ida = 255 - da;
159
160 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
161 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
162 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
163 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
164 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
165 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
166 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
167}
168
reed@android.coma0f5d152009-06-22 17:38:10 +0000169///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
reed@android.coma0f5d152009-06-22 17:38:10 +0000171// kPlus_Mode
172static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000173 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000174 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
175 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
176 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000177 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178}
179
reed@android.coma0f5d152009-06-22 17:38:10 +0000180// kMultiply_Mode
181static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
183 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
184 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
185 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
186 return SkPackARGB32(a, r, g, b);
187}
188
reed@android.coma0f5d152009-06-22 17:38:10 +0000189// kScreen_Mode
190static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 return a + b - SkAlphaMulAlpha(a, b);
192}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000194 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
195 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
196 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
197 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 return SkPackARGB32(a, r, g, b);
199}
200
reed@android.coma0f5d152009-06-22 17:38:10 +0000201// kOverlay_Mode
202static inline int overlay_byte(int sc, int dc, int sa, int da) {
203 int tmp = sc * (255 - da) + dc * (255 - sa);
204 int rc;
205 if (2 * dc <= da) {
206 rc = 2 * sc * dc;
207 } else {
208 rc = sa * da - 2 * (da - dc) * (sa - sc);
209 }
210 return clamp_div255round(rc + tmp);
211}
212static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
213 int sa = SkGetPackedA32(src);
214 int da = SkGetPackedA32(dst);
215 int a = srcover_byte(sa, da);
216 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
217 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
218 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
219 return SkPackARGB32(a, r, g, b);
220}
221
222// kDarken_Mode
223static inline int darken_byte(int sc, int dc, int sa, int da) {
224 int sd = sc * da;
225 int ds = dc * sa;
226 if (sd < ds) {
227 // srcover
228 return sc + dc - SkDiv255Round(ds);
229 } else {
230 // dstover
231 return dc + sc - SkDiv255Round(sd);
232 }
233}
234static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
235 int sa = SkGetPackedA32(src);
236 int da = SkGetPackedA32(dst);
237 int a = srcover_byte(sa, da);
238 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
239 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
240 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
241 return SkPackARGB32(a, r, g, b);
242}
243
244// kLighten_Mode
245static inline int lighten_byte(int sc, int dc, int sa, int da) {
246 int sd = sc * da;
247 int ds = dc * sa;
248 if (sd > ds) {
249 // srcover
250 return sc + dc - SkDiv255Round(ds);
251 } else {
252 // dstover
253 return dc + sc - SkDiv255Round(sd);
254 }
255}
256static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
257 int sa = SkGetPackedA32(src);
258 int da = SkGetPackedA32(dst);
259 int a = srcover_byte(sa, da);
260 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
261 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
262 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
263 return SkPackARGB32(a, r, g, b);
264}
265
266// kColorDodge_Mode
267static inline int colordodge_byte(int sc, int dc, int sa, int da) {
268 int diff = sa - sc;
269 int rc;
270 if (0 == diff) {
271 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
272 rc = SkDiv255Round(rc);
273 } else {
274 int tmp = (dc * sa << 15) / (da * diff);
275 rc = SkDiv255Round(sa * da) * tmp >> 15;
276 // don't clamp here, since we'll do it in our modeproc
277 }
278 return rc;
279}
280static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
281 // added to avoid div-by-zero in colordodge_byte
282 if (0 == dst) {
283 return src;
284 }
285
286 int sa = SkGetPackedA32(src);
287 int da = SkGetPackedA32(dst);
288 int a = srcover_byte(sa, da);
289 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
290 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
291 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
292 r = clamp_max(r, a);
293 g = clamp_max(g, a);
294 b = clamp_max(b, a);
295 return SkPackARGB32(a, r, g, b);
296}
297
298// kColorBurn_Mode
299static inline int colorburn_byte(int sc, int dc, int sa, int da) {
300 int rc;
301 if (dc == da && 0 == sc) {
302 rc = sa * da + dc * (255 - sa);
303 } else if (0 == sc) {
304 return SkAlphaMulAlpha(dc, 255 - sa);
305 } else {
306 int tmp = (sa * (da - dc) * 256) / (sc * da);
307 if (tmp > 256) {
308 tmp = 256;
309 }
310 int tmp2 = sa * da;
311 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
312 }
313 return SkDiv255Round(rc);
314}
315static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
316 // added to avoid div-by-zero in colorburn_byte
317 if (0 == dst) {
318 return src;
319 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000320
reed@android.coma0f5d152009-06-22 17:38:10 +0000321 int sa = SkGetPackedA32(src);
322 int da = SkGetPackedA32(dst);
323 int a = srcover_byte(sa, da);
324 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
325 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
326 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
327 return SkPackARGB32(a, r, g, b);
328}
329
330// kHardLight_Mode
331static inline int hardlight_byte(int sc, int dc, int sa, int da) {
332 int rc;
333 if (2 * sc <= sa) {
334 rc = 2 * sc * dc;
335 } else {
336 rc = sa * da - 2 * (da - dc) * (sa - sc);
337 }
338 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
339}
340static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
341 int sa = SkGetPackedA32(src);
342 int da = SkGetPackedA32(dst);
343 int a = srcover_byte(sa, da);
344 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
345 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
346 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
347 return SkPackARGB32(a, r, g, b);
348}
349
350// returns 255 * sqrt(n/255)
351static U8CPU sqrt_unit_byte(U8CPU n) {
352 return SkSqrtBits(n, 15+4);
353}
354
355// kSoftLight_Mode
356static inline int softlight_byte(int sc, int dc, int sa, int da) {
357 int m = da ? dc * 256 / da : 0;
358 int rc;
359 if (2 * sc <= sa) {
360 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
361 } else if (4 * dc <= da) {
362 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
363 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
364 } else {
365 int tmp = sqrt_unit_byte(m) - m;
366 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
367 }
368 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
369}
370static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
371 int sa = SkGetPackedA32(src);
372 int da = SkGetPackedA32(dst);
373 int a = srcover_byte(sa, da);
374 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
375 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
376 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
377 return SkPackARGB32(a, r, g, b);
378}
379
380// kDifference_Mode
381static inline int difference_byte(int sc, int dc, int sa, int da) {
382 int tmp = SkMin32(sc * da, dc * sa);
383 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
384}
385static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
386 int sa = SkGetPackedA32(src);
387 int da = SkGetPackedA32(dst);
388 int a = srcover_byte(sa, da);
389 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
390 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
391 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
392 return SkPackARGB32(a, r, g, b);
393}
394
395// kExclusion_Mode
396static inline int exclusion_byte(int sc, int dc, int sa, int da) {
397 // this equations is wacky, wait for SVG to confirm it
398 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
399 return clamp_div255round(r);
400}
401static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
402 int sa = SkGetPackedA32(src);
403 int da = SkGetPackedA32(dst);
404 int a = srcover_byte(sa, da);
405 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
406 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
407 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000408 return SkPackARGB32(a, r, g, b);
409}
410
vandebo@chromium.org48543272011-02-08 19:28:07 +0000411struct ProcCoeff {
412 SkXfermodeProc fProc;
413 SkXfermode::Coeff fSC;
414 SkXfermode::Coeff fDC;
415};
416
417#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
418
419static const ProcCoeff gProcCoeffs[] = {
420 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
421 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
422 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
423 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
424 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
425 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
426 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
427 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
428 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
429 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
430 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
431 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
432
reed@google.com521e34e2011-04-12 18:55:21 +0000433 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
434 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000435 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
436 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
437 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
438 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
439 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
440 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
441 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
442 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
443 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
444 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
445};
446
447///////////////////////////////////////////////////////////////////////////////
448
449bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
450 return false;
451}
452
453bool SkXfermode::asMode(Mode* mode) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000454 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000455}
456
457SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
458 // no-op. subclasses should override this
459 return dst;
460}
461
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000462void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
463 const SkPMColor* SK_RESTRICT src, int count,
464 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000465 SkASSERT(dst && src && count >= 0);
466
467 if (NULL == aa) {
468 for (int i = count - 1; i >= 0; --i) {
469 dst[i] = this->xferColor(src[i], dst[i]);
470 }
471 } else {
472 for (int i = count - 1; i >= 0; --i) {
473 unsigned a = aa[i];
474 if (0 != a) {
475 SkPMColor dstC = dst[i];
476 SkPMColor C = this->xferColor(src[i], dstC);
477 if (0xFF != a) {
478 C = SkFourByteInterp(C, dstC, a);
479 }
480 dst[i] = C;
481 }
482 }
483 }
484}
485
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000486void SkXfermode::xfer16(uint16_t* dst,
487 const SkPMColor* SK_RESTRICT src, int count,
488 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000489 SkASSERT(dst && src && count >= 0);
490
491 if (NULL == aa) {
492 for (int i = count - 1; i >= 0; --i) {
493 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
494 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
495 }
496 } else {
497 for (int i = count - 1; i >= 0; --i) {
498 unsigned a = aa[i];
499 if (0 != a) {
500 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
501 SkPMColor C = this->xferColor(src[i], dstC);
502 if (0xFF != a) {
503 C = SkFourByteInterp(C, dstC, a);
504 }
505 dst[i] = SkPixel32ToPixel16_ToU16(C);
506 }
507 }
508 }
509}
510
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000511void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
512 const SkPMColor* SK_RESTRICT src, int count,
513 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000514{
515 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000516
vandebo@chromium.org48543272011-02-08 19:28:07 +0000517 if (NULL == aa) {
518 for (int i = count - 1; i >= 0; --i) {
519 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
520 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
521 }
522 } else {
523 for (int i = count - 1; i >= 0; --i) {
524 unsigned a = aa[i];
525 if (0 != a) {
526 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
527 SkPMColor C = this->xferColor(src[i], dstC);
528 if (0xFF != a) {
529 C = SkFourByteInterp(C, dstC, a);
530 }
531 dst[i] = SkPixel32ToPixel4444(C);
532 }
533 }
534 }
535}
536
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000537void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000538 const SkPMColor src[], int count,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000539 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000540{
541 SkASSERT(dst && src && count >= 0);
542
543 if (NULL == aa) {
544 for (int i = count - 1; i >= 0; --i) {
545 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
546 dst[i] = SkToU8(SkGetPackedA32(res));
547 }
548 } else {
549 for (int i = count - 1; i >= 0; --i) {
550 unsigned a = aa[i];
551 if (0 != a) {
552 SkAlpha dstA = dst[i];
553 unsigned A = SkGetPackedA32(this->xferColor(src[i],
554 (SkPMColor)(dstA << SK_A32_SHIFT)));
555 if (0xFF != a) {
556 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
557 }
558 dst[i] = SkToU8(A);
559 }
560 }
561 }
562}
563
564///////////////////////////////////////////////////////////////////////////////
565
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000566void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
567 const SkPMColor* SK_RESTRICT src, int count,
568 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000569 SkASSERT(dst && src && count >= 0);
570
571 SkXfermodeProc proc = fProc;
572
573 if (NULL != proc) {
574 if (NULL == aa) {
575 for (int i = count - 1; i >= 0; --i) {
576 dst[i] = proc(src[i], dst[i]);
577 }
578 } else {
579 for (int i = count - 1; i >= 0; --i) {
580 unsigned a = aa[i];
581 if (0 != a) {
582 SkPMColor dstC = dst[i];
583 SkPMColor C = proc(src[i], dstC);
584 if (a != 0xFF) {
585 C = SkFourByteInterp(C, dstC, a);
586 }
587 dst[i] = C;
588 }
589 }
590 }
591 }
592}
593
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000594void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
595 const SkPMColor* SK_RESTRICT src, int count,
596 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000597 SkASSERT(dst && src && count >= 0);
598
599 SkXfermodeProc proc = fProc;
600
601 if (NULL != proc) {
602 if (NULL == aa) {
603 for (int i = count - 1; i >= 0; --i) {
604 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
605 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
606 }
607 } else {
608 for (int i = count - 1; i >= 0; --i) {
609 unsigned a = aa[i];
610 if (0 != a) {
611 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
612 SkPMColor C = proc(src[i], dstC);
613 if (0xFF != a) {
614 C = SkFourByteInterp(C, dstC, a);
615 }
616 dst[i] = SkPixel32ToPixel16_ToU16(C);
617 }
618 }
619 }
620 }
621}
622
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000623void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
624 const SkPMColor* SK_RESTRICT src, int count,
625 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000626 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000627
vandebo@chromium.org48543272011-02-08 19:28:07 +0000628 SkXfermodeProc proc = fProc;
629
630 if (NULL != proc) {
631 if (NULL == aa) {
632 for (int i = count - 1; i >= 0; --i) {
633 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
634 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
635 }
636 } else {
637 for (int i = count - 1; i >= 0; --i) {
638 unsigned a = aa[i];
639 if (0 != a) {
640 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
641 SkPMColor C = proc(src[i], dstC);
642 if (0xFF != a) {
643 C = SkFourByteInterp(C, dstC, a);
644 }
645 dst[i] = SkPixel32ToPixel4444(C);
646 }
647 }
648 }
649 }
650}
651
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000652void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
653 const SkPMColor* SK_RESTRICT src, int count,
654 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000655 SkASSERT(dst && src && count >= 0);
656
657 SkXfermodeProc proc = fProc;
658
659 if (NULL != proc) {
660 if (NULL == aa) {
661 for (int i = count - 1; i >= 0; --i) {
662 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
663 dst[i] = SkToU8(SkGetPackedA32(res));
664 }
665 } else {
666 for (int i = count - 1; i >= 0; --i) {
667 unsigned a = aa[i];
668 if (0 != a) {
669 SkAlpha dstA = dst[i];
670 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
671 unsigned A = SkGetPackedA32(res);
672 if (0xFF != a) {
673 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
674 }
675 dst[i] = SkToU8(A);
676 }
677 }
678 }
679 }
680}
681
682SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
683 : SkXfermode(buffer) {
reed@google.com34342f62012-06-25 14:36:28 +0000684 fProc = NULL;
685 if (!buffer.isCrossProcess()) {
686 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
687 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000688}
689
djsollen@google.com54924242012-03-29 15:18:04 +0000690void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
691 this->INHERITED::flatten(buffer);
reed@google.com34342f62012-06-25 14:36:28 +0000692 if (!buffer.isCrossProcess()) {
yangsu@google.comf468e472011-08-10 18:34:50 +0000693 buffer.writeFunctionPtr((void*)fProc);
694 }
vandebo@chromium.org48543272011-02-08 19:28:07 +0000695}
696
vandebo@chromium.org48543272011-02-08 19:28:07 +0000697///////////////////////////////////////////////////////////////////////////////
698///////////////////////////////////////////////////////////////////////////////
699
700class SkProcCoeffXfermode : public SkProcXfermode {
701public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000702 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
703 : INHERITED(rec.fProc) {
704 fMode = mode;
705 // these may be valid, or may be CANNOT_USE_COEFF
706 fSrcCoeff = rec.fSC;
707 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000708 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000709
710 virtual bool asMode(Mode* mode) {
711 if (mode) {
712 *mode = fMode;
713 }
714 return true;
715 }
716
vandebo@chromium.org48543272011-02-08 19:28:07 +0000717 virtual bool asCoeff(Coeff* sc, Coeff* dc) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000718 if (CANNOT_USE_COEFF == fSrcCoeff) {
719 return false;
720 }
721
vandebo@chromium.org48543272011-02-08 19:28:07 +0000722 if (sc) {
723 *sc = fSrcCoeff;
724 }
725 if (dc) {
726 *dc = fDstCoeff;
727 }
728 return true;
729 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000730
djsollen@google.comba28d032012-03-26 17:57:35 +0000731 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000732
vandebo@chromium.org48543272011-02-08 19:28:07 +0000733protected:
djsollen@google.com54924242012-03-29 15:18:04 +0000734 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000735 fMode = (SkXfermode::Mode)buffer.readU32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000736
737 const ProcCoeff& rec = gProcCoeffs[fMode];
738 // these may be valid, or may be CANNOT_USE_COEFF
739 fSrcCoeff = rec.fSC;
740 fDstCoeff = rec.fDC;
741 // now update our function-ptr in the super class
742 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000743 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000744
djsollen@google.com54924242012-03-29 15:18:04 +0000745 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
746 this->INHERITED::flatten(buffer);
747 buffer.write32(fMode);
748 }
749
vandebo@chromium.org48543272011-02-08 19:28:07 +0000750private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000751 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000752 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000753
vandebo@chromium.org48543272011-02-08 19:28:07 +0000754
755 typedef SkProcXfermode INHERITED;
756};
757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758///////////////////////////////////////////////////////////////////////////////
759
760class SkClearXfermode : public SkProcCoeffXfermode {
761public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000762 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763
reed@google.com86ab6c62011-11-28 15:26:14 +0000764 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
765 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766
djsollen@google.comba28d032012-03-26 17:57:35 +0000767 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769private:
770 SkClearXfermode(SkFlattenableReadBuffer& buffer)
771 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773};
774
reed@google.com86ab6c62011-11-28 15:26:14 +0000775void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
776 const SkPMColor* SK_RESTRICT, int count,
777 const SkAlpha* SK_RESTRICT aa) {
778 SkASSERT(dst && count >= 0);
779
780 if (NULL == aa) {
781 memset(dst, 0, count << 2);
782 } else {
783 for (int i = count - 1; i >= 0; --i) {
784 unsigned a = aa[i];
785 if (0xFF == a) {
786 dst[i] = 0;
787 } else if (a != 0) {
788 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
789 }
790 }
791 }
792}
793void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
794 const SkPMColor* SK_RESTRICT, int count,
795 const SkAlpha* SK_RESTRICT aa) {
796 SkASSERT(dst && count >= 0);
797
798 if (NULL == aa) {
799 memset(dst, 0, count);
800 } else {
801 for (int i = count - 1; i >= 0; --i) {
802 unsigned a = aa[i];
803 if (0xFF == a) {
804 dst[i] = 0;
805 } else if (0 != a) {
806 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
807 }
808 }
809 }
810}
811
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812///////////////////////////////////////////////////////////////////////////////
813
814class SkSrcXfermode : public SkProcCoeffXfermode {
815public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000816 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817
reed@google.com86ab6c62011-11-28 15:26:14 +0000818 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
819 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820
djsollen@google.comba28d032012-03-26 17:57:35 +0000821 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823private:
824 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
825 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000826
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827};
828
reed@google.com86ab6c62011-11-28 15:26:14 +0000829void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
830 const SkPMColor* SK_RESTRICT src, int count,
831 const SkAlpha* SK_RESTRICT aa) {
832 SkASSERT(dst && src && count >= 0);
833
834 if (NULL == aa) {
835 memcpy(dst, src, count << 2);
836 } else {
837 for (int i = count - 1; i >= 0; --i) {
838 unsigned a = aa[i];
839 if (a == 0xFF) {
840 dst[i] = src[i];
841 } else if (a != 0) {
842 dst[i] = SkFourByteInterp(src[i], dst[i], a);
843 }
844 }
845 }
846}
847
848void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
849 const SkPMColor* SK_RESTRICT src, int count,
850 const SkAlpha* SK_RESTRICT aa) {
851 SkASSERT(dst && src && count >= 0);
852
853 if (NULL == aa) {
854 for (int i = count - 1; i >= 0; --i) {
855 dst[i] = SkToU8(SkGetPackedA32(src[i]));
856 }
857 } else {
858 for (int i = count - 1; i >= 0; --i) {
859 unsigned a = aa[i];
860 if (0 != a) {
861 unsigned srcA = SkGetPackedA32(src[i]);
862 if (a == 0xFF) {
863 dst[i] = SkToU8(srcA);
864 } else {
865 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
866 }
867 }
868 }
869 }
870}
871
872////////////////////////////////////////////////////////////////////////////////////
873
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874class SkDstInXfermode : public SkProcCoeffXfermode {
875public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000876 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000877
reed@google.com86ab6c62011-11-28 15:26:14 +0000878 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000879
djsollen@google.comba28d032012-03-26 17:57:35 +0000880 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000881
882private:
883 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
884
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885 typedef SkProcCoeffXfermode INHERITED;
886};
887
reed@google.com86ab6c62011-11-28 15:26:14 +0000888void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
889 const SkPMColor* SK_RESTRICT src, int count,
890 const SkAlpha* SK_RESTRICT aa) {
891 SkASSERT(dst && src);
892
893 if (count <= 0) {
894 return;
895 }
896 if (NULL != aa) {
897 return this->INHERITED::xfer32(dst, src, count, aa);
898 }
899
900 do {
901 unsigned a = SkGetPackedA32(*src);
902 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
903 dst++;
904 src++;
905 } while (--count != 0);
906}
907
908/////////////////////////////////////////////////////////////////////////////////////////
909
reed@android.com8a1c16f2008-12-17 15:59:43 +0000910class SkDstOutXfermode : public SkProcCoeffXfermode {
911public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000912 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000913
reed@google.com86ab6c62011-11-28 15:26:14 +0000914 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000915
djsollen@google.comba28d032012-03-26 17:57:35 +0000916 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000917
918private:
919 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
920 : INHERITED(buffer) {}
921
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922 typedef SkProcCoeffXfermode INHERITED;
923};
924
reed@google.com86ab6c62011-11-28 15:26:14 +0000925void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
926 const SkPMColor* SK_RESTRICT src, int count,
927 const SkAlpha* SK_RESTRICT aa) {
928 SkASSERT(dst && src);
929
930 if (count <= 0) {
931 return;
932 }
933 if (NULL != aa) {
934 return this->INHERITED::xfer32(dst, src, count, aa);
935 }
936
937 do {
938 unsigned a = SkGetPackedA32(*src);
939 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
940 dst++;
941 src++;
942 } while (--count != 0);
943}
944
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945///////////////////////////////////////////////////////////////////////////////
946
reed@android.coma0f5d152009-06-22 17:38:10 +0000947SkXfermode* SkXfermode::Create(Mode mode) {
948 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
949 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950
reed@google.comc0d4aa22011-04-13 21:12:04 +0000951 const ProcCoeff& rec = gProcCoeffs[mode];
952
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953 switch (mode) {
954 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000955 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000957 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 case kSrcOver_Mode:
959 return NULL;
960 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000961 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000963 return SkNEW_ARGS(SkDstOutXfermode, (rec));
964 default:
965 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 }
967}
968
reed@google.com43c50c82011-04-14 15:50:52 +0000969SkXfermodeProc SkXfermode::GetProc(Mode mode) {
970 SkXfermodeProc proc = NULL;
971 if ((unsigned)mode < kModeCount) {
972 proc = gProcCoeffs[mode].fProc;
973 }
974 return proc;
975}
976
977bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
978 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000979
reed@google.com43c50c82011-04-14 15:50:52 +0000980 if ((unsigned)mode >= (unsigned)kModeCount) {
981 // illegal mode parameter
982 return false;
983 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000984
reed@google.com43c50c82011-04-14 15:50:52 +0000985 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000986
reed@google.com43c50c82011-04-14 15:50:52 +0000987 if (CANNOT_USE_COEFF == rec.fSC) {
988 return false;
989 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000990
reed@google.com43c50c82011-04-14 15:50:52 +0000991 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
992 if (src) {
993 *src = rec.fSC;
994 }
995 if (dst) {
996 *dst = rec.fDC;
997 }
998 return true;
999}
1000
1001bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002 if (NULL == xfer) {
1003 if (mode) {
1004 *mode = kSrcOver_Mode;
1005 }
1006 return true;
1007 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001008 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009}
1010
reed@google.com43c50c82011-04-14 15:50:52 +00001011bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
1012 if (NULL == xfer) {
1013 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 }
reed@google.com43c50c82011-04-14 15:50:52 +00001015 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016}
1017
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +00001018bool SkXfermode::IsMode(SkXfermode* xfer, Mode mode) {
1019 // if xfer==null then the mode is srcover
1020 Mode m = kSrcOver_Mode;
1021 if (xfer && !xfer->asMode(&m)) {
1022 return false;
1023 }
1024 return mode == m;
1025}
1026
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027///////////////////////////////////////////////////////////////////////////////
1028//////////// 16bit xfermode procs
1029
1030#ifdef SK_DEBUG
1031static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1032static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1033#endif
1034
1035static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1036 SkASSERT(require_255(src));
1037 return SkPixel32ToPixel16(src);
1038}
1039
1040static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1041 return dst;
1042}
1043
1044static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1045 SkASSERT(require_0(src));
1046 return dst;
1047}
1048
1049static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1050 SkASSERT(require_255(src));
1051 return SkPixel32ToPixel16(src);
1052}
1053
1054static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1055 SkASSERT(require_0(src));
1056 return dst;
1057}
1058
1059static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1060 SkASSERT(require_255(src));
1061 return dst;
1062}
1063
1064static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1065 SkASSERT(require_255(src));
1066 return SkPixel32ToPixel16(src);
1067}
1068
1069static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1070 SkASSERT(require_255(src));
1071 return dst;
1072}
1073
1074static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1075 SkASSERT(require_0(src));
1076 return dst;
1077}
1078
1079static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1080 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001081
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082 return SkPackRGB16(
1083 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1084 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1085 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1086}
1087
1088static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1089 SkASSERT(require_0(src));
1090 return dst;
1091}
1092
1093static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1094 SkASSERT(require_255(src));
1095 return SkPixel32ToPixel16(src);
1096}
1097
1098static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1099 SkASSERT(require_255(src));
1100 return dst;
1101}
1102
1103/*********
1104 darken and lighten boil down to this.
1105
1106 darken = (1 - Sa) * Dc + min(Sc, Dc)
1107 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1108
1109 if (Sa == 0) these become
1110 darken = Dc + min(0, Dc) = 0
1111 lighten = Dc + max(0, Dc) = Dc
1112
1113 if (Sa == 1) these become
1114 darken = min(Sc, Dc)
1115 lighten = max(Sc, Dc)
1116*/
1117
1118static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1119 SkASSERT(require_0(src));
1120 return 0;
1121}
1122
1123static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1124 SkASSERT(require_255(src));
1125 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1126 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1127 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1128 return SkPackRGB16(r, g, b);
1129}
1130
1131static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1132 SkASSERT(require_0(src));
1133 return dst;
1134}
1135
1136static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1137 SkASSERT(require_255(src));
1138 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1139 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1140 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1141 return SkPackRGB16(r, g, b);
1142}
1143
1144struct Proc16Rec {
1145 SkXfermodeProc16 fProc16_0;
1146 SkXfermodeProc16 fProc16_255;
1147 SkXfermodeProc16 fProc16_General;
1148};
1149
reed@android.coma0f5d152009-06-22 17:38:10 +00001150static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 { NULL, NULL, NULL }, // CLEAR
1152 { NULL, src_modeproc16_255, NULL },
1153 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1154 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1155 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1156 { NULL, srcin_modeproc16_255, NULL },
1157 { NULL, dstin_modeproc16_255, NULL },
1158 { NULL, NULL, NULL },// SRC_OUT
1159 { dstout_modeproc16_0, NULL, NULL },
1160 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1161 { NULL, dstatop_modeproc16_255, NULL },
1162 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001163
1164 { NULL, NULL, NULL }, // plus
1165 { NULL, NULL, NULL }, // multiply
1166 { NULL, NULL, NULL }, // screen
1167 { NULL, NULL, NULL }, // overlay
1168 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1169 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1170 { NULL, NULL, NULL }, // colordodge
1171 { NULL, NULL, NULL }, // colorburn
1172 { NULL, NULL, NULL }, // hardlight
1173 { NULL, NULL, NULL }, // softlight
1174 { NULL, NULL, NULL }, // difference
1175 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176};
1177
reed@android.coma0f5d152009-06-22 17:38:10 +00001178SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001180 if ((unsigned)mode < kModeCount) {
1181 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182 unsigned a = SkColorGetA(srcColor);
1183
1184 if (0 == a) {
1185 proc16 = rec.fProc16_0;
1186 } else if (255 == a) {
1187 proc16 = rec.fProc16_255;
1188 } else {
1189 proc16 = rec.fProc16_General;
1190 }
1191 }
1192 return proc16;
1193}
1194
caryclark@google.comd26147a2011-12-15 14:16:43 +00001195SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1196 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1197 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1198 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1199 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1200 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1201SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END