3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkXfermode.h"
11 #include "SkXfermode_opts_SSE2.h"
12 #include "SkXfermode_proccoeff.h"
13 #include "SkColorPriv.h"
14 #include "SkLazyPtr.h"
15 #include "SkMathPriv.h"
16 #include "SkReadBuffer.h"
18 #include "SkUtilsArm.h"
19 #include "SkWriteBuffer.h"
21 #if !SK_ARM_NEON_IS_NONE
22 #include "SkXfermode_opts_arm_neon.h"
25 #define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
28 // idea for higher precision blends in xfer procs (and slightly faster)
29 // see DstATop as a probable caller
30 static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
35 unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
36 unsigned result = (prod + (prod >> 8)) >> 8;
37 SkASSERT(result <= 255);
42 static inline unsigned saturated_add(unsigned a, unsigned b) {
52 static inline int clamp_signed_byte(int n) {
61 static inline int clamp_div255round(int prod) {
64 } else if (prod >= 255*255) {
67 return SkDiv255Round(prod);
71 ///////////////////////////////////////////////////////////////////////////////
73 // kClear_Mode, //!< [0, 0]
74 static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
78 // kSrc_Mode, //!< [Sa, Sc]
79 static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
83 // kDst_Mode, //!< [Da, Dc]
84 static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
88 // kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
89 static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
91 // this is the old, more-correct way, but it doesn't guarantee that dst==255
92 // will always stay opaque
93 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
95 // this is slightly faster, but more importantly guarantees that dst==255
96 // will always stay opaque
97 return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
101 // kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
102 static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
103 // this is the reverse of srcover, just flipping src and dst
104 // see srcover's comment about the 256 for opaqueness guarantees
105 return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
108 // kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
109 static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
110 return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
113 // kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
114 static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
115 return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
118 // kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
119 static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
120 return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
123 // kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
124 static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
125 return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
128 // kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
129 static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
130 unsigned sa = SkGetPackedA32(src);
131 unsigned da = SkGetPackedA32(dst);
132 unsigned isa = 255 - sa;
134 return SkPackARGB32(da,
135 SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
136 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
137 SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
138 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
139 SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
140 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
143 // kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
144 static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
145 unsigned sa = SkGetPackedA32(src);
146 unsigned da = SkGetPackedA32(dst);
147 unsigned ida = 255 - da;
149 return SkPackARGB32(sa,
150 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
151 SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
152 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
153 SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
154 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
155 SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
158 // kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
159 static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
160 unsigned sa = SkGetPackedA32(src);
161 unsigned da = SkGetPackedA32(dst);
162 unsigned isa = 255 - sa;
163 unsigned ida = 255 - da;
165 return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
166 SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
167 SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
168 SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
169 SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
170 SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
171 SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
174 ///////////////////////////////////////////////////////////////////////////////
177 static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
178 unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
179 unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
180 unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
181 unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
182 return SkPackARGB32(a, r, g, b);
186 static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
187 int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
188 int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
189 int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
190 int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
191 return SkPackARGB32(a, r, g, b);
194 static inline int srcover_byte(int a, int b) {
195 return a + b - SkAlphaMulAlpha(a, b);
199 // B(Cb, Cs) = Cb x Cs
200 // multiply uses its own version of blendfunc_byte because sa and da are not needed
201 static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
202 return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
205 static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
206 int sa = SkGetPackedA32(src);
207 int da = SkGetPackedA32(dst);
208 int a = srcover_byte(sa, da);
209 int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
210 int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
211 int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
212 return SkPackARGB32(a, r, g, b);
216 static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
217 int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
218 int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
219 int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
220 int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
221 return SkPackARGB32(a, r, g, b);
225 static inline int overlay_byte(int sc, int dc, int sa, int da) {
226 int tmp = sc * (255 - da) + dc * (255 - sa);
231 rc = sa * da - 2 * (da - dc) * (sa - sc);
233 return clamp_div255round(rc + tmp);
235 static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
236 int sa = SkGetPackedA32(src);
237 int da = SkGetPackedA32(dst);
238 int a = srcover_byte(sa, da);
239 int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
240 int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
241 int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
242 return SkPackARGB32(a, r, g, b);
246 static inline int darken_byte(int sc, int dc, int sa, int da) {
251 return sc + dc - SkDiv255Round(ds);
254 return dc + sc - SkDiv255Round(sd);
257 static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
258 int sa = SkGetPackedA32(src);
259 int da = SkGetPackedA32(dst);
260 int a = srcover_byte(sa, da);
261 int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
262 int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
263 int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
264 return SkPackARGB32(a, r, g, b);
268 static inline int lighten_byte(int sc, int dc, int sa, int da) {
273 return sc + dc - SkDiv255Round(ds);
276 return dc + sc - SkDiv255Round(sd);
279 static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
280 int sa = SkGetPackedA32(src);
281 int da = SkGetPackedA32(dst);
282 int a = srcover_byte(sa, da);
283 int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
284 int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
285 int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
286 return SkPackARGB32(a, r, g, b);
290 static inline int colordodge_byte(int sc, int dc, int sa, int da) {
294 return SkAlphaMulAlpha(sc, 255 - da);
295 } else if (0 == diff) {
296 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
298 diff = dc * sa / diff;
299 rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
301 return clamp_div255round(rc);
303 static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
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 return SkPackARGB32(a, r, g, b);
314 static inline int colorburn_byte(int sc, int dc, int sa, int da) {
317 rc = sa * da + sc * (255 - da) + dc * (255 - sa);
318 } else if (0 == sc) {
319 return SkAlphaMulAlpha(dc, 255 - sa);
321 int tmp = (da - dc) * sa / sc;
322 rc = sa * (da - ((da < tmp) ? da : tmp))
323 + sc * (255 - da) + dc * (255 - sa);
325 return clamp_div255round(rc);
327 static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
328 int sa = SkGetPackedA32(src);
329 int da = SkGetPackedA32(dst);
330 int a = srcover_byte(sa, da);
331 int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
332 int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
333 int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
334 return SkPackARGB32(a, r, g, b);
338 static inline int hardlight_byte(int sc, int dc, int sa, int da) {
343 rc = sa * da - 2 * (da - dc) * (sa - sc);
345 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
347 static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
348 int sa = SkGetPackedA32(src);
349 int da = SkGetPackedA32(dst);
350 int a = srcover_byte(sa, da);
351 int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
352 int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
353 int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
354 return SkPackARGB32(a, r, g, b);
357 // returns 255 * sqrt(n/255)
358 static U8CPU sqrt_unit_byte(U8CPU n) {
359 return SkSqrtBits(n, 15+4);
363 static inline int softlight_byte(int sc, int dc, int sa, int da) {
364 int m = da ? dc * 256 / da : 0;
367 rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
368 } else if (4 * dc <= da) {
369 int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
370 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
372 int tmp = sqrt_unit_byte(m) - m;
373 rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
375 return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
377 static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
378 int sa = SkGetPackedA32(src);
379 int da = SkGetPackedA32(dst);
380 int a = srcover_byte(sa, da);
381 int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
382 int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
383 int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
384 return SkPackARGB32(a, r, g, b);
388 static inline int difference_byte(int sc, int dc, int sa, int da) {
389 int tmp = SkMin32(sc * da, dc * sa);
390 return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
392 static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
393 int sa = SkGetPackedA32(src);
394 int da = SkGetPackedA32(dst);
395 int a = srcover_byte(sa, da);
396 int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
397 int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
398 int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
399 return SkPackARGB32(a, r, g, b);
403 static inline int exclusion_byte(int sc, int dc, int, int) {
404 // this equations is wacky, wait for SVG to confirm it
405 //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
407 // The above equation can be simplified as follows
408 int r = 255*(sc + dc) - 2 * sc * dc;
409 return clamp_div255round(r);
411 static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
412 int sa = SkGetPackedA32(src);
413 int da = SkGetPackedA32(dst);
414 int a = srcover_byte(sa, da);
415 int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
416 int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
417 int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
418 return SkPackARGB32(a, r, g, b);
421 // The CSS compositing spec introduces the following formulas:
422 // (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
423 // SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
424 // while PDF and CG uses the one from Rec. Rec. 601
425 // See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
426 static inline int Lum(int r, int g, int b)
428 return SkDiv255Round(r * 77 + g * 150 + b * 28);
431 static inline int min2(int a, int b) { return a < b ? a : b; }
432 static inline int max2(int a, int b) { return a > b ? a : b; }
433 #define minimum(a, b, c) min2(min2(a, b), c)
434 #define maximum(a, b, c) max2(max2(a, b), c)
436 static inline int Sat(int r, int g, int b) {
437 return maximum(r, g, b) - minimum(r, g, b);
440 static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
442 *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
452 static inline void SetSat(int* r, int* g, int* b, int s) {
455 setSaturationComponents(r, g, b, s);
456 } else if(*r <= *b) {
457 setSaturationComponents(r, b, g, s);
459 setSaturationComponents(b, r, g, s);
461 } else if(*r <= *b) {
462 setSaturationComponents(g, r, b, s);
463 } else if(*g <= *b) {
464 setSaturationComponents(g, b, r, s);
466 setSaturationComponents(b, g, r, s);
470 static inline void clipColor(int* r, int* g, int* b, int a) {
471 int L = Lum(*r, *g, *b);
472 int n = minimum(*r, *g, *b);
473 int x = maximum(*r, *g, *b);
475 if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
476 *r = L + SkMulDiv(*r - L, L, denom);
477 *g = L + SkMulDiv(*g - L, L, denom);
478 *b = L + SkMulDiv(*b - L, L, denom);
481 if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
483 *r = L + SkMulDiv(*r - L, numer, denom);
484 *g = L + SkMulDiv(*g - L, numer, denom);
485 *b = L + SkMulDiv(*b - L, numer, denom);
489 static inline void SetLum(int* r, int* g, int* b, int a, int l) {
490 int d = l - Lum(*r, *g, *b);
495 clipColor(r, g, b, a);
498 // non-separable blend modes are done in non-premultiplied alpha
499 #define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
500 clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
503 // B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
504 // Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
505 static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
506 int sr = SkGetPackedR32(src);
507 int sg = SkGetPackedG32(src);
508 int sb = SkGetPackedB32(src);
509 int sa = SkGetPackedA32(src);
511 int dr = SkGetPackedR32(dst);
512 int dg = SkGetPackedG32(dst);
513 int db = SkGetPackedB32(dst);
514 int da = SkGetPackedA32(dst);
521 SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
522 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
529 int a = srcover_byte(sa, da);
530 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
531 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
532 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
533 return SkPackARGB32(a, r, g, b);
537 // B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
538 // Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
539 static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
540 int sr = SkGetPackedR32(src);
541 int sg = SkGetPackedG32(src);
542 int sb = SkGetPackedB32(src);
543 int sa = SkGetPackedA32(src);
545 int dr = SkGetPackedR32(dst);
546 int dg = SkGetPackedG32(dst);
547 int db = SkGetPackedB32(dst);
548 int da = SkGetPackedA32(dst);
555 SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
556 SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
563 int a = srcover_byte(sa, da);
564 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
565 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
566 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
567 return SkPackARGB32(a, r, g, b);
571 // B(Cb, Cs) = SetLum(Cs, Lum(Cb))
572 // Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
573 static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
574 int sr = SkGetPackedR32(src);
575 int sg = SkGetPackedG32(src);
576 int sb = SkGetPackedB32(src);
577 int sa = SkGetPackedA32(src);
579 int dr = SkGetPackedR32(dst);
580 int dg = SkGetPackedG32(dst);
581 int db = SkGetPackedB32(dst);
582 int da = SkGetPackedA32(dst);
589 SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
596 int a = srcover_byte(sa, da);
597 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
598 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
599 int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
600 return SkPackARGB32(a, r, g, b);
604 // B(Cb, Cs) = SetLum(Cb, Lum(Cs))
605 // Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
606 static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
607 int sr = SkGetPackedR32(src);
608 int sg = SkGetPackedG32(src);
609 int sb = SkGetPackedB32(src);
610 int sa = SkGetPackedA32(src);
612 int dr = SkGetPackedR32(dst);
613 int dg = SkGetPackedG32(dst);
614 int db = SkGetPackedB32(dst);
615 int da = SkGetPackedA32(dst);
622 SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
629 int a = srcover_byte(sa, da);
630 int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
631 int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
632 int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
633 return SkPackARGB32(a, r, g, b);
636 const ProcCoeff gProcCoeffs[] = {
637 { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
638 { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
639 { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
640 { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
641 { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
642 { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
643 { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
644 { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
645 { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
646 { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
647 { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
648 { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
650 { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
651 { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
652 { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
653 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
654 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
655 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
656 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
657 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
658 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
659 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
660 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
661 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
662 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
663 { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
664 { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
665 { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
666 { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
669 ///////////////////////////////////////////////////////////////////////////////
671 bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
675 bool SkXfermode::asMode(Mode* mode) const {
679 bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrTexture*) const {
683 bool SkXfermode::asFragmentProcessorOrCoeff(SkXfermode* xfermode, GrFragmentProcessor** fp,
684 Coeff* src, Coeff* dst, GrTexture* background) {
685 if (NULL == xfermode) {
686 return ModeAsCoeff(kSrcOver_Mode, src, dst);
687 } else if (xfermode->asCoeff(src, dst)) {
690 return xfermode->asFragmentProcessor(fp, background);
694 SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
695 // no-op. subclasses should override this
699 void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
700 const SkPMColor* SK_RESTRICT src, int count,
701 const SkAlpha* SK_RESTRICT aa) const {
702 SkASSERT(dst && src && count >= 0);
705 for (int i = count - 1; i >= 0; --i) {
706 dst[i] = this->xferColor(src[i], dst[i]);
709 for (int i = count - 1; i >= 0; --i) {
712 SkPMColor dstC = dst[i];
713 SkPMColor C = this->xferColor(src[i], dstC);
715 C = SkFourByteInterp(C, dstC, a);
723 void SkXfermode::xfer16(uint16_t* dst,
724 const SkPMColor* SK_RESTRICT src, int count,
725 const SkAlpha* SK_RESTRICT aa) const {
726 SkASSERT(dst && src && count >= 0);
729 for (int i = count - 1; i >= 0; --i) {
730 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
731 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
734 for (int i = count - 1; i >= 0; --i) {
737 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
738 SkPMColor C = this->xferColor(src[i], dstC);
740 C = SkFourByteInterp(C, dstC, a);
742 dst[i] = SkPixel32ToPixel16_ToU16(C);
748 void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
749 const SkPMColor src[], int count,
750 const SkAlpha* SK_RESTRICT aa) const {
751 SkASSERT(dst && src && count >= 0);
754 for (int i = count - 1; i >= 0; --i) {
755 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
756 dst[i] = SkToU8(SkGetPackedA32(res));
759 for (int i = count - 1; i >= 0; --i) {
762 SkAlpha dstA = dst[i];
763 unsigned A = SkGetPackedA32(this->xferColor(src[i],
764 (SkPMColor)(dstA << SK_A32_SHIFT)));
766 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
774 //////////////////////////////////////////////////////////////////////////////
778 #include "GrProcessor.h"
779 #include "GrCoordTransform.h"
780 #include "GrProcessorUnitTest.h"
781 #include "GrTBackendProcessorFactory.h"
782 #include "gl/GrGLProcessor.h"
783 #include "gl/builders/GrGLProgramBuilder.h"
786 * GrProcessor that implements the all the separable xfer modes that cannot be expressed as Coeffs.
788 class XferEffect : public GrFragmentProcessor {
790 static bool IsSupportedMode(SkXfermode::Mode mode) {
791 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
794 static GrFragmentProcessor* Create(SkXfermode::Mode mode, GrTexture* background) {
795 if (!IsSupportedMode(mode)) {
798 return SkNEW_ARGS(XferEffect, (mode, background));
802 virtual void getConstantColorComponents(GrColor* color,
803 uint32_t* validFlags) const SK_OVERRIDE {
807 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
808 return GrTBackendFragmentProcessorFactory<XferEffect>::getInstance();
811 static const char* Name() { return "XferEffect"; }
813 SkXfermode::Mode mode() const { return fMode; }
814 const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
816 class GLProcessor : public GrGLFragmentProcessor {
818 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
819 : INHERITED(factory) {
821 virtual void emitCode(GrGLProgramBuilder* builder,
822 const GrFragmentProcessor& fp,
823 const GrProcessorKey& key,
824 const char* outputColor,
825 const char* inputColor,
826 const TransformedCoordsArray& coords,
827 const TextureSamplerArray& samplers) SK_OVERRIDE {
828 SkXfermode::Mode mode = fp.cast<XferEffect>().mode();
829 const GrTexture* backgroundTex =
830 fp.cast<XferEffect>().backgroundAccess().getTexture();
831 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
832 const char* dstColor;
834 dstColor = "bgColor";
835 fsBuilder->codeAppendf("\t\tvec4 %s = ", dstColor);
836 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
837 fsBuilder->codeAppendf(";\n");
839 dstColor = fsBuilder->dstColor();
843 // We don't try to optimize for this case at all
844 if (NULL == inputColor) {
845 fsBuilder->codeAppendf("\t\tconst vec4 ones = vec4(1);\n");
848 fsBuilder->codeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
850 // These all perform src-over on the alpha channel.
851 fsBuilder->codeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
852 outputColor, inputColor, inputColor, dstColor);
855 case SkXfermode::kOverlay_Mode:
856 // Overlay is Hard-Light with the src and dst reversed
857 HardLight(fsBuilder, outputColor, dstColor, inputColor);
859 case SkXfermode::kDarken_Mode:
860 fsBuilder->codeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
861 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
863 inputColor, dstColor, inputColor,
864 dstColor, inputColor, dstColor);
866 case SkXfermode::kLighten_Mode:
867 fsBuilder->codeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
868 "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
870 inputColor, dstColor, inputColor,
871 dstColor, inputColor, dstColor);
873 case SkXfermode::kColorDodge_Mode:
874 ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'r');
875 ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'g');
876 ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'b');
878 case SkXfermode::kColorBurn_Mode:
879 ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'r');
880 ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'g');
881 ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'b');
883 case SkXfermode::kHardLight_Mode:
884 HardLight(fsBuilder, outputColor, inputColor, dstColor);
886 case SkXfermode::kSoftLight_Mode:
887 fsBuilder->codeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
888 fsBuilder->codeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
889 fsBuilder->codeAppendf("\t\t} else {\n");
890 SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
891 SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
892 SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
893 fsBuilder->codeAppendf("\t\t}\n");
895 case SkXfermode::kDifference_Mode:
896 fsBuilder->codeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
897 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
898 outputColor, inputColor, dstColor, inputColor, dstColor,
899 dstColor, inputColor);
901 case SkXfermode::kExclusion_Mode:
902 fsBuilder->codeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
903 "2.0 * %s.rgb * %s.rgb;\n",
904 outputColor, dstColor, inputColor, dstColor, inputColor);
906 case SkXfermode::kMultiply_Mode:
907 fsBuilder->codeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
908 "(1.0 - %s.a) * %s.rgb + "
909 "%s.rgb * %s.rgb;\n",
910 outputColor, inputColor, dstColor, dstColor, inputColor,
911 inputColor, dstColor);
913 case SkXfermode::kHue_Mode: {
914 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
915 SkString setSat, setLum;
916 AddSatFunction(fsBuilder, &setSat);
917 AddLumFunction(fsBuilder, &setLum);
918 fsBuilder->codeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
919 dstColor, inputColor);
920 fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
921 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
923 fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
924 outputColor, inputColor, dstColor, dstColor, inputColor);
927 case SkXfermode::kSaturation_Mode: {
928 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
929 SkString setSat, setLum;
930 AddSatFunction(fsBuilder, &setSat);
931 AddLumFunction(fsBuilder, &setLum);
932 fsBuilder->codeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
933 dstColor, inputColor);
934 fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
935 outputColor, setLum.c_str(), setSat.c_str(), inputColor,
937 fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
938 outputColor, inputColor, dstColor, dstColor, inputColor);
941 case SkXfermode::kColor_Mode: {
942 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
944 AddLumFunction(fsBuilder, &setLum);
945 fsBuilder->codeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
946 inputColor, dstColor);
947 fsBuilder->codeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
948 outputColor, setLum.c_str(), dstColor, inputColor);
949 fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
950 outputColor, inputColor, dstColor, dstColor, inputColor);
953 case SkXfermode::kLuminosity_Mode: {
954 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
956 AddLumFunction(fsBuilder, &setLum);
957 fsBuilder->codeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
958 inputColor, dstColor);
959 fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
960 outputColor, setLum.c_str(), dstColor, inputColor);
961 fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
962 outputColor, inputColor, dstColor, dstColor, inputColor);
966 SkFAIL("Unknown XferEffect mode.");
971 static inline void GenKey(const GrProcessor& proc, const GrGLCaps&,
972 GrProcessorKeyBuilder* b) {
973 // The background may come from the dst or from a texture.
974 uint32_t key = proc.numTextures();
976 key |= proc.cast<XferEffect>().mode() << 1;
981 static void HardLight(GrGLFragmentShaderBuilder* fsBuilder,
985 static const char kComponents[] = {'r', 'g', 'b'};
986 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
987 char component = kComponents[i];
988 fsBuilder->codeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
989 fsBuilder->codeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
990 fsBuilder->codeAppend("\t\t} else {\n");
991 fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
992 final, component, src, dst, dst, dst, component, src, src, component);
993 fsBuilder->codeAppend("\t\t}\n");
995 fsBuilder->codeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
996 final, src, dst, dst, src);
999 // Does one component of color-dodge
1000 static void ColorDodgeComponent(GrGLFragmentShaderBuilder* fsBuilder,
1004 const char component) {
1005 fsBuilder->codeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
1006 fsBuilder->codeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
1007 final, component, src, component, dst);
1008 fsBuilder->codeAppend("\t\t} else {\n");
1009 fsBuilder->codeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
1010 fsBuilder->codeAppend("\t\t\tif (0.0 == d) {\n");
1011 fsBuilder->codeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1012 final, component, src, dst, src, component, dst, dst, component,
1014 fsBuilder->codeAppend("\t\t\t} else {\n");
1015 fsBuilder->codeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
1016 dst, dst, component, src);
1017 fsBuilder->codeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1018 final, component, src, src, component, dst, dst, component, src);
1019 fsBuilder->codeAppend("\t\t\t}\n");
1020 fsBuilder->codeAppend("\t\t}\n");
1023 // Does one component of color-burn
1024 static void ColorBurnComponent(GrGLFragmentShaderBuilder* fsBuilder,
1028 const char component) {
1029 fsBuilder->codeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
1030 fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1031 final, component, src, dst, src, component, dst, dst, component,
1033 fsBuilder->codeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
1034 fsBuilder->codeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
1035 final, component, dst, component, src);
1036 fsBuilder->codeAppend("\t\t} else {\n");
1037 fsBuilder->codeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
1038 dst, dst, dst, component, src, src, component);
1039 fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
1040 final, component, src, src, component, dst, dst, component, src);
1041 fsBuilder->codeAppend("\t\t}\n");
1044 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
1045 static void SoftLightComponentPosDstAlpha(GrGLFragmentShaderBuilder* fsBuilder,
1049 const char component) {
1051 fsBuilder->codeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
1052 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
1053 fsBuilder->codeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
1054 final, component, dst, component, dst, component, src, src,
1055 component, dst, dst, src, component, dst, component, src, src,
1057 // else if (4D < Da)
1058 fsBuilder->codeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
1059 dst, component, dst);
1060 fsBuilder->codeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
1061 dst, component, dst, component);
1062 fsBuilder->codeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
1063 fsBuilder->codeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
1064 fsBuilder->codeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
1065 // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
1066 fsBuilder->codeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
1067 final, component, src, component, src, component, dst, component,
1068 src, src, component, dst, src, src, component, src, src,
1070 fsBuilder->codeAppendf("\t\t\t} else {\n");
1071 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
1072 fsBuilder->codeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
1073 final, component, dst, dst, component, src, src, component, dst,
1074 src, component, dst, component, src, src, component, src,
1076 fsBuilder->codeAppendf("\t\t\t}\n");
1079 // Adds a function that takes two colors and an alpha as input. It produces a color with the
1080 // hue and saturation of the first color, the luminosity of the second color, and the input
1081 // alpha. It has this signature:
1082 // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
1083 static void AddLumFunction(GrGLFragmentShaderBuilder* fsBuilder, SkString* setLumFunction) {
1084 // Emit a helper that gets the luminance of a color.
1085 SkString getFunction;
1086 GrGLShaderVar getLumArgs[] = {
1087 GrGLShaderVar("color", kVec3f_GrSLType),
1089 SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
1090 fsBuilder->emitFunction(kFloat_GrSLType,
1092 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
1096 // Emit the set luminance function.
1097 GrGLShaderVar setLumArgs[] = {
1098 GrGLShaderVar("hueSat", kVec3f_GrSLType),
1099 GrGLShaderVar("alpha", kFloat_GrSLType),
1100 GrGLShaderVar("lumColor", kVec3f_GrSLType),
1102 SkString setLumBody;
1103 setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
1104 setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
1105 setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
1106 setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
1107 "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
1108 "\tif (minComp < 0.0) {\n"
1109 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
1111 "\tif (maxComp > alpha) {\n"
1112 "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
1114 "\treturn outColor;\n");
1115 fsBuilder->emitFunction(kVec3f_GrSLType,
1117 SK_ARRAY_COUNT(setLumArgs), setLumArgs,
1122 // Adds a function that creates a color with the hue and luminosity of one input color and
1123 // the saturation of another color. It will have this signature:
1124 // float set_saturation(vec3 hueLumColor, vec3 satColor)
1125 static void AddSatFunction(GrGLFragmentShaderBuilder* fsBuilder, SkString* setSatFunction) {
1126 // Emit a helper that gets the saturation of a color
1127 SkString getFunction;
1128 GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
1129 SkString getSatBody;
1130 getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
1131 "min(min(color.r, color.g), color.b);\n");
1132 fsBuilder->emitFunction(kFloat_GrSLType,
1134 SK_ARRAY_COUNT(getSatArgs), getSatArgs,
1138 // Emit a helper that sets the saturation given sorted input channels. This used
1139 // to use inout params for min, mid, and max components but that seems to cause
1140 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
1141 // adjusted min, mid, and max inputs, respectively.
1142 SkString helperFunction;
1143 GrGLShaderVar helperArgs[] = {
1144 GrGLShaderVar("minComp", kFloat_GrSLType),
1145 GrGLShaderVar("midComp", kFloat_GrSLType),
1146 GrGLShaderVar("maxComp", kFloat_GrSLType),
1147 GrGLShaderVar("sat", kFloat_GrSLType),
1149 static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
1150 "\t\tvec3 result;\n"
1151 "\t\tresult.r = 0.0;\n"
1152 "\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
1153 "\t\tresult.b = sat;\n"
1154 "\t\treturn result;\n"
1156 "\t\treturn vec3(0, 0, 0);\n"
1158 fsBuilder->emitFunction(kVec3f_GrSLType,
1159 "set_saturation_helper",
1160 SK_ARRAY_COUNT(helperArgs), helperArgs,
1164 GrGLShaderVar setSatArgs[] = {
1165 GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
1166 GrGLShaderVar("satColor", kVec3f_GrSLType),
1168 const char* helpFunc = helperFunction.c_str();
1169 SkString setSatBody;
1170 setSatBody.appendf("\tfloat sat = %s(satColor);\n"
1171 "\tif (hueLumColor.r <= hueLumColor.g) {\n"
1172 "\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
1173 "\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
1174 "\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
1175 "\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
1177 "\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
1179 "\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
1180 "\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
1181 "\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
1182 "\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
1184 "\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
1186 "\treturn hueLumColor;\n",
1187 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
1188 helpFunc, helpFunc);
1189 fsBuilder->emitFunction(kVec3f_GrSLType,
1191 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
1197 typedef GrGLFragmentProcessor INHERITED;
1200 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
1203 XferEffect(SkXfermode::Mode mode, GrTexture* background)
1206 fBackgroundTransform.reset(kLocal_GrCoordSet, background);
1207 this->addCoordTransform(&fBackgroundTransform);
1208 fBackgroundAccess.reset(background);
1209 this->addTextureAccess(&fBackgroundAccess);
1211 this->setWillReadDstColor();
1214 virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE {
1215 const XferEffect& s = other.cast<XferEffect>();
1216 return fMode == s.fMode &&
1217 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
1220 SkXfermode::Mode fMode;
1221 GrCoordTransform fBackgroundTransform;
1222 GrTextureAccess fBackgroundAccess;
1224 typedef GrFragmentProcessor INHERITED;
1227 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(XferEffect);
1228 GrFragmentProcessor* XferEffect::TestCreate(SkRandom* rand,
1230 const GrDrawTargetCaps&,
1232 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
1234 return SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL));
1239 ///////////////////////////////////////////////////////////////////////////////
1240 ///////////////////////////////////////////////////////////////////////////////
1242 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1243 SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
1244 uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
1245 if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
1246 // out of range, just set to something harmless
1247 mode32 = SkXfermode::kSrcOut_Mode;
1249 fMode = (SkXfermode::Mode)mode32;
1251 const ProcCoeff& rec = gProcCoeffs[fMode];
1253 // these may be valid, or may be CANNOT_USE_COEFF
1254 fSrcCoeff = rec.fSC;
1255 fDstCoeff = rec.fDC;
1259 SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
1260 uint32_t mode32 = buffer.read32();
1261 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
1264 return SkXfermode::Create((SkXfermode::Mode)mode32);
1267 void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
1268 buffer.write32(fMode);
1271 bool SkProcCoeffXfermode::asMode(Mode* mode) const {
1278 bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
1279 if (CANNOT_USE_COEFF == fSrcCoeff) {
1292 void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1293 const SkPMColor* SK_RESTRICT src, int count,
1294 const SkAlpha* SK_RESTRICT aa) const {
1295 SkASSERT(dst && src && count >= 0);
1297 SkXfermodeProc proc = fProc;
1301 for (int i = count - 1; i >= 0; --i) {
1302 dst[i] = proc(src[i], dst[i]);
1305 for (int i = count - 1; i >= 0; --i) {
1308 SkPMColor dstC = dst[i];
1309 SkPMColor C = proc(src[i], dstC);
1311 C = SkFourByteInterp(C, dstC, a);
1320 void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
1321 const SkPMColor* SK_RESTRICT src, int count,
1322 const SkAlpha* SK_RESTRICT aa) const {
1323 SkASSERT(dst && src && count >= 0);
1325 SkXfermodeProc proc = fProc;
1329 for (int i = count - 1; i >= 0; --i) {
1330 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1331 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
1334 for (int i = count - 1; i >= 0; --i) {
1337 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
1338 SkPMColor C = proc(src[i], dstC);
1340 C = SkFourByteInterp(C, dstC, a);
1342 dst[i] = SkPixel32ToPixel16_ToU16(C);
1349 void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1350 const SkPMColor* SK_RESTRICT src, int count,
1351 const SkAlpha* SK_RESTRICT aa) const {
1352 SkASSERT(dst && src && count >= 0);
1354 SkXfermodeProc proc = fProc;
1358 for (int i = count - 1; i >= 0; --i) {
1359 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
1360 dst[i] = SkToU8(SkGetPackedA32(res));
1363 for (int i = count - 1; i >= 0; --i) {
1366 SkAlpha dstA = dst[i];
1367 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
1368 unsigned A = SkGetPackedA32(res);
1370 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
1380 bool SkProcCoeffXfermode::asFragmentProcessor(GrFragmentProcessor** fp,
1381 GrTexture* background) const {
1382 if (XferEffect::IsSupportedMode(fMode)) {
1384 *fp = XferEffect::Create(fMode, background);
1393 const char* SkXfermode::ModeName(Mode mode) {
1394 SkASSERT((unsigned) mode <= (unsigned)kLastMode);
1395 const char* gModeStrings[] = {
1396 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
1397 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
1398 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
1399 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
1400 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
1402 return gModeStrings[mode];
1403 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
1406 #ifndef SK_IGNORE_TO_STRING
1407 void SkProcCoeffXfermode::toString(SkString* str) const {
1408 str->append("SkProcCoeffXfermode: ");
1410 str->append("mode: ");
1411 str->append(ModeName(fMode));
1413 static const char* gCoeffStrings[kCoeffCount] = {
1414 "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
1417 str->append(" src: ");
1418 if (CANNOT_USE_COEFF == fSrcCoeff) {
1419 str->append("can't use");
1421 str->append(gCoeffStrings[fSrcCoeff]);
1424 str->append(" dst: ");
1425 if (CANNOT_USE_COEFF == fDstCoeff) {
1426 str->append("can't use");
1428 str->append(gCoeffStrings[fDstCoeff]);
1433 ///////////////////////////////////////////////////////////////////////////////
1435 class SkClearXfermode : public SkProcCoeffXfermode {
1437 static SkClearXfermode* Create(const ProcCoeff& rec) {
1438 return SkNEW_ARGS(SkClearXfermode, (rec));
1441 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1442 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1444 SK_TO_STRING_OVERRIDE()
1447 SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
1448 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1449 SkClearXfermode(SkReadBuffer& buffer) : SkProcCoeffXfermode(buffer) {}
1452 typedef SkProcCoeffXfermode INHERITED;
1455 void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1456 const SkPMColor* SK_RESTRICT, int count,
1457 const SkAlpha* SK_RESTRICT aa) const {
1458 SkASSERT(dst && count >= 0);
1461 memset(dst, 0, count << 2);
1463 for (int i = count - 1; i >= 0; --i) {
1467 } else if (a != 0) {
1468 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
1473 void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1474 const SkPMColor* SK_RESTRICT, int count,
1475 const SkAlpha* SK_RESTRICT aa) const {
1476 SkASSERT(dst && count >= 0);
1479 memset(dst, 0, count);
1481 for (int i = count - 1; i >= 0; --i) {
1485 } else if (0 != a) {
1486 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
1492 #ifndef SK_IGNORE_TO_STRING
1493 void SkClearXfermode::toString(SkString* str) const {
1494 this->INHERITED::toString(str);
1498 ///////////////////////////////////////////////////////////////////////////////
1500 class SkSrcXfermode : public SkProcCoeffXfermode {
1502 static SkSrcXfermode* Create(const ProcCoeff& rec) {
1503 return SkNEW_ARGS(SkSrcXfermode, (rec));
1506 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1507 virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1509 SK_TO_STRING_OVERRIDE()
1512 SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
1513 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1514 SkSrcXfermode(SkReadBuffer& buffer) : SkProcCoeffXfermode(buffer) {}
1516 typedef SkProcCoeffXfermode INHERITED;
1519 void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1520 const SkPMColor* SK_RESTRICT src, int count,
1521 const SkAlpha* SK_RESTRICT aa) const {
1522 SkASSERT(dst && src && count >= 0);
1525 memcpy(dst, src, count << 2);
1527 for (int i = count - 1; i >= 0; --i) {
1531 } else if (a != 0) {
1532 dst[i] = SkFourByteInterp(src[i], dst[i], a);
1538 void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
1539 const SkPMColor* SK_RESTRICT src, int count,
1540 const SkAlpha* SK_RESTRICT aa) const {
1541 SkASSERT(dst && src && count >= 0);
1544 for (int i = count - 1; i >= 0; --i) {
1545 dst[i] = SkToU8(SkGetPackedA32(src[i]));
1548 for (int i = count - 1; i >= 0; --i) {
1551 unsigned srcA = SkGetPackedA32(src[i]);
1553 dst[i] = SkToU8(srcA);
1555 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
1561 #ifndef SK_IGNORE_TO_STRING
1562 void SkSrcXfermode::toString(SkString* str) const {
1563 this->INHERITED::toString(str);
1567 ///////////////////////////////////////////////////////////////////////////////
1569 class SkDstInXfermode : public SkProcCoeffXfermode {
1571 static SkDstInXfermode* Create(const ProcCoeff& rec) {
1572 return SkNEW_ARGS(SkDstInXfermode, (rec));
1575 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1577 SK_TO_STRING_OVERRIDE()
1580 SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
1581 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1582 SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
1585 typedef SkProcCoeffXfermode INHERITED;
1588 void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1589 const SkPMColor* SK_RESTRICT src, int count,
1590 const SkAlpha* SK_RESTRICT aa) const {
1591 SkASSERT(dst && src);
1597 return this->INHERITED::xfer32(dst, src, count, aa);
1601 unsigned a = SkGetPackedA32(*src);
1602 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
1605 } while (--count != 0);
1608 #ifndef SK_IGNORE_TO_STRING
1609 void SkDstInXfermode::toString(SkString* str) const {
1610 this->INHERITED::toString(str);
1614 ///////////////////////////////////////////////////////////////////////////////
1616 class SkDstOutXfermode : public SkProcCoeffXfermode {
1618 static SkDstOutXfermode* Create(const ProcCoeff& rec) {
1619 return SkNEW_ARGS(SkDstOutXfermode, (rec));
1622 virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
1624 SK_TO_STRING_OVERRIDE()
1627 SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
1628 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1629 SkDstOutXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
1632 typedef SkProcCoeffXfermode INHERITED;
1635 void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
1636 const SkPMColor* SK_RESTRICT src, int count,
1637 const SkAlpha* SK_RESTRICT aa) const {
1638 SkASSERT(dst && src);
1644 return this->INHERITED::xfer32(dst, src, count, aa);
1648 unsigned a = SkGetPackedA32(*src);
1649 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1652 } while (--count != 0);
1655 #ifndef SK_IGNORE_TO_STRING
1656 void SkDstOutXfermode::toString(SkString* str) const {
1657 this->INHERITED::toString(str);
1661 ///////////////////////////////////////////////////////////////////////////////
1663 extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec, SkXfermode::Mode mode);
1664 extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
1666 // Technically, can't be static and passed as a template parameter. So we use anonymous namespace.
1668 SkXfermode* create_mode(int iMode) {
1669 SkXfermode::Mode mode = (SkXfermode::Mode)iMode;
1671 ProcCoeff rec = gProcCoeffs[mode];
1672 SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
1677 SkXfermode* xfer = NULL;
1678 // check if we have a platform optim for that
1679 SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
1683 // All modes can in theory be represented by the ProcCoeff rec, since
1684 // it contains function ptrs. However, a few modes are both simple and
1685 // commonly used, so we call those out for their own subclasses here.
1687 case SkXfermode::kClear_Mode:
1688 xfer = SkClearXfermode::Create(rec);
1690 case SkXfermode::kSrc_Mode:
1691 xfer = SkSrcXfermode::Create(rec);
1693 case SkXfermode::kSrcOver_Mode:
1694 SkASSERT(false); // should not land here
1696 case SkXfermode::kDstIn_Mode:
1697 xfer = SkDstInXfermode::Create(rec);
1699 case SkXfermode::kDstOut_Mode:
1700 xfer = SkDstOutXfermode::Create(rec);
1703 // no special-case, just rely in the rec and its function-ptrs
1704 xfer = SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
1713 SkXfermode* SkXfermode::Create(Mode mode) {
1714 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1716 if ((unsigned)mode >= kModeCount) {
1721 // Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcover
1722 // so we can just return NULL from the factory.
1723 if (kSrcOver_Mode == mode) {
1727 SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, kModeCount, create_mode);
1728 return SkSafeRef(cached[mode]);
1731 SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1732 SkXfermodeProc proc = NULL;
1733 if ((unsigned)mode < kModeCount) {
1734 proc = gProcCoeffs[mode].fProc;
1739 bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1740 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1742 if ((unsigned)mode >= (unsigned)kModeCount) {
1743 // illegal mode parameter
1747 const ProcCoeff& rec = gProcCoeffs[mode];
1749 if (CANNOT_USE_COEFF == rec.fSC) {
1753 SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1763 bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
1766 *mode = kSrcOver_Mode;
1770 return xfer->asMode(mode);
1773 bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
1775 return ModeAsCoeff(kSrcOver_Mode, src, dst);
1777 return xfer->asCoeff(src, dst);
1780 bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
1781 // if xfer==null then the mode is srcover
1782 Mode m = kSrcOver_Mode;
1783 if (xfer && !xfer->asMode(&m)) {
1789 ///////////////////////////////////////////////////////////////////////////////
1790 //////////// 16bit xfermode procs
1793 static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1794 static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1797 static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1798 SkASSERT(require_255(src));
1799 return SkPixel32ToPixel16(src);
1802 static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1806 static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1807 SkASSERT(require_0(src));
1811 static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1812 SkASSERT(require_255(src));
1813 return SkPixel32ToPixel16(src);
1816 static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1817 SkASSERT(require_0(src));
1821 static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1822 SkASSERT(require_255(src));
1826 static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1827 SkASSERT(require_255(src));
1828 return SkPixel32ToPixel16(src);
1831 static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1832 SkASSERT(require_255(src));
1836 static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1837 SkASSERT(require_0(src));
1841 static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1842 unsigned isa = 255 - SkGetPackedA32(src);
1845 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1846 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1847 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1850 static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1851 SkASSERT(require_0(src));
1855 static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1856 SkASSERT(require_255(src));
1857 return SkPixel32ToPixel16(src);
1860 static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1861 SkASSERT(require_255(src));
1866 darken and lighten boil down to this.
1868 darken = (1 - Sa) * Dc + min(Sc, Dc)
1869 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1871 if (Sa == 0) these become
1872 darken = Dc + min(0, Dc) = 0
1873 lighten = Dc + max(0, Dc) = Dc
1875 if (Sa == 1) these become
1876 darken = min(Sc, Dc)
1877 lighten = max(Sc, Dc)
1880 static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1881 SkASSERT(require_0(src));
1885 static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1886 SkASSERT(require_255(src));
1887 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1888 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1889 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1890 return SkPackRGB16(r, g, b);
1893 static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1894 SkASSERT(require_0(src));
1898 static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1899 SkASSERT(require_255(src));
1900 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1901 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1902 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1903 return SkPackRGB16(r, g, b);
1907 SkXfermodeProc16 fProc16_0;
1908 SkXfermodeProc16 fProc16_255;
1909 SkXfermodeProc16 fProc16_General;
1912 static const Proc16Rec gModeProcs16[] = {
1913 { NULL, NULL, NULL }, // CLEAR
1914 { NULL, src_modeproc16_255, NULL },
1915 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1916 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1917 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1918 { NULL, srcin_modeproc16_255, NULL },
1919 { NULL, dstin_modeproc16_255, NULL },
1920 { NULL, NULL, NULL },// SRC_OUT
1921 { dstout_modeproc16_0, NULL, NULL },
1922 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1923 { NULL, dstatop_modeproc16_255, NULL },
1924 { NULL, NULL, NULL }, // XOR
1926 { NULL, NULL, NULL }, // plus
1927 { NULL, NULL, NULL }, // modulate
1928 { NULL, NULL, NULL }, // screen
1929 { NULL, NULL, NULL }, // overlay
1930 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1931 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1932 { NULL, NULL, NULL }, // colordodge
1933 { NULL, NULL, NULL }, // colorburn
1934 { NULL, NULL, NULL }, // hardlight
1935 { NULL, NULL, NULL }, // softlight
1936 { NULL, NULL, NULL }, // difference
1937 { NULL, NULL, NULL }, // exclusion
1938 { NULL, NULL, NULL }, // multiply
1939 { NULL, NULL, NULL }, // hue
1940 { NULL, NULL, NULL }, // saturation
1941 { NULL, NULL, NULL }, // color
1942 { NULL, NULL, NULL }, // luminosity
1945 SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
1946 SkXfermodeProc16 proc16 = NULL;
1947 if ((unsigned)mode < kModeCount) {
1948 const Proc16Rec& rec = gModeProcs16[mode];
1949 unsigned a = SkColorGetA(srcColor);
1952 proc16 = rec.fProc16_0;
1953 } else if (255 == a) {
1954 proc16 = rec.fProc16_255;
1956 proc16 = rec.fProc16_General;
1962 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1963 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1964 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END