1 // Aseprite Document Library
2 // Copyright (c) 2001-2017 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 //
7 // --
8 //
9 // Some references about alpha compositing and blend modes:
10 //
11 //   http://dev.w3.org/fxtf/compositing-1/
12 //   http://www.adobe.com/devnet/pdf/pdf_reference.html
13 //
14 
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include "doc/blend_funcs.h"
20 
21 #include "base/base.h"
22 #include "base/debug.h"
23 #include "doc/blend_internals.h"
24 
25 #include <cmath>
26 
27 namespace  {
28 
29 #define blend_multiply(b, s, t)   (MUL_UN8((b), (s), (t)))
30 #define blend_screen(b, s, t)     ((b) + (s) - MUL_UN8((b), (s), (t)))
31 #define blend_overlay(b, s, t)    (blend_hard_light(s, b, t))
32 #define blend_darken(b, s)        (MIN((b), (s)))
33 #define blend_lighten(b, s)       (MAX((b), (s)))
34 #define blend_hard_light(b, s, t) ((s) < 128 ?                          \
35                                    blend_multiply((b), (s)<<1, (t)):    \
36                                    blend_screen((b), ((s)<<1)-255, (t)))
37 #define blend_difference(b, s)    (ABS((b) - (s)))
38 #define blend_exclusion(b, s, t)  ((t) = MUL_UN8((b), (s), (t)), ((b) + (s) - 2*(t)))
39 
blend_divide(uint32_t b,uint32_t s)40 inline uint32_t blend_divide(uint32_t b, uint32_t s)
41 {
42   if (b == 0)
43     return 0;
44   else if (b >= s)
45     return 255;
46   else
47     return DIV_UN8(b, s); // return b / s
48 }
49 
blend_color_dodge(uint32_t b,uint32_t s)50 inline uint32_t blend_color_dodge(uint32_t b, uint32_t s)
51 {
52   if (b == 0)
53     return 0;
54 
55   s = (255 - s);
56   if (b >= s)
57     return 255;
58   else
59     return DIV_UN8(b, s); // return b / (1-s)
60 }
61 
blend_color_burn(uint32_t b,uint32_t s)62 inline uint32_t blend_color_burn(uint32_t b, uint32_t s)
63 {
64   if (b == 255)
65     return 255;
66 
67   b = (255 - b);
68   if (b >= s)
69     return 0;
70   else
71     return 255 - DIV_UN8(b, s); // return 1 - ((1-b)/s)
72 }
73 
blend_soft_light(uint32_t _b,uint32_t _s)74 inline uint32_t blend_soft_light(uint32_t _b, uint32_t _s)
75 {
76   double b = _b / 255.0;
77   double s = _s / 255.0;
78   double r, d;
79 
80   if (b <= 0.25)
81     d = ((16*b-12)*b+4)*b;
82   else
83     d = std::sqrt(b);
84 
85   if (s <= 0.5)
86     r = b - (1.0 - 2.0 * s) * b * (1.0 - b);
87   else
88     r = b + (2.0 * s - 1.0) * (d - b);
89 
90   return (uint32_t)(r * 255 + 0.5);
91 }
92 
93 } // annonymous namespace
94 
95 namespace doc {
96 
97 //////////////////////////////////////////////////////////////////////
98 // RGB blenders
99 
rgba_blender_src(color_t backdrop,color_t src,int opacity)100 color_t rgba_blender_src(color_t backdrop, color_t src, int opacity)
101 {
102   return src;
103 }
104 
rgba_blender_merge(color_t backdrop,color_t src,int opacity)105 color_t rgba_blender_merge(color_t backdrop, color_t src, int opacity)
106 {
107   int Br, Bg, Bb, Ba;
108   int Sr, Sg, Sb, Sa;
109   int Rr, Rg, Rb, Ra;
110   int t;
111 
112   Br = rgba_getr(backdrop);
113   Bg = rgba_getg(backdrop);
114   Bb = rgba_getb(backdrop);
115   Ba = rgba_geta(backdrop);
116 
117   Sr = rgba_getr(src);
118   Sg = rgba_getg(src);
119   Sb = rgba_getb(src);
120   Sa = rgba_geta(src);
121 
122   if (Ba == 0) {
123     Rr = Sr;
124     Rg = Sg;
125     Rb = Sb;
126   }
127   else if (Sa == 0) {
128     Rr = Br;
129     Rg = Bg;
130     Rb = Bb;
131   }
132   else {
133     Rr = Br + MUL_UN8((Sr - Br), opacity, t);
134     Rg = Bg + MUL_UN8((Sg - Bg), opacity, t);
135     Rb = Bb + MUL_UN8((Sb - Bb), opacity, t);
136   }
137   Ra = Ba + MUL_UN8((Sa - Ba), opacity, t);
138   if (Ra == 0)
139     Rr = Rg = Rb = 0;
140 
141   return rgba(Rr, Rg, Rb, Ra);
142 }
143 
rgba_blender_neg_bw(color_t backdrop,color_t src,int opacity)144 color_t rgba_blender_neg_bw(color_t backdrop, color_t src, int opacity)
145 {
146   if (!(backdrop & rgba_a_mask))
147     return rgba(0, 0, 0, 255);
148   else if (rgba_luma(backdrop) < 128)
149     return rgba(255, 255, 255, 255);
150   else
151     return rgba(0, 0, 0, 255);
152 }
153 
rgba_blender_red_tint(color_t backdrop,color_t src,int opacity)154 color_t rgba_blender_red_tint(color_t backdrop, color_t src, int opacity)
155 {
156   int v = rgba_luma(src);
157   src = rgba((255+v)/2, v/2, v/2, rgba_geta(src));
158   return rgba_blender_normal(backdrop, src, opacity);
159 }
160 
rgba_blender_blue_tint(color_t backdrop,color_t src,int opacity)161 color_t rgba_blender_blue_tint(color_t backdrop, color_t src, int opacity)
162 {
163   int v = rgba_luma(src);
164   src = rgba(v/2, v/2, (255+v)/2, rgba_geta(src));
165   return rgba_blender_normal(backdrop, src, opacity);
166 }
167 
rgba_blender_normal(color_t backdrop,color_t src,int opacity)168 color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity)
169 {
170   int t;
171 
172   if ((backdrop & rgba_a_mask) == 0) {
173     int a = rgba_geta(src);
174     a = MUL_UN8(a, opacity, t);
175     a <<= rgba_a_shift;
176     return (src & rgba_rgb_mask) | a;
177   }
178   else if ((src & rgba_a_mask) == 0) {
179     return backdrop;
180   }
181 
182   const int Br = rgba_getr(backdrop);
183   const int Bg = rgba_getg(backdrop);
184   const int Bb = rgba_getb(backdrop);
185   const int Ba = rgba_geta(backdrop);
186 
187   const int Sr = rgba_getr(src);
188   const int Sg = rgba_getg(src);
189   const int Sb = rgba_getb(src);
190   int Sa = rgba_geta(src);
191   Sa = MUL_UN8(Sa, opacity, t);
192 
193   // Ra = Sa + Ba*(1-Sa)
194   //    = Sa + Ba - Ba*Sa
195   const int Ra = Sa + Ba - MUL_UN8(Ba, Sa, t);
196 
197   // Ra = Sa + Ba*(1-Sa)
198   // Ba = (Ra-Sa) / (1-Sa)
199   // Rc = (Sc*Sa + Bc*Ba*(1-Sa)) / Ra                Replacing Ba with (Ra-Sa) / (1-Sa)...
200   //    = (Sc*Sa + Bc*(Ra-Sa)/(1-Sa)*(1-Sa)) / Ra
201   //    = (Sc*Sa + Bc*(Ra-Sa)) / Ra
202   //    = Sc*Sa/Ra + Bc*Ra/Ra - Bc*Sa/Ra
203   //    = Sc*Sa/Ra + Bc - Bc*Sa/Ra
204   //    = Bc + (Sc-Bc)*Sa/Ra
205   const int Rr = Br + (Sr-Br) * Sa / Ra;
206   const int Rg = Bg + (Sg-Bg) * Sa / Ra;
207   const int Rb = Bb + (Sb-Bb) * Sa / Ra;
208 
209   return rgba(Rr, Rg, Rb, Ra);
210 }
211 
rgba_blender_multiply(color_t backdrop,color_t src,int opacity)212 color_t rgba_blender_multiply(color_t backdrop, color_t src, int opacity)
213 {
214   int t;
215   int r = blend_multiply(rgba_getr(backdrop), rgba_getr(src), t);
216   int g = blend_multiply(rgba_getg(backdrop), rgba_getg(src), t);
217   int b = blend_multiply(rgba_getb(backdrop), rgba_getb(src), t);
218   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
219   return rgba_blender_normal(backdrop, src, opacity);
220 }
221 
rgba_blender_screen(color_t backdrop,color_t src,int opacity)222 color_t rgba_blender_screen(color_t backdrop, color_t src, int opacity)
223 {
224   int t;
225   int r = blend_screen(rgba_getr(backdrop), rgba_getr(src), t);
226   int g = blend_screen(rgba_getg(backdrop), rgba_getg(src), t);
227   int b = blend_screen(rgba_getb(backdrop), rgba_getb(src), t);
228   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
229   return rgba_blender_normal(backdrop, src, opacity);
230 }
231 
rgba_blender_overlay(color_t backdrop,color_t src,int opacity)232 color_t rgba_blender_overlay(color_t backdrop, color_t src, int opacity)
233 {
234   int t;
235   int r = blend_overlay(rgba_getr(backdrop), rgba_getr(src), t);
236   int g = blend_overlay(rgba_getg(backdrop), rgba_getg(src), t);
237   int b = blend_overlay(rgba_getb(backdrop), rgba_getb(src), t);
238   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
239   return rgba_blender_normal(backdrop, src, opacity);
240 }
241 
rgba_blender_darken(color_t backdrop,color_t src,int opacity)242 color_t rgba_blender_darken(color_t backdrop, color_t src, int opacity)
243 {
244   int r = blend_darken(rgba_getr(backdrop), rgba_getr(src));
245   int g = blend_darken(rgba_getg(backdrop), rgba_getg(src));
246   int b = blend_darken(rgba_getb(backdrop), rgba_getb(src));
247   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
248   return rgba_blender_normal(backdrop, src, opacity);
249 }
250 
rgba_blender_lighten(color_t backdrop,color_t src,int opacity)251 color_t rgba_blender_lighten(color_t backdrop, color_t src, int opacity)
252 {
253   int r = blend_lighten(rgba_getr(backdrop), rgba_getr(src));
254   int g = blend_lighten(rgba_getg(backdrop), rgba_getg(src));
255   int b = blend_lighten(rgba_getb(backdrop), rgba_getb(src));
256   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
257   return rgba_blender_normal(backdrop, src, opacity);
258 }
259 
rgba_blender_color_dodge(color_t backdrop,color_t src,int opacity)260 color_t rgba_blender_color_dodge(color_t backdrop, color_t src, int opacity)
261 {
262   int r = blend_color_dodge(rgba_getr(backdrop), rgba_getr(src));
263   int g = blend_color_dodge(rgba_getg(backdrop), rgba_getg(src));
264   int b = blend_color_dodge(rgba_getb(backdrop), rgba_getb(src));
265   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
266   return rgba_blender_normal(backdrop, src, opacity);
267 }
268 
rgba_blender_color_burn(color_t backdrop,color_t src,int opacity)269 color_t rgba_blender_color_burn(color_t backdrop, color_t src, int opacity)
270 {
271   int r = blend_color_burn(rgba_getr(backdrop), rgba_getr(src));
272   int g = blend_color_burn(rgba_getg(backdrop), rgba_getg(src));
273   int b = blend_color_burn(rgba_getb(backdrop), rgba_getb(src));
274   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
275   return rgba_blender_normal(backdrop, src, opacity);
276 }
277 
rgba_blender_hard_light(color_t backdrop,color_t src,int opacity)278 color_t rgba_blender_hard_light(color_t backdrop, color_t src, int opacity)
279 {
280   int t;
281   int r = blend_hard_light(rgba_getr(backdrop), rgba_getr(src), t);
282   int g = blend_hard_light(rgba_getg(backdrop), rgba_getg(src), t);
283   int b = blend_hard_light(rgba_getb(backdrop), rgba_getb(src), t);
284   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
285   return rgba_blender_normal(backdrop, src, opacity);
286 }
287 
rgba_blender_soft_light(color_t backdrop,color_t src,int opacity)288 color_t rgba_blender_soft_light(color_t backdrop, color_t src, int opacity)
289 {
290   int r = blend_soft_light(rgba_getr(backdrop), rgba_getr(src));
291   int g = blend_soft_light(rgba_getg(backdrop), rgba_getg(src));
292   int b = blend_soft_light(rgba_getb(backdrop), rgba_getb(src));
293   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
294   return rgba_blender_normal(backdrop, src, opacity);
295 }
296 
rgba_blender_difference(color_t backdrop,color_t src,int opacity)297 color_t rgba_blender_difference(color_t backdrop, color_t src, int opacity)
298 {
299   int r = blend_difference(rgba_getr(backdrop), rgba_getr(src));
300   int g = blend_difference(rgba_getg(backdrop), rgba_getg(src));
301   int b = blend_difference(rgba_getb(backdrop), rgba_getb(src));
302   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
303   return rgba_blender_normal(backdrop, src, opacity);
304 }
305 
rgba_blender_exclusion(color_t backdrop,color_t src,int opacity)306 color_t rgba_blender_exclusion(color_t backdrop, color_t src, int opacity)
307 {
308   int t;
309   int r = blend_exclusion(rgba_getr(backdrop), rgba_getr(src), t);
310   int g = blend_exclusion(rgba_getg(backdrop), rgba_getg(src), t);
311   int b = blend_exclusion(rgba_getb(backdrop), rgba_getb(src), t);
312   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
313   return rgba_blender_normal(backdrop, src, opacity);
314 }
315 
316 //////////////////////////////////////////////////////////////////////
317 // HSV blenders
318 
lum(double r,double g,double b)319 static double lum(double r, double g, double b)
320 {
321   return 0.3*r + 0.59*g + 0.11*b;
322 }
323 
sat(double r,double g,double b)324 static double sat(double r, double g, double b)
325 {
326   return MAX(r, MAX(g, b)) - MIN(r, MIN(g, b));
327 }
328 
clip_color(double & r,double & g,double & b)329 static void clip_color(double& r, double& g, double& b)
330 {
331   double l = lum(r, g, b);
332   double n = MIN(r, MIN(g, b));
333   double x = MAX(r, MAX(g, b));
334 
335   if (n < 0) {
336     r = l + (((r - l) * l) / (l - n));
337     g = l + (((g - l) * l) / (l - n));
338     b = l + (((b - l) * l) / (l - n));
339   }
340 
341   if (x > 1) {
342     r = l + (((r - l) * (1 - l)) / (x - l));
343     g = l + (((g - l) * (1 - l)) / (x - l));
344     b = l + (((b - l) * (1 - l)) / (x - l));
345   }
346 }
347 
set_lum(double & r,double & g,double & b,double l)348 static void set_lum(double& r, double& g, double& b, double l)
349 {
350   double d = l - lum(r, g, b);
351   r += d;
352   g += d;
353   b += d;
354   clip_color(r, g, b);
355 }
356 
set_sat(double & r,double & g,double & b,double s)357 static void set_sat(double& r, double& g, double& b, double s)
358 {
359   double& min = MIN(r, MIN(g, b));
360   double& mid = MID(r, g, b);
361   double& max = MAX(r, MAX(g, b));
362 
363   if (max > min) {
364     mid = ((mid - min)*s) / (max - min);
365     max = s;
366   }
367   else
368     mid = max = 0;
369 
370   min = 0;
371 }
372 
rgba_blender_hsl_hue(color_t backdrop,color_t src,int opacity)373 color_t rgba_blender_hsl_hue(color_t backdrop, color_t src, int opacity)
374 {
375   double r = rgba_getr(backdrop)/255.0;
376   double g = rgba_getg(backdrop)/255.0;
377   double b = rgba_getb(backdrop)/255.0;
378   double s = sat(r, g, b);
379   double l = lum(r, g, b);
380 
381   r = rgba_getr(src)/255.0;
382   g = rgba_getg(src)/255.0;
383   b = rgba_getb(src)/255.0;
384 
385   set_sat(r, g, b, s);
386   set_lum(r, g, b, l);
387 
388   src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
389   return rgba_blender_normal(backdrop, src, opacity);
390 }
391 
rgba_blender_hsl_saturation(color_t backdrop,color_t src,int opacity)392 color_t rgba_blender_hsl_saturation(color_t backdrop, color_t src, int opacity)
393 {
394   double r = rgba_getr(src)/255.0;
395   double g = rgba_getg(src)/255.0;
396   double b = rgba_getb(src)/255.0;
397   double s = sat(r, g, b);
398 
399   r = rgba_getr(backdrop)/255.0;
400   g = rgba_getg(backdrop)/255.0;
401   b = rgba_getb(backdrop)/255.0;
402   double l = lum(r, g, b);
403 
404   set_sat(r, g, b, s);
405   set_lum(r, g, b, l);
406 
407   src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
408   return rgba_blender_normal(backdrop, src, opacity);
409 }
410 
rgba_blender_hsl_color(color_t backdrop,color_t src,int opacity)411 color_t rgba_blender_hsl_color(color_t backdrop, color_t src, int opacity)
412 {
413   double r = rgba_getr(backdrop)/255.0;
414   double g = rgba_getg(backdrop)/255.0;
415   double b = rgba_getb(backdrop)/255.0;
416   double l = lum(r, g, b);
417 
418   r = rgba_getr(src)/255.0;
419   g = rgba_getg(src)/255.0;
420   b = rgba_getb(src)/255.0;
421 
422   set_lum(r, g, b, l);
423 
424   src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
425   return rgba_blender_normal(backdrop, src, opacity);
426 }
427 
rgba_blender_hsl_luminosity(color_t backdrop,color_t src,int opacity)428 color_t rgba_blender_hsl_luminosity(color_t backdrop, color_t src, int opacity)
429 {
430   double r = rgba_getr(src)/255.0;
431   double g = rgba_getg(src)/255.0;
432   double b = rgba_getb(src)/255.0;
433   double l = lum(r, g, b);
434 
435   r = rgba_getr(backdrop)/255.0;
436   g = rgba_getg(backdrop)/255.0;
437   b = rgba_getb(backdrop)/255.0;
438 
439   set_lum(r, g, b, l);
440 
441   src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
442   return rgba_blender_normal(backdrop, src, opacity);
443 }
444 
rgba_blender_addition(color_t backdrop,color_t src,int opacity)445 color_t rgba_blender_addition(color_t backdrop, color_t src, int opacity)
446 {
447   int r = rgba_getr(backdrop) + rgba_getr(src);
448   int g = rgba_getg(backdrop) + rgba_getg(src);
449   int b = rgba_getb(backdrop) + rgba_getb(src);
450   src = rgba(MIN(r, 255), MIN(g, 255), MIN(b, 255), 0) | (src & rgba_a_mask);
451   return rgba_blender_normal(backdrop, src, opacity);
452 }
453 
rgba_blender_subtract(color_t backdrop,color_t src,int opacity)454 color_t rgba_blender_subtract(color_t backdrop, color_t src, int opacity)
455 {
456   int r = rgba_getr(backdrop) - rgba_getr(src);
457   int g = rgba_getg(backdrop) - rgba_getg(src);
458   int b = rgba_getb(backdrop) - rgba_getb(src);
459   src = rgba(MAX(r, 0), MAX(g, 0), MAX(b, 0), 0) | (src & rgba_a_mask);
460   return rgba_blender_normal(backdrop, src, opacity);
461 }
462 
rgba_blender_divide(color_t backdrop,color_t src,int opacity)463 color_t rgba_blender_divide(color_t backdrop, color_t src, int opacity)
464 {
465   int r = blend_divide(rgba_getr(backdrop), rgba_getr(src));
466   int g = blend_divide(rgba_getg(backdrop), rgba_getg(src));
467   int b = blend_divide(rgba_getb(backdrop), rgba_getb(src));
468   src = rgba(r, g, b, 0) | (src & rgba_a_mask);
469   return rgba_blender_normal(backdrop, src, opacity);
470 }
471 
472 //////////////////////////////////////////////////////////////////////
473 // GRAY blenders
474 
graya_blender_src(color_t backdrop,color_t src,int opacity)475 color_t graya_blender_src(color_t backdrop, color_t src, int opacity)
476 {
477   return src;
478 }
479 
graya_blender_merge(color_t backdrop,color_t src,int opacity)480 color_t graya_blender_merge(color_t backdrop, color_t src, int opacity)
481 {
482   int Bk, Ba;
483   int Sk, Sa;
484   int Rk, Ra;
485   int t;
486 
487   Bk = graya_getv(backdrop);
488   Ba = graya_geta(backdrop);
489 
490   Sk = graya_getv(src);
491   Sa = graya_geta(src);
492 
493   if (Ba == 0) {
494     Rk = Sk;
495   }
496   else if (Sa == 0) {
497     Rk = Bk;
498   }
499   else {
500     Rk = Bk + MUL_UN8((Sk-Bk), opacity, t);
501   }
502   Ra = Ba + MUL_UN8((Sa-Ba), opacity, t);
503   if (Ra == 0)
504     Rk = 0;
505 
506   return graya(Rk, Ra);
507 }
508 
graya_blender_neg_bw(color_t backdrop,color_t src,int opacity)509 color_t graya_blender_neg_bw(color_t backdrop, color_t src, int opacity)
510 {
511   if ((backdrop & graya_a_mask) == 0)
512     return src;
513   else if (graya_getv(backdrop) < 128)
514     return graya(255, 255);
515   else
516     return graya(0, 255);
517 }
518 
graya_blender_normal(color_t backdrop,color_t src,int opacity)519 color_t graya_blender_normal(color_t backdrop, color_t src, int opacity)
520 {
521   int t;
522 
523   if ((backdrop & graya_a_mask) == 0) {
524     int a = graya_geta(src);
525     a = MUL_UN8(a, opacity, t);
526     a <<= graya_a_shift;
527     return (src & 0xff) | a;
528   }
529   else if ((src & graya_a_mask) == 0)
530     return backdrop;
531 
532   int Bg, Ba;
533   int Sg, Sa;
534   int Rg, Ra;
535 
536   Bg = graya_getv(backdrop);
537   Ba = graya_geta(backdrop);
538 
539   Sg = graya_getv(src);
540   Sa = graya_geta(src);
541   Sa = MUL_UN8(Sa, opacity, t);
542 
543   Ra = Ba + Sa - MUL_UN8(Ba, Sa, t);
544   Rg = Bg + (Sg-Bg) * Sa / Ra;
545 
546   return graya(Rg, Ra);
547 }
548 
graya_blender_multiply(color_t backdrop,color_t src,int opacity)549 color_t graya_blender_multiply(color_t backdrop, color_t src, int opacity)
550 {
551   int t;
552   int v = blend_multiply(graya_getv(backdrop), graya_getv(src), t);
553   src = graya(v, 0) | (src & graya_a_mask);
554   return graya_blender_normal(backdrop, src, opacity);
555 }
556 
graya_blender_screen(color_t backdrop,color_t src,int opacity)557 color_t graya_blender_screen(color_t backdrop, color_t src, int opacity)
558 {
559   int t;
560   int v = blend_screen(graya_getv(backdrop), graya_getv(src), t);
561   src = graya(v, 0) | (src & graya_a_mask);
562   return graya_blender_normal(backdrop, src, opacity);
563 }
564 
graya_blender_overlay(color_t backdrop,color_t src,int opacity)565 color_t graya_blender_overlay(color_t backdrop, color_t src, int opacity)
566 {
567   int t;
568   int v = blend_overlay(graya_getv(backdrop), graya_getv(src), t);
569   src = graya(v, 0) | (src & graya_a_mask);
570   return graya_blender_normal(backdrop, src, opacity);
571 }
572 
graya_blender_darken(color_t backdrop,color_t src,int opacity)573 color_t graya_blender_darken(color_t backdrop, color_t src, int opacity)
574 {
575   int v = blend_darken(graya_getv(backdrop), graya_getv(src));
576   src = graya(v, 0) | (src & graya_a_mask);
577   return graya_blender_normal(backdrop, src, opacity);
578 }
579 
graya_blender_lighten(color_t backdrop,color_t src,int opacity)580 color_t graya_blender_lighten(color_t backdrop, color_t src, int opacity)
581 {
582   int v = blend_lighten(graya_getv(backdrop), graya_getv(src));
583   src = graya(v, 0) | (src & graya_a_mask);
584   return graya_blender_normal(backdrop, src, opacity);
585 }
586 
graya_blender_color_dodge(color_t backdrop,color_t src,int opacity)587 color_t graya_blender_color_dodge(color_t backdrop, color_t src, int opacity)
588 {
589   int v = blend_color_dodge(graya_getv(backdrop), graya_getv(src));
590   src = graya(v, 0) | (src & graya_a_mask);
591   return graya_blender_normal(backdrop, src, opacity);
592 }
593 
graya_blender_color_burn(color_t backdrop,color_t src,int opacity)594 color_t graya_blender_color_burn(color_t backdrop, color_t src, int opacity)
595 {
596   int v = blend_color_burn(graya_getv(backdrop), graya_getv(src));
597   src = graya(v, 0) | (src & graya_a_mask);
598   return graya_blender_normal(backdrop, src, opacity);
599 }
600 
graya_blender_hard_light(color_t backdrop,color_t src,int opacity)601 color_t graya_blender_hard_light(color_t backdrop, color_t src, int opacity)
602 {
603   int t;
604   int v = blend_hard_light(graya_getv(backdrop), graya_getv(src), t);
605   src = graya(v, 0) | (src & graya_a_mask);
606   return graya_blender_normal(backdrop, src, opacity);
607 }
608 
graya_blender_soft_light(color_t backdrop,color_t src,int opacity)609 color_t graya_blender_soft_light(color_t backdrop, color_t src, int opacity)
610 {
611   int v = blend_soft_light(graya_getv(backdrop), graya_getv(src));
612   src = graya(v, 0) | (src & graya_a_mask);
613   return graya_blender_normal(backdrop, src, opacity);
614 }
615 
graya_blender_difference(color_t backdrop,color_t src,int opacity)616 color_t graya_blender_difference(color_t backdrop, color_t src, int opacity)
617 {
618   int v = blend_difference(graya_getv(backdrop), graya_getv(src));
619   src = graya(v, 0) | (src & graya_a_mask);
620   return graya_blender_normal(backdrop, src, opacity);
621 }
622 
graya_blender_exclusion(color_t backdrop,color_t src,int opacity)623 color_t graya_blender_exclusion(color_t backdrop, color_t src, int opacity)
624 {
625   int t;
626   int v = blend_exclusion(graya_getv(backdrop), graya_getv(src), t);
627   src = graya(v, 0) | (src & graya_a_mask);
628   return graya_blender_normal(backdrop, src, opacity);
629 }
630 
graya_blender_addition(color_t backdrop,color_t src,int opacity)631 color_t graya_blender_addition(color_t backdrop, color_t src, int opacity)
632 {
633   int v = graya_getv(backdrop) + graya_getv(src);
634   src = graya(MIN(v, 255), 0) | (src & graya_a_mask);
635   return graya_blender_normal(backdrop, src, opacity);
636 }
637 
graya_blender_subtract(color_t backdrop,color_t src,int opacity)638 color_t graya_blender_subtract(color_t backdrop, color_t src, int opacity)
639 {
640   int v = graya_getv(backdrop) - graya_getv(src);
641   src = graya(MAX(v, 0), 0) | (src & graya_a_mask);
642   return graya_blender_normal(backdrop, src, opacity);
643 }
644 
graya_blender_divide(color_t backdrop,color_t src,int opacity)645 color_t graya_blender_divide(color_t backdrop, color_t src, int opacity)
646 {
647   int v = blend_divide(graya_getv(backdrop), graya_getv(src));
648   src = graya(v, 0) | (src & graya_a_mask);
649   return graya_blender_normal(backdrop, src, opacity);
650 }
651 
652 //////////////////////////////////////////////////////////////////////
653 // indexed
654 
indexed_blender_src(color_t dst,color_t src,int opacity)655 color_t indexed_blender_src(color_t dst, color_t src, int opacity)
656 {
657   return src;
658 }
659 
660 //////////////////////////////////////////////////////////////////////
661 // getters
662 
get_rgba_blender(BlendMode blendmode)663 BlendFunc get_rgba_blender(BlendMode blendmode)
664 {
665   switch (blendmode) {
666     case BlendMode::SRC:            return rgba_blender_src;
667     case BlendMode::MERGE:          return rgba_blender_merge;
668     case BlendMode::NEG_BW:         return rgba_blender_neg_bw;
669     case BlendMode::RED_TINT:       return rgba_blender_red_tint;
670     case BlendMode::BLUE_TINT:      return rgba_blender_blue_tint;
671 
672     case BlendMode::NORMAL:         return rgba_blender_normal;
673     case BlendMode::MULTIPLY:       return rgba_blender_multiply;
674     case BlendMode::SCREEN:         return rgba_blender_screen;
675     case BlendMode::OVERLAY:        return rgba_blender_overlay;
676     case BlendMode::DARKEN:         return rgba_blender_darken;
677     case BlendMode::LIGHTEN:        return rgba_blender_lighten;
678     case BlendMode::COLOR_DODGE:    return rgba_blender_color_dodge;
679     case BlendMode::COLOR_BURN:     return rgba_blender_color_burn;
680     case BlendMode::HARD_LIGHT:     return rgba_blender_hard_light;
681     case BlendMode::SOFT_LIGHT:     return rgba_blender_soft_light;
682     case BlendMode::DIFFERENCE:     return rgba_blender_difference;
683     case BlendMode::EXCLUSION:      return rgba_blender_exclusion;
684     case BlendMode::HSL_HUE:        return rgba_blender_hsl_hue;
685     case BlendMode::HSL_SATURATION: return rgba_blender_hsl_saturation;
686     case BlendMode::HSL_COLOR:      return rgba_blender_hsl_color;
687     case BlendMode::HSL_LUMINOSITY: return rgba_blender_hsl_luminosity;
688     case BlendMode::ADDITION:       return rgba_blender_addition;
689     case BlendMode::SUBTRACT:       return rgba_blender_subtract;
690     case BlendMode::DIVIDE:         return rgba_blender_divide;
691   }
692   ASSERT(false);
693   return rgba_blender_src;
694 }
695 
get_graya_blender(BlendMode blendmode)696 BlendFunc get_graya_blender(BlendMode blendmode)
697 {
698   switch (blendmode) {
699     case BlendMode::SRC:            return graya_blender_src;
700     case BlendMode::MERGE:          return graya_blender_merge;
701     case BlendMode::NEG_BW:         return graya_blender_neg_bw;
702     case BlendMode::RED_TINT:       return graya_blender_normal;
703     case BlendMode::BLUE_TINT:      return graya_blender_normal;
704 
705     case BlendMode::NORMAL:         return graya_blender_normal;
706     case BlendMode::MULTIPLY:       return graya_blender_multiply;
707     case BlendMode::SCREEN:         return graya_blender_screen;
708     case BlendMode::OVERLAY:        return graya_blender_overlay;
709     case BlendMode::DARKEN:         return graya_blender_darken;
710     case BlendMode::LIGHTEN:        return graya_blender_lighten;
711     case BlendMode::COLOR_DODGE:    return graya_blender_color_dodge;
712     case BlendMode::COLOR_BURN:     return graya_blender_color_burn;
713     case BlendMode::HARD_LIGHT:     return graya_blender_hard_light;
714     case BlendMode::SOFT_LIGHT:     return graya_blender_soft_light;
715     case BlendMode::DIFFERENCE:     return graya_blender_difference;
716     case BlendMode::EXCLUSION:      return graya_blender_exclusion;
717     case BlendMode::HSL_HUE:        return graya_blender_normal;
718     case BlendMode::HSL_SATURATION: return graya_blender_normal;
719     case BlendMode::HSL_COLOR:      return graya_blender_normal;
720     case BlendMode::HSL_LUMINOSITY: return graya_blender_normal;
721     case BlendMode::ADDITION:       return graya_blender_addition;
722     case BlendMode::SUBTRACT:       return graya_blender_subtract;
723     case BlendMode::DIVIDE:         return graya_blender_divide;
724   }
725   ASSERT(false);
726   return graya_blender_src;
727 }
728 
get_indexed_blender(BlendMode blendmode)729 BlendFunc get_indexed_blender(BlendMode blendmode)
730 {
731   return indexed_blender_src;
732 }
733 
734 } // namespace doc
735