blob: 90cf13a81866e196f5b4e7309e7be7ad6c478afe [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkXfermode.h"
18#include "SkColorPriv.h"
19
20#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
21
22static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha) {
23 unsigned scale = SkAlpha255To256(alpha);
24
25 unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
26 unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
27 unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
28 unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
29
30 return SkPackARGB32(a, r, g, b);
31}
32
reed@android.comfc25abd2009-01-15 14:38:33 +000033#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000034// idea for higher precision blends in xfer procs (and slightly faster)
35// see DstATop as a probable caller
36static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
37 SkASSERT(a <= 255);
38 SkASSERT(b <= 255);
39 SkASSERT(c <= 255);
40 SkASSERT(d <= 255);
41 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
42 unsigned result = (prod + (prod >> 8)) >> 8;
43 SkASSERT(result <= 255);
44 return result;
45}
reed@android.comfc25abd2009-01-15 14:38:33 +000046#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
deanm@chromium.orgda946992009-07-03 12:54:24 +000048static inline unsigned saturated_add(unsigned a, unsigned b) {
reed@android.com543ed932009-04-24 12:43:40 +000049 SkASSERT(a <= 255);
50 SkASSERT(b <= 255);
51 unsigned sum = a + b;
52 if (sum > 255) {
53 sum = 255;
54 }
55 return sum;
56}
57
deanm@chromium.orgda946992009-07-03 12:54:24 +000058static inline int clamp_signed_byte(int n) {
reed@android.coma0f5d152009-06-22 17:38:10 +000059 if (n < 0) {
60 n = 0;
61 } else if (n > 255) {
62 n = 255;
63 }
64 return n;
65}
66
deanm@chromium.orgda946992009-07-03 12:54:24 +000067static inline int clamp_div255round(int prod) {
reed@android.coma0f5d152009-06-22 17:38:10 +000068 if (prod <= 0) {
69 return 0;
70 } else if (prod >= 255*255) {
71 return 255;
72 } else {
73 return SkDiv255Round(prod);
74 }
75}
76
deanm@chromium.orgda946992009-07-03 12:54:24 +000077static inline int clamp_max(int value, int max) {
reed@android.coma0f5d152009-06-22 17:38:10 +000078 if (value > max) {
79 value = max;
80 }
81 return value;
82}
83
reed@android.com8a1c16f2008-12-17 15:59:43 +000084///////////////////////////////////////////////////////////////////////////////
85
reed@android.com8a1c16f2008-12-17 15:59:43 +000086// kClear_Mode, //!< [0, 0]
87static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
88 return 0;
89}
90
91// kSrc_Mode, //!< [Sa, Sc]
92static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
93 return src;
94}
95
96// kDst_Mode, //!< [Da, Dc]
97static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
98 return dst;
99}
100
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000101// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000103#if 0
104 // this is the old, more-correct way, but it doesn't guarantee that dst==255
105 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000107#else
108 // this is slightly faster, but more importantly guarantees that dst==255
109 // will always stay opaque
110 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
111#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112}
113
reed@android.com1116fb22009-03-03 20:31:12 +0000114// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000116 // this is the reverse of srcover, just flipping src and dst
117 // see srcover's comment about the 256 for opaqueness guarantees
118 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119}
120
121// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
122static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
123 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
124}
125
126// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
127static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
128 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
129}
130
131// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
132static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
133 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
134}
135
136// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
137static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
138 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
139}
140
141// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
142static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
143 unsigned sa = SkGetPackedA32(src);
144 unsigned da = SkGetPackedA32(dst);
145 unsigned isa = 255 - sa;
146
147 return SkPackARGB32(da,
148 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
149 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
150 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
151 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
152 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
153 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
154}
155
156// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
157static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
158 unsigned sa = SkGetPackedA32(src);
159 unsigned da = SkGetPackedA32(dst);
160 unsigned ida = 255 - da;
161
162 return SkPackARGB32(sa,
163 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
164 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
165 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
166 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
167 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
168 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
169}
170
171// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
172static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
173 unsigned sa = SkGetPackedA32(src);
174 unsigned da = SkGetPackedA32(dst);
175 unsigned isa = 255 - sa;
176 unsigned ida = 255 - da;
177
178 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
179 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
180 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
181 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
182 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
183 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
184 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
185}
186
reed@android.coma0f5d152009-06-22 17:38:10 +0000187///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188
reed@android.coma0f5d152009-06-22 17:38:10 +0000189// kPlus_Mode
190static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000191 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
deanm@chromium.orgda946992009-07-03 12:54:24 +0000192 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
193 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
194 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
reed@android.coma0f5d152009-06-22 17:38:10 +0000195 return SkPackARGB32(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196}
197
reed@android.coma0f5d152009-06-22 17:38:10 +0000198// kMultiply_Mode
199static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
201 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
202 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
203 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
204 return SkPackARGB32(a, r, g, b);
205}
206
reed@android.coma0f5d152009-06-22 17:38:10 +0000207// kScreen_Mode
208static inline int srcover_byte(int a, int b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 return a + b - SkAlphaMulAlpha(a, b);
210}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.coma0f5d152009-06-22 17:38:10 +0000212 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
213 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
214 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
215 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 return SkPackARGB32(a, r, g, b);
217}
218
reed@android.coma0f5d152009-06-22 17:38:10 +0000219// kOverlay_Mode
220static inline int overlay_byte(int sc, int dc, int sa, int da) {
221 int tmp = sc * (255 - da) + dc * (255 - sa);
222 int rc;
223 if (2 * dc <= da) {
224 rc = 2 * sc * dc;
225 } else {
226 rc = sa * da - 2 * (da - dc) * (sa - sc);
227 }
228 return clamp_div255round(rc + tmp);
229}
230static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
231 int sa = SkGetPackedA32(src);
232 int da = SkGetPackedA32(dst);
233 int a = srcover_byte(sa, da);
234 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
235 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
236 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
237 return SkPackARGB32(a, r, g, b);
238}
239
240// kDarken_Mode
241static inline int darken_byte(int sc, int dc, int sa, int da) {
242 int sd = sc * da;
243 int ds = dc * sa;
244 if (sd < ds) {
245 // srcover
246 return sc + dc - SkDiv255Round(ds);
247 } else {
248 // dstover
249 return dc + sc - SkDiv255Round(sd);
250 }
251}
252static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
253 int sa = SkGetPackedA32(src);
254 int da = SkGetPackedA32(dst);
255 int a = srcover_byte(sa, da);
256 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
257 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
258 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
259 return SkPackARGB32(a, r, g, b);
260}
261
262// kLighten_Mode
263static inline int lighten_byte(int sc, int dc, int sa, int da) {
264 int sd = sc * da;
265 int ds = dc * sa;
266 if (sd > ds) {
267 // srcover
268 return sc + dc - SkDiv255Round(ds);
269 } else {
270 // dstover
271 return dc + sc - SkDiv255Round(sd);
272 }
273}
274static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
275 int sa = SkGetPackedA32(src);
276 int da = SkGetPackedA32(dst);
277 int a = srcover_byte(sa, da);
278 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
279 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
280 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
281 return SkPackARGB32(a, r, g, b);
282}
283
284// kColorDodge_Mode
285static inline int colordodge_byte(int sc, int dc, int sa, int da) {
286 int diff = sa - sc;
287 int rc;
288 if (0 == diff) {
289 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
290 rc = SkDiv255Round(rc);
291 } else {
292 int tmp = (dc * sa << 15) / (da * diff);
293 rc = SkDiv255Round(sa * da) * tmp >> 15;
294 // don't clamp here, since we'll do it in our modeproc
295 }
296 return rc;
297}
298static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
299 // added to avoid div-by-zero in colordodge_byte
300 if (0 == dst) {
301 return src;
302 }
303
304 int sa = SkGetPackedA32(src);
305 int da = SkGetPackedA32(dst);
306 int a = srcover_byte(sa, da);
307 int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
308 int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
309 int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
310 r = clamp_max(r, a);
311 g = clamp_max(g, a);
312 b = clamp_max(b, a);
313 return SkPackARGB32(a, r, g, b);
314}
315
316// kColorBurn_Mode
317static inline int colorburn_byte(int sc, int dc, int sa, int da) {
318 int rc;
319 if (dc == da && 0 == sc) {
320 rc = sa * da + dc * (255 - sa);
321 } else if (0 == sc) {
322 return SkAlphaMulAlpha(dc, 255 - sa);
323 } else {
324 int tmp = (sa * (da - dc) * 256) / (sc * da);
325 if (tmp > 256) {
326 tmp = 256;
327 }
328 int tmp2 = sa * da;
329 rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
330 }
331 return SkDiv255Round(rc);
332}
333static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
334 // added to avoid div-by-zero in colorburn_byte
335 if (0 == dst) {
336 return src;
337 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000338
reed@android.coma0f5d152009-06-22 17:38:10 +0000339 int sa = SkGetPackedA32(src);
340 int da = SkGetPackedA32(dst);
341 int a = srcover_byte(sa, da);
342 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
343 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
344 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
345 return SkPackARGB32(a, r, g, b);
346}
347
348// kHardLight_Mode
349static inline int hardlight_byte(int sc, int dc, int sa, int da) {
350 int rc;
351 if (2 * sc <= sa) {
352 rc = 2 * sc * dc;
353 } else {
354 rc = sa * da - 2 * (da - dc) * (sa - sc);
355 }
356 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
357}
358static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
359 int sa = SkGetPackedA32(src);
360 int da = SkGetPackedA32(dst);
361 int a = srcover_byte(sa, da);
362 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
363 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
364 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
365 return SkPackARGB32(a, r, g, b);
366}
367
368// returns 255 * sqrt(n/255)
369static U8CPU sqrt_unit_byte(U8CPU n) {
370 return SkSqrtBits(n, 15+4);
371}
372
373// kSoftLight_Mode
374static inline int softlight_byte(int sc, int dc, int sa, int da) {
375 int m = da ? dc * 256 / da : 0;
376 int rc;
377 if (2 * sc <= sa) {
378 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
379 } else if (4 * dc <= da) {
380 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
381 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
382 } else {
383 int tmp = sqrt_unit_byte(m) - m;
384 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
385 }
386 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
387}
388static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
389 int sa = SkGetPackedA32(src);
390 int da = SkGetPackedA32(dst);
391 int a = srcover_byte(sa, da);
392 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
393 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
394 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
395 return SkPackARGB32(a, r, g, b);
396}
397
398// kDifference_Mode
399static inline int difference_byte(int sc, int dc, int sa, int da) {
400 int tmp = SkMin32(sc * da, dc * sa);
401 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
402}
403static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
404 int sa = SkGetPackedA32(src);
405 int da = SkGetPackedA32(dst);
406 int a = srcover_byte(sa, da);
407 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
408 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
409 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
410 return SkPackARGB32(a, r, g, b);
411}
412
413// kExclusion_Mode
414static inline int exclusion_byte(int sc, int dc, int sa, int da) {
415 // this equations is wacky, wait for SVG to confirm it
416 int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
417 return clamp_div255round(r);
418}
419static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
420 int sa = SkGetPackedA32(src);
421 int da = SkGetPackedA32(dst);
422 int a = srcover_byte(sa, da);
423 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
424 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
425 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
reed@android.com543ed932009-04-24 12:43:40 +0000426 return SkPackARGB32(a, r, g, b);
427}
428
vandebo@chromium.org48543272011-02-08 19:28:07 +0000429struct ProcCoeff {
430 SkXfermodeProc fProc;
431 SkXfermode::Coeff fSC;
432 SkXfermode::Coeff fDC;
433};
434
435#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
436
437static const ProcCoeff gProcCoeffs[] = {
438 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
439 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
440 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
441 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
442 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
443 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
444 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
445 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
446 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
447 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
448 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
449 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
450
reed@google.com521e34e2011-04-12 18:55:21 +0000451 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
452 { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
vandebo@chromium.org48543272011-02-08 19:28:07 +0000453 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
454 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
455 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
456 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
457 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
458 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
459 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
460 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
461 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
462 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
463};
464
465///////////////////////////////////////////////////////////////////////////////
466
467bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
468 return false;
469}
470
471bool SkXfermode::asMode(Mode* mode) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000472 return false;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000473}
474
475SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
476 // no-op. subclasses should override this
477 return dst;
478}
479
480void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
481 const SK_RESTRICT SkPMColor src[], int count,
482 const SK_RESTRICT SkAlpha aa[]) {
483 SkASSERT(dst && src && count >= 0);
484
485 if (NULL == aa) {
486 for (int i = count - 1; i >= 0; --i) {
487 dst[i] = this->xferColor(src[i], dst[i]);
488 }
489 } else {
490 for (int i = count - 1; i >= 0; --i) {
491 unsigned a = aa[i];
492 if (0 != a) {
493 SkPMColor dstC = dst[i];
494 SkPMColor C = this->xferColor(src[i], dstC);
495 if (0xFF != a) {
496 C = SkFourByteInterp(C, dstC, a);
497 }
498 dst[i] = C;
499 }
500 }
501 }
502}
503
504void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
505 const SK_RESTRICT SkPMColor src[], int count,
506 const SK_RESTRICT SkAlpha aa[]) {
507 SkASSERT(dst && src && count >= 0);
508
509 if (NULL == aa) {
510 for (int i = count - 1; i >= 0; --i) {
511 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
512 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
513 }
514 } else {
515 for (int i = count - 1; i >= 0; --i) {
516 unsigned a = aa[i];
517 if (0 != a) {
518 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
519 SkPMColor C = this->xferColor(src[i], dstC);
520 if (0xFF != a) {
521 C = SkFourByteInterp(C, dstC, a);
522 }
523 dst[i] = SkPixel32ToPixel16_ToU16(C);
524 }
525 }
526 }
527}
528
529void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
530 const SK_RESTRICT SkPMColor src[], int count,
531 const SK_RESTRICT SkAlpha aa[])
532{
533 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000534
vandebo@chromium.org48543272011-02-08 19:28:07 +0000535 if (NULL == aa) {
536 for (int i = count - 1; i >= 0; --i) {
537 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
538 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
539 }
540 } else {
541 for (int i = count - 1; i >= 0; --i) {
542 unsigned a = aa[i];
543 if (0 != a) {
544 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
545 SkPMColor C = this->xferColor(src[i], dstC);
546 if (0xFF != a) {
547 C = SkFourByteInterp(C, dstC, a);
548 }
549 dst[i] = SkPixel32ToPixel4444(C);
550 }
551 }
552 }
553}
554
555void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
556 const SkPMColor src[], int count,
557 const SK_RESTRICT SkAlpha aa[])
558{
559 SkASSERT(dst && src && count >= 0);
560
561 if (NULL == aa) {
562 for (int i = count - 1; i >= 0; --i) {
563 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
564 dst[i] = SkToU8(SkGetPackedA32(res));
565 }
566 } else {
567 for (int i = count - 1; i >= 0; --i) {
568 unsigned a = aa[i];
569 if (0 != a) {
570 SkAlpha dstA = dst[i];
571 unsigned A = SkGetPackedA32(this->xferColor(src[i],
572 (SkPMColor)(dstA << SK_A32_SHIFT)));
573 if (0xFF != a) {
574 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
575 }
576 dst[i] = SkToU8(A);
577 }
578 }
579 }
580}
581
582///////////////////////////////////////////////////////////////////////////////
583
584void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
585 const SK_RESTRICT SkPMColor src[], int count,
586 const SK_RESTRICT SkAlpha aa[]) {
587 SkASSERT(dst && src && count >= 0);
588
589 SkXfermodeProc proc = fProc;
590
591 if (NULL != proc) {
592 if (NULL == aa) {
593 for (int i = count - 1; i >= 0; --i) {
594 dst[i] = proc(src[i], dst[i]);
595 }
596 } else {
597 for (int i = count - 1; i >= 0; --i) {
598 unsigned a = aa[i];
599 if (0 != a) {
600 SkPMColor dstC = dst[i];
601 SkPMColor C = proc(src[i], dstC);
602 if (a != 0xFF) {
603 C = SkFourByteInterp(C, dstC, a);
604 }
605 dst[i] = C;
606 }
607 }
608 }
609 }
610}
611
612void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
613 const SK_RESTRICT SkPMColor src[], int count,
614 const SK_RESTRICT SkAlpha aa[]) {
615 SkASSERT(dst && src && count >= 0);
616
617 SkXfermodeProc proc = fProc;
618
619 if (NULL != proc) {
620 if (NULL == aa) {
621 for (int i = count - 1; i >= 0; --i) {
622 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
623 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
624 }
625 } else {
626 for (int i = count - 1; i >= 0; --i) {
627 unsigned a = aa[i];
628 if (0 != a) {
629 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
630 SkPMColor C = proc(src[i], dstC);
631 if (0xFF != a) {
632 C = SkFourByteInterp(C, dstC, a);
633 }
634 dst[i] = SkPixel32ToPixel16_ToU16(C);
635 }
636 }
637 }
638 }
639}
640
641void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
642 const SK_RESTRICT SkPMColor src[], int count,
643 const SK_RESTRICT SkAlpha aa[]) {
644 SkASSERT(dst && src && count >= 0);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000645
vandebo@chromium.org48543272011-02-08 19:28:07 +0000646 SkXfermodeProc proc = fProc;
647
648 if (NULL != proc) {
649 if (NULL == aa) {
650 for (int i = count - 1; i >= 0; --i) {
651 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
652 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
653 }
654 } else {
655 for (int i = count - 1; i >= 0; --i) {
656 unsigned a = aa[i];
657 if (0 != a) {
658 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
659 SkPMColor C = proc(src[i], dstC);
660 if (0xFF != a) {
661 C = SkFourByteInterp(C, dstC, a);
662 }
663 dst[i] = SkPixel32ToPixel4444(C);
664 }
665 }
666 }
667 }
668}
669
670void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
671 const SK_RESTRICT SkPMColor src[], int count,
672 const SK_RESTRICT SkAlpha aa[]) {
673 SkASSERT(dst && src && count >= 0);
674
675 SkXfermodeProc proc = fProc;
676
677 if (NULL != proc) {
678 if (NULL == aa) {
679 for (int i = count - 1; i >= 0; --i) {
680 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
681 dst[i] = SkToU8(SkGetPackedA32(res));
682 }
683 } else {
684 for (int i = count - 1; i >= 0; --i) {
685 unsigned a = aa[i];
686 if (0 != a) {
687 SkAlpha dstA = dst[i];
688 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
689 unsigned A = SkGetPackedA32(res);
690 if (0xFF != a) {
691 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
692 }
693 dst[i] = SkToU8(A);
694 }
695 }
696 }
697 }
698}
699
700SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
701 : SkXfermode(buffer) {
702 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
703}
704
705void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
706 buffer.writeFunctionPtr((void*)fProc);
707}
708
vandebo@chromium.org48543272011-02-08 19:28:07 +0000709///////////////////////////////////////////////////////////////////////////////
710///////////////////////////////////////////////////////////////////////////////
711
712class SkProcCoeffXfermode : public SkProcXfermode {
713public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000714 SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
715 : INHERITED(rec.fProc) {
716 fMode = mode;
717 // these may be valid, or may be CANNOT_USE_COEFF
718 fSrcCoeff = rec.fSC;
719 fDstCoeff = rec.fDC;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000720 }
reed@google.comc0d4aa22011-04-13 21:12:04 +0000721
722 virtual bool asMode(Mode* mode) {
723 if (mode) {
724 *mode = fMode;
725 }
726 return true;
727 }
728
vandebo@chromium.org48543272011-02-08 19:28:07 +0000729 virtual bool asCoeff(Coeff* sc, Coeff* dc) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000730 if (CANNOT_USE_COEFF == fSrcCoeff) {
731 return false;
732 }
733
vandebo@chromium.org48543272011-02-08 19:28:07 +0000734 if (sc) {
735 *sc = fSrcCoeff;
736 }
737 if (dc) {
738 *dc = fDstCoeff;
739 }
740 return true;
741 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000742
vandebo@chromium.org48543272011-02-08 19:28:07 +0000743 virtual Factory getFactory() { return CreateProc; }
744 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
745 this->INHERITED::flatten(buffer);
reed@google.comc0d4aa22011-04-13 21:12:04 +0000746 buffer.write32(fMode);
vandebo@chromium.org48543272011-02-08 19:28:07 +0000747 buffer.write32(fSrcCoeff);
748 buffer.write32(fDstCoeff);
749 }
750
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000751 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
752 return SkNEW_ARGS(SkProcCoeffXfermode, (buffer));
753 }
754
vandebo@chromium.org48543272011-02-08 19:28:07 +0000755protected:
756 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
757 : INHERITED(buffer) {
reed@google.comc0d4aa22011-04-13 21:12:04 +0000758 fMode = (SkXfermode::Mode)buffer.readU32();
vandebo@chromium.org48543272011-02-08 19:28:07 +0000759 fSrcCoeff = (Coeff)buffer.readU32();
760 fDstCoeff = (Coeff)buffer.readU32();
761 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000762
vandebo@chromium.org48543272011-02-08 19:28:07 +0000763private:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000764 Mode fMode;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000765 Coeff fSrcCoeff, fDstCoeff;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000766
vandebo@chromium.org48543272011-02-08 19:28:07 +0000767
768 typedef SkProcXfermode INHERITED;
769};
770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771///////////////////////////////////////////////////////////////////////////////
772
773class SkClearXfermode : public SkProcCoeffXfermode {
774public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000775 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776
777 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
778 const SK_RESTRICT SkPMColor[], int count,
779 const SK_RESTRICT SkAlpha aa[]) {
780 SkASSERT(dst && count >= 0);
781
782 if (NULL == aa) {
783 memset(dst, 0, count << 2);
784 } else {
785 for (int i = count - 1; i >= 0; --i) {
786 unsigned a = aa[i];
787 if (0xFF == a) {
788 dst[i] = 0;
789 } else if (a != 0) {
790 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
791 }
792 }
793 }
794 }
795 virtual void xferA8(SK_RESTRICT SkAlpha dst[],
796 const SK_RESTRICT SkPMColor[], int count,
797 const SK_RESTRICT SkAlpha aa[]) {
798 SkASSERT(dst && count >= 0);
799
800 if (NULL == aa) {
801 memset(dst, 0, count);
802 } else {
803 for (int i = count - 1; i >= 0; --i) {
804 unsigned a = aa[i];
805 if (0xFF == a) {
806 dst[i] = 0;
807 } else if (0 != a) {
808 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
809 }
810 }
811 }
812 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000813
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814 virtual Factory getFactory() { return CreateProc; }
815
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000816 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
817 return SkNEW_ARGS(SkClearXfermode, (buffer));
818 }
819
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820private:
821 SkClearXfermode(SkFlattenableReadBuffer& buffer)
822 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000823
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824};
825
826///////////////////////////////////////////////////////////////////////////////
827
828class SkSrcXfermode : public SkProcCoeffXfermode {
829public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000830 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831
832 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
833 const SK_RESTRICT SkPMColor src[], int count,
834 const SK_RESTRICT SkAlpha aa[]) {
835 SkASSERT(dst && src && count >= 0);
836
837 if (NULL == aa) {
838 memcpy(dst, src, count << 2);
839 } else {
840 for (int i = count - 1; i >= 0; --i) {
841 unsigned a = aa[i];
842 if (a == 0xFF) {
843 dst[i] = src[i];
844 } else if (a != 0) {
845 dst[i] = SkFourByteInterp(src[i], dst[i], a);
846 }
847 }
848 }
849 }
850
851 virtual void xferA8(SK_RESTRICT SkAlpha dst[],
852 const SK_RESTRICT SkPMColor src[], int count,
853 const SK_RESTRICT SkAlpha aa[]) {
854 SkASSERT(dst && src && count >= 0);
855
856 if (NULL == aa) {
857 for (int i = count - 1; i >= 0; --i) {
858 dst[i] = SkToU8(SkGetPackedA32(src[i]));
859 }
860 } else {
861 for (int i = count - 1; i >= 0; --i) {
862 unsigned a = aa[i];
863 if (0 != a) {
864 unsigned srcA = SkGetPackedA32(src[i]);
865 if (a == 0xFF) {
866 dst[i] = SkToU8(srcA);
867 } else {
868 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
869 }
870 }
871 }
872 }
873 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000874
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 virtual Factory getFactory() { return CreateProc; }
876
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000877 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
878 return SkNEW_ARGS(SkSrcXfermode, (buffer));
879 }
880
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881private:
882 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
883 : SkProcCoeffXfermode(buffer) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000884
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885};
886
887class SkDstInXfermode : public SkProcCoeffXfermode {
888public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000889 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000890
reed@android.com8a1c16f2008-12-17 15:59:43 +0000891 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
892 const SK_RESTRICT SkPMColor src[], int count,
893 const SK_RESTRICT SkAlpha aa[]) {
894 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000895
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 if (count <= 0) {
897 return;
898 }
899 if (NULL != aa) {
900 return this->INHERITED::xfer32(dst, src, count, aa);
901 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000902
reed@android.com8a1c16f2008-12-17 15:59:43 +0000903 do {
904 unsigned a = SkGetPackedA32(*src);
905 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
906 dst++;
907 src++;
908 } while (--count != 0);
909 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000910
reed@android.com8a1c16f2008-12-17 15:59:43 +0000911 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000912
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
914 return SkNEW_ARGS(SkDstInXfermode, (buffer));
915 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000916
917private:
918 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
919
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920 typedef SkProcCoeffXfermode INHERITED;
921};
922
923class SkDstOutXfermode : public SkProcCoeffXfermode {
924public:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000925 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000926
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
928 const SK_RESTRICT SkPMColor src[], int count,
929 const SK_RESTRICT SkAlpha aa[]) {
930 SkASSERT(dst && src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000931
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932 if (count <= 0) {
933 return;
934 }
935 if (NULL != aa) {
936 return this->INHERITED::xfer32(dst, src, count, aa);
937 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000938
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939 do {
940 unsigned a = SkGetPackedA32(*src);
941 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
942 dst++;
943 src++;
944 } while (--count != 0);
945 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000946
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947 virtual Factory getFactory() { return CreateProc; }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000948
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
950 return SkNEW_ARGS(SkDstOutXfermode, (buffer));
951 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000952
953private:
954 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
955 : INHERITED(buffer) {}
956
reed@android.com8a1c16f2008-12-17 15:59:43 +0000957 typedef SkProcCoeffXfermode INHERITED;
958};
959
960///////////////////////////////////////////////////////////////////////////////
961
reed@android.coma0f5d152009-06-22 17:38:10 +0000962SkXfermode* SkXfermode::Create(Mode mode) {
963 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
964 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965
reed@google.comc0d4aa22011-04-13 21:12:04 +0000966 const ProcCoeff& rec = gProcCoeffs[mode];
967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 switch (mode) {
969 case kClear_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000970 return SkNEW_ARGS(SkClearXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 case kSrc_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000972 return SkNEW_ARGS(SkSrcXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 case kSrcOver_Mode:
974 return NULL;
975 case kDstIn_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000976 return SkNEW_ARGS(SkDstInXfermode, (rec));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 case kDstOut_Mode:
reed@google.comc0d4aa22011-04-13 21:12:04 +0000978 return SkNEW_ARGS(SkDstOutXfermode, (rec));
979 default:
980 return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 }
982}
983
reed@google.com43c50c82011-04-14 15:50:52 +0000984SkXfermodeProc SkXfermode::GetProc(Mode mode) {
985 SkXfermodeProc proc = NULL;
986 if ((unsigned)mode < kModeCount) {
987 proc = gProcCoeffs[mode].fProc;
988 }
989 return proc;
990}
991
992bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
993 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000994
reed@google.com43c50c82011-04-14 15:50:52 +0000995 if ((unsigned)mode >= (unsigned)kModeCount) {
996 // illegal mode parameter
997 return false;
998 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000999
reed@google.com43c50c82011-04-14 15:50:52 +00001000 const ProcCoeff& rec = gProcCoeffs[mode];
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001001
reed@google.com43c50c82011-04-14 15:50:52 +00001002 if (CANNOT_USE_COEFF == rec.fSC) {
1003 return false;
1004 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001005
reed@google.com43c50c82011-04-14 15:50:52 +00001006 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1007 if (src) {
1008 *src = rec.fSC;
1009 }
1010 if (dst) {
1011 *dst = rec.fDC;
1012 }
1013 return true;
1014}
1015
1016bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 if (NULL == xfer) {
1018 if (mode) {
1019 *mode = kSrcOver_Mode;
1020 }
1021 return true;
1022 }
reed@google.comc0d4aa22011-04-13 21:12:04 +00001023 return xfer->asMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024}
1025
reed@google.com43c50c82011-04-14 15:50:52 +00001026bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
1027 if (NULL == xfer) {
1028 return ModeAsCoeff(kSrcOver_Mode, src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 }
reed@google.com43c50c82011-04-14 15:50:52 +00001030 return xfer->asCoeff(src, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031}
1032
1033///////////////////////////////////////////////////////////////////////////////
1034//////////// 16bit xfermode procs
1035
1036#ifdef SK_DEBUG
1037static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1038static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1039#endif
1040
1041static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1042 SkASSERT(require_255(src));
1043 return SkPixel32ToPixel16(src);
1044}
1045
1046static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1047 return dst;
1048}
1049
1050static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1051 SkASSERT(require_0(src));
1052 return dst;
1053}
1054
1055static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1056 SkASSERT(require_255(src));
1057 return SkPixel32ToPixel16(src);
1058}
1059
1060static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1061 SkASSERT(require_0(src));
1062 return dst;
1063}
1064
1065static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1066 SkASSERT(require_255(src));
1067 return dst;
1068}
1069
1070static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1071 SkASSERT(require_255(src));
1072 return SkPixel32ToPixel16(src);
1073}
1074
1075static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1076 SkASSERT(require_255(src));
1077 return dst;
1078}
1079
1080static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1081 SkASSERT(require_0(src));
1082 return dst;
1083}
1084
1085static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1086 unsigned isa = 255 - SkGetPackedA32(src);
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001087
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 return SkPackRGB16(
1089 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1090 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1091 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1092}
1093
1094static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1095 SkASSERT(require_0(src));
1096 return dst;
1097}
1098
1099static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1100 SkASSERT(require_255(src));
1101 return SkPixel32ToPixel16(src);
1102}
1103
1104static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1105 SkASSERT(require_255(src));
1106 return dst;
1107}
1108
1109/*********
1110 darken and lighten boil down to this.
1111
1112 darken = (1 - Sa) * Dc + min(Sc, Dc)
1113 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1114
1115 if (Sa == 0) these become
1116 darken = Dc + min(0, Dc) = 0
1117 lighten = Dc + max(0, Dc) = Dc
1118
1119 if (Sa == 1) these become
1120 darken = min(Sc, Dc)
1121 lighten = max(Sc, Dc)
1122*/
1123
1124static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1125 SkASSERT(require_0(src));
1126 return 0;
1127}
1128
1129static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1130 SkASSERT(require_255(src));
1131 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1132 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1133 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1134 return SkPackRGB16(r, g, b);
1135}
1136
1137static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1138 SkASSERT(require_0(src));
1139 return dst;
1140}
1141
1142static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1143 SkASSERT(require_255(src));
1144 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1145 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1146 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1147 return SkPackRGB16(r, g, b);
1148}
1149
1150struct Proc16Rec {
1151 SkXfermodeProc16 fProc16_0;
1152 SkXfermodeProc16 fProc16_255;
1153 SkXfermodeProc16 fProc16_General;
1154};
1155
reed@android.coma0f5d152009-06-22 17:38:10 +00001156static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 { NULL, NULL, NULL }, // CLEAR
1158 { NULL, src_modeproc16_255, NULL },
1159 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1160 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1161 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1162 { NULL, srcin_modeproc16_255, NULL },
1163 { NULL, dstin_modeproc16_255, NULL },
1164 { NULL, NULL, NULL },// SRC_OUT
1165 { dstout_modeproc16_0, NULL, NULL },
1166 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1167 { NULL, dstatop_modeproc16_255, NULL },
1168 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001169
1170 { NULL, NULL, NULL }, // plus
1171 { NULL, NULL, NULL }, // multiply
1172 { NULL, NULL, NULL }, // screen
1173 { NULL, NULL, NULL }, // overlay
1174 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1175 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1176 { NULL, NULL, NULL }, // colordodge
1177 { NULL, NULL, NULL }, // colorburn
1178 { NULL, NULL, NULL }, // hardlight
1179 { NULL, NULL, NULL }, // softlight
1180 { NULL, NULL, NULL }, // difference
1181 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182};
1183
reed@android.coma0f5d152009-06-22 17:38:10 +00001184SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001186 if ((unsigned)mode < kModeCount) {
1187 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 unsigned a = SkColorGetA(srcColor);
1189
1190 if (0 == a) {
1191 proc16 = rec.fProc16_0;
1192 } else if (255 == a) {
1193 proc16 = rec.fProc16_255;
1194 } else {
1195 proc16 = rec.fProc16_General;
1196 }
1197 }
1198 return proc16;
1199}
1200
tomhudson@google.com1447c6f2011-04-27 14:09:52 +00001201static SkFlattenable::Registrar
1202 gSkProcCoeffXfermodeReg("SkProcCoeffXfermode",
1203 SkProcCoeffXfermode::CreateProc);
1204
1205static SkFlattenable::Registrar
1206 gSkClearXfermodeReg("SkClearXfermode", SkClearXfermode::CreateProc);
1207
1208static SkFlattenable::Registrar
1209 gSkSrcXfermodeReg("SkSrcXfermode", SkSrcXfermode::CreateProc);
1210
1211static SkFlattenable::Registrar
1212 gSkDstInXfermodeReg("SkDstInXfermode", SkDstInXfermode::CreateProc);
1213
1214static SkFlattenable::Registrar
1215 gSkDstOutXfermodeReg("SkDstOutXfermode", SkDstOutXfermode::CreateProc);