1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // Adaptation for high precision colors has been sponsored by
17 // Liberty Technology Systems, Inc., visit http://lib-sys.com
18 //
19 // Liberty Technology Systems, Inc. is the provider of
20 // PostScript and PDF technology for software developers.
21 //
22 //----------------------------------------------------------------------------
23 
24 #ifndef AGG_PIXFMT_RGBA_INCLUDED
25 #define AGG_PIXFMT_RGBA_INCLUDED
26 
27 #include <string.h>
28 #include <math.h>
29 #include "agg_pixfmt_base.h"
30 #include "agg_rendering_buffer.h"
31 
32 namespace agg
33 {
sd_min(T a,T b)34     template<class T> inline T sd_min(T a, T b) { return (a < b) ? a : b; }
sd_max(T a,T b)35     template<class T> inline T sd_max(T a, T b) { return (a > b) ? a : b; }
36 
clip(rgba & c)37     inline rgba & clip(rgba & c)
38     {
39         if (c.a > 1) c.a = 1; else if (c.a < 0) c.a = 0;
40         if (c.r > c.a) c.r = c.a; else if (c.r < 0) c.r = 0;
41         if (c.g > c.a) c.g = c.a; else if (c.g < 0) c.g = 0;
42         if (c.b > c.a) c.b = c.a; else if (c.b < 0) c.b = 0;
43         return c;
44     }
45 
46     //=========================================================multiplier_rgba
47     template<class ColorT, class Order>
48     struct multiplier_rgba
49     {
50         typedef ColorT color_type;
51         typedef typename color_type::value_type value_type;
52 
53         //--------------------------------------------------------------------
premultiplymultiplier_rgba54         static AGG_INLINE void premultiply(value_type* p)
55         {
56             value_type a = p[Order::A];
57             p[Order::R] = color_type::multiply(p[Order::R], a);
58             p[Order::G] = color_type::multiply(p[Order::G], a);
59             p[Order::B] = color_type::multiply(p[Order::B], a);
60         }
61 
62 
63         //--------------------------------------------------------------------
demultiplymultiplier_rgba64         static AGG_INLINE void demultiply(value_type* p)
65         {
66             value_type a = p[Order::A];
67             p[Order::R] = color_type::demultiply(p[Order::R], a);
68             p[Order::G] = color_type::demultiply(p[Order::G], a);
69             p[Order::B] = color_type::demultiply(p[Order::B], a);
70         }
71     };
72 
73     //=====================================================apply_gamma_dir_rgba
74     template<class ColorT, class Order, class GammaLut>
75     class apply_gamma_dir_rgba
76     {
77     public:
78         typedef ColorT color_type;
79         typedef typename color_type::value_type value_type;
80 
apply_gamma_dir_rgba(const GammaLut & gamma)81         apply_gamma_dir_rgba(const GammaLut& gamma) : m_gamma(gamma) {}
82 
operator()83         AGG_INLINE void operator () (value_type* p)
84         {
85             p[Order::R] = m_gamma.dir(p[Order::R]);
86             p[Order::G] = m_gamma.dir(p[Order::G]);
87             p[Order::B] = m_gamma.dir(p[Order::B]);
88         }
89 
90     private:
91         const GammaLut& m_gamma;
92     };
93 
94     //=====================================================apply_gamma_inv_rgba
95     template<class ColorT, class Order, class GammaLut> class apply_gamma_inv_rgba
96     {
97     public:
98         typedef ColorT color_type;
99         typedef typename color_type::value_type value_type;
100 
apply_gamma_inv_rgba(const GammaLut & gamma)101         apply_gamma_inv_rgba(const GammaLut& gamma) : m_gamma(gamma) {}
102 
operator()103         AGG_INLINE void operator () (value_type* p)
104         {
105             p[Order::R] = m_gamma.inv(p[Order::R]);
106             p[Order::G] = m_gamma.inv(p[Order::G]);
107             p[Order::B] = m_gamma.inv(p[Order::B]);
108         }
109 
110     private:
111         const GammaLut& m_gamma;
112     };
113 
114 
115     template<class ColorT, class Order>
116     struct conv_rgba_pre
117     {
118         typedef ColorT color_type;
119         typedef Order order_type;
120         typedef typename color_type::value_type value_type;
121 
122         //--------------------------------------------------------------------
set_plain_colorconv_rgba_pre123         static AGG_INLINE void set_plain_color(value_type* p, color_type c)
124         {
125             c.premultiply();
126             p[Order::R] = c.r;
127             p[Order::G] = c.g;
128             p[Order::B] = c.b;
129             p[Order::A] = c.a;
130         }
131 
132         //--------------------------------------------------------------------
get_plain_colorconv_rgba_pre133         static AGG_INLINE color_type get_plain_color(const value_type* p)
134         {
135             return color_type(
136                 p[Order::R],
137                 p[Order::G],
138                 p[Order::B],
139                 p[Order::A]).demultiply();
140         }
141     };
142 
143     template<class ColorT, class Order>
144     struct conv_rgba_plain
145     {
146         typedef ColorT color_type;
147         typedef Order order_type;
148         typedef typename color_type::value_type value_type;
149 
150         //--------------------------------------------------------------------
set_plain_colorconv_rgba_plain151         static AGG_INLINE void set_plain_color(value_type* p, color_type c)
152         {
153             p[Order::R] = c.r;
154             p[Order::G] = c.g;
155             p[Order::B] = c.b;
156             p[Order::A] = c.a;
157         }
158 
159         //--------------------------------------------------------------------
get_plain_colorconv_rgba_plain160         static AGG_INLINE color_type get_plain_color(const value_type* p)
161         {
162             return color_type(
163                 p[Order::R],
164                 p[Order::G],
165                 p[Order::B],
166                 p[Order::A]);
167         }
168     };
169 
170     //=============================================================blender_rgba
171     // Blends "plain" (i.e. non-premultiplied) colors into a premultiplied buffer.
172     template<class ColorT, class Order>
173     struct blender_rgba : conv_rgba_pre<ColorT, Order>
174     {
175         typedef ColorT color_type;
176         typedef Order order_type;
177         typedef typename color_type::value_type value_type;
178         typedef typename color_type::calc_type calc_type;
179         typedef typename color_type::long_type long_type;
180 
181         // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
182         // compositing function. Since the render buffer is in fact premultiplied
183         // we omit the initial premultiplication and final demultiplication.
184 
185         //--------------------------------------------------------------------
blend_pixblender_rgba186         static AGG_INLINE void blend_pix(value_type* p,
187             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
188         {
189             blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
190         }
191 
192         //--------------------------------------------------------------------
blend_pixblender_rgba193         static AGG_INLINE void blend_pix(value_type* p,
194             value_type cr, value_type cg, value_type cb, value_type alpha)
195         {
196             p[Order::R] = color_type::lerp(p[Order::R], cr, alpha);
197             p[Order::G] = color_type::lerp(p[Order::G], cg, alpha);
198             p[Order::B] = color_type::lerp(p[Order::B], cb, alpha);
199             p[Order::A] = color_type::prelerp(p[Order::A], alpha, alpha);
200         }
201     };
202 
203 
204     //========================================================blender_rgba_pre
205     // Blends premultiplied colors into a premultiplied buffer.
206     template<class ColorT, class Order>
207     struct blender_rgba_pre : conv_rgba_pre<ColorT, Order>
208     {
209         typedef ColorT color_type;
210         typedef Order order_type;
211         typedef typename color_type::value_type value_type;
212         typedef typename color_type::calc_type calc_type;
213         typedef typename color_type::long_type long_type;
214 
215         // Blend pixels using the premultiplied form of Alvy-Ray Smith's
216         // compositing function.
217 
218         //--------------------------------------------------------------------
blend_pixblender_rgba_pre219         static AGG_INLINE void blend_pix(value_type* p,
220             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
221         {
222             blend_pix(p,
223                 color_type::mult_cover(cr, cover),
224                 color_type::mult_cover(cg, cover),
225                 color_type::mult_cover(cb, cover),
226                 color_type::mult_cover(alpha, cover));
227         }
228 
229         //--------------------------------------------------------------------
blend_pixblender_rgba_pre230         static AGG_INLINE void blend_pix(value_type* p,
231             value_type cr, value_type cg, value_type cb, value_type alpha)
232         {
233             p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha);
234             p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha);
235             p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha);
236             p[Order::A] = color_type::prelerp(p[Order::A], alpha, alpha);
237         }
238     };
239 
240     //======================================================blender_rgba_plain
241     // Blends "plain" (non-premultiplied) colors into a plain (non-premultiplied) buffer.
242     template<class ColorT, class Order>
243     struct blender_rgba_plain : conv_rgba_plain<ColorT, Order>
244     {
245         typedef ColorT color_type;
246         typedef Order order_type;
247         typedef typename color_type::value_type value_type;
248         typedef typename color_type::calc_type calc_type;
249         typedef typename color_type::long_type long_type;
250 
251         // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
252         // compositing function.
253 
254         //--------------------------------------------------------------------
blend_pixblender_rgba_plain255         static AGG_INLINE void blend_pix(value_type* p,
256             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
257         {
258             blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
259         }
260 
261         //--------------------------------------------------------------------
blend_pixblender_rgba_plain262         static AGG_INLINE void blend_pix(value_type* p,
263             value_type cr, value_type cg, value_type cb, value_type alpha)
264         {
265             if (alpha > color_type::empty_value())
266             {
267                 calc_type a = p[Order::A];
268                 calc_type r = color_type::multiply(p[Order::R], a);
269                 calc_type g = color_type::multiply(p[Order::G], a);
270                 calc_type b = color_type::multiply(p[Order::B], a);
271                 p[Order::R] = color_type::lerp(r, cr, alpha);
272                 p[Order::G] = color_type::lerp(g, cg, alpha);
273                 p[Order::B] = color_type::lerp(b, cb, alpha);
274                 p[Order::A] = color_type::prelerp(a, alpha, alpha);
275                 multiplier_rgba<ColorT, Order>::demultiply(p);
276             }
277         }
278     };
279 
280     // SVG compositing operations.
281     // For specifications, see http://www.w3.org/TR/SVGCompositing/
282 
283     //=========================================================comp_op_rgba_clear
284     template<class ColorT, class Order>
285     struct comp_op_rgba_clear : blender_base<ColorT, Order>
286     {
287         typedef ColorT color_type;
288         typedef typename color_type::value_type value_type;
289         using blender_base<ColorT, Order>::get;
290         using blender_base<ColorT, Order>::set;
291 
292         // Dca' = 0
293         // Da'  = 0
blend_pixcomp_op_rgba_clear294         static AGG_INLINE void blend_pix(value_type* p,
295             value_type r, value_type g, value_type b, value_type a, cover_type cover)
296         {
297             if (cover >= cover_full)
298             {
299                 p[0] = p[1] = p[2] = p[3] = color_type::empty_value();
300             }
301             else if (cover > cover_none)
302             {
303                 set(p, get(p, cover_full - cover));
304             }
305         }
306     };
307 
308     //===========================================================comp_op_rgba_src
309     template<class ColorT, class Order>
310     struct comp_op_rgba_src : blender_base<ColorT, Order>
311     {
312         typedef ColorT color_type;
313         typedef typename color_type::value_type value_type;
314         using blender_base<ColorT, Order>::get;
315         using blender_base<ColorT, Order>::set;
316 
317         // Dca' = Sca
318         // Da'  = Sa
blend_pixcomp_op_rgba_src319         static AGG_INLINE void blend_pix(value_type* p,
320             value_type r, value_type g, value_type b, value_type a, cover_type cover)
321         {
322             if (cover >= cover_full)
323             {
324                 set(p, r, g, b, a);
325             }
326             else
327             {
328                 rgba s = get(r, g, b, a, cover);
329                 rgba d = get(p, cover_full - cover);
330                 d.r += s.r;
331                 d.g += s.g;
332                 d.b += s.b;
333                 d.a += s.a;
334                 set(p, d);
335             }
336         }
337     };
338 
339     //===========================================================comp_op_rgba_dst
340     template<class ColorT, class Order>
341     struct comp_op_rgba_dst : blender_base<ColorT, Order>
342     {
343         typedef ColorT color_type;
344         typedef typename color_type::value_type value_type;
345 
346         // Dca' = Dca.Sa + Dca.(1 - Sa) = Dca
347         // Da'  = Da.Sa + Da.(1 - Sa) = Da
blend_pixcomp_op_rgba_dst348         static AGG_INLINE void blend_pix(value_type* p,
349             value_type r, value_type g, value_type b, value_type a, cover_type cover)
350         {
351             // Well, that was easy!
352         }
353     };
354 
355     //======================================================comp_op_rgba_src_over
356     template<class ColorT, class Order>
357     struct comp_op_rgba_src_over : blender_base<ColorT, Order>
358     {
359         typedef ColorT color_type;
360         typedef typename color_type::value_type value_type;
361         using blender_base<ColorT, Order>::get;
362         using blender_base<ColorT, Order>::set;
363 
364         // Dca' = Sca + Dca.(1 - Sa) = Dca + Sca - Dca.Sa
365         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_src_over366         static AGG_INLINE void blend_pix(value_type* p,
367             value_type r, value_type g, value_type b, value_type a, cover_type cover)
368         {
369 #if 1
370             blender_rgba_pre<ColorT, Order>::blend_pix(p, r, g, b, a, cover);
371 #else
372             rgba s = get(r, g, b, a, cover);
373             rgba d = get(p);
374             d.r += s.r - d.r * s.a;
375             d.g += s.g - d.g * s.a;
376             d.b += s.b - d.b * s.a;
377             d.a += s.a - d.a * s.a;
378             set(p, d);
379 #endif
380         }
381     };
382 
383     //======================================================comp_op_rgba_dst_over
384     template<class ColorT, class Order>
385     struct comp_op_rgba_dst_over : blender_base<ColorT, Order>
386     {
387         typedef ColorT color_type;
388         typedef typename color_type::value_type value_type;
389         using blender_base<ColorT, Order>::get;
390         using blender_base<ColorT, Order>::set;
391 
392         // Dca' = Dca + Sca.(1 - Da)
393         // Da'  = Sa + Da - Sa.Da = Da + Sa.(1 - Da)
blend_pixcomp_op_rgba_dst_over394         static AGG_INLINE void blend_pix(value_type* p,
395             value_type r, value_type g, value_type b, value_type a, cover_type cover)
396         {
397             rgba s = get(r, g, b, a, cover);
398             rgba d = get(p);
399             double d1a = 1 - d.a;
400             d.r += s.r * d1a;
401             d.g += s.g * d1a;
402             d.b += s.b * d1a;
403             d.a += s.a * d1a;
404             set(p, d);
405         }
406     };
407 
408     //======================================================comp_op_rgba_src_in
409     template<class ColorT, class Order>
410     struct comp_op_rgba_src_in : blender_base<ColorT, Order>
411     {
412         typedef ColorT color_type;
413         typedef typename color_type::value_type value_type;
414         using blender_base<ColorT, Order>::get;
415         using blender_base<ColorT, Order>::set;
416 
417         // Dca' = Sca.Da
418         // Da'  = Sa.Da
blend_pixcomp_op_rgba_src_in419         static AGG_INLINE void blend_pix(value_type* p,
420             value_type r, value_type g, value_type b, value_type a, cover_type cover)
421         {
422             double da = ColorT::to_double(p[Order::A]);
423             if (da > 0)
424             {
425                 rgba s = get(r, g, b, a, cover);
426                 rgba d = get(p, cover_full - cover);
427                 d.r += s.r * da;
428                 d.g += s.g * da;
429                 d.b += s.b * da;
430                 d.a += s.a * da;
431                 set(p, d);
432             }
433         }
434     };
435 
436     //======================================================comp_op_rgba_dst_in
437     template<class ColorT, class Order>
438     struct comp_op_rgba_dst_in : blender_base<ColorT, Order>
439     {
440         typedef ColorT color_type;
441         typedef typename color_type::value_type value_type;
442         using blender_base<ColorT, Order>::get;
443         using blender_base<ColorT, Order>::set;
444 
445         // Dca' = Dca.Sa
446         // Da'  = Sa.Da
blend_pixcomp_op_rgba_dst_in447         static AGG_INLINE void blend_pix(value_type* p,
448             value_type r, value_type g, value_type b, value_type a, cover_type cover)
449         {
450             double sa = ColorT::to_double(a);
451             rgba d = get(p, cover_full - cover);
452             rgba d2 = get(p, cover);
453             d.r += d2.r * sa;
454             d.g += d2.g * sa;
455             d.b += d2.b * sa;
456             d.a += d2.a * sa;
457             set(p, d);
458         }
459     };
460 
461     //======================================================comp_op_rgba_src_out
462     template<class ColorT, class Order>
463     struct comp_op_rgba_src_out : blender_base<ColorT, Order>
464     {
465         typedef ColorT color_type;
466         typedef typename color_type::value_type value_type;
467         using blender_base<ColorT, Order>::get;
468         using blender_base<ColorT, Order>::set;
469 
470         // Dca' = Sca.(1 - Da)
471         // Da'  = Sa.(1 - Da)
blend_pixcomp_op_rgba_src_out472         static AGG_INLINE void blend_pix(value_type* p,
473             value_type r, value_type g, value_type b, value_type a, cover_type cover)
474         {
475             rgba s = get(r, g, b, a, cover);
476             rgba d = get(p, cover_full - cover);
477             double d1a = 1 - ColorT::to_double(p[Order::A]);
478             d.r += s.r * d1a;
479             d.g += s.g * d1a;
480             d.b += s.b * d1a;
481             d.a += s.a * d1a;
482             set(p, d);
483         }
484     };
485 
486     //======================================================comp_op_rgba_dst_out
487     template<class ColorT, class Order>
488     struct comp_op_rgba_dst_out : blender_base<ColorT, Order>
489     {
490         typedef ColorT color_type;
491         typedef typename color_type::value_type value_type;
492         using blender_base<ColorT, Order>::get;
493         using blender_base<ColorT, Order>::set;
494 
495         // Dca' = Dca.(1 - Sa)
496         // Da'  = Da.(1 - Sa)
blend_pixcomp_op_rgba_dst_out497         static AGG_INLINE void blend_pix(value_type* p,
498             value_type r, value_type g, value_type b, value_type a, cover_type cover)
499         {
500             rgba d = get(p, cover_full - cover);
501             rgba dc = get(p, cover);
502             double s1a = 1 - ColorT::to_double(a);
503             d.r += dc.r * s1a;
504             d.g += dc.g * s1a;
505             d.b += dc.b * s1a;
506             d.a += dc.a * s1a;
507             set(p, d);
508         }
509     };
510 
511     //=====================================================comp_op_rgba_src_atop
512     template<class ColorT, class Order>
513     struct comp_op_rgba_src_atop : blender_base<ColorT, Order>
514     {
515         typedef ColorT color_type;
516         typedef typename color_type::value_type value_type;
517         using blender_base<ColorT, Order>::get;
518         using blender_base<ColorT, Order>::set;
519 
520         // Dca' = Sca.Da + Dca.(1 - Sa)
521         // Da'  = Da
blend_pixcomp_op_rgba_src_atop522         static AGG_INLINE void blend_pix(value_type* p,
523             value_type r, value_type g, value_type b, value_type a, cover_type cover)
524         {
525             rgba s = get(r, g, b, a, cover);
526             rgba d = get(p);
527             double s1a = 1 - s.a;
528             d.r = s.r * d.a + d.r * s1a;
529             d.g = s.g * d.a + d.g * s1a;
530             d.b = s.b * d.a + d.g * s1a;
531             set(p, d);
532         }
533     };
534 
535     //=====================================================comp_op_rgba_dst_atop
536     template<class ColorT, class Order>
537     struct comp_op_rgba_dst_atop : blender_base<ColorT, Order>
538     {
539         typedef ColorT color_type;
540         typedef typename color_type::value_type value_type;
541         using blender_base<ColorT, Order>::get;
542         using blender_base<ColorT, Order>::set;
543 
544         // Dca' = Dca.Sa + Sca.(1 - Da)
545         // Da'  = Sa
blend_pixcomp_op_rgba_dst_atop546         static AGG_INLINE void blend_pix(value_type* p,
547             value_type r, value_type g, value_type b, value_type a, cover_type cover)
548         {
549             rgba sc = get(r, g, b, a, cover);
550             rgba dc = get(p, cover);
551             rgba d = get(p, cover_full - cover);
552             double sa = ColorT::to_double(a);
553             double d1a = 1 - ColorT::to_double(p[Order::A]);
554             d.r += dc.r * sa + sc.r * d1a;
555             d.g += dc.g * sa + sc.g * d1a;
556             d.b += dc.b * sa + sc.b * d1a;
557             d.a += sc.a;
558             set(p, d);
559         }
560     };
561 
562     //=========================================================comp_op_rgba_xor
563     template<class ColorT, class Order>
564     struct comp_op_rgba_xor : blender_base<ColorT, Order>
565     {
566         typedef ColorT color_type;
567         typedef typename color_type::value_type value_type;
568         using blender_base<ColorT, Order>::get;
569         using blender_base<ColorT, Order>::set;
570 
571         // Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
572         // Da'  = Sa + Da - 2.Sa.Da
blend_pixcomp_op_rgba_xor573         static AGG_INLINE void blend_pix(value_type* p,
574             value_type r, value_type g, value_type b, value_type a, cover_type cover)
575         {
576             rgba s = get(r, g, b, a, cover);
577             rgba d = get(p);
578             double s1a = 1 - s.a;
579             double d1a = 1 - ColorT::to_double(p[Order::A]);
580             d.r = s.r * d1a + d.r * s1a;
581             d.g = s.g * d1a + d.g * s1a;
582             d.b = s.b * d1a + d.b * s1a;
583             d.a = s.a + d.a - 2 * s.a * d.a;
584             set(p, d);
585         }
586     };
587 
588     //=========================================================comp_op_rgba_plus
589     template<class ColorT, class Order>
590     struct comp_op_rgba_plus : blender_base<ColorT, Order>
591     {
592         typedef ColorT color_type;
593         typedef typename color_type::value_type value_type;
594         using blender_base<ColorT, Order>::get;
595         using blender_base<ColorT, Order>::set;
596 
597         // Dca' = Sca + Dca
598         // Da'  = Sa + Da
blend_pixcomp_op_rgba_plus599         static AGG_INLINE void blend_pix(value_type* p,
600             value_type r, value_type g, value_type b, value_type a, cover_type cover)
601         {
602             rgba s = get(r, g, b, a, cover);
603             if (s.a > 0)
604             {
605                 rgba d = get(p);
606                 d.a = sd_min(d.a + s.a, 1.0);
607                 d.r = sd_min(d.r + s.r, d.a);
608                 d.g = sd_min(d.g + s.g, d.a);
609                 d.b = sd_min(d.b + s.b, d.a);
610                 set(p, clip(d));
611             }
612         }
613     };
614 
615     //========================================================comp_op_rgba_minus
616     // Note: not included in SVG spec.
617     template<class ColorT, class Order>
618     struct comp_op_rgba_minus : blender_base<ColorT, Order>
619     {
620         typedef ColorT color_type;
621         typedef typename color_type::value_type value_type;
622         using blender_base<ColorT, Order>::get;
623         using blender_base<ColorT, Order>::set;
624 
625         // Dca' = Dca - Sca
626         // Da' = 1 - (1 - Sa).(1 - Da) = Da + Sa - Sa.Da
blend_pixcomp_op_rgba_minus627         static AGG_INLINE void blend_pix(value_type* p,
628             value_type r, value_type g, value_type b, value_type a, cover_type cover)
629         {
630             rgba s = get(r, g, b, a, cover);
631             if (s.a > 0)
632             {
633                 rgba d = get(p);
634                 d.a += s.a - s.a * d.a;
635                 d.r = sd_max(d.r - s.r, 0.0);
636                 d.g = sd_max(d.g - s.g, 0.0);
637                 d.b = sd_max(d.b - s.b, 0.0);
638                 set(p, clip(d));
639             }
640         }
641     };
642 
643     //=====================================================comp_op_rgba_multiply
644     template<class ColorT, class Order>
645     struct comp_op_rgba_multiply : blender_base<ColorT, Order>
646     {
647         typedef ColorT color_type;
648         typedef typename color_type::value_type value_type;
649         using blender_base<ColorT, Order>::get;
650         using blender_base<ColorT, Order>::set;
651 
652         // Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
653         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_multiply654         static AGG_INLINE void blend_pix(value_type* p,
655             value_type r, value_type g, value_type b, value_type a, cover_type cover)
656         {
657             rgba s = get(r, g, b, a, cover);
658             if (s.a > 0)
659             {
660                 rgba d = get(p);
661                 double s1a = 1 - s.a;
662                 double d1a = 1 - d.a;
663                 d.r = s.r * d.r + s.r * d1a + d.r * s1a;
664                 d.g = s.g * d.g + s.g * d1a + d.g * s1a;
665                 d.b = s.b * d.b + s.b * d1a + d.b * s1a;
666                 d.a += s.a - s.a * d.a;
667                 set(p, clip(d));
668             }
669         }
670     };
671 
672     //=====================================================comp_op_rgba_screen
673     template<class ColorT, class Order>
674     struct comp_op_rgba_screen : blender_base<ColorT, Order>
675     {
676         typedef ColorT color_type;
677         typedef typename color_type::value_type value_type;
678         using blender_base<ColorT, Order>::get;
679         using blender_base<ColorT, Order>::set;
680 
681         // Dca' = Sca + Dca - Sca.Dca
682         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_screen683         static AGG_INLINE void blend_pix(value_type* p,
684             value_type r, value_type g, value_type b, value_type a, cover_type cover)
685         {
686             rgba s = get(r, g, b, a, cover);
687             if (s.a > 0)
688             {
689                 rgba d = get(p);
690                 d.r += s.r - s.r * d.r;
691                 d.g += s.g - s.g * d.g;
692                 d.b += s.b - s.b * d.b;
693                 d.a += s.a - s.a * d.a;
694                 set(p, clip(d));
695             }
696         }
697     };
698 
699     //=====================================================comp_op_rgba_overlay
700     template<class ColorT, class Order>
701     struct comp_op_rgba_overlay : blender_base<ColorT, Order>
702     {
703         typedef ColorT color_type;
704         typedef typename color_type::value_type value_type;
705         using blender_base<ColorT, Order>::get;
706         using blender_base<ColorT, Order>::set;
707 
708         // if 2.Dca <= Da
709         //   Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
710         // otherwise
711         //   Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
712         //
713         // Da' = Sa + Da - Sa.Da
calccomp_op_rgba_overlay714         static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a)
715         {
716             return (2 * dca <= da) ?
717                 2 * sca * dca + sca * d1a + dca * s1a :
718                 sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a;
719         }
720 
blend_pixcomp_op_rgba_overlay721         static AGG_INLINE void blend_pix(value_type* p,
722             value_type r, value_type g, value_type b, value_type a, cover_type cover)
723         {
724             rgba s = get(r, g, b, a, cover);
725             if (s.a > 0)
726             {
727                 rgba d = get(p);
728                 double d1a = 1 - d.a;
729                 double s1a = 1 - s.a;
730                 double sada = s.a * d.a;
731                 d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a);
732                 d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a);
733                 d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a);
734                 d.a += s.a - s.a * d.a;
735                 set(p, clip(d));
736             }
737         }
738     };
739 
740     //=====================================================comp_op_rgba_darken
741     template<class ColorT, class Order>
742     struct comp_op_rgba_darken : blender_base<ColorT, Order>
743     {
744         typedef ColorT color_type;
745         typedef typename color_type::value_type value_type;
746         using blender_base<ColorT, Order>::get;
747         using blender_base<ColorT, Order>::set;
748 
749         // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
750         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_darken751         static AGG_INLINE void blend_pix(value_type* p,
752             value_type r, value_type g, value_type b, value_type a, cover_type cover)
753         {
754             rgba s = get(r, g, b, a, cover);
755             if (s.a > 0)
756             {
757                 rgba d = get(p);
758                 double d1a = 1 - d.a;
759                 double s1a = 1 - s.a;
760                 d.r = sd_min(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a;
761                 d.g = sd_min(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a;
762                 d.b = sd_min(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a;
763                 d.a += s.a - s.a * d.a;
764                 set(p, clip(d));
765             }
766         }
767     };
768 
769     //=====================================================comp_op_rgba_lighten
770     template<class ColorT, class Order>
771     struct comp_op_rgba_lighten : blender_base<ColorT, Order>
772     {
773         typedef ColorT color_type;
774         typedef typename color_type::value_type value_type;
775         using blender_base<ColorT, Order>::get;
776         using blender_base<ColorT, Order>::set;
777 
778         // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
779         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_lighten780         static AGG_INLINE void blend_pix(value_type* p,
781             value_type r, value_type g, value_type b, value_type a, cover_type cover)
782         {
783             rgba s = get(r, g, b, a, cover);
784             if (s.a > 0)
785             {
786                 rgba d = get(p);
787                 double d1a = 1 - d.a;
788                 double s1a = 1 - s.a;
789                 d.r = sd_max(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a;
790                 d.g = sd_max(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a;
791                 d.b = sd_max(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a;
792                 d.a += s.a - s.a * d.a;
793                 set(p, clip(d));
794             }
795         }
796     };
797 
798     //=====================================================comp_op_rgba_color_dodge
799     template<class ColorT, class Order>
800     struct comp_op_rgba_color_dodge : blender_base<ColorT, Order>
801     {
802         typedef ColorT color_type;
803         typedef typename color_type::value_type value_type;
804         using blender_base<ColorT, Order>::get;
805         using blender_base<ColorT, Order>::set;
806 
807         // if Sca == Sa and Dca == 0
808         //     Dca' = Sca.(1 - Da) + Dca.(1 - Sa) = Sca.(1 - Da)
809         // otherwise if Sca == Sa
810         //     Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
811         // otherwise if Sca < Sa
812         //     Dca' = Sa.Da.min(1, Dca/Da.Sa/(Sa - Sca)) + Sca.(1 - Da) + Dca.(1 - Sa)
813         //
814         // Da'  = Sa + Da - Sa.Da
calccomp_op_rgba_color_dodge815         static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a)
816         {
817             if (sca < sa) return sada * sd_min(1.0, (dca / da) * sa / (sa - sca)) + sca * d1a + dca * s1a;
818             if (dca > 0) return sada + sca * d1a + dca * s1a;
819             return sca * d1a;
820         }
821 
blend_pixcomp_op_rgba_color_dodge822         static AGG_INLINE void blend_pix(value_type* p,
823             value_type r, value_type g, value_type b, value_type a, cover_type cover)
824         {
825             rgba s = get(r, g, b, a, cover);
826             if (s.a > 0)
827             {
828                 rgba d = get(p);
829                 if (d.a > 0)
830                 {
831                     double sada = s.a * d.a;
832                     double s1a = 1 - s.a;
833                     double d1a = 1 - d.a;
834                     d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a);
835                     d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a);
836                     d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a);
837                     d.a += s.a - s.a * d.a;
838                     set(p, clip(d));
839                 }
840                 else set(p, s);
841             }
842         }
843     };
844 
845     //=====================================================comp_op_rgba_color_burn
846     template<class ColorT, class Order>
847     struct comp_op_rgba_color_burn : blender_base<ColorT, Order>
848     {
849         typedef ColorT color_type;
850         typedef typename color_type::value_type value_type;
851         using blender_base<ColorT, Order>::get;
852         using blender_base<ColorT, Order>::set;
853 
854         // if Sca == 0 and Dca == Da
855         //   Dca' = Sa.Da + Dca.(1 - Sa)
856         // otherwise if Sca == 0
857         //   Dca' = Dca.(1 - Sa)
858         // otherwise if Sca > 0
859         //   Dca' =  Sa.Da.(1 - min(1, (1 - Dca/Da).Sa/Sca)) + Sca.(1 - Da) + Dca.(1 - Sa)
calccomp_op_rgba_color_burn860         static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a)
861         {
862             if (sca > 0) return sada * (1 - sd_min(1.0, (1 - dca / da) * sa / sca)) + sca * d1a + dca * s1a;
863             if (dca > da) return sada + dca * s1a;
864             return dca * s1a;
865         }
866 
blend_pixcomp_op_rgba_color_burn867         static AGG_INLINE void blend_pix(value_type* p,
868             value_type r, value_type g, value_type b, value_type a, cover_type cover)
869         {
870             rgba s = get(r, g, b, a, cover);
871             if (s.a > 0)
872             {
873                 rgba d = get(p);
874                 if (d.a > 0)
875                 {
876                     double sada = s.a * d.a;
877                     double s1a = 1 - s.a;
878                     double d1a = 1 - d.a;
879                     d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a);
880                     d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a);
881                     d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a);
882                     d.a += s.a - sada;
883                     set(p, clip(d));
884                 }
885                 else set(p, s);
886             }
887         }
888     };
889 
890     //=====================================================comp_op_rgba_hard_light
891     template<class ColorT, class Order>
892     struct comp_op_rgba_hard_light : blender_base<ColorT, Order>
893     {
894         typedef ColorT color_type;
895         typedef typename color_type::value_type value_type;
896         using blender_base<ColorT, Order>::get;
897         using blender_base<ColorT, Order>::set;
898 
899         // if 2.Sca < Sa
900         //    Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
901         // otherwise
902         //    Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
903         //
904         // Da'  = Sa + Da - Sa.Da
calccomp_op_rgba_hard_light905         static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a)
906         {
907             return (2 * sca < sa) ?
908                 2 * sca * dca + sca * d1a + dca * s1a :
909                 sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a;
910         }
911 
blend_pixcomp_op_rgba_hard_light912         static AGG_INLINE void blend_pix(value_type* p,
913             value_type r, value_type g, value_type b, value_type a, cover_type cover)
914         {
915             rgba s = get(r, g, b, a, cover);
916             if (s.a > 0)
917             {
918                 rgba d = get(p);
919                 double d1a = 1 - d.a;
920                 double s1a = 1 - s.a;
921                 double sada = s.a * d.a;
922                 d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a);
923                 d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a);
924                 d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a);
925                 d.a += s.a - sada;
926                 set(p, clip(d));
927             }
928         }
929     };
930 
931     //=====================================================comp_op_rgba_soft_light
932     template<class ColorT, class Order>
933     struct comp_op_rgba_soft_light : blender_base<ColorT, Order>
934     {
935         typedef ColorT color_type;
936         typedef typename color_type::value_type value_type;
937         using blender_base<ColorT, Order>::get;
938         using blender_base<ColorT, Order>::set;
939 
940         // if 2.Sca <= Sa
941         //   Dca' = Dca.Sa - (Sa.Da - 2.Sca.Da).Dca.Sa.(Sa.Da - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
942         // otherwise if 2.Sca > Sa and 4.Dca <= Da
943         //   Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((((16.Dsa.Sa - 12).Dsa.Sa + 4).Dsa.Da) - Dsa.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
944         // otherwise if 2.Sca > Sa and 4.Dca > Da
945         //   Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((Dca.Sa)^0.5 - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
946         //
947         // Da'  = Sa + Da - Sa.Da
calccomp_op_rgba_soft_light948         static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a)
949         {
950             double dcasa = dca * sa;
951             if (2 * sca <= sa) return dcasa - (sada - 2 * sca * da) * dcasa * (sada - dcasa) + sca * d1a + dca * s1a;
952             if (4 * dca <= da) return dcasa + (2 * sca * da - sada) * ((((16 * dcasa - 12) * dcasa + 4) * dca * da) - dca * da) + sca * d1a + dca * s1a;
953             return dcasa + (2 * sca * da - sada) * (sqrt(dcasa) - dcasa) + sca * d1a + dca * s1a;
954         }
955 
blend_pixcomp_op_rgba_soft_light956         static AGG_INLINE void blend_pix(value_type* p,
957             value_type r, value_type g, value_type b, value_type a, cover_type cover)
958         {
959             rgba s = get(r, g, b, a, cover);
960             if (s.a > 0)
961             {
962                 rgba d = get(p);
963                 if (d.a > 0)
964                 {
965                     double sada = s.a * d.a;
966                     double s1a = 1 - s.a;
967                     double d1a = 1 - d.a;
968                     d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a);
969                     d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a);
970                     d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a);
971                     d.a += s.a - sada;
972                     set(p, clip(d));
973                 }
974                 else set(p, s);
975             }
976         }
977     };
978 
979     //=====================================================comp_op_rgba_difference
980     template<class ColorT, class Order>
981     struct comp_op_rgba_difference : blender_base<ColorT, Order>
982     {
983         typedef ColorT color_type;
984         typedef typename color_type::value_type value_type;
985         using blender_base<ColorT, Order>::get;
986         using blender_base<ColorT, Order>::set;
987 
988         // Dca' = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
989         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_difference990         static AGG_INLINE void blend_pix(value_type* p,
991             value_type r, value_type g, value_type b, value_type a, cover_type cover)
992         {
993             rgba s = get(r, g, b, a, cover);
994             if (s.a > 0)
995             {
996                 rgba d = get(p);
997                 d.r += s.r - 2 * sd_min(s.r * d.a, d.r * s.a);
998                 d.g += s.g - 2 * sd_min(s.g * d.a, d.g * s.a);
999                 d.b += s.b - 2 * sd_min(s.b * d.a, d.b * s.a);
1000                 d.a += s.a - s.a * d.a;
1001                 set(p, clip(d));
1002             }
1003         }
1004     };
1005 
1006     //=====================================================comp_op_rgba_exclusion
1007     template<class ColorT, class Order>
1008     struct comp_op_rgba_exclusion : blender_base<ColorT, Order>
1009     {
1010         typedef ColorT color_type;
1011         typedef typename color_type::value_type value_type;
1012         using blender_base<ColorT, Order>::get;
1013         using blender_base<ColorT, Order>::set;
1014 
1015         // Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
1016         // Da'  = Sa + Da - Sa.Da
blend_pixcomp_op_rgba_exclusion1017         static AGG_INLINE void blend_pix(value_type* p,
1018             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1019         {
1020             rgba s = get(r, g, b, a, cover);
1021             if (s.a > 0)
1022             {
1023                 rgba d = get(p);
1024                 double d1a = 1 - d.a;
1025                 double s1a = 1 - s.a;
1026                 d.r = (s.r * d.a + d.r * s.a - 2 * s.r * d.r) + s.r * d1a + d.r * s1a;
1027                 d.g = (s.g * d.a + d.g * s.a - 2 * s.g * d.g) + s.g * d1a + d.g * s1a;
1028                 d.b = (s.b * d.a + d.b * s.a - 2 * s.b * d.b) + s.b * d1a + d.b * s1a;
1029                 d.a += s.a - s.a * d.a;
1030                 set(p, clip(d));
1031             }
1032         }
1033     };
1034 
1035 #if 0
1036     //=====================================================comp_op_rgba_contrast
1037     template<class ColorT, class Order> struct comp_op_rgba_contrast
1038     {
1039         typedef ColorT color_type;
1040         typedef Order order_type;
1041         typedef typename color_type::value_type value_type;
1042         typedef typename color_type::calc_type calc_type;
1043         typedef typename color_type::long_type long_type;
1044         enum base_scale_e
1045         {
1046             base_shift = color_type::base_shift,
1047             base_mask  = color_type::base_mask
1048         };
1049 
1050 
1051         static AGG_INLINE void blend_pix(value_type* p,
1052                                          unsigned sr, unsigned sg, unsigned sb,
1053                                          unsigned sa, unsigned cover)
1054         {
1055             if (cover < 255)
1056             {
1057                 sr = (sr * cover + 255) >> 8;
1058                 sg = (sg * cover + 255) >> 8;
1059                 sb = (sb * cover + 255) >> 8;
1060                 sa = (sa * cover + 255) >> 8;
1061             }
1062             long_type dr = p[Order::R];
1063             long_type dg = p[Order::G];
1064             long_type db = p[Order::B];
1065             int       da = p[Order::A];
1066             long_type d2a = da >> 1;
1067             unsigned s2a = sa >> 1;
1068 
1069             int r = (int)((((dr - d2a) * int((sr - s2a)*2 + base_mask)) >> base_shift) + d2a);
1070             int g = (int)((((dg - d2a) * int((sg - s2a)*2 + base_mask)) >> base_shift) + d2a);
1071             int b = (int)((((db - d2a) * int((sb - s2a)*2 + base_mask)) >> base_shift) + d2a);
1072 
1073             r = (r < 0) ? 0 : r;
1074             g = (g < 0) ? 0 : g;
1075             b = (b < 0) ? 0 : b;
1076 
1077             p[Order::R] = (value_type)((r > da) ? da : r);
1078             p[Order::G] = (value_type)((g > da) ? da : g);
1079             p[Order::B] = (value_type)((b > da) ? da : b);
1080         }
1081     };
1082 
1083     //=====================================================comp_op_rgba_invert
1084     template<class ColorT, class Order> struct comp_op_rgba_invert
1085     {
1086         typedef ColorT color_type;
1087         typedef Order order_type;
1088         typedef typename color_type::value_type value_type;
1089         typedef typename color_type::calc_type calc_type;
1090         typedef typename color_type::long_type long_type;
1091         enum base_scale_e
1092         {
1093             base_shift = color_type::base_shift,
1094             base_mask  = color_type::base_mask
1095         };
1096 
1097         // Dca' = (Da - Dca) * Sa + Dca.(1 - Sa)
1098         // Da'  = Sa + Da - Sa.Da
1099         static AGG_INLINE void blend_pix(value_type* p,
1100                                          unsigned sr, unsigned sg, unsigned sb,
1101                                          unsigned sa, unsigned cover)
1102         {
1103             sa = (sa * cover + 255) >> 8;
1104             if (sa)
1105             {
1106                 calc_type da = p[Order::A];
1107                 calc_type dr = ((da - p[Order::R]) * sa + base_mask) >> base_shift;
1108                 calc_type dg = ((da - p[Order::G]) * sa + base_mask) >> base_shift;
1109                 calc_type db = ((da - p[Order::B]) * sa + base_mask) >> base_shift;
1110                 calc_type s1a = base_mask - sa;
1111                 p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift));
1112                 p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift));
1113                 p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift));
1114                 p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
1115             }
1116         }
1117     };
1118 
1119     //=================================================comp_op_rgba_invert_rgb
1120     template<class ColorT, class Order> struct comp_op_rgba_invert_rgb
1121     {
1122         typedef ColorT color_type;
1123         typedef Order order_type;
1124         typedef typename color_type::value_type value_type;
1125         typedef typename color_type::calc_type calc_type;
1126         typedef typename color_type::long_type long_type;
1127         enum base_scale_e
1128         {
1129             base_shift = color_type::base_shift,
1130             base_mask  = color_type::base_mask
1131         };
1132 
1133         // Dca' = (Da - Dca) * Sca + Dca.(1 - Sa)
1134         // Da'  = Sa + Da - Sa.Da
1135         static AGG_INLINE void blend_pix(value_type* p,
1136                                          unsigned sr, unsigned sg, unsigned sb,
1137                                          unsigned sa, unsigned cover)
1138         {
1139             if (cover < 255)
1140             {
1141                 sr = (sr * cover + 255) >> 8;
1142                 sg = (sg * cover + 255) >> 8;
1143                 sb = (sb * cover + 255) >> 8;
1144                 sa = (sa * cover + 255) >> 8;
1145             }
1146             if (sa)
1147             {
1148                 calc_type da = p[Order::A];
1149                 calc_type dr = ((da - p[Order::R]) * sr + base_mask) >> base_shift;
1150                 calc_type dg = ((da - p[Order::G]) * sg + base_mask) >> base_shift;
1151                 calc_type db = ((da - p[Order::B]) * sb + base_mask) >> base_shift;
1152                 calc_type s1a = base_mask - sa;
1153                 p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift));
1154                 p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift));
1155                 p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift));
1156                 p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
1157             }
1158         }
1159     };
1160 #endif
1161 
1162 
1163     //======================================================comp_op_table_rgba
1164     template<class ColorT, class Order> struct comp_op_table_rgba
1165     {
1166         typedef typename ColorT::value_type value_type;
1167         typedef typename ColorT::calc_type calc_type;
1168         typedef void (*comp_op_func_type)(value_type* p,
1169                                           value_type cr,
1170                                           value_type cg,
1171                                           value_type cb,
1172                                           value_type ca,
1173                                           cover_type cover);
1174         static comp_op_func_type g_comp_op_func[];
1175     };
1176 
1177     //==========================================================g_comp_op_func
1178     template<class ColorT, class Order>
1179     typename comp_op_table_rgba<ColorT, Order>::comp_op_func_type
1180     comp_op_table_rgba<ColorT, Order>::g_comp_op_func[] =
1181     {
1182         comp_op_rgba_clear      <ColorT,Order>::blend_pix,
1183         comp_op_rgba_src        <ColorT,Order>::blend_pix,
1184         comp_op_rgba_dst        <ColorT,Order>::blend_pix,
1185         comp_op_rgba_src_over   <ColorT,Order>::blend_pix,
1186         comp_op_rgba_dst_over   <ColorT,Order>::blend_pix,
1187         comp_op_rgba_src_in     <ColorT,Order>::blend_pix,
1188         comp_op_rgba_dst_in     <ColorT,Order>::blend_pix,
1189         comp_op_rgba_src_out    <ColorT,Order>::blend_pix,
1190         comp_op_rgba_dst_out    <ColorT,Order>::blend_pix,
1191         comp_op_rgba_src_atop   <ColorT,Order>::blend_pix,
1192         comp_op_rgba_dst_atop   <ColorT,Order>::blend_pix,
1193         comp_op_rgba_xor        <ColorT,Order>::blend_pix,
1194         comp_op_rgba_plus       <ColorT,Order>::blend_pix,
1195         //comp_op_rgba_minus      <ColorT,Order>::blend_pix,
1196         comp_op_rgba_multiply   <ColorT,Order>::blend_pix,
1197         comp_op_rgba_screen     <ColorT,Order>::blend_pix,
1198         comp_op_rgba_overlay    <ColorT,Order>::blend_pix,
1199         comp_op_rgba_darken     <ColorT,Order>::blend_pix,
1200         comp_op_rgba_lighten    <ColorT,Order>::blend_pix,
1201         comp_op_rgba_color_dodge<ColorT,Order>::blend_pix,
1202         comp_op_rgba_color_burn <ColorT,Order>::blend_pix,
1203         comp_op_rgba_hard_light <ColorT,Order>::blend_pix,
1204         comp_op_rgba_soft_light <ColorT,Order>::blend_pix,
1205         comp_op_rgba_difference <ColorT,Order>::blend_pix,
1206         comp_op_rgba_exclusion  <ColorT,Order>::blend_pix,
1207         //comp_op_rgba_contrast   <ColorT,Order>::blend_pix,
1208         //comp_op_rgba_invert     <ColorT,Order>::blend_pix,
1209         //comp_op_rgba_invert_rgb <ColorT,Order>::blend_pix,
1210         0
1211     };
1212 
1213 
1214     //==============================================================comp_op_e
1215     enum comp_op_e
1216     {
1217         comp_op_clear,         //----comp_op_clear
1218         comp_op_src,           //----comp_op_src
1219         comp_op_dst,           //----comp_op_dst
1220         comp_op_src_over,      //----comp_op_src_over
1221         comp_op_dst_over,      //----comp_op_dst_over
1222         comp_op_src_in,        //----comp_op_src_in
1223         comp_op_dst_in,        //----comp_op_dst_in
1224         comp_op_src_out,       //----comp_op_src_out
1225         comp_op_dst_out,       //----comp_op_dst_out
1226         comp_op_src_atop,      //----comp_op_src_atop
1227         comp_op_dst_atop,      //----comp_op_dst_atop
1228         comp_op_xor,           //----comp_op_xor
1229         comp_op_plus,          //----comp_op_plus
1230         //comp_op_minus,         //----comp_op_minus
1231         comp_op_multiply,      //----comp_op_multiply
1232         comp_op_screen,        //----comp_op_screen
1233         comp_op_overlay,       //----comp_op_overlay
1234         comp_op_darken,        //----comp_op_darken
1235         comp_op_lighten,       //----comp_op_lighten
1236         comp_op_color_dodge,   //----comp_op_color_dodge
1237         comp_op_color_burn,    //----comp_op_color_burn
1238         comp_op_hard_light,    //----comp_op_hard_light
1239         comp_op_soft_light,    //----comp_op_soft_light
1240         comp_op_difference,    //----comp_op_difference
1241         comp_op_exclusion,     //----comp_op_exclusion
1242         //comp_op_contrast,      //----comp_op_contrast
1243         //comp_op_invert,        //----comp_op_invert
1244         //comp_op_invert_rgb,    //----comp_op_invert_rgb
1245 
1246         end_of_comp_op_e
1247     };
1248 
1249 
1250 
1251 
1252 
1253 
1254 
1255     //====================================================comp_op_adaptor_rgba
1256     template<class ColorT, class Order>
1257     struct comp_op_adaptor_rgba
1258     {
1259         typedef ColorT color_type;
1260         typedef Order order_type;
1261         typedef typename color_type::value_type value_type;
1262         typedef typename color_type::calc_type calc_type;
1263         typedef typename color_type::long_type long_type;
1264 
blend_pixcomp_op_adaptor_rgba1265         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1266             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1267         {
1268             comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op](p,
1269                 color_type::multiply(r, a),
1270                 color_type::multiply(g, a),
1271                 color_type::multiply(b, a),
1272                 a, cover);
1273         }
1274     };
1275 
1276     //=========================================comp_op_adaptor_clip_to_dst_rgba
1277     template<class ColorT, class Order>
1278     struct comp_op_adaptor_clip_to_dst_rgba
1279     {
1280         typedef ColorT color_type;
1281         typedef Order order_type;
1282         typedef typename color_type::value_type value_type;
1283         typedef typename color_type::calc_type calc_type;
1284         typedef typename color_type::long_type long_type;
1285 
blend_pixcomp_op_adaptor_clip_to_dst_rgba1286         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1287             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1288         {
1289             r = color_type::multiply(r, a);
1290             g = color_type::multiply(g, a);
1291             b = color_type::multiply(b, a);
1292             value_type da = p[Order::A];
1293             comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op](p,
1294                 color_type::multiply(r, da),
1295                 color_type::multiply(g, da),
1296                 color_type::multiply(b, da),
1297                 color_type::multiply(a, da), cover);
1298         }
1299     };
1300 
1301     //================================================comp_op_adaptor_rgba_pre
1302     template<class ColorT, class Order>
1303     struct comp_op_adaptor_rgba_pre
1304     {
1305         typedef ColorT color_type;
1306         typedef Order order_type;
1307         typedef typename color_type::value_type value_type;
1308         typedef typename color_type::calc_type calc_type;
1309         typedef typename color_type::long_type long_type;
1310 
blend_pixcomp_op_adaptor_rgba_pre1311         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1312             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1313         {
1314             comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op](p, r, g, b, a, cover);
1315         }
1316     };
1317 
1318     //=====================================comp_op_adaptor_clip_to_dst_rgba_pre
1319     template<class ColorT, class Order>
1320     struct comp_op_adaptor_clip_to_dst_rgba_pre
1321     {
1322         typedef ColorT color_type;
1323         typedef Order order_type;
1324         typedef typename color_type::value_type value_type;
1325         typedef typename color_type::calc_type calc_type;
1326         typedef typename color_type::long_type long_type;
1327 
blend_pixcomp_op_adaptor_clip_to_dst_rgba_pre1328         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1329             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1330         {
1331             value_type da = p[Order::A];
1332             comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op](p,
1333                 color_type::multiply(r, da),
1334                 color_type::multiply(g, da),
1335                 color_type::multiply(b, da),
1336                 color_type::multiply(a, da), cover);
1337         }
1338     };
1339 
1340     //====================================================comp_op_adaptor_rgba_plain
1341     template<class ColorT, class Order>
1342     struct comp_op_adaptor_rgba_plain
1343     {
1344         typedef ColorT color_type;
1345         typedef Order order_type;
1346         typedef typename color_type::value_type value_type;
1347         typedef typename color_type::calc_type calc_type;
1348         typedef typename color_type::long_type long_type;
1349 
blend_pixcomp_op_adaptor_rgba_plain1350         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1351             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1352         {
1353             multiplier_rgba<ColorT, Order>::premultiply(p);
1354             comp_op_adaptor_rgba<ColorT, Order>::blend_pix(op, p, r, g, b, a, cover);
1355             multiplier_rgba<ColorT, Order>::demultiply(p);
1356         }
1357     };
1358 
1359     //=========================================comp_op_adaptor_clip_to_dst_rgba_plain
1360     template<class ColorT, class Order>
1361     struct comp_op_adaptor_clip_to_dst_rgba_plain
1362     {
1363         typedef ColorT color_type;
1364         typedef Order order_type;
1365         typedef typename color_type::value_type value_type;
1366         typedef typename color_type::calc_type calc_type;
1367         typedef typename color_type::long_type long_type;
1368 
blend_pixcomp_op_adaptor_clip_to_dst_rgba_plain1369         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1370             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1371         {
1372             multiplier_rgba<ColorT, Order>::premultiply(p);
1373             comp_op_adaptor_clip_to_dst_rgba<ColorT, Order>::blend_pix(op, p, r, g, b, a, cover);
1374             multiplier_rgba<ColorT, Order>::demultiply(p);
1375         }
1376     };
1377 
1378     //=======================================================comp_adaptor_rgba
1379     template<class BlenderPre>
1380     struct comp_adaptor_rgba
1381     {
1382         typedef typename BlenderPre::color_type color_type;
1383         typedef typename BlenderPre::order_type order_type;
1384         typedef typename color_type::value_type value_type;
1385         typedef typename color_type::calc_type calc_type;
1386         typedef typename color_type::long_type long_type;
1387 
blend_pixcomp_adaptor_rgba1388         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1389             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1390         {
1391             BlenderPre::blend_pix(p,
1392                 color_type::multiply(r, a),
1393                 color_type::multiply(g, a),
1394                 color_type::multiply(b, a),
1395                 a, cover);
1396         }
1397     };
1398 
1399     //==========================================comp_adaptor_clip_to_dst_rgba
1400     template<class BlenderPre>
1401     struct comp_adaptor_clip_to_dst_rgba
1402     {
1403         typedef typename BlenderPre::color_type color_type;
1404         typedef typename BlenderPre::order_type order_type;
1405         typedef typename color_type::value_type value_type;
1406         typedef typename color_type::calc_type calc_type;
1407         typedef typename color_type::long_type long_type;
1408 
blend_pixcomp_adaptor_clip_to_dst_rgba1409         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1410             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1411         {
1412             r = color_type::multiply(r, a);
1413             g = color_type::multiply(g, a);
1414             b = color_type::multiply(b, a);
1415             value_type da = p[order_type::A];
1416             BlenderPre::blend_pix(p,
1417                 color_type::multiply(r, da),
1418                 color_type::multiply(g, da),
1419                 color_type::multiply(b, da),
1420                 color_type::multiply(a, da), cover);
1421         }
1422     };
1423 
1424     //=======================================================comp_adaptor_rgba_pre
1425     template<class BlenderPre>
1426     struct comp_adaptor_rgba_pre
1427     {
1428         typedef typename BlenderPre::color_type color_type;
1429         typedef typename BlenderPre::order_type order_type;
1430         typedef typename color_type::value_type value_type;
1431         typedef typename color_type::calc_type calc_type;
1432         typedef typename color_type::long_type long_type;
1433 
blend_pixcomp_adaptor_rgba_pre1434         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1435             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1436         {
1437             BlenderPre::blend_pix(p, r, g, b, a, cover);
1438         }
1439     };
1440 
1441     //======================================comp_adaptor_clip_to_dst_rgba_pre
1442     template<class BlenderPre>
1443     struct comp_adaptor_clip_to_dst_rgba_pre
1444     {
1445         typedef typename BlenderPre::color_type color_type;
1446         typedef typename BlenderPre::order_type order_type;
1447         typedef typename color_type::value_type value_type;
1448         typedef typename color_type::calc_type calc_type;
1449         typedef typename color_type::long_type long_type;
1450 
blend_pixcomp_adaptor_clip_to_dst_rgba_pre1451         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1452             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1453         {
1454             unsigned da = p[order_type::A];
1455             BlenderPre::blend_pix(p,
1456                 color_type::multiply(r, da),
1457                 color_type::multiply(g, da),
1458                 color_type::multiply(b, da),
1459                 color_type::multiply(a, da),
1460                 cover);
1461         }
1462     };
1463 
1464     //=======================================================comp_adaptor_rgba_plain
1465     template<class BlenderPre>
1466     struct comp_adaptor_rgba_plain
1467     {
1468         typedef typename BlenderPre::color_type color_type;
1469         typedef typename BlenderPre::order_type order_type;
1470         typedef typename color_type::value_type value_type;
1471         typedef typename color_type::calc_type calc_type;
1472         typedef typename color_type::long_type long_type;
1473 
blend_pixcomp_adaptor_rgba_plain1474         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1475             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1476         {
1477             multiplier_rgba<color_type, order_type>::premultiply(p);
1478             comp_adaptor_rgba<BlenderPre>::blend_pix(op, p, r, g, b, a, cover);
1479             multiplier_rgba<color_type, order_type>::demultiply(p);
1480         }
1481     };
1482 
1483     //==========================================comp_adaptor_clip_to_dst_rgba_plain
1484     template<class BlenderPre>
1485     struct comp_adaptor_clip_to_dst_rgba_plain
1486     {
1487         typedef typename BlenderPre::color_type color_type;
1488         typedef typename BlenderPre::order_type order_type;
1489         typedef typename color_type::value_type value_type;
1490         typedef typename color_type::calc_type calc_type;
1491         typedef typename color_type::long_type long_type;
1492 
blend_pixcomp_adaptor_clip_to_dst_rgba_plain1493         static AGG_INLINE void blend_pix(unsigned op, value_type* p,
1494             value_type r, value_type g, value_type b, value_type a, cover_type cover)
1495         {
1496             multiplier_rgba<color_type, order_type>::premultiply(p);
1497             comp_adaptor_clip_to_dst_rgba<BlenderPre>::blend_pix(op, p, r, g, b, a, cover);
1498             multiplier_rgba<color_type, order_type>::demultiply(p);
1499         }
1500     };
1501 
1502 
1503     //=================================================pixfmt_alpha_blend_rgba
1504     template<class Blender, class RenBuf>
1505     class pixfmt_alpha_blend_rgba
1506     {
1507     public:
1508         typedef pixfmt_rgba_tag pixfmt_category;
1509         typedef RenBuf   rbuf_type;
1510         typedef typename rbuf_type::row_data row_data;
1511         typedef Blender  blender_type;
1512         typedef typename blender_type::color_type color_type;
1513         typedef typename blender_type::order_type order_type;
1514         typedef typename color_type::value_type value_type;
1515         typedef typename color_type::calc_type calc_type;
1516         enum
1517         {
1518             pix_step = 4,
1519             pix_width = sizeof(value_type) * pix_step,
1520         };
1521         struct pixel_type
1522         {
1523             value_type c[pix_step];
1524 
setpixel_type1525             void set(value_type r, value_type g, value_type b, value_type a)
1526             {
1527                 c[order_type::R] = r;
1528                 c[order_type::G] = g;
1529                 c[order_type::B] = b;
1530                 c[order_type::A] = a;
1531             }
1532 
setpixel_type1533             void set(const color_type& color)
1534             {
1535                 set(color.r, color.g, color.b, color.a);
1536             }
1537 
getpixel_type1538             void get(value_type& r, value_type& g, value_type& b, value_type& a) const
1539             {
1540                 r = c[order_type::R];
1541                 g = c[order_type::G];
1542                 b = c[order_type::B];
1543                 a = c[order_type::A];
1544             }
1545 
getpixel_type1546             color_type get() const
1547             {
1548                 return color_type(
1549                     c[order_type::R],
1550                     c[order_type::G],
1551                     c[order_type::B],
1552                     c[order_type::A]);
1553             }
1554 
nextpixel_type1555             pixel_type* next()
1556             {
1557                 return this + 1;
1558             }
1559 
nextpixel_type1560             const pixel_type* next() const
1561             {
1562                 return this + 1;
1563             }
1564 
advancepixel_type1565             pixel_type* advance(int n)
1566             {
1567                 return this + n;
1568             }
1569 
advancepixel_type1570             const pixel_type* advance(int n) const
1571             {
1572                 return this + n;
1573             }
1574         };
1575 
1576     private:
1577         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c,unsigned cover)1578         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
1579         {
1580             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
1581         }
1582 
1583         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c)1584         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c)
1585         {
1586             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
1587         }
1588 
1589         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c,unsigned cover)1590         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover)
1591         {
1592             if (!c.is_transparent())
1593             {
1594                 if (c.is_opaque() && cover == cover_mask)
1595                 {
1596                     p->set(c.r, c.g, c.b, c.a);
1597                 }
1598                 else
1599                 {
1600                     m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
1601                 }
1602             }
1603         }
1604 
1605         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c)1606         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
1607         {
1608             if (!c.is_transparent())
1609             {
1610                 if (c.is_opaque())
1611                 {
1612                     p->set(c.r, c.g, c.b, c.a);
1613                 }
1614                 else
1615                 {
1616                     m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
1617                 }
1618             }
1619         }
1620 
1621     public:
1622         //--------------------------------------------------------------------
pixfmt_alpha_blend_rgba()1623         pixfmt_alpha_blend_rgba() : m_rbuf(0) {}
pixfmt_alpha_blend_rgba(rbuf_type & rb)1624         explicit pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {}
attach(rbuf_type & rb)1625         void attach(rbuf_type& rb) { m_rbuf = &rb; }
1626 
1627         //--------------------------------------------------------------------
1628         template<class PixFmt>
attach(PixFmt & pixf,int x1,int y1,int x2,int y2)1629         bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
1630         {
1631             rect_i r(x1, y1, x2, y2);
1632             if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
1633             {
1634                 int stride = pixf.stride();
1635                 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
1636                                (r.x2 - r.x1) + 1,
1637                                (r.y2 - r.y1) + 1,
1638                                stride);
1639                 return true;
1640             }
1641             return false;
1642         }
1643 
1644         //--------------------------------------------------------------------
width()1645         AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
height()1646         AGG_INLINE unsigned height() const { return m_rbuf->height(); }
stride()1647         AGG_INLINE int      stride() const { return m_rbuf->stride(); }
1648 
1649         //--------------------------------------------------------------------
row_ptr(int y)1650         AGG_INLINE       int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
row_ptr(int y)1651         AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row(int y)1652         AGG_INLINE row_data     row(int y)     const { return m_rbuf->row(y); }
1653 
1654         //--------------------------------------------------------------------
pix_ptr(int x,int y)1655         AGG_INLINE int8u* pix_ptr(int x, int y)
1656         {
1657             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
1658         }
1659 
pix_ptr(int x,int y)1660         AGG_INLINE const int8u* pix_ptr(int x, int y) const
1661         {
1662             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
1663         }
1664 
1665         // Return pointer to pixel value, forcing row to be allocated.
pix_value_ptr(int x,int y,unsigned len)1666         AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
1667         {
1668             return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step));
1669         }
1670 
1671         // Return pointer to pixel value, or null if row not allocated.
pix_value_ptr(int x,int y)1672         AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
1673         {
1674             int8u* p = m_rbuf->row_ptr(y);
1675             return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0;
1676         }
1677 
1678         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(void * p)1679         AGG_INLINE static pixel_type* pix_value_ptr(void* p)
1680         {
1681             return (pixel_type*)p;
1682         }
1683 
1684         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(const void * p)1685         AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
1686         {
1687             return (const pixel_type*)p;
1688         }
1689 
1690         //--------------------------------------------------------------------
write_plain_color(void * p,color_type c)1691         AGG_INLINE static void write_plain_color(void* p, color_type c)
1692         {
1693             blender_type::set_plain_color(pix_value_ptr(p)->c, c);
1694         }
1695 
1696         //--------------------------------------------------------------------
read_plain_color(const void * p)1697         AGG_INLINE static color_type read_plain_color(const void* p)
1698         {
1699             return blender_type::get_plain_color(pix_value_ptr(p)->c);
1700         }
1701 
1702         //--------------------------------------------------------------------
make_pix(int8u * p,const color_type & c)1703         AGG_INLINE static void make_pix(int8u* p, const color_type& c)
1704         {
1705             ((pixel_type*)p)->set(c);
1706         }
1707 
1708         //--------------------------------------------------------------------
pixel(int x,int y)1709         AGG_INLINE color_type pixel(int x, int y) const
1710         {
1711             if (const pixel_type* p = pix_value_ptr(x, y))
1712             {
1713                 return p->get();
1714             }
1715             return color_type::no_color();
1716         }
1717 
1718         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)1719         AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
1720         {
1721             pix_value_ptr(x, y, 1)->set(c);
1722         }
1723 
1724         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,int8u cover)1725         AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
1726         {
1727             copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
1728         }
1729 
1730         //--------------------------------------------------------------------
copy_hline(int x,int y,unsigned len,const color_type & c)1731         AGG_INLINE void copy_hline(int x, int y,
1732                                    unsigned len,
1733                                    const color_type& c)
1734         {
1735             pixel_type v;
1736             v.set(c);
1737             pixel_type* p = pix_value_ptr(x, y, len);
1738             do
1739             {
1740                 *p = v;
1741                 p = p->next();
1742             }
1743             while (--len);
1744         }
1745 
1746 
1747         //--------------------------------------------------------------------
copy_vline(int x,int y,unsigned len,const color_type & c)1748         AGG_INLINE void copy_vline(int x, int y,
1749                                    unsigned len,
1750                                    const color_type& c)
1751         {
1752             pixel_type v;
1753             v.set(c);
1754             do
1755             {
1756                 *pix_value_ptr(x, y++, 1) = v;
1757             }
1758             while (--len);
1759         }
1760 
1761         //--------------------------------------------------------------------
blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)1762         void blend_hline(int x, int y,
1763                          unsigned len,
1764                          const color_type& c,
1765                          int8u cover)
1766         {
1767             if (!c.is_transparent())
1768             {
1769                 pixel_type* p = pix_value_ptr(x, y, len);
1770                 if (c.is_opaque() && cover == cover_mask)
1771                 {
1772                     pixel_type v;
1773                     v.set(c);
1774                     do
1775                     {
1776                         *p = v;
1777                         p = p->next();
1778                     }
1779                     while (--len);
1780                 }
1781                 else
1782                 {
1783                     if (cover == cover_mask)
1784                     {
1785                         do
1786                         {
1787                             blend_pix(p, c);
1788                             p = p->next();
1789                         }
1790                         while (--len);
1791                     }
1792                     else
1793                     {
1794                         do
1795                         {
1796                             blend_pix(p, c, cover);
1797                             p = p->next();
1798                         }
1799                         while (--len);
1800                     }
1801                 }
1802             }
1803         }
1804 
1805 
1806         //--------------------------------------------------------------------
blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)1807         void blend_vline(int x, int y,
1808                          unsigned len,
1809                          const color_type& c,
1810                          int8u cover)
1811         {
1812             if (!c.is_transparent())
1813             {
1814                 if (c.is_opaque() && cover == cover_mask)
1815                 {
1816                     pixel_type v;
1817                     v.set(c);
1818                     do
1819                     {
1820                         *pix_value_ptr(x, y++, 1) = v;
1821                     }
1822                     while (--len);
1823                 }
1824                 else
1825                 {
1826                     if (cover == cover_mask)
1827                     {
1828                         do
1829                         {
1830                             blend_pix(pix_value_ptr(x, y++, 1), c, c.a);
1831                         }
1832                         while (--len);
1833                     }
1834                     else
1835                     {
1836                         do
1837                         {
1838                             blend_pix(pix_value_ptr(x, y++, 1), c, cover);
1839                         }
1840                         while (--len);
1841                     }
1842                 }
1843             }
1844         }
1845 
1846 
1847         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)1848         void blend_solid_hspan(int x, int y,
1849                                unsigned len,
1850                                const color_type& c,
1851                                const int8u* covers)
1852         {
1853             if (!c.is_transparent())
1854             {
1855                 pixel_type* p = pix_value_ptr(x, y, len);
1856                 do
1857                 {
1858                     if (c.is_opaque() && *covers == cover_mask)
1859                     {
1860                         p->set(c);
1861                     }
1862                     else
1863                     {
1864                         blend_pix(p, c, *covers);
1865                     }
1866                     p = p->next();
1867                     ++covers;
1868                 }
1869                 while (--len);
1870             }
1871         }
1872 
1873 
1874         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)1875         void blend_solid_vspan(int x, int y,
1876                                unsigned len,
1877                                const color_type& c,
1878                                const int8u* covers)
1879         {
1880             if (!c.is_transparent())
1881             {
1882                 do
1883                 {
1884                     pixel_type* p = pix_value_ptr(x, y++, 1);
1885                     if (c.is_opaque() && *covers == cover_mask)
1886                     {
1887                         p->set(c);
1888                     }
1889                     else
1890                     {
1891                         blend_pix(p, c, *covers);
1892                     }
1893                     ++covers;
1894                 }
1895                 while (--len);
1896             }
1897         }
1898 
1899         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,unsigned len,const color_type * colors)1900         void copy_color_hspan(int x, int y,
1901                               unsigned len,
1902                               const color_type* colors)
1903         {
1904             pixel_type* p = pix_value_ptr(x, y, len);
1905             do
1906             {
1907                 p->set(*colors++);
1908                 p = p->next();
1909             }
1910             while (--len);
1911         }
1912 
1913 
1914         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,unsigned len,const color_type * colors)1915         void copy_color_vspan(int x, int y,
1916                               unsigned len,
1917                               const color_type* colors)
1918         {
1919             do
1920             {
1921                 pix_value_ptr(x, y++, 1)->set(*colors++);
1922             }
1923             while (--len);
1924         }
1925 
1926         //--------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)1927         void blend_color_hspan(int x, int y,
1928                                unsigned len,
1929                                const color_type* colors,
1930                                const int8u* covers,
1931                                int8u cover)
1932         {
1933             pixel_type* p = pix_value_ptr(x, y, len);
1934             if (covers)
1935             {
1936                 do
1937                 {
1938                     copy_or_blend_pix(p, *colors++, *covers++);
1939                     p = p->next();
1940                 }
1941                 while (--len);
1942             }
1943             else
1944             {
1945                 if (cover == cover_mask)
1946                 {
1947                     do
1948                     {
1949                         copy_or_blend_pix(p, *colors++);
1950                         p = p->next();
1951                     }
1952                     while (--len);
1953                 }
1954                 else
1955                 {
1956                     do
1957                     {
1958                         copy_or_blend_pix(p, *colors++, cover);
1959                         p = p->next();
1960                     }
1961                     while (--len);
1962                 }
1963             }
1964         }
1965 
1966         //--------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)1967         void blend_color_vspan(int x, int y,
1968                                unsigned len,
1969                                const color_type* colors,
1970                                const int8u* covers,
1971                                int8u cover)
1972         {
1973             if (covers)
1974             {
1975                 do
1976                 {
1977                     copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
1978                 }
1979                 while (--len);
1980             }
1981             else
1982             {
1983                 if (cover == cover_mask)
1984                 {
1985                     do
1986                     {
1987                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
1988                     }
1989                     while (--len);
1990                 }
1991                 else
1992                 {
1993                     do
1994                     {
1995                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
1996                     }
1997                     while (--len);
1998                 }
1999             }
2000         }
2001 
2002         //--------------------------------------------------------------------
for_each_pixel(Function f)2003         template<class Function> void for_each_pixel(Function f)
2004         {
2005             for (unsigned y = 0; y < height(); ++y)
2006             {
2007                 row_data r = m_rbuf->row(y);
2008                 if (r.ptr)
2009                 {
2010                     unsigned len = r.x2 - r.x1 + 1;
2011                     pixel_type* p = pix_value_ptr(r.x1, y, len);
2012                     do
2013                     {
2014                         f(p->c);
2015                         p = p->next();
2016                     }
2017                     while (--len);
2018                 }
2019             }
2020         }
2021 
2022         //--------------------------------------------------------------------
premultiply()2023         void premultiply()
2024         {
2025             for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply);
2026         }
2027 
2028         //--------------------------------------------------------------------
demultiply()2029         void demultiply()
2030         {
2031             for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply);
2032         }
2033 
2034         //--------------------------------------------------------------------
apply_gamma_dir(const GammaLut & g)2035         template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
2036         {
2037             for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g));
2038         }
2039 
2040         //--------------------------------------------------------------------
apply_gamma_inv(const GammaLut & g)2041         template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
2042         {
2043             for_each_pixel(apply_gamma_inv_rgba<color_type, order_type, GammaLut>(g));
2044         }
2045 
2046         //--------------------------------------------------------------------
copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)2047         template<class RenBuf2> void copy_from(const RenBuf2& from,
2048                                                int xdst, int ydst,
2049                                                int xsrc, int ysrc,
2050                                                unsigned len)
2051         {
2052             if (const int8u* p = from.row_ptr(ysrc))
2053             {
2054                 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
2055                         p + xsrc * pix_width,
2056                         len * pix_width);
2057             }
2058         }
2059 
2060         //--------------------------------------------------------------------
2061         // Blend from another RGBA surface.
2062         template<class SrcPixelFormatRenderer>
blend_from(const SrcPixelFormatRenderer & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2063         void blend_from(const SrcPixelFormatRenderer& from,
2064                         int xdst, int ydst,
2065                         int xsrc, int ysrc,
2066                         unsigned len,
2067                         int8u cover)
2068         {
2069             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2070 
2071             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2072             {
2073                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2074                 int srcinc = 1;
2075                 int dstinc = 1;
2076 
2077                 if (xdst > xsrc)
2078                 {
2079                     psrc = psrc->advance(len - 1);
2080                     pdst = pdst->advance(len - 1);
2081                     srcinc = -1;
2082                     dstinc = -1;
2083                 }
2084 
2085                 if (cover == cover_mask)
2086                 {
2087                     do
2088                     {
2089                         copy_or_blend_pix(pdst, psrc->get());
2090                         psrc = psrc->advance(srcinc);
2091                         pdst = pdst->advance(dstinc);
2092                     }
2093                     while (--len);
2094                 }
2095                 else
2096                 {
2097                     do
2098                     {
2099                         copy_or_blend_pix(pdst, psrc->get(), cover);
2100                         psrc = psrc->advance(srcinc);
2101                         pdst = pdst->advance(dstinc);
2102                     }
2103                     while (--len);
2104                 }
2105             }
2106         }
2107 
2108         //--------------------------------------------------------------------
2109         // Combine single color with grayscale surface and blend.
2110         template<class SrcPixelFormatRenderer>
blend_from_color(const SrcPixelFormatRenderer & from,const color_type & color,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2111         void blend_from_color(const SrcPixelFormatRenderer& from,
2112                               const color_type& color,
2113                               int xdst, int ydst,
2114                               int xsrc, int ysrc,
2115                               unsigned len,
2116                               int8u cover)
2117         {
2118             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2119             typedef typename SrcPixelFormatRenderer::color_type src_color_type;
2120 
2121             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2122             {
2123                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2124 
2125                 do
2126                 {
2127                     copy_or_blend_pix(pdst, color,
2128                         src_color_type::scale_cover(cover, psrc->c[0]));
2129                     psrc = psrc->next();
2130                     pdst = pdst->next();
2131                 }
2132                 while (--len);
2133             }
2134         }
2135 
2136         //--------------------------------------------------------------------
2137         // Blend from color table, using grayscale surface as indexes into table.
2138         // Obviously, this only works for integer value types.
2139         template<class SrcPixelFormatRenderer>
blend_from_lut(const SrcPixelFormatRenderer & from,const color_type * color_lut,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2140         void blend_from_lut(const SrcPixelFormatRenderer& from,
2141                             const color_type* color_lut,
2142                             int xdst, int ydst,
2143                             int xsrc, int ysrc,
2144                             unsigned len,
2145                             int8u cover)
2146         {
2147             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2148 
2149             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2150             {
2151                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2152 
2153                 if (cover == cover_mask)
2154                 {
2155                     do
2156                     {
2157                         copy_or_blend_pix(pdst, color_lut[psrc->c[0]]);
2158                         psrc = psrc->next();
2159                         pdst = pdst->next();
2160                     }
2161                     while (--len);
2162                 }
2163                 else
2164                 {
2165                     do
2166                     {
2167                         copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
2168                         psrc = psrc->next();
2169                         pdst = pdst->next();
2170                     }
2171                     while (--len);
2172                 }
2173             }
2174         }
2175 
2176     private:
2177         rbuf_type* m_rbuf;
2178         Blender    m_blender;
2179     };
2180 
2181     //================================================pixfmt_custom_blend_rgba
2182     template<class Blender, class RenBuf> class pixfmt_custom_blend_rgba
2183     {
2184     public:
2185         typedef pixfmt_rgba_tag pixfmt_category;
2186         typedef RenBuf   rbuf_type;
2187         typedef typename rbuf_type::row_data row_data;
2188         typedef Blender  blender_type;
2189         typedef typename blender_type::color_type color_type;
2190         typedef typename blender_type::order_type order_type;
2191         typedef typename color_type::value_type value_type;
2192         typedef typename color_type::calc_type calc_type;
2193         enum
2194         {
2195             pix_step = 4,
2196             pix_width  = sizeof(value_type) * pix_step,
2197         };
2198         struct pixel_type
2199         {
2200             value_type c[pix_step];
2201 
setpixel_type2202             void set(value_type r, value_type g, value_type b, value_type a)
2203             {
2204                 c[order_type::R] = r;
2205                 c[order_type::G] = g;
2206                 c[order_type::B] = b;
2207                 c[order_type::A] = a;
2208             }
2209 
setpixel_type2210             void set(const color_type& color)
2211             {
2212                 set(color.r, color.g, color.b, color.a);
2213             }
2214 
getpixel_type2215             void get(value_type& r, value_type& g, value_type& b, value_type& a) const
2216             {
2217                 r = c[order_type::R];
2218                 g = c[order_type::G];
2219                 b = c[order_type::B];
2220                 a = c[order_type::A];
2221             }
2222 
getpixel_type2223             color_type get() const
2224             {
2225                 return color_type(
2226                     c[order_type::R],
2227                     c[order_type::G],
2228                     c[order_type::B],
2229                     c[order_type::A]);
2230             }
2231 
nextpixel_type2232             pixel_type* next()
2233             {
2234                 return this + 1;
2235             }
2236 
nextpixel_type2237             const pixel_type* next() const
2238             {
2239                 return this + 1;
2240             }
2241 
advancepixel_type2242             pixel_type* advance(int n)
2243             {
2244                 return this + n;
2245             }
2246 
advancepixel_type2247             const pixel_type* advance(int n) const
2248             {
2249                 return this + n;
2250             }
2251         };
2252 
2253 
2254     private:
2255         //--------------------------------------------------------------------
2256         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full)
2257         {
2258             m_blender.blend_pix(m_comp_op, p->c, c.r, c.g, c.b, c.a, cover);
2259         }
2260 
2261         //--------------------------------------------------------------------
2262         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full)
2263         {
2264             if (!c.is_transparent())
2265             {
2266                 if (c.is_opaque() && cover == cover_mask)
2267                 {
2268                     p->set(c.r, c.g, c.b, c.a);
2269                 }
2270                 else
2271                 {
2272                     blend_pix(p, c, cover);
2273                 }
2274             }
2275         }
2276 
2277     public:
2278         //--------------------------------------------------------------------
pixfmt_custom_blend_rgba()2279         pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {}
2280         explicit pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned comp_op=3) :
2281             m_rbuf(&rb),
2282             m_comp_op(comp_op)
2283         {}
attach(rbuf_type & rb)2284         void attach(rbuf_type& rb) { m_rbuf = &rb; }
2285 
2286         //--------------------------------------------------------------------
2287         template<class PixFmt>
attach(PixFmt & pixf,int x1,int y1,int x2,int y2)2288         bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
2289         {
2290             rect_i r(x1, y1, x2, y2);
2291             if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
2292             {
2293                 int stride = pixf.stride();
2294                 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
2295                                (r.x2 - r.x1) + 1,
2296                                (r.y2 - r.y1) + 1,
2297                                stride);
2298                 return true;
2299             }
2300             return false;
2301         }
2302 
2303         //--------------------------------------------------------------------
comp_op(unsigned op)2304         void comp_op(unsigned op) { m_comp_op = op; }
comp_op()2305         unsigned comp_op() const  { return m_comp_op; }
2306 
2307         //--------------------------------------------------------------------
width()2308         AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
height()2309         AGG_INLINE unsigned height() const { return m_rbuf->height(); }
stride()2310         AGG_INLINE int      stride() const { return m_rbuf->stride(); }
2311 
2312         //--------------------------------------------------------------------
row_ptr(int y)2313         AGG_INLINE       int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
row_ptr(int y)2314         AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row(int y)2315         AGG_INLINE row_data     row(int y)     const { return m_rbuf->row(y); }
2316 
2317         //--------------------------------------------------------------------
pix_ptr(int x,int y)2318         AGG_INLINE int8u* pix_ptr(int x, int y)
2319         {
2320             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
2321         }
2322 
pix_ptr(int x,int y)2323         AGG_INLINE const int8u* pix_ptr(int x, int y) const
2324         {
2325             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
2326         }
2327 
2328         // Return pointer to pixel value, forcing row to be allocated.
pix_value_ptr(int x,int y,unsigned len)2329         AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
2330         {
2331             return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step));
2332         }
2333 
2334         // Return pointer to pixel value, or null if row not allocated.
pix_value_ptr(int x,int y)2335         AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
2336         {
2337             int8u* p = m_rbuf->row_ptr(y);
2338             return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0;
2339         }
2340 
2341         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(void * p)2342         AGG_INLINE static pixel_type* pix_value_ptr(void* p)
2343         {
2344             return (pixel_type*)p;
2345         }
2346 
2347         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(const void * p)2348         AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
2349         {
2350             return (const pixel_type*)p;
2351         }
2352 
2353         //--------------------------------------------------------------------
make_pix(int8u * p,const color_type & c)2354         AGG_INLINE static void make_pix(int8u* p, const color_type& c)
2355         {
2356             ((pixel_type*)p)->set(c);
2357         }
2358 
2359         //--------------------------------------------------------------------
pixel(int x,int y)2360         AGG_INLINE color_type pixel(int x, int y) const
2361         {
2362             if (const pixel_type* p = pix_value_ptr(x, y))
2363             {
2364                 return p->get();
2365             }
2366             return color_type::no_color();
2367         }
2368 
2369         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)2370         AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
2371         {
2372             make_pix(pix_value_ptr(x, y, 1), c);
2373         }
2374 
2375         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,int8u cover)2376         AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
2377         {
2378             blend_pix(pix_value_ptr(x, y, 1), c, cover);
2379         }
2380 
2381         //--------------------------------------------------------------------
copy_hline(int x,int y,unsigned len,const color_type & c)2382         AGG_INLINE void copy_hline(int x, int y,
2383                                    unsigned len,
2384                                    const color_type& c)
2385         {
2386             pixel_type v;
2387             v.set(c);
2388             pixel_type* p = pix_value_ptr(x, y, len);
2389             do
2390             {
2391                 *p = v;
2392                 p = p->next();
2393             }
2394             while (--len);
2395         }
2396 
2397 
2398         //--------------------------------------------------------------------
copy_vline(int x,int y,unsigned len,const color_type & c)2399         AGG_INLINE void copy_vline(int x, int y,
2400                                    unsigned len,
2401                                    const color_type& c)
2402         {
2403             pixel_type v;
2404             v.set(c);
2405             do
2406             {
2407                 *pix_value_ptr(x, y++, 1) = v;
2408             }
2409             while (--len);
2410         }
2411 
2412         //--------------------------------------------------------------------
blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)2413         void blend_hline(int x, int y, unsigned len,
2414                          const color_type& c, int8u cover)
2415         {
2416 
2417             pixel_type* p = pix_value_ptr(x, y, len);
2418             do
2419             {
2420                 blend_pix(p, c, cover);
2421                 p = p->next();
2422             }
2423             while (--len);
2424         }
2425 
2426         //--------------------------------------------------------------------
blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)2427         void blend_vline(int x, int y, unsigned len,
2428                          const color_type& c, int8u cover)
2429         {
2430             do
2431             {
2432                 blend_pix(pix_value_ptr(x, y++, 1), c, cover);
2433             }
2434             while (--len);
2435         }
2436 
2437         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)2438         void blend_solid_hspan(int x, int y, unsigned len,
2439                                const color_type& c, const int8u* covers)
2440         {
2441             pixel_type* p = pix_value_ptr(x, y, len);
2442 
2443             do
2444             {
2445                 blend_pix(p, c, *covers++);
2446                 p = p->next();
2447             }
2448             while (--len);
2449         }
2450 
2451         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)2452         void blend_solid_vspan(int x, int y, unsigned len,
2453                                const color_type& c, const int8u* covers)
2454         {
2455             do
2456             {
2457                 blend_pix(pix_value_ptr(x, y++, 1), c, *covers++);
2458             }
2459             while (--len);
2460         }
2461 
2462         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,unsigned len,const color_type * colors)2463         void copy_color_hspan(int x, int y,
2464                               unsigned len,
2465                               const color_type* colors)
2466         {
2467             pixel_type* p = pix_value_ptr(x, y, len);
2468 
2469             do
2470             {
2471                 p->set(*colors++);
2472                 p = p->next();
2473             }
2474             while (--len);
2475         }
2476 
2477         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,unsigned len,const color_type * colors)2478         void copy_color_vspan(int x, int y,
2479                               unsigned len,
2480                               const color_type* colors)
2481         {
2482             do
2483             {
2484                 pix_value_ptr(x, y++, 1)->set(*colors++);
2485             }
2486             while (--len);
2487         }
2488 
2489         //--------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)2490         void blend_color_hspan(int x, int y, unsigned len,
2491                                const color_type* colors,
2492                                const int8u* covers,
2493                                int8u cover)
2494         {
2495             pixel_type* p = pix_value_ptr(x, y, len);
2496 
2497             do
2498             {
2499                 blend_pix(p, *colors++, covers ? *covers++ : cover);
2500                 p = p->next();
2501             }
2502             while (--len);
2503         }
2504 
2505         //--------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)2506         void blend_color_vspan(int x, int y, unsigned len,
2507                                const color_type* colors,
2508                                const int8u* covers,
2509                                int8u cover)
2510         {
2511             do
2512             {
2513                 blend_pix(pix_value_ptr(x, y++, 1), *colors++, covers ? *covers++ : cover);
2514             }
2515             while (--len);
2516 
2517         }
2518 
2519         //--------------------------------------------------------------------
for_each_pixel(Function f)2520         template<class Function> void for_each_pixel(Function f)
2521         {
2522             unsigned y;
2523             for (y = 0; y < height(); ++y)
2524             {
2525                 row_data r = m_rbuf->row(y);
2526                 if (r.ptr)
2527                 {
2528                     unsigned len = r.x2 - r.x1 + 1;
2529                     pixel_type* p = pix_value_ptr(r.x1, y, len);
2530                     do
2531                     {
2532                         f(p->c);
2533                         p = p->next();
2534                     }
2535                     while (--len);
2536                 }
2537             }
2538         }
2539 
2540         //--------------------------------------------------------------------
premultiply()2541         void premultiply()
2542         {
2543             for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply);
2544         }
2545 
2546         //--------------------------------------------------------------------
demultiply()2547         void demultiply()
2548         {
2549             for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply);
2550         }
2551 
2552         //--------------------------------------------------------------------
apply_gamma_dir(const GammaLut & g)2553         template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
2554         {
2555             for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g));
2556         }
2557 
2558         //--------------------------------------------------------------------
apply_gamma_inv(const GammaLut & g)2559         template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
2560         {
2561             for_each_pixel(apply_gamma_inv_rgba<color_type, order_type, GammaLut>(g));
2562         }
2563 
2564         //--------------------------------------------------------------------
copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)2565         template<class RenBuf2> void copy_from(const RenBuf2& from,
2566                                                int xdst, int ydst,
2567                                                int xsrc, int ysrc,
2568                                                unsigned len)
2569         {
2570             if (const int8u* p = from.row_ptr(ysrc))
2571             {
2572                 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
2573                         p + xsrc * pix_width,
2574                         len * pix_width);
2575             }
2576         }
2577 
2578         //--------------------------------------------------------------------
2579         // Blend from another RGBA surface.
2580         template<class SrcPixelFormatRenderer>
blend_from(const SrcPixelFormatRenderer & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2581         void blend_from(const SrcPixelFormatRenderer& from,
2582                         int xdst, int ydst,
2583                         int xsrc, int ysrc,
2584                         unsigned len,
2585                         int8u cover)
2586         {
2587             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2588 
2589             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2590             {
2591                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2592                 int srcinc = 1;
2593                 int dstinc = 1;
2594 
2595                 if (xdst > xsrc)
2596                 {
2597                     psrc = psrc->advance(len - 1);
2598                     pdst = pdst->advance(len - 1);
2599                     srcinc = -1;
2600                     dstinc = -1;
2601                 }
2602 
2603                 do
2604                 {
2605                     blend_pix(pdst, psrc->get(), cover);
2606                     psrc = psrc->advance(srcinc);
2607                     pdst = pdst->advance(dstinc);
2608                 }
2609                 while (--len);
2610             }
2611         }
2612 
2613         //--------------------------------------------------------------------
2614         // Blend from single color, using grayscale surface as alpha channel.
2615         template<class SrcPixelFormatRenderer>
blend_from_color(const SrcPixelFormatRenderer & from,const color_type & color,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2616         void blend_from_color(const SrcPixelFormatRenderer& from,
2617                               const color_type& color,
2618                               int xdst, int ydst,
2619                               int xsrc, int ysrc,
2620                               unsigned len,
2621                               int8u cover)
2622         {
2623             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2624             typedef typename SrcPixelFormatRenderer::color_type src_color_type;
2625 
2626             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2627             {
2628                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2629 
2630                 do
2631                 {
2632                     blend_pix(pdst, color,
2633                         src_color_type::scale_cover(cover, psrc->c[0]));
2634                     psrc = psrc->next();
2635                     pdst = pdst->next();
2636                 }
2637                 while (--len);
2638             }
2639         }
2640 
2641         //--------------------------------------------------------------------
2642         // Blend from color table, using grayscale surface as indexes into table.
2643         // Obviously, this only works for integer value types.
2644         template<class SrcPixelFormatRenderer>
blend_from_lut(const SrcPixelFormatRenderer & from,const color_type * color_lut,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2645         void blend_from_lut(const SrcPixelFormatRenderer& from,
2646                             const color_type* color_lut,
2647                             int xdst, int ydst,
2648                             int xsrc, int ysrc,
2649                             unsigned len,
2650                             int8u cover)
2651         {
2652             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2653 
2654             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2655             {
2656                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2657 
2658                 do
2659                 {
2660                     blend_pix(pdst, color_lut[psrc->c[0]], cover);
2661                     psrc = psrc->next();
2662                     pdst = pdst->next();
2663                 }
2664                 while (--len);
2665             }
2666         }
2667 
2668     private:
2669         rbuf_type* m_rbuf;
2670         Blender m_blender;
2671         unsigned m_comp_op;
2672     };
2673 
2674 
2675     //-----------------------------------------------------------------------
2676     typedef blender_rgba<rgba8, order_rgba> blender_rgba32;
2677     typedef blender_rgba<rgba8, order_argb> blender_argb32;
2678     typedef blender_rgba<rgba8, order_abgr> blender_abgr32;
2679     typedef blender_rgba<rgba8, order_bgra> blender_bgra32;
2680 
2681     typedef blender_rgba<srgba8, order_rgba> blender_srgba32;
2682     typedef blender_rgba<srgba8, order_argb> blender_sargb32;
2683     typedef blender_rgba<srgba8, order_abgr> blender_sabgr32;
2684     typedef blender_rgba<srgba8, order_bgra> blender_sbgra32;
2685 
2686     typedef blender_rgba_pre<rgba8, order_rgba> blender_rgba32_pre;
2687     typedef blender_rgba_pre<rgba8, order_argb> blender_argb32_pre;
2688     typedef blender_rgba_pre<rgba8, order_abgr> blender_abgr32_pre;
2689     typedef blender_rgba_pre<rgba8, order_bgra> blender_bgra32_pre;
2690 
2691     typedef blender_rgba_pre<srgba8, order_rgba> blender_srgba32_pre;
2692     typedef blender_rgba_pre<srgba8, order_argb> blender_sargb32_pre;
2693     typedef blender_rgba_pre<srgba8, order_abgr> blender_sabgr32_pre;
2694     typedef blender_rgba_pre<srgba8, order_bgra> blender_sbgra32_pre;
2695 
2696     typedef blender_rgba_plain<rgba8, order_rgba> blender_rgba32_plain;
2697     typedef blender_rgba_plain<rgba8, order_argb> blender_argb32_plain;
2698     typedef blender_rgba_plain<rgba8, order_abgr> blender_abgr32_plain;
2699     typedef blender_rgba_plain<rgba8, order_bgra> blender_bgra32_plain;
2700 
2701     typedef blender_rgba_plain<srgba8, order_rgba> blender_srgba32_plain;
2702     typedef blender_rgba_plain<srgba8, order_argb> blender_sargb32_plain;
2703     typedef blender_rgba_plain<srgba8, order_abgr> blender_sabgr32_plain;
2704     typedef blender_rgba_plain<srgba8, order_bgra> blender_sbgra32_plain;
2705 
2706     typedef blender_rgba<rgba16, order_rgba> blender_rgba64;
2707     typedef blender_rgba<rgba16, order_argb> blender_argb64;
2708     typedef blender_rgba<rgba16, order_abgr> blender_abgr64;
2709     typedef blender_rgba<rgba16, order_bgra> blender_bgra64;
2710 
2711     typedef blender_rgba_pre<rgba16, order_rgba> blender_rgba64_pre;
2712     typedef blender_rgba_pre<rgba16, order_argb> blender_argb64_pre;
2713     typedef blender_rgba_pre<rgba16, order_abgr> blender_abgr64_pre;
2714     typedef blender_rgba_pre<rgba16, order_bgra> blender_bgra64_pre;
2715 
2716 	typedef blender_rgba_plain<rgba16, order_rgba> blender_rgba64_plain;
2717 	typedef blender_rgba_plain<rgba16, order_argb> blender_argb64_plain;
2718 	typedef blender_rgba_plain<rgba16, order_abgr> blender_abgr64_plain;
2719 	typedef blender_rgba_plain<rgba16, order_bgra> blender_bgra64_plain;
2720 
2721 	typedef blender_rgba<rgba32, order_rgba> blender_rgba128;
2722     typedef blender_rgba<rgba32, order_argb> blender_argb128;
2723     typedef blender_rgba<rgba32, order_abgr> blender_abgr128;
2724     typedef blender_rgba<rgba32, order_bgra> blender_bgra128;
2725 
2726     typedef blender_rgba_pre<rgba32, order_rgba> blender_rgba128_pre;
2727     typedef blender_rgba_pre<rgba32, order_argb> blender_argb128_pre;
2728     typedef blender_rgba_pre<rgba32, order_abgr> blender_abgr128_pre;
2729     typedef blender_rgba_pre<rgba32, order_bgra> blender_bgra128_pre;
2730 
2731     typedef blender_rgba_plain<rgba32, order_rgba> blender_rgba128_plain;
2732     typedef blender_rgba_plain<rgba32, order_argb> blender_argb128_plain;
2733     typedef blender_rgba_plain<rgba32, order_abgr> blender_abgr128_plain;
2734     typedef blender_rgba_plain<rgba32, order_bgra> blender_bgra128_plain;
2735 
2736 
2737     //-----------------------------------------------------------------------
2738     typedef pixfmt_alpha_blend_rgba<blender_rgba32, rendering_buffer> pixfmt_rgba32;
2739     typedef pixfmt_alpha_blend_rgba<blender_argb32, rendering_buffer> pixfmt_argb32;
2740     typedef pixfmt_alpha_blend_rgba<blender_abgr32, rendering_buffer> pixfmt_abgr32;
2741     typedef pixfmt_alpha_blend_rgba<blender_bgra32, rendering_buffer> pixfmt_bgra32;
2742 
2743     typedef pixfmt_alpha_blend_rgba<blender_srgba32, rendering_buffer> pixfmt_srgba32;
2744     typedef pixfmt_alpha_blend_rgba<blender_sargb32, rendering_buffer> pixfmt_sargb32;
2745     typedef pixfmt_alpha_blend_rgba<blender_sabgr32, rendering_buffer> pixfmt_sabgr32;
2746     typedef pixfmt_alpha_blend_rgba<blender_sbgra32, rendering_buffer> pixfmt_sbgra32;
2747 
2748     typedef pixfmt_alpha_blend_rgba<blender_rgba32_pre, rendering_buffer> pixfmt_rgba32_pre;
2749     typedef pixfmt_alpha_blend_rgba<blender_argb32_pre, rendering_buffer> pixfmt_argb32_pre;
2750     typedef pixfmt_alpha_blend_rgba<blender_abgr32_pre, rendering_buffer> pixfmt_abgr32_pre;
2751     typedef pixfmt_alpha_blend_rgba<blender_bgra32_pre, rendering_buffer> pixfmt_bgra32_pre;
2752 
2753     typedef pixfmt_alpha_blend_rgba<blender_srgba32_pre, rendering_buffer> pixfmt_srgba32_pre;
2754     typedef pixfmt_alpha_blend_rgba<blender_sargb32_pre, rendering_buffer> pixfmt_sargb32_pre;
2755     typedef pixfmt_alpha_blend_rgba<blender_sabgr32_pre, rendering_buffer> pixfmt_sabgr32_pre;
2756     typedef pixfmt_alpha_blend_rgba<blender_sbgra32_pre, rendering_buffer> pixfmt_sbgra32_pre;
2757 
2758     typedef pixfmt_alpha_blend_rgba<blender_rgba32_plain, rendering_buffer> pixfmt_rgba32_plain;
2759     typedef pixfmt_alpha_blend_rgba<blender_argb32_plain, rendering_buffer> pixfmt_argb32_plain;
2760     typedef pixfmt_alpha_blend_rgba<blender_abgr32_plain, rendering_buffer> pixfmt_abgr32_plain;
2761     typedef pixfmt_alpha_blend_rgba<blender_bgra32_plain, rendering_buffer> pixfmt_bgra32_plain;
2762 
2763     typedef pixfmt_alpha_blend_rgba<blender_srgba32_plain, rendering_buffer> pixfmt_srgba32_plain;
2764     typedef pixfmt_alpha_blend_rgba<blender_sargb32_plain, rendering_buffer> pixfmt_sargb32_plain;
2765     typedef pixfmt_alpha_blend_rgba<blender_sabgr32_plain, rendering_buffer> pixfmt_sabgr32_plain;
2766     typedef pixfmt_alpha_blend_rgba<blender_sbgra32_plain, rendering_buffer> pixfmt_sbgra32_plain;
2767 
2768     typedef pixfmt_alpha_blend_rgba<blender_rgba64, rendering_buffer> pixfmt_rgba64;
2769     typedef pixfmt_alpha_blend_rgba<blender_argb64, rendering_buffer> pixfmt_argb64;
2770     typedef pixfmt_alpha_blend_rgba<blender_abgr64, rendering_buffer> pixfmt_abgr64;
2771     typedef pixfmt_alpha_blend_rgba<blender_bgra64, rendering_buffer> pixfmt_bgra64;
2772 
2773     typedef pixfmt_alpha_blend_rgba<blender_rgba64_pre, rendering_buffer> pixfmt_rgba64_pre;
2774     typedef pixfmt_alpha_blend_rgba<blender_argb64_pre, rendering_buffer> pixfmt_argb64_pre;
2775     typedef pixfmt_alpha_blend_rgba<blender_abgr64_pre, rendering_buffer> pixfmt_abgr64_pre;
2776     typedef pixfmt_alpha_blend_rgba<blender_bgra64_pre, rendering_buffer> pixfmt_bgra64_pre;
2777 
2778 	typedef pixfmt_alpha_blend_rgba<blender_rgba64_plain, rendering_buffer> pixfmt_rgba64_plain;
2779 	typedef pixfmt_alpha_blend_rgba<blender_argb64_plain, rendering_buffer> pixfmt_argb64_plain;
2780 	typedef pixfmt_alpha_blend_rgba<blender_abgr64_plain, rendering_buffer> pixfmt_abgr64_plain;
2781 	typedef pixfmt_alpha_blend_rgba<blender_bgra64_plain, rendering_buffer> pixfmt_bgra64_plain;
2782 
2783 	typedef pixfmt_alpha_blend_rgba<blender_rgba128, rendering_buffer> pixfmt_rgba128;
2784     typedef pixfmt_alpha_blend_rgba<blender_argb128, rendering_buffer> pixfmt_argb128;
2785     typedef pixfmt_alpha_blend_rgba<blender_abgr128, rendering_buffer> pixfmt_abgr128;
2786     typedef pixfmt_alpha_blend_rgba<blender_bgra128, rendering_buffer> pixfmt_bgra128;
2787 
2788     typedef pixfmt_alpha_blend_rgba<blender_rgba128_pre, rendering_buffer> pixfmt_rgba128_pre;
2789     typedef pixfmt_alpha_blend_rgba<blender_argb128_pre, rendering_buffer> pixfmt_argb128_pre;
2790     typedef pixfmt_alpha_blend_rgba<blender_abgr128_pre, rendering_buffer> pixfmt_abgr128_pre;
2791     typedef pixfmt_alpha_blend_rgba<blender_bgra128_pre, rendering_buffer> pixfmt_bgra128_pre;
2792 
2793     typedef pixfmt_alpha_blend_rgba<blender_rgba128_plain, rendering_buffer> pixfmt_rgba128_plain;
2794     typedef pixfmt_alpha_blend_rgba<blender_argb128_plain, rendering_buffer> pixfmt_argb128_plain;
2795     typedef pixfmt_alpha_blend_rgba<blender_abgr128_plain, rendering_buffer> pixfmt_abgr128_plain;
2796     typedef pixfmt_alpha_blend_rgba<blender_bgra128_plain, rendering_buffer> pixfmt_bgra128_plain;
2797 
2798 }
2799 
2800 #endif
2801 
2802