blob: 8773c400d42234e111be928bd7b51190adeabf22 [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
15static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha) {
16 unsigned scale = SkAlpha255To256(alpha);
17
18 unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
19 unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
20 unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
21 unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
22
23 return SkPackARGB32(a, r, g, b);
24}
25
reed@android.comfc25abd2009-01-15 14:38:33 +000026#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000027// idea for higher precision blends in xfer procs (and slightly faster)
28// see DstATop as a probable caller
29static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
30 SkASSERT(a <= 255);
31 SkASSERT(b <= 255);
32 SkASSERT(c <= 255);
33 SkASSERT(d <= 255);
34 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
35 unsigned result = (prod + (prod >> 8)) >> 8;
36 SkASSERT(result <= 255);
37 return result;
38}
reed@android.comfc25abd2009-01-15 14:38:33 +000039#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
deanm@chromium.orgda946992009-07-03 12:54:24 +000041static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000042 SkASSERT(a <= 255);
43 SkASSERT(b <= 255);
44 unsigned sum = a + b;
45 if (sum > 255) {
46 sum = 255;
47 }
48 return sum;
49}
50
deanm@chromium.orgda946992009-07-03 12:54:24 +000051static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000052 if (n < 0) {
53 n = 0;
54 } else if (n > 255) {
55 n = 255;
56 }
57 return n;
58}
59
deanm@chromium.orgda946992009-07-03 12:54:24 +000060static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000061 if (prod <= 0) {
62 return 0;
63 } else if (prod >= 255*255) {
64 return 255;
65 } else {
66 return SkDiv255Round(prod);
67 }
68}
69
deanm@chromium.orgda946992009-07-03 12:54:24 +000070static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000071 if (value > max) {
72 value = max;
73 }
74 return value;
75}
76
reed@android.com8a1c16f2008-12-17 15:59:43 +000077///////////////////////////////////////////////////////////////////////////////
78
reed@android.com8a1c16f2008-12-17 15:59:43 +000079// kClear_Mode, //!< [0, 0]
80static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
81 return 0;
82}
83
84// kSrc_Mode, //!< [Sa, Sc]
85static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
86 return src;
87}
88
89// kDst_Mode, //!< [Da, Dc]
90static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
91 return dst;
92}
93
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000094// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +000095static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +000096#if 0
97 // this is the old, more-correct way, but it doesn't guarantee that dst==255
98 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000100#else
101 // this is slightly faster, but more importantly guarantees that dst==255
102 // will always stay opaque
103 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
104#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
reed@android.com1116fb22009-03-03 20:31:12 +0000107// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000109 // this is the reverse of srcover, just flipping src and dst
110 // see srcover's comment about the 256 for opaqueness guarantees
111 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112}
113
114// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
115static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
116 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
117}
118
119// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
120static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
121 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
122}
123
124// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
125static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
126 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
127}
128
129// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
130static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
131 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
132}
133
134// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
135static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
136 unsigned sa = SkGetPackedA32(src);
137 unsigned da = SkGetPackedA32(dst);
138 unsigned isa = 255 - sa;
139
140 return SkPackARGB32(da,
141 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
142 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
143 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
144 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
145 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
146 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
147}
148
149// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
150static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
151 unsigned sa = SkGetPackedA32(src);
152 unsigned da = SkGetPackedA32(dst);
153 unsigned ida = 255 - da;
154
155 return SkPackARGB32(sa,
156 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
157 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
158 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
159 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
160 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
161 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
162}
163
164// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
165static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
166 unsigned sa = SkGetPackedA32(src);
167 unsigned da = SkGetPackedA32(dst);
168 unsigned isa = 255 - sa;
169 unsigned ida = 255 - da;
170
171 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
172 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
173 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
174 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
175 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
176 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
177 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
178}
179
reed@android.coma0f5d152009-06-22 17:38:10 +0000180///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181
reed@android.coma0f5d152009-06-22 17:38:10 +0000182// kPlus_Mode
183static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000184 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000185 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
186 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
187 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000188 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189}
190
reed@android.coma0f5d152009-06-22 17:38:10 +0000191// kMultiply_Mode
192static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
194 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
195 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
196 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
197 return SkPackARGB32(a, r, g, b);
198}
199
reed@android.coma0f5d152009-06-22 17:38:10 +0000200// kScreen_Mode
201static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 return a + b - SkAlphaMulAlpha(a, b);
203}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000205 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
206 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
207 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
208 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 return SkPackARGB32(a, r, g, b);
210}
211
reed@android.coma0f5d152009-06-22 17:38:10 +0000212// kOverlay_Mode
213static inline int overlay_byte(int sc, int dc, int sa, int da) {
214 int tmp = sc * (255 - da) + dc * (255 - sa);
215 int rc;
216 if (2 * dc <= da) {
217 rc = 2 * sc * dc;
218 } else {
219 rc = sa * da - 2 * (da - dc) * (sa - sc);
220 }
221 return clamp_div255round(rc + tmp);
222}
223static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
224 int sa = SkGetPackedA32(src);
225 int da = SkGetPackedA32(dst);
226 int a = srcover_byte(sa, da);
227 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
228 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
229 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
230 return SkPackARGB32(a, r, g, b);
231}
232
233// kDarken_Mode
234static inline int darken_byte(int sc, int dc, int sa, int da) {
235 int sd = sc * da;
236 int ds = dc * sa;
237 if (sd < ds) {
238 // srcover
239 return sc + dc - SkDiv255Round(ds);
240 } else {
241 // dstover
242 return dc + sc - SkDiv255Round(sd);
243 }
244}
245static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
246 int sa = SkGetPackedA32(src);
247 int da = SkGetPackedA32(dst);
248 int a = srcover_byte(sa, da);
249 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
250 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
251 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
252 return SkPackARGB32(a, r, g, b);
253}
254
255// kLighten_Mode
256static inline int lighten_byte(int sc, int dc, int sa, int da) {
257 int sd = sc * da;
258 int ds = dc * sa;
259 if (sd > ds) {
260 // srcover
261 return sc + dc - SkDiv255Round(ds);
262 } else {
263 // dstover
264 return dc + sc - SkDiv255Round(sd);
265 }
266}
267static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
268 int sa = SkGetPackedA32(src);
269 int da = SkGetPackedA32(dst);
270 int a = srcover_byte(sa, da);
271 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
272 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
273 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
274 return SkPackARGB32(a, r, g, b);
275}
276
277// kColorDodge_Mode
278static inline int colordodge_byte(int sc, int dc, int sa, int da) {
279 int diff = sa - sc;
280 int rc;
281 if (0 == diff) {
282 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
283 rc = SkDiv255Round(rc);
284 } else {
285 int tmp = (dc * sa << 15) / (da * diff);
286 rc = SkDiv255Round(sa * da) * tmp >> 15;
287 // don't clamp here, since we'll do it in our modeproc
288 }
289 return rc;
290}
291static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
292 // added to avoid div-by-zero in colordodge_byte
293 if (0 == dst) {
294 return src;
295 }
296
297 int sa = SkGetPackedA32(src);
298 int da = SkGetPackedA32(dst);
299 int a = srcover_byte(sa, da);
300 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
301 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
302 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
303 r = clamp_max(r, a);
304 g = clamp_max(g, a);
305 b = clamp_max(b, a);
306 return SkPackARGB32(a, r, g, b);
307}
308
309// kColorBurn_Mode
310static inline int colorburn_byte(int sc, int dc, int sa, int da) {
311 int rc;
312 if (dc == da && 0 == sc) {
313 rc = sa * da + dc * (255 - sa);
314 } else if (0 == sc) {
315 return SkAlphaMulAlpha(dc, 255 - sa);
316 } else {
317 int tmp = (sa * (da - dc) * 256) / (sc * da);
318 if (tmp > 256) {
319 tmp = 256;
320 }
321 int tmp2 = sa * da;
322 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
323 }
324 return SkDiv255Round(rc);
325}
326static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
327 // added to avoid div-by-zero in colorburn_byte
328 if (0 == dst) {
329 return src;
330 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000331
reed@android.coma0f5d152009-06-22 17:38:10 +0000332 int sa = SkGetPackedA32(src);
333 int da = SkGetPackedA32(dst);
334 int a = srcover_byte(sa, da);
335 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
336 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
337 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
338 return SkPackARGB32(a, r, g, b);
339}
340
341// kHardLight_Mode
342static inline int hardlight_byte(int sc, int dc, int sa, int da) {
343 int rc;
344 if (2 * sc <= sa) {
345 rc = 2 * sc * dc;
346 } else {
347 rc = sa * da - 2 * (da - dc) * (sa - sc);
348 }
349 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
350}
351static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
352 int sa = SkGetPackedA32(src);
353 int da = SkGetPackedA32(dst);
354 int a = srcover_byte(sa, da);
355 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
356 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
357 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
358 return SkPackARGB32(a, r, g, b);
359}
360
361// returns 255 * sqrt(n/255)
362static U8CPU sqrt_unit_byte(U8CPU n) {
363 return SkSqrtBits(n, 15+4);
364}
365
366// kSoftLight_Mode
367static inline int softlight_byte(int sc, int dc, int sa, int da) {
368 int m = da ? dc * 256 / da : 0;
369 int rc;
370 if (2 * sc <= sa) {
371 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
372 } else if (4 * dc <= da) {
373 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
374 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
375 } else {
376 int tmp = sqrt_unit_byte(m) - m;
377 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
378 }
379 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
380}
381static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
382 int sa = SkGetPackedA32(src);
383 int da = SkGetPackedA32(dst);
384 int a = srcover_byte(sa, da);
385 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
386 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
387 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
388 return SkPackARGB32(a, r, g, b);
389}
390
391// kDifference_Mode
392static inline int difference_byte(int sc, int dc, int sa, int da) {
393 int tmp = SkMin32(sc * da, dc * sa);
394 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
395}
396static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
397 int sa = SkGetPackedA32(src);
398 int da = SkGetPackedA32(dst);
399 int a = srcover_byte(sa, da);
400 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
401 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
402 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
403 return SkPackARGB32(a, r, g, b);
404}
405
406// kExclusion_Mode
407static inline int exclusion_byte(int sc, int dc, int sa, int da) {
408 // this equations is wacky, wait for SVG to confirm it
409 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
410 return clamp_div255round(r);
411}
412static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
413 int sa = SkGetPackedA32(src);
414 int da = SkGetPackedA32(dst);
415 int a = srcover_byte(sa, da);
416 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
417 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
418 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000419 return SkPackARGB32(a, r, g, b);
420}
421
vandebo@chromium.org48543272011-02-08 19:28:07 +0000422struct ProcCoeff {
423 SkXfermodeProc fProc;
424 SkXfermode::Coeff fSC;
425 SkXfermode::Coeff fDC;
426};
427
428#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
429
430static const ProcCoeff gProcCoeffs[] = {
431 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
432 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
433 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
434 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
435 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
436 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
437 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
438 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
439 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
440 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
441 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
442 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
443
reed@google.com521e34e2011-04-12 18:55:21 +0000444 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
445 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000446 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
447 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
448 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
449 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
450 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
451 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
452 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
453 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
454 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
455 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
456};
457
458///////////////////////////////////////////////////////////////////////////////
459
460bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
461 return false;
462}
463
464bool SkXfermode::asMode(Mode* mode) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000465 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000466}
467
468SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
469 // no-op. subclasses should override this
470 return dst;
471}
472
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000473void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
474 const SkPMColor* SK_RESTRICT src, int count,
475 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000476 SkASSERT(dst && src && count >= 0);
477
478 if (NULL == aa) {
479 for (int i = count - 1; i >= 0; --i) {
480 dst[i] = this->xferColor(src[i], dst[i]);
481 }
482 } else {
483 for (int i = count - 1; i >= 0; --i) {
484 unsigned a = aa[i];
485 if (0 != a) {
486 SkPMColor dstC = dst[i];
487 SkPMColor C = this->xferColor(src[i], dstC);
488 if (0xFF != a) {
489 C = SkFourByteInterp(C, dstC, a);
490 }
491 dst[i] = C;
492 }
493 }
494 }
495}
496
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000497void SkXfermode::xfer16(uint16_t* dst,
498 const SkPMColor* SK_RESTRICT src, int count,
499 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000500 SkASSERT(dst && src && count >= 0);
501
502 if (NULL == aa) {
503 for (int i = count - 1; i >= 0; --i) {
504 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
505 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
506 }
507 } else {
508 for (int i = count - 1; i >= 0; --i) {
509 unsigned a = aa[i];
510 if (0 != a) {
511 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
512 SkPMColor C = this->xferColor(src[i], dstC);
513 if (0xFF != a) {
514 C = SkFourByteInterp(C, dstC, a);
515 }
516 dst[i] = SkPixel32ToPixel16_ToU16(C);
517 }
518 }
519 }
520}
521
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000522void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
523 const SkPMColor* SK_RESTRICT src, int count,
524 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000525{
526 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000527
vandebo@chromium.org48543272011-02-08 19:28:07 +0000528 if (NULL == aa) {
529 for (int i = count - 1; i >= 0; --i) {
530 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
531 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
532 }
533 } else {
534 for (int i = count - 1; i >= 0; --i) {
535 unsigned a = aa[i];
536 if (0 != a) {
537 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
538 SkPMColor C = this->xferColor(src[i], dstC);
539 if (0xFF != a) {
540 C = SkFourByteInterp(C, dstC, a);
541 }
542 dst[i] = SkPixel32ToPixel4444(C);
543 }
544 }
545 }
546}
547
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000548void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
vandebo@chromium.org48543272011-02-08 19:28:07 +0000549 const SkPMColor src[], int count,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000550 const SkAlpha* SK_RESTRICT aa)
vandebo@chromium.org48543272011-02-08 19:28:07 +0000551{
552 SkASSERT(dst && src && count >= 0);
553
554 if (NULL == aa) {
555 for (int i = count - 1; i >= 0; --i) {
556 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
557 dst[i] = SkToU8(SkGetPackedA32(res));
558 }
559 } else {
560 for (int i = count - 1; i >= 0; --i) {
561 unsigned a = aa[i];
562 if (0 != a) {
563 SkAlpha dstA = dst[i];
564 unsigned A = SkGetPackedA32(this->xferColor(src[i],
565 (SkPMColor)(dstA << SK_A32_SHIFT)));
566 if (0xFF != a) {
567 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
568 }
569 dst[i] = SkToU8(A);
570 }
571 }
572 }
573}
574
575///////////////////////////////////////////////////////////////////////////////
576
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000577void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
578 const SkPMColor* SK_RESTRICT src, int count,
579 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000580 SkASSERT(dst && src && count >= 0);
581
582 SkXfermodeProc proc = fProc;
583
584 if (NULL != proc) {
585 if (NULL == aa) {
586 for (int i = count - 1; i >= 0; --i) {
587 dst[i] = proc(src[i], dst[i]);
588 }
589 } else {
590 for (int i = count - 1; i >= 0; --i) {
591 unsigned a = aa[i];
592 if (0 != a) {
593 SkPMColor dstC = dst[i];
594 SkPMColor C = proc(src[i], dstC);
595 if (a != 0xFF) {
596 C = SkFourByteInterp(C, dstC, a);
597 }
598 dst[i] = C;
599 }
600 }
601 }
602 }
603}
604
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000605void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
606 const SkPMColor* SK_RESTRICT src, int count,
607 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000608 SkASSERT(dst && src && count >= 0);
609
610 SkXfermodeProc proc = fProc;
611
612 if (NULL != proc) {
613 if (NULL == aa) {
614 for (int i = count - 1; i >= 0; --i) {
615 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
616 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
617 }
618 } else {
619 for (int i = count - 1; i >= 0; --i) {
620 unsigned a = aa[i];
621 if (0 != a) {
622 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
623 SkPMColor C = proc(src[i], dstC);
624 if (0xFF != a) {
625 C = SkFourByteInterp(C, dstC, a);
626 }
627 dst[i] = SkPixel32ToPixel16_ToU16(C);
628 }
629 }
630 }
631 }
632}
633
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000634void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
635 const SkPMColor* SK_RESTRICT src, int count,
636 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000637 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000638
vandebo@chromium.org48543272011-02-08 19:28:07 +0000639 SkXfermodeProc proc = fProc;
640
641 if (NULL != proc) {
642 if (NULL == aa) {
643 for (int i = count - 1; i >= 0; --i) {
644 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
645 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
646 }
647 } else {
648 for (int i = count - 1; i >= 0; --i) {
649 unsigned a = aa[i];
650 if (0 != a) {
651 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
652 SkPMColor C = proc(src[i], dstC);
653 if (0xFF != a) {
654 C = SkFourByteInterp(C, dstC, a);
655 }
656 dst[i] = SkPixel32ToPixel4444(C);
657 }
658 }
659 }
660 }
661}
662
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000663void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
664 const SkPMColor* SK_RESTRICT src, int count,
665 const SkAlpha* SK_RESTRICT aa) {
vandebo@chromium.org48543272011-02-08 19:28:07 +0000666 SkASSERT(dst && src && count >= 0);
667
668 SkXfermodeProc proc = fProc;
669
670 if (NULL != proc) {
671 if (NULL == aa) {
672 for (int i = count - 1; i >= 0; --i) {
673 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
674 dst[i] = SkToU8(SkGetPackedA32(res));
675 }
676 } else {
677 for (int i = count - 1; i >= 0; --i) {
678 unsigned a = aa[i];
679 if (0 != a) {
680 SkAlpha dstA = dst[i];
681 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
682 unsigned A = SkGetPackedA32(res);
683 if (0xFF != a) {
684 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
685 }
686 dst[i] = SkToU8(A);
687 }
688 }
689 }
690 }
691}
692
693SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
694 : SkXfermode(buffer) {
695 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
696}
697
698void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
699 buffer.writeFunctionPtr((void*)fProc);
700}
701
vandebo@chromium.org48543272011-02-08 19:28:07 +0000702///////////////////////////////////////////////////////////////////////////////
703///////////////////////////////////////////////////////////////////////////////
704
705class SkProcCoeffXfermode : public SkProcXfermode {
706public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000707 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
708 : INHERITED(rec.fProc) {
709 fMode = mode;
710 // these may be valid, or may be CANNOT_USE_COEFF
711 fSrcCoeff = rec.fSC;
712 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000713 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000714
715 virtual bool asMode(Mode* mode) {
716 if (mode) {
717 *mode = fMode;
718 }
719 return true;
720 }
721
vandebo@chromium.org48543272011-02-08 19:28:07 +0000722 virtual bool asCoeff(Coeff* sc, Coeff* dc) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000723 if (CANNOT_USE_COEFF == fSrcCoeff) {
724 return false;
725 }
726
vandebo@chromium.org48543272011-02-08 19:28:07 +0000727 if (sc) {
728 *sc = fSrcCoeff;
729 }
730 if (dc) {
731 *dc = fDstCoeff;
732 }
733 return true;
734 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000735
vandebo@chromium.org48543272011-02-08 19:28:07 +0000736 virtual Factory getFactory() { return CreateProc; }
737 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
738 this->INHERITED::flatten(buffer);
reed@google.comc0d4aa22011-04-13 21:12:04 +0000739 buffer.write32(fMode);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000740 }
741
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000742 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
743 return SkNEW_ARGS(SkProcCoeffXfermode, (buffer));
744 }
745
vandebo@chromium.org48543272011-02-08 19:28:07 +0000746protected:
747 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
748 : INHERITED(buffer) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000749 fMode = (SkXfermode::Mode)buffer.readU32();
reed@google.comc34d7cf2011-08-09 22:42:10 +0000750
751 const ProcCoeff& rec = gProcCoeffs[fMode];
752 // these may be valid, or may be CANNOT_USE_COEFF
753 fSrcCoeff = rec.fSC;
754 fDstCoeff = rec.fDC;
755 // now update our function-ptr in the super class
756 this->INHERITED::setProc(rec.fProc);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000757 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000758
vandebo@chromium.org48543272011-02-08 19:28:07 +0000759private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000760 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000761 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000762
vandebo@chromium.org48543272011-02-08 19:28:07 +0000763
764 typedef SkProcXfermode INHERITED;
765};
766
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767///////////////////////////////////////////////////////////////////////////////
768
769class SkClearXfermode : public SkProcCoeffXfermode {
770public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000771 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000773 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
774 const SkPMColor* SK_RESTRICT, int count,
775 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776 SkASSERT(dst && count >= 0);
777
778 if (NULL == aa) {
779 memset(dst, 0, count << 2);
780 } else {
781 for (int i = count - 1; i >= 0; --i) {
782 unsigned a = aa[i];
783 if (0xFF == a) {
784 dst[i] = 0;
785 } else if (a != 0) {
786 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
787 }
788 }
789 }
790 }
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000791 virtual void xferA8(SkAlpha* SK_RESTRICT dst,
792 const SkPMColor* SK_RESTRICT, int count,
793 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 SkASSERT(dst && count >= 0);
795
796 if (NULL == aa) {
797 memset(dst, 0, count);
798 } else {
799 for (int i = count - 1; i >= 0; --i) {
800 unsigned a = aa[i];
801 if (0xFF == a) {
802 dst[i] = 0;
803 } else if (0 != a) {
804 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
805 }
806 }
807 }
808 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000809
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 virtual Factory getFactory() { return CreateProc; }
811
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000812 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
813 return SkNEW_ARGS(SkClearXfermode, (buffer));
814 }
815
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816private:
817 SkClearXfermode(SkFlattenableReadBuffer& buffer)
818 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000819
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820};
821
822///////////////////////////////////////////////////////////////////////////////
823
824class SkSrcXfermode : public SkProcCoeffXfermode {
825public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000826 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000828 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
829 const SkPMColor* SK_RESTRICT src, int count,
830 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 SkASSERT(dst && src && count >= 0);
832
833 if (NULL == aa) {
834 memcpy(dst, src, count << 2);
835 } else {
836 for (int i = count - 1; i >= 0; --i) {
837 unsigned a = aa[i];
838 if (a == 0xFF) {
839 dst[i] = src[i];
840 } else if (a != 0) {
841 dst[i] = SkFourByteInterp(src[i], dst[i], a);
842 }
843 }
844 }
845 }
846
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000847 virtual void xferA8(SkAlpha* SK_RESTRICT dst,
848 const SkPMColor* SK_RESTRICT src, int count,
849 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 SkASSERT(dst && src && count >= 0);
851
852 if (NULL == aa) {
853 for (int i = count - 1; i >= 0; --i) {
854 dst[i] = SkToU8(SkGetPackedA32(src[i]));
855 }
856 } else {
857 for (int i = count - 1; i >= 0; --i) {
858 unsigned a = aa[i];
859 if (0 != a) {
860 unsigned srcA = SkGetPackedA32(src[i]);
861 if (a == 0xFF) {
862 dst[i] = SkToU8(srcA);
863 } else {
864 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
865 }
866 }
867 }
868 }
869 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000870
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871 virtual Factory getFactory() { return CreateProc; }
872
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000873 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
874 return SkNEW_ARGS(SkSrcXfermode, (buffer));
875 }
876
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877private:
878 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
879 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000880
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881};
882
883class SkDstInXfermode : public SkProcCoeffXfermode {
884public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000885 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000886
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000887 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
888 const SkPMColor* SK_RESTRICT src, int count,
889 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000891
reed@android.com8a1c16f2008-12-17 15:59:43 +0000892 if (count <= 0) {
893 return;
894 }
895 if (NULL != aa) {
896 return this->INHERITED::xfer32(dst, src, count, aa);
897 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000898
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899 do {
900 unsigned a = SkGetPackedA32(*src);
901 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
902 dst++;
903 src++;
904 } while (--count != 0);
905 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000906
reed@android.com8a1c16f2008-12-17 15:59:43 +0000907 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000908
reed@android.com8a1c16f2008-12-17 15:59:43 +0000909 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
910 return SkNEW_ARGS(SkDstInXfermode, (buffer));
911 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000912
913private:
914 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
915
reed@android.com8a1c16f2008-12-17 15:59:43 +0000916 typedef SkProcCoeffXfermode INHERITED;
917};
918
919class SkDstOutXfermode : public SkProcCoeffXfermode {
920public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000921 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000922
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000923 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
924 const SkPMColor* SK_RESTRICT src, int count,
925 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000927
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928 if (count <= 0) {
929 return;
930 }
931 if (NULL != aa) {
932 return this->INHERITED::xfer32(dst, src, count, aa);
933 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000934
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935 do {
936 unsigned a = SkGetPackedA32(*src);
937 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
938 dst++;
939 src++;
940 } while (--count != 0);
941 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000942
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000944
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
946 return SkNEW_ARGS(SkDstOutXfermode, (buffer));
947 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000948
949private:
950 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
951 : INHERITED(buffer) {}
952
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953 typedef SkProcCoeffXfermode INHERITED;
954};
955
956///////////////////////////////////////////////////////////////////////////////
957
reed@android.coma0f5d152009-06-22 17:38:10 +0000958SkXfermode* SkXfermode::Create(Mode mode) {
959 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
960 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961
reed@google.comc0d4aa22011-04-13 21:12:04 +0000962 const ProcCoeff& rec = gProcCoeffs[mode];
963
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 switch (mode) {
965 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000966 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000968 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 case kSrcOver_Mode:
970 return NULL;
971 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000972 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000974 return SkNEW_ARGS(SkDstOutXfermode, (rec));
975 default:
976 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 }
978}
979
reed@google.com43c50c82011-04-14 15:50:52 +0000980SkXfermodeProc SkXfermode::GetProc(Mode mode) {
981 SkXfermodeProc proc = NULL;
982 if ((unsigned)mode < kModeCount) {
983 proc = gProcCoeffs[mode].fProc;
984 }
985 return proc;
986}
987
988bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
989 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000990
reed@google.com43c50c82011-04-14 15:50:52 +0000991 if ((unsigned)mode >= (unsigned)kModeCount) {
992 // illegal mode parameter
993 return false;
994 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000995
reed@google.com43c50c82011-04-14 15:50:52 +0000996 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000997
reed@google.com43c50c82011-04-14 15:50:52 +0000998 if (CANNOT_USE_COEFF == rec.fSC) {
999 return false;
1000 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001001
reed@google.com43c50c82011-04-14 15:50:52 +00001002 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1003 if (src) {
1004 *src = rec.fSC;
1005 }
1006 if (dst) {
1007 *dst = rec.fDC;
1008 }
1009 return true;
1010}
1011
1012bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013 if (NULL == xfer) {
1014 if (mode) {
1015 *mode = kSrcOver_Mode;
1016 }
1017 return true;
1018 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001019 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020}
1021
reed@google.com43c50c82011-04-14 15:50:52 +00001022bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
1023 if (NULL == xfer) {
1024 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025 }
reed@google.com43c50c82011-04-14 15:50:52 +00001026 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027}
1028
1029///////////////////////////////////////////////////////////////////////////////
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
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001197static SkFlattenable::Registrar
1198 gSkProcCoeffXfermodeReg("SkProcCoeffXfermode",
1199 SkProcCoeffXfermode::CreateProc);
1200
1201static SkFlattenable::Registrar
1202 gSkClearXfermodeReg("SkClearXfermode", SkClearXfermode::CreateProc);
1203
1204static SkFlattenable::Registrar
1205 gSkSrcXfermodeReg("SkSrcXfermode", SkSrcXfermode::CreateProc);
1206
1207static SkFlattenable::Registrar
1208 gSkDstInXfermodeReg("SkDstInXfermode", SkDstInXfermode::CreateProc);
1209
1210static SkFlattenable::Registrar
1211 gSkDstOutXfermodeReg("SkDstOutXfermode", SkDstOutXfermode::CreateProc);