blob: e5dbb85b53e0ce6525096032972f04b5d0a4c9bc [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 buffer.write32(fSrcCoeff);
741 buffer.write32(fDstCoeff);
742 }
743
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000744 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
745 return SkNEW_ARGS(SkProcCoeffXfermode, (buffer));
746 }
747
vandebo@chromium.org48543272011-02-08 19:28:07 +0000748protected:
749 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
750 : INHERITED(buffer) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000751 fMode = (SkXfermode::Mode)buffer.readU32();
vandebo@chromium.org48543272011-02-08 19:28:07 +0000752 fSrcCoeff = (Coeff)buffer.readU32();
753 fDstCoeff = (Coeff)buffer.readU32();
754 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000755
vandebo@chromium.org48543272011-02-08 19:28:07 +0000756private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000757 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000758 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000759
vandebo@chromium.org48543272011-02-08 19:28:07 +0000760
761 typedef SkProcXfermode INHERITED;
762};
763
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764///////////////////////////////////////////////////////////////////////////////
765
766class SkClearXfermode : public SkProcCoeffXfermode {
767public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000768 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000770 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
771 const SkPMColor* SK_RESTRICT, int count,
772 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 SkASSERT(dst && count >= 0);
774
775 if (NULL == aa) {
776 memset(dst, 0, count << 2);
777 } else {
778 for (int i = count - 1; i >= 0; --i) {
779 unsigned a = aa[i];
780 if (0xFF == a) {
781 dst[i] = 0;
782 } else if (a != 0) {
783 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
784 }
785 }
786 }
787 }
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000788 virtual void xferA8(SkAlpha* SK_RESTRICT dst,
789 const SkPMColor* SK_RESTRICT, int count,
790 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 SkASSERT(dst && count >= 0);
792
793 if (NULL == aa) {
794 memset(dst, 0, count);
795 } else {
796 for (int i = count - 1; i >= 0; --i) {
797 unsigned a = aa[i];
798 if (0xFF == a) {
799 dst[i] = 0;
800 } else if (0 != a) {
801 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
802 }
803 }
804 }
805 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000806
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807 virtual Factory getFactory() { return CreateProc; }
808
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000809 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
810 return SkNEW_ARGS(SkClearXfermode, (buffer));
811 }
812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813private:
814 SkClearXfermode(SkFlattenableReadBuffer& buffer)
815 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817};
818
819///////////////////////////////////////////////////////////////////////////////
820
821class SkSrcXfermode : public SkProcCoeffXfermode {
822public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000823 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000825 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
826 const SkPMColor* SK_RESTRICT src, int count,
827 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 SkASSERT(dst && src && count >= 0);
829
830 if (NULL == aa) {
831 memcpy(dst, src, count << 2);
832 } else {
833 for (int i = count - 1; i >= 0; --i) {
834 unsigned a = aa[i];
835 if (a == 0xFF) {
836 dst[i] = src[i];
837 } else if (a != 0) {
838 dst[i] = SkFourByteInterp(src[i], dst[i], a);
839 }
840 }
841 }
842 }
843
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000844 virtual void xferA8(SkAlpha* SK_RESTRICT dst,
845 const SkPMColor* SK_RESTRICT src, int count,
846 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 SkASSERT(dst && src && count >= 0);
848
849 if (NULL == aa) {
850 for (int i = count - 1; i >= 0; --i) {
851 dst[i] = SkToU8(SkGetPackedA32(src[i]));
852 }
853 } else {
854 for (int i = count - 1; i >= 0; --i) {
855 unsigned a = aa[i];
856 if (0 != a) {
857 unsigned srcA = SkGetPackedA32(src[i]);
858 if (a == 0xFF) {
859 dst[i] = SkToU8(srcA);
860 } else {
861 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
862 }
863 }
864 }
865 }
866 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000867
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 virtual Factory getFactory() { return CreateProc; }
869
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000870 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
871 return SkNEW_ARGS(SkSrcXfermode, (buffer));
872 }
873
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874private:
875 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
876 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000877
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878};
879
880class SkDstInXfermode : public SkProcCoeffXfermode {
881public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000882 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000883
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000884 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
885 const SkPMColor* SK_RESTRICT src, int count,
886 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000888
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889 if (count <= 0) {
890 return;
891 }
892 if (NULL != aa) {
893 return this->INHERITED::xfer32(dst, src, count, aa);
894 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000895
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 do {
897 unsigned a = SkGetPackedA32(*src);
898 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
899 dst++;
900 src++;
901 } while (--count != 0);
902 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000903
reed@android.com8a1c16f2008-12-17 15:59:43 +0000904 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000905
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
907 return SkNEW_ARGS(SkDstInXfermode, (buffer));
908 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000909
910private:
911 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
912
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 typedef SkProcCoeffXfermode INHERITED;
914};
915
916class SkDstOutXfermode : public SkProcCoeffXfermode {
917public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000918 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000919
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000920 virtual void xfer32(SkPMColor* SK_RESTRICT dst,
921 const SkPMColor* SK_RESTRICT src, int count,
922 const SkAlpha* SK_RESTRICT aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000924
reed@android.com8a1c16f2008-12-17 15:59:43 +0000925 if (count <= 0) {
926 return;
927 }
928 if (NULL != aa) {
929 return this->INHERITED::xfer32(dst, src, count, aa);
930 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000931
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932 do {
933 unsigned a = SkGetPackedA32(*src);
934 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
935 dst++;
936 src++;
937 } while (--count != 0);
938 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000939
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000941
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
943 return SkNEW_ARGS(SkDstOutXfermode, (buffer));
944 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000945
946private:
947 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
948 : INHERITED(buffer) {}
949
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 typedef SkProcCoeffXfermode INHERITED;
951};
952
953///////////////////////////////////////////////////////////////////////////////
954
reed@android.coma0f5d152009-06-22 17:38:10 +0000955SkXfermode* SkXfermode::Create(Mode mode) {
956 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
957 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958
reed@google.comc0d4aa22011-04-13 21:12:04 +0000959 const ProcCoeff& rec = gProcCoeffs[mode];
960
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961 switch (mode) {
962 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000963 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000965 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 case kSrcOver_Mode:
967 return NULL;
968 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000969 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000971 return SkNEW_ARGS(SkDstOutXfermode, (rec));
972 default:
973 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975}
976
reed@google.com43c50c82011-04-14 15:50:52 +0000977SkXfermodeProc SkXfermode::GetProc(Mode mode) {
978 SkXfermodeProc proc = NULL;
979 if ((unsigned)mode < kModeCount) {
980 proc = gProcCoeffs[mode].fProc;
981 }
982 return proc;
983}
984
985bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
986 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000987
reed@google.com43c50c82011-04-14 15:50:52 +0000988 if ((unsigned)mode >= (unsigned)kModeCount) {
989 // illegal mode parameter
990 return false;
991 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000992
reed@google.com43c50c82011-04-14 15:50:52 +0000993 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000994
reed@google.com43c50c82011-04-14 15:50:52 +0000995 if (CANNOT_USE_COEFF == rec.fSC) {
996 return false;
997 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000998
reed@google.com43c50c82011-04-14 15:50:52 +0000999 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1000 if (src) {
1001 *src = rec.fSC;
1002 }
1003 if (dst) {
1004 *dst = rec.fDC;
1005 }
1006 return true;
1007}
1008
1009bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 if (NULL == xfer) {
1011 if (mode) {
1012 *mode = kSrcOver_Mode;
1013 }
1014 return true;
1015 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001016 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017}
1018
reed@google.com43c50c82011-04-14 15:50:52 +00001019bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
1020 if (NULL == xfer) {
1021 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022 }
reed@google.com43c50c82011-04-14 15:50:52 +00001023 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024}
1025
1026///////////////////////////////////////////////////////////////////////////////
1027//////////// 16bit xfermode procs
1028
1029#ifdef SK_DEBUG
1030static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1031static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1032#endif
1033
1034static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1035 SkASSERT(require_255(src));
1036 return SkPixel32ToPixel16(src);
1037}
1038
1039static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1040 return dst;
1041}
1042
1043static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1044 SkASSERT(require_0(src));
1045 return dst;
1046}
1047
1048static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1049 SkASSERT(require_255(src));
1050 return SkPixel32ToPixel16(src);
1051}
1052
1053static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1054 SkASSERT(require_0(src));
1055 return dst;
1056}
1057
1058static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1059 SkASSERT(require_255(src));
1060 return dst;
1061}
1062
1063static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1064 SkASSERT(require_255(src));
1065 return SkPixel32ToPixel16(src);
1066}
1067
1068static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1069 SkASSERT(require_255(src));
1070 return dst;
1071}
1072
1073static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1074 SkASSERT(require_0(src));
1075 return dst;
1076}
1077
1078static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1079 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001080
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 return SkPackRGB16(
1082 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1083 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1084 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1085}
1086
1087static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1088 SkASSERT(require_0(src));
1089 return dst;
1090}
1091
1092static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1093 SkASSERT(require_255(src));
1094 return SkPixel32ToPixel16(src);
1095}
1096
1097static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1098 SkASSERT(require_255(src));
1099 return dst;
1100}
1101
1102/*********
1103 darken and lighten boil down to this.
1104
1105 darken = (1 - Sa) * Dc + min(Sc, Dc)
1106 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1107
1108 if (Sa == 0) these become
1109 darken = Dc + min(0, Dc) = 0
1110 lighten = Dc + max(0, Dc) = Dc
1111
1112 if (Sa == 1) these become
1113 darken = min(Sc, Dc)
1114 lighten = max(Sc, Dc)
1115*/
1116
1117static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1118 SkASSERT(require_0(src));
1119 return 0;
1120}
1121
1122static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1123 SkASSERT(require_255(src));
1124 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1125 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1126 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1127 return SkPackRGB16(r, g, b);
1128}
1129
1130static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1131 SkASSERT(require_0(src));
1132 return dst;
1133}
1134
1135static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1136 SkASSERT(require_255(src));
1137 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1138 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1139 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1140 return SkPackRGB16(r, g, b);
1141}
1142
1143struct Proc16Rec {
1144 SkXfermodeProc16 fProc16_0;
1145 SkXfermodeProc16 fProc16_255;
1146 SkXfermodeProc16 fProc16_General;
1147};
1148
reed@android.coma0f5d152009-06-22 17:38:10 +00001149static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150 { NULL, NULL, NULL }, // CLEAR
1151 { NULL, src_modeproc16_255, NULL },
1152 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1153 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1154 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1155 { NULL, srcin_modeproc16_255, NULL },
1156 { NULL, dstin_modeproc16_255, NULL },
1157 { NULL, NULL, NULL },// SRC_OUT
1158 { dstout_modeproc16_0, NULL, NULL },
1159 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1160 { NULL, dstatop_modeproc16_255, NULL },
1161 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001162
1163 { NULL, NULL, NULL }, // plus
1164 { NULL, NULL, NULL }, // multiply
1165 { NULL, NULL, NULL }, // screen
1166 { NULL, NULL, NULL }, // overlay
1167 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1168 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1169 { NULL, NULL, NULL }, // colordodge
1170 { NULL, NULL, NULL }, // colorburn
1171 { NULL, NULL, NULL }, // hardlight
1172 { NULL, NULL, NULL }, // softlight
1173 { NULL, NULL, NULL }, // difference
1174 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175};
1176
reed@android.coma0f5d152009-06-22 17:38:10 +00001177SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001178 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001179 if ((unsigned)mode < kModeCount) {
1180 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 unsigned a = SkColorGetA(srcColor);
1182
1183 if (0 == a) {
1184 proc16 = rec.fProc16_0;
1185 } else if (255 == a) {
1186 proc16 = rec.fProc16_255;
1187 } else {
1188 proc16 = rec.fProc16_General;
1189 }
1190 }
1191 return proc16;
1192}
1193
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001194static SkFlattenable::Registrar
1195 gSkProcCoeffXfermodeReg("SkProcCoeffXfermode",
1196 SkProcCoeffXfermode::CreateProc);
1197
1198static SkFlattenable::Registrar
1199 gSkClearXfermodeReg("SkClearXfermode", SkClearXfermode::CreateProc);
1200
1201static SkFlattenable::Registrar
1202 gSkSrcXfermodeReg("SkSrcXfermode", SkSrcXfermode::CreateProc);
1203
1204static SkFlattenable::Registrar
1205 gSkDstInXfermodeReg("SkDstInXfermode", SkDstInXfermode::CreateProc);
1206
1207static SkFlattenable::Registrar
1208 gSkDstOutXfermodeReg("SkDstOutXfermode", SkDstOutXfermode::CreateProc);