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, value_type, value_type, value_type, 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*,
349             value_type, value_type, value_type, value_type, cover_type)
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, value_type, value_type, 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, value_type, value_type, 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, 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, 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, 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, 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             num_components = 4,
1519             pix_step = 4,
1520             pix_width = sizeof(value_type) * pix_step,
1521         };
1522         struct pixel_type
1523         {
1524             value_type c[num_components];
1525 
setpixel_type1526             void set(value_type r, value_type g, value_type b, value_type a)
1527             {
1528                 c[order_type::R] = r;
1529                 c[order_type::G] = g;
1530                 c[order_type::B] = b;
1531                 c[order_type::A] = a;
1532             }
1533 
setpixel_type1534             void set(const color_type& color)
1535             {
1536                 set(color.r, color.g, color.b, color.a);
1537             }
1538 
getpixel_type1539             void get(value_type& r, value_type& g, value_type& b, value_type& a) const
1540             {
1541                 r = c[order_type::R];
1542                 g = c[order_type::G];
1543                 b = c[order_type::B];
1544                 a = c[order_type::A];
1545             }
1546 
getpixel_type1547             color_type get() const
1548             {
1549                 return color_type(
1550                     c[order_type::R],
1551                     c[order_type::G],
1552                     c[order_type::B],
1553                     c[order_type::A]);
1554             }
1555 
nextpixel_type1556             pixel_type* next()
1557             {
1558                 return (pixel_type*)(c + pix_step);
1559             }
1560 
nextpixel_type1561             const pixel_type* next() const
1562             {
1563                 return (const pixel_type*)(c + pix_step);
1564             }
1565 
advancepixel_type1566             pixel_type* advance(int n)
1567             {
1568                 return (pixel_type*)(c + n * pix_step);
1569             }
1570 
advancepixel_type1571             const pixel_type* advance(int n) const
1572             {
1573                 return (const pixel_type*)(c + n * pix_step);
1574             }
1575         };
1576 
1577     private:
1578         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c,unsigned cover)1579         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
1580         {
1581             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
1582         }
1583 
1584         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c)1585         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c)
1586         {
1587             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
1588         }
1589 
1590         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c,unsigned cover)1591         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover)
1592         {
1593             if (!c.is_transparent())
1594             {
1595                 if (c.is_opaque() && cover == cover_mask)
1596                 {
1597                     p->set(c.r, c.g, c.b, c.a);
1598                 }
1599                 else
1600                 {
1601                     m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
1602                 }
1603             }
1604         }
1605 
1606         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c)1607         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
1608         {
1609             if (!c.is_transparent())
1610             {
1611                 if (c.is_opaque())
1612                 {
1613                     p->set(c.r, c.g, c.b, c.a);
1614                 }
1615                 else
1616                 {
1617                     m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
1618                 }
1619             }
1620         }
1621 
1622     public:
1623         //--------------------------------------------------------------------
pixfmt_alpha_blend_rgba()1624         pixfmt_alpha_blend_rgba() : m_rbuf(0) {}
pixfmt_alpha_blend_rgba(rbuf_type & rb)1625         explicit pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {}
attach(rbuf_type & rb)1626         void attach(rbuf_type& rb) { m_rbuf = &rb; }
1627 
1628         //--------------------------------------------------------------------
1629         template<class PixFmt>
attach(PixFmt & pixf,int x1,int y1,int x2,int y2)1630         bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
1631         {
1632             rect_i r(x1, y1, x2, y2);
1633             if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
1634             {
1635                 int stride = pixf.stride();
1636                 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
1637                                (r.x2 - r.x1) + 1,
1638                                (r.y2 - r.y1) + 1,
1639                                stride);
1640                 return true;
1641             }
1642             return false;
1643         }
1644 
1645         //--------------------------------------------------------------------
width()1646         AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
height()1647         AGG_INLINE unsigned height() const { return m_rbuf->height(); }
stride()1648         AGG_INLINE int      stride() const { return m_rbuf->stride(); }
1649 
1650         //--------------------------------------------------------------------
row_ptr(int y)1651         AGG_INLINE       int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
row_ptr(int y)1652         AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row(int y)1653         AGG_INLINE row_data     row(int y)     const { return m_rbuf->row(y); }
1654 
1655         //--------------------------------------------------------------------
pix_ptr(int x,int y)1656         AGG_INLINE int8u* pix_ptr(int x, int y)
1657         {
1658             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
1659         }
1660 
pix_ptr(int x,int y)1661         AGG_INLINE const int8u* pix_ptr(int x, int y) const
1662         {
1663             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
1664         }
1665 
1666         // Return pointer to pixel value, forcing row to be allocated.
pix_value_ptr(int x,int y,unsigned len)1667         AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
1668         {
1669             return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step));
1670         }
1671 
1672         // Return pointer to pixel value, or null if row not allocated.
pix_value_ptr(int x,int y)1673         AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
1674         {
1675             int8u* p = m_rbuf->row_ptr(y);
1676             return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0;
1677         }
1678 
1679         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(void * p)1680         AGG_INLINE static pixel_type* pix_value_ptr(void* p)
1681         {
1682             return (pixel_type*)p;
1683         }
1684 
1685         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(const void * p)1686         AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
1687         {
1688             return (const pixel_type*)p;
1689         }
1690 
1691         //--------------------------------------------------------------------
write_plain_color(void * p,color_type c)1692         AGG_INLINE static void write_plain_color(void* p, color_type c)
1693         {
1694             blender_type::set_plain_color(pix_value_ptr(p)->c, c);
1695         }
1696 
1697         //--------------------------------------------------------------------
read_plain_color(const void * p)1698         AGG_INLINE static color_type read_plain_color(const void* p)
1699         {
1700             return blender_type::get_plain_color(pix_value_ptr(p)->c);
1701         }
1702 
1703         //--------------------------------------------------------------------
make_pix(int8u * p,const color_type & c)1704         AGG_INLINE static void make_pix(int8u* p, const color_type& c)
1705         {
1706             ((pixel_type*)p)->set(c);
1707         }
1708 
1709         //--------------------------------------------------------------------
pixel(int x,int y)1710         AGG_INLINE color_type pixel(int x, int y) const
1711         {
1712             if (const pixel_type* p = pix_value_ptr(x, y))
1713             {
1714                 return p->get();
1715             }
1716             return color_type::no_color();
1717         }
1718 
1719         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)1720         AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
1721         {
1722             pix_value_ptr(x, y, 1)->set(c);
1723         }
1724 
1725         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,int8u cover)1726         AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
1727         {
1728             copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
1729         }
1730 
1731         //--------------------------------------------------------------------
copy_hline(int x,int y,unsigned len,const color_type & c)1732         AGG_INLINE void copy_hline(int x, int y,
1733                                    unsigned len,
1734                                    const color_type& c)
1735         {
1736             pixel_type v;
1737             v.set(c);
1738             pixel_type* p = pix_value_ptr(x, y, len);
1739             do
1740             {
1741                 *p = v;
1742                 p = p->next();
1743             }
1744             while (--len);
1745         }
1746 
1747 
1748         //--------------------------------------------------------------------
copy_vline(int x,int y,unsigned len,const color_type & c)1749         AGG_INLINE void copy_vline(int x, int y,
1750                                    unsigned len,
1751                                    const color_type& c)
1752         {
1753             pixel_type v;
1754             v.set(c);
1755             do
1756             {
1757                 *pix_value_ptr(x, y++, 1) = v;
1758             }
1759             while (--len);
1760         }
1761 
1762         //--------------------------------------------------------------------
blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)1763         void blend_hline(int x, int y,
1764                          unsigned len,
1765                          const color_type& c,
1766                          int8u cover)
1767         {
1768             if (!c.is_transparent())
1769             {
1770                 pixel_type* p = pix_value_ptr(x, y, len);
1771                 if (c.is_opaque() && cover == cover_mask)
1772                 {
1773                     pixel_type v;
1774                     v.set(c);
1775                     do
1776                     {
1777                         *p = v;
1778                         p = p->next();
1779                     }
1780                     while (--len);
1781                 }
1782                 else
1783                 {
1784                     if (cover == cover_mask)
1785                     {
1786                         do
1787                         {
1788                             blend_pix(p, c);
1789                             p = p->next();
1790                         }
1791                         while (--len);
1792                     }
1793                     else
1794                     {
1795                         do
1796                         {
1797                             blend_pix(p, c, cover);
1798                             p = p->next();
1799                         }
1800                         while (--len);
1801                     }
1802                 }
1803             }
1804         }
1805 
1806 
1807         //--------------------------------------------------------------------
blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)1808         void blend_vline(int x, int y,
1809                          unsigned len,
1810                          const color_type& c,
1811                          int8u cover)
1812         {
1813             if (!c.is_transparent())
1814             {
1815                 if (c.is_opaque() && cover == cover_mask)
1816                 {
1817                     pixel_type v;
1818                     v.set(c);
1819                     do
1820                     {
1821                         *pix_value_ptr(x, y++, 1) = v;
1822                     }
1823                     while (--len);
1824                 }
1825                 else
1826                 {
1827                     if (cover == cover_mask)
1828                     {
1829                         do
1830                         {
1831                             blend_pix(pix_value_ptr(x, y++, 1), c, c.a);
1832                         }
1833                         while (--len);
1834                     }
1835                     else
1836                     {
1837                         do
1838                         {
1839                             blend_pix(pix_value_ptr(x, y++, 1), c, cover);
1840                         }
1841                         while (--len);
1842                     }
1843                 }
1844             }
1845         }
1846 
1847 
1848         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)1849         void blend_solid_hspan(int x, int y,
1850                                unsigned len,
1851                                const color_type& c,
1852                                const int8u* covers)
1853         {
1854             if (!c.is_transparent())
1855             {
1856                 pixel_type* p = pix_value_ptr(x, y, len);
1857                 do
1858                 {
1859                     if (c.is_opaque() && *covers == cover_mask)
1860                     {
1861                         p->set(c);
1862                     }
1863                     else
1864                     {
1865                         blend_pix(p, c, *covers);
1866                     }
1867                     p = p->next();
1868                     ++covers;
1869                 }
1870                 while (--len);
1871             }
1872         }
1873 
1874 
1875         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)1876         void blend_solid_vspan(int x, int y,
1877                                unsigned len,
1878                                const color_type& c,
1879                                const int8u* covers)
1880         {
1881             if (!c.is_transparent())
1882             {
1883                 do
1884                 {
1885                     pixel_type* p = pix_value_ptr(x, y++, 1);
1886                     if (c.is_opaque() && *covers == cover_mask)
1887                     {
1888                         p->set(c);
1889                     }
1890                     else
1891                     {
1892                         blend_pix(p, c, *covers);
1893                     }
1894                     ++covers;
1895                 }
1896                 while (--len);
1897             }
1898         }
1899 
1900         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,unsigned len,const color_type * colors)1901         void copy_color_hspan(int x, int y,
1902                               unsigned len,
1903                               const color_type* colors)
1904         {
1905             pixel_type* p = pix_value_ptr(x, y, len);
1906             do
1907             {
1908                 p->set(*colors++);
1909                 p = p->next();
1910             }
1911             while (--len);
1912         }
1913 
1914 
1915         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,unsigned len,const color_type * colors)1916         void copy_color_vspan(int x, int y,
1917                               unsigned len,
1918                               const color_type* colors)
1919         {
1920             do
1921             {
1922                 pix_value_ptr(x, y++, 1)->set(*colors++);
1923             }
1924             while (--len);
1925         }
1926 
1927         //--------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)1928         void blend_color_hspan(int x, int y,
1929                                unsigned len,
1930                                const color_type* colors,
1931                                const int8u* covers,
1932                                int8u cover)
1933         {
1934             pixel_type* p = pix_value_ptr(x, y, len);
1935             if (covers)
1936             {
1937                 do
1938                 {
1939                     copy_or_blend_pix(p, *colors++, *covers++);
1940                     p = p->next();
1941                 }
1942                 while (--len);
1943             }
1944             else
1945             {
1946                 if (cover == cover_mask)
1947                 {
1948                     do
1949                     {
1950                         copy_or_blend_pix(p, *colors++);
1951                         p = p->next();
1952                     }
1953                     while (--len);
1954                 }
1955                 else
1956                 {
1957                     do
1958                     {
1959                         copy_or_blend_pix(p, *colors++, cover);
1960                         p = p->next();
1961                     }
1962                     while (--len);
1963                 }
1964             }
1965         }
1966 
1967         //--------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)1968         void blend_color_vspan(int x, int y,
1969                                unsigned len,
1970                                const color_type* colors,
1971                                const int8u* covers,
1972                                int8u cover)
1973         {
1974             if (covers)
1975             {
1976                 do
1977                 {
1978                     copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
1979                 }
1980                 while (--len);
1981             }
1982             else
1983             {
1984                 if (cover == cover_mask)
1985                 {
1986                     do
1987                     {
1988                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
1989                     }
1990                     while (--len);
1991                 }
1992                 else
1993                 {
1994                     do
1995                     {
1996                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
1997                     }
1998                     while (--len);
1999                 }
2000             }
2001         }
2002 
2003         //--------------------------------------------------------------------
for_each_pixel(Function f)2004         template<class Function> void for_each_pixel(Function f)
2005         {
2006             for (unsigned y = 0; y < height(); ++y)
2007             {
2008                 row_data r = m_rbuf->row(y);
2009                 if (r.ptr)
2010                 {
2011                     unsigned len = r.x2 - r.x1 + 1;
2012                     pixel_type* p = pix_value_ptr(r.x1, y, len);
2013                     do
2014                     {
2015                         f(p->c);
2016                         p = p->next();
2017                     }
2018                     while (--len);
2019                 }
2020             }
2021         }
2022 
2023         //--------------------------------------------------------------------
premultiply()2024         void premultiply()
2025         {
2026             for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply);
2027         }
2028 
2029         //--------------------------------------------------------------------
demultiply()2030         void demultiply()
2031         {
2032             for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply);
2033         }
2034 
2035         //--------------------------------------------------------------------
apply_gamma_dir(const GammaLut & g)2036         template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
2037         {
2038             for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g));
2039         }
2040 
2041         //--------------------------------------------------------------------
apply_gamma_inv(const GammaLut & g)2042         template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
2043         {
2044             for_each_pixel(apply_gamma_inv_rgba<color_type, order_type, GammaLut>(g));
2045         }
2046 
2047         //--------------------------------------------------------------------
copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)2048         template<class RenBuf2> void copy_from(const RenBuf2& from,
2049                                                int xdst, int ydst,
2050                                                int xsrc, int ysrc,
2051                                                unsigned len)
2052         {
2053             if (const int8u* p = from.row_ptr(ysrc))
2054             {
2055                 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
2056                         p + xsrc * pix_width,
2057                         len * pix_width);
2058             }
2059         }
2060 
2061         //--------------------------------------------------------------------
2062         // Blend from another RGBA surface.
2063         template<class SrcPixelFormatRenderer>
blend_from(const SrcPixelFormatRenderer & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2064         void blend_from(const SrcPixelFormatRenderer& from,
2065                         int xdst, int ydst,
2066                         int xsrc, int ysrc,
2067                         unsigned len,
2068                         int8u cover)
2069         {
2070             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2071 
2072             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2073             {
2074                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2075                 int srcinc = 1;
2076                 int dstinc = 1;
2077 
2078                 if (xdst > xsrc)
2079                 {
2080                     psrc = psrc->advance(len - 1);
2081                     pdst = pdst->advance(len - 1);
2082                     srcinc = -1;
2083                     dstinc = -1;
2084                 }
2085 
2086                 if (cover == cover_mask)
2087                 {
2088                     do
2089                     {
2090                         copy_or_blend_pix(pdst, psrc->get());
2091                         psrc = psrc->advance(srcinc);
2092                         pdst = pdst->advance(dstinc);
2093                     }
2094                     while (--len);
2095                 }
2096                 else
2097                 {
2098                     do
2099                     {
2100                         copy_or_blend_pix(pdst, psrc->get(), cover);
2101                         psrc = psrc->advance(srcinc);
2102                         pdst = pdst->advance(dstinc);
2103                     }
2104                     while (--len);
2105                 }
2106             }
2107         }
2108 
2109         //--------------------------------------------------------------------
2110         // Combine single color with grayscale surface and blend.
2111         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)2112         void blend_from_color(const SrcPixelFormatRenderer& from,
2113                               const color_type& color,
2114                               int xdst, int ydst,
2115                               int xsrc, int ysrc,
2116                               unsigned len,
2117                               int8u cover)
2118         {
2119             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2120             typedef typename SrcPixelFormatRenderer::color_type src_color_type;
2121 
2122             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2123             {
2124                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2125 
2126                 do
2127                 {
2128                     copy_or_blend_pix(pdst, color,
2129                         src_color_type::scale_cover(cover, psrc->c[0]));
2130                     psrc = psrc->next();
2131                     pdst = pdst->next();
2132                 }
2133                 while (--len);
2134             }
2135         }
2136 
2137         //--------------------------------------------------------------------
2138         // Blend from color table, using grayscale surface as indexes into table.
2139         // Obviously, this only works for integer value types.
2140         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)2141         void blend_from_lut(const SrcPixelFormatRenderer& from,
2142                             const color_type* color_lut,
2143                             int xdst, int ydst,
2144                             int xsrc, int ysrc,
2145                             unsigned len,
2146                             int8u cover)
2147         {
2148             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2149 
2150             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2151             {
2152                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2153 
2154                 if (cover == cover_mask)
2155                 {
2156                     do
2157                     {
2158                         copy_or_blend_pix(pdst, color_lut[psrc->c[0]]);
2159                         psrc = psrc->next();
2160                         pdst = pdst->next();
2161                     }
2162                     while (--len);
2163                 }
2164                 else
2165                 {
2166                     do
2167                     {
2168                         copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
2169                         psrc = psrc->next();
2170                         pdst = pdst->next();
2171                     }
2172                     while (--len);
2173                 }
2174             }
2175         }
2176 
2177     private:
2178         rbuf_type* m_rbuf;
2179         Blender    m_blender;
2180     };
2181 
2182     //================================================pixfmt_custom_blend_rgba
2183     template<class Blender, class RenBuf> class pixfmt_custom_blend_rgba
2184     {
2185     public:
2186         typedef pixfmt_rgba_tag pixfmt_category;
2187         typedef RenBuf   rbuf_type;
2188         typedef typename rbuf_type::row_data row_data;
2189         typedef Blender  blender_type;
2190         typedef typename blender_type::color_type color_type;
2191         typedef typename blender_type::order_type order_type;
2192         typedef typename color_type::value_type value_type;
2193         typedef typename color_type::calc_type calc_type;
2194         enum
2195         {
2196             num_components = 4,
2197             pix_step = 4,
2198             pix_width  = sizeof(value_type) * pix_step,
2199         };
2200         struct pixel_type
2201         {
2202             value_type c[num_components];
2203 
setpixel_type2204             void set(value_type r, value_type g, value_type b, value_type a)
2205             {
2206                 c[order_type::R] = r;
2207                 c[order_type::G] = g;
2208                 c[order_type::B] = b;
2209                 c[order_type::A] = a;
2210             }
2211 
setpixel_type2212             void set(const color_type& color)
2213             {
2214                 set(color.r, color.g, color.b, color.a);
2215             }
2216 
getpixel_type2217             void get(value_type& r, value_type& g, value_type& b, value_type& a) const
2218             {
2219                 r = c[order_type::R];
2220                 g = c[order_type::G];
2221                 b = c[order_type::B];
2222                 a = c[order_type::A];
2223             }
2224 
getpixel_type2225             color_type get() const
2226             {
2227                 return color_type(
2228                     c[order_type::R],
2229                     c[order_type::G],
2230                     c[order_type::B],
2231                     c[order_type::A]);
2232             }
2233 
nextpixel_type2234             pixel_type* next()
2235             {
2236                 return (pixel_type*)(c + pix_step);
2237             }
2238 
nextpixel_type2239             const pixel_type* next() const
2240             {
2241                 return (const pixel_type*)(c + pix_step);
2242             }
2243 
advancepixel_type2244             pixel_type* advance(int n)
2245             {
2246                 return (pixel_type*)(c + n * pix_step);
2247             }
2248 
advancepixel_type2249             const pixel_type* advance(int n) const
2250             {
2251                 return (const pixel_type*)(c + n * pix_step);
2252             }
2253         };
2254 
2255 
2256     private:
2257         //--------------------------------------------------------------------
2258         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full)
2259         {
2260             m_blender.blend_pix(m_comp_op, p->c, c.r, c.g, c.b, c.a, cover);
2261         }
2262 
2263         //--------------------------------------------------------------------
2264         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full)
2265         {
2266             if (!c.is_transparent())
2267             {
2268                 if (c.is_opaque() && cover == cover_mask)
2269                 {
2270                     p->set(c.r, c.g, c.b, c.a);
2271                 }
2272                 else
2273                 {
2274                     blend_pix(p, c, cover);
2275                 }
2276             }
2277         }
2278 
2279     public:
2280         //--------------------------------------------------------------------
pixfmt_custom_blend_rgba()2281         pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {}
2282         explicit pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned comp_op=3) :
2283             m_rbuf(&rb),
2284             m_comp_op(comp_op)
2285         {}
attach(rbuf_type & rb)2286         void attach(rbuf_type& rb) { m_rbuf = &rb; }
2287 
2288         //--------------------------------------------------------------------
2289         template<class PixFmt>
attach(PixFmt & pixf,int x1,int y1,int x2,int y2)2290         bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
2291         {
2292             rect_i r(x1, y1, x2, y2);
2293             if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
2294             {
2295                 int stride = pixf.stride();
2296                 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
2297                                (r.x2 - r.x1) + 1,
2298                                (r.y2 - r.y1) + 1,
2299                                stride);
2300                 return true;
2301             }
2302             return false;
2303         }
2304 
2305         //--------------------------------------------------------------------
comp_op(unsigned op)2306         void comp_op(unsigned op) { m_comp_op = op; }
comp_op()2307         unsigned comp_op() const  { return m_comp_op; }
2308 
2309         //--------------------------------------------------------------------
width()2310         AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
height()2311         AGG_INLINE unsigned height() const { return m_rbuf->height(); }
stride()2312         AGG_INLINE int      stride() const { return m_rbuf->stride(); }
2313 
2314         //--------------------------------------------------------------------
row_ptr(int y)2315         AGG_INLINE       int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
row_ptr(int y)2316         AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row(int y)2317         AGG_INLINE row_data     row(int y)     const { return m_rbuf->row(y); }
2318 
2319         //--------------------------------------------------------------------
pix_ptr(int x,int y)2320         AGG_INLINE int8u* pix_ptr(int x, int y)
2321         {
2322             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
2323         }
2324 
pix_ptr(int x,int y)2325         AGG_INLINE const int8u* pix_ptr(int x, int y) const
2326         {
2327             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step);
2328         }
2329 
2330         // Return pointer to pixel value, forcing row to be allocated.
pix_value_ptr(int x,int y,unsigned len)2331         AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
2332         {
2333             return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step));
2334         }
2335 
2336         // Return pointer to pixel value, or null if row not allocated.
pix_value_ptr(int x,int y)2337         AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
2338         {
2339             int8u* p = m_rbuf->row_ptr(y);
2340             return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0;
2341         }
2342 
2343         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(void * p)2344         AGG_INLINE static pixel_type* pix_value_ptr(void* p)
2345         {
2346             return (pixel_type*)p;
2347         }
2348 
2349         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(const void * p)2350         AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
2351         {
2352             return (const pixel_type*)p;
2353         }
2354 
2355         //--------------------------------------------------------------------
make_pix(int8u * p,const color_type & c)2356         AGG_INLINE static void make_pix(int8u* p, const color_type& c)
2357         {
2358             ((pixel_type*)p)->set(c);
2359         }
2360 
2361         //--------------------------------------------------------------------
pixel(int x,int y)2362         AGG_INLINE color_type pixel(int x, int y) const
2363         {
2364             if (const pixel_type* p = pix_value_ptr(x, y))
2365             {
2366                 return p->get();
2367             }
2368             return color_type::no_color();
2369         }
2370 
2371         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)2372         AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
2373         {
2374             pix_value_ptr(x, y, 1)->set(c);
2375         }
2376 
2377         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,int8u cover)2378         AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
2379         {
2380             blend_pix(pix_value_ptr(x, y, 1), c, cover);
2381         }
2382 
2383         //--------------------------------------------------------------------
copy_hline(int x,int y,unsigned len,const color_type & c)2384         AGG_INLINE void copy_hline(int x, int y,
2385                                    unsigned len,
2386                                    const color_type& c)
2387         {
2388             pixel_type v;
2389             v.set(c);
2390             pixel_type* p = pix_value_ptr(x, y, len);
2391             do
2392             {
2393                 *p = v;
2394                 p = p->next();
2395             }
2396             while (--len);
2397         }
2398 
2399 
2400         //--------------------------------------------------------------------
copy_vline(int x,int y,unsigned len,const color_type & c)2401         AGG_INLINE void copy_vline(int x, int y,
2402                                    unsigned len,
2403                                    const color_type& c)
2404         {
2405             pixel_type v;
2406             v.set(c);
2407             do
2408             {
2409                 *pix_value_ptr(x, y++, 1) = v;
2410             }
2411             while (--len);
2412         }
2413 
2414         //--------------------------------------------------------------------
blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)2415         void blend_hline(int x, int y, unsigned len,
2416                          const color_type& c, int8u cover)
2417         {
2418 
2419             pixel_type* p = pix_value_ptr(x, y, len);
2420             do
2421             {
2422                 blend_pix(p, c, cover);
2423                 p = p->next();
2424             }
2425             while (--len);
2426         }
2427 
2428         //--------------------------------------------------------------------
blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)2429         void blend_vline(int x, int y, unsigned len,
2430                          const color_type& c, int8u cover)
2431         {
2432             do
2433             {
2434                 blend_pix(pix_value_ptr(x, y++, 1), c, cover);
2435             }
2436             while (--len);
2437         }
2438 
2439         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)2440         void blend_solid_hspan(int x, int y, unsigned len,
2441                                const color_type& c, const int8u* covers)
2442         {
2443             pixel_type* p = pix_value_ptr(x, y, len);
2444 
2445             do
2446             {
2447                 blend_pix(p, c, *covers++);
2448                 p = p->next();
2449             }
2450             while (--len);
2451         }
2452 
2453         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)2454         void blend_solid_vspan(int x, int y, unsigned len,
2455                                const color_type& c, const int8u* covers)
2456         {
2457             do
2458             {
2459                 blend_pix(pix_value_ptr(x, y++, 1), c, *covers++);
2460             }
2461             while (--len);
2462         }
2463 
2464         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,unsigned len,const color_type * colors)2465         void copy_color_hspan(int x, int y,
2466                               unsigned len,
2467                               const color_type* colors)
2468         {
2469             pixel_type* p = pix_value_ptr(x, y, len);
2470 
2471             do
2472             {
2473                 p->set(*colors++);
2474                 p = p->next();
2475             }
2476             while (--len);
2477         }
2478 
2479         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,unsigned len,const color_type * colors)2480         void copy_color_vspan(int x, int y,
2481                               unsigned len,
2482                               const color_type* colors)
2483         {
2484             do
2485             {
2486                 pix_value_ptr(x, y++, 1)->set(*colors++);
2487             }
2488             while (--len);
2489         }
2490 
2491         //--------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)2492         void blend_color_hspan(int x, int y, unsigned len,
2493                                const color_type* colors,
2494                                const int8u* covers,
2495                                int8u cover)
2496         {
2497             pixel_type* p = pix_value_ptr(x, y, len);
2498 
2499             do
2500             {
2501                 blend_pix(p, *colors++, covers ? *covers++ : cover);
2502                 p = p->next();
2503             }
2504             while (--len);
2505         }
2506 
2507         //--------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)2508         void blend_color_vspan(int x, int y, unsigned len,
2509                                const color_type* colors,
2510                                const int8u* covers,
2511                                int8u cover)
2512         {
2513             do
2514             {
2515                 blend_pix(pix_value_ptr(x, y++, 1), *colors++, covers ? *covers++ : cover);
2516             }
2517             while (--len);
2518 
2519         }
2520 
2521         //--------------------------------------------------------------------
for_each_pixel(Function f)2522         template<class Function> void for_each_pixel(Function f)
2523         {
2524             unsigned y;
2525             for (y = 0; y < height(); ++y)
2526             {
2527                 row_data r = m_rbuf->row(y);
2528                 if (r.ptr)
2529                 {
2530                     unsigned len = r.x2 - r.x1 + 1;
2531                     pixel_type* p = pix_value_ptr(r.x1, y, len);
2532                     do
2533                     {
2534                         f(p->c);
2535                         p = p->next();
2536                     }
2537                     while (--len);
2538                 }
2539             }
2540         }
2541 
2542         //--------------------------------------------------------------------
premultiply()2543         void premultiply()
2544         {
2545             for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply);
2546         }
2547 
2548         //--------------------------------------------------------------------
demultiply()2549         void demultiply()
2550         {
2551             for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply);
2552         }
2553 
2554         //--------------------------------------------------------------------
apply_gamma_dir(const GammaLut & g)2555         template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
2556         {
2557             for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g));
2558         }
2559 
2560         //--------------------------------------------------------------------
apply_gamma_inv(const GammaLut & g)2561         template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
2562         {
2563             for_each_pixel(apply_gamma_inv_rgba<color_type, order_type, GammaLut>(g));
2564         }
2565 
2566         //--------------------------------------------------------------------
copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)2567         template<class RenBuf2> void copy_from(const RenBuf2& from,
2568                                                int xdst, int ydst,
2569                                                int xsrc, int ysrc,
2570                                                unsigned len)
2571         {
2572             if (const int8u* p = from.row_ptr(ysrc))
2573             {
2574                 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
2575                         p + xsrc * pix_width,
2576                         len * pix_width);
2577             }
2578         }
2579 
2580         //--------------------------------------------------------------------
2581         // Blend from another RGBA surface.
2582         template<class SrcPixelFormatRenderer>
blend_from(const SrcPixelFormatRenderer & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)2583         void blend_from(const SrcPixelFormatRenderer& from,
2584                         int xdst, int ydst,
2585                         int xsrc, int ysrc,
2586                         unsigned len,
2587                         int8u cover)
2588         {
2589             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2590 
2591             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2592             {
2593                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2594                 int srcinc = 1;
2595                 int dstinc = 1;
2596 
2597                 if (xdst > xsrc)
2598                 {
2599                     psrc = psrc->advance(len - 1);
2600                     pdst = pdst->advance(len - 1);
2601                     srcinc = -1;
2602                     dstinc = -1;
2603                 }
2604 
2605                 do
2606                 {
2607                     blend_pix(pdst, psrc->get(), cover);
2608                     psrc = psrc->advance(srcinc);
2609                     pdst = pdst->advance(dstinc);
2610                 }
2611                 while (--len);
2612             }
2613         }
2614 
2615         //--------------------------------------------------------------------
2616         // Blend from single color, using grayscale surface as alpha channel.
2617         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)2618         void blend_from_color(const SrcPixelFormatRenderer& from,
2619                               const color_type& color,
2620                               int xdst, int ydst,
2621                               int xsrc, int ysrc,
2622                               unsigned len,
2623                               int8u cover)
2624         {
2625             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2626             typedef typename SrcPixelFormatRenderer::color_type src_color_type;
2627 
2628             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2629             {
2630                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2631 
2632                 do
2633                 {
2634                     blend_pix(pdst, color,
2635                         src_color_type::scale_cover(cover, psrc->c[0]));
2636                     psrc = psrc->next();
2637                     pdst = pdst->next();
2638                 }
2639                 while (--len);
2640             }
2641         }
2642 
2643         //--------------------------------------------------------------------
2644         // Blend from color table, using grayscale surface as indexes into table.
2645         // Obviously, this only works for integer value types.
2646         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)2647         void blend_from_lut(const SrcPixelFormatRenderer& from,
2648                             const color_type* color_lut,
2649                             int xdst, int ydst,
2650                             int xsrc, int ysrc,
2651                             unsigned len,
2652                             int8u cover)
2653         {
2654             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
2655 
2656             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
2657             {
2658                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
2659 
2660                 do
2661                 {
2662                     blend_pix(pdst, color_lut[psrc->c[0]], cover);
2663                     psrc = psrc->next();
2664                     pdst = pdst->next();
2665                 }
2666                 while (--len);
2667             }
2668         }
2669 
2670     private:
2671         rbuf_type* m_rbuf;
2672         Blender m_blender;
2673         unsigned m_comp_op;
2674     };
2675 
2676 
2677     //-----------------------------------------------------------------------
2678     typedef blender_rgba<rgba8, order_rgba> blender_rgba32;
2679     typedef blender_rgba<rgba8, order_argb> blender_argb32;
2680     typedef blender_rgba<rgba8, order_abgr> blender_abgr32;
2681     typedef blender_rgba<rgba8, order_bgra> blender_bgra32;
2682 
2683     typedef blender_rgba<srgba8, order_rgba> blender_srgba32;
2684     typedef blender_rgba<srgba8, order_argb> blender_sargb32;
2685     typedef blender_rgba<srgba8, order_abgr> blender_sabgr32;
2686     typedef blender_rgba<srgba8, order_bgra> blender_sbgra32;
2687 
2688     typedef blender_rgba_pre<rgba8, order_rgba> blender_rgba32_pre;
2689     typedef blender_rgba_pre<rgba8, order_argb> blender_argb32_pre;
2690     typedef blender_rgba_pre<rgba8, order_abgr> blender_abgr32_pre;
2691     typedef blender_rgba_pre<rgba8, order_bgra> blender_bgra32_pre;
2692 
2693     typedef blender_rgba_pre<srgba8, order_rgba> blender_srgba32_pre;
2694     typedef blender_rgba_pre<srgba8, order_argb> blender_sargb32_pre;
2695     typedef blender_rgba_pre<srgba8, order_abgr> blender_sabgr32_pre;
2696     typedef blender_rgba_pre<srgba8, order_bgra> blender_sbgra32_pre;
2697 
2698     typedef blender_rgba_plain<rgba8, order_rgba> blender_rgba32_plain;
2699     typedef blender_rgba_plain<rgba8, order_argb> blender_argb32_plain;
2700     typedef blender_rgba_plain<rgba8, order_abgr> blender_abgr32_plain;
2701     typedef blender_rgba_plain<rgba8, order_bgra> blender_bgra32_plain;
2702 
2703     typedef blender_rgba_plain<srgba8, order_rgba> blender_srgba32_plain;
2704     typedef blender_rgba_plain<srgba8, order_argb> blender_sargb32_plain;
2705     typedef blender_rgba_plain<srgba8, order_abgr> blender_sabgr32_plain;
2706     typedef blender_rgba_plain<srgba8, order_bgra> blender_sbgra32_plain;
2707 
2708     typedef blender_rgba<rgba16, order_rgba> blender_rgba64;
2709     typedef blender_rgba<rgba16, order_argb> blender_argb64;
2710     typedef blender_rgba<rgba16, order_abgr> blender_abgr64;
2711     typedef blender_rgba<rgba16, order_bgra> blender_bgra64;
2712 
2713     typedef blender_rgba_pre<rgba16, order_rgba> blender_rgba64_pre;
2714     typedef blender_rgba_pre<rgba16, order_argb> blender_argb64_pre;
2715     typedef blender_rgba_pre<rgba16, order_abgr> blender_abgr64_pre;
2716     typedef blender_rgba_pre<rgba16, order_bgra> blender_bgra64_pre;
2717 
2718 	typedef blender_rgba_plain<rgba16, order_rgba> blender_rgba64_plain;
2719 	typedef blender_rgba_plain<rgba16, order_argb> blender_argb64_plain;
2720 	typedef blender_rgba_plain<rgba16, order_abgr> blender_abgr64_plain;
2721 	typedef blender_rgba_plain<rgba16, order_bgra> blender_bgra64_plain;
2722 
2723 	typedef blender_rgba<rgba32, order_rgba> blender_rgba128;
2724     typedef blender_rgba<rgba32, order_argb> blender_argb128;
2725     typedef blender_rgba<rgba32, order_abgr> blender_abgr128;
2726     typedef blender_rgba<rgba32, order_bgra> blender_bgra128;
2727 
2728     typedef blender_rgba_pre<rgba32, order_rgba> blender_rgba128_pre;
2729     typedef blender_rgba_pre<rgba32, order_argb> blender_argb128_pre;
2730     typedef blender_rgba_pre<rgba32, order_abgr> blender_abgr128_pre;
2731     typedef blender_rgba_pre<rgba32, order_bgra> blender_bgra128_pre;
2732 
2733     typedef blender_rgba_plain<rgba32, order_rgba> blender_rgba128_plain;
2734     typedef blender_rgba_plain<rgba32, order_argb> blender_argb128_plain;
2735     typedef blender_rgba_plain<rgba32, order_abgr> blender_abgr128_plain;
2736     typedef blender_rgba_plain<rgba32, order_bgra> blender_bgra128_plain;
2737 
2738 
2739     //-----------------------------------------------------------------------
2740     typedef pixfmt_alpha_blend_rgba<blender_rgba32, rendering_buffer> pixfmt_rgba32;
2741     typedef pixfmt_alpha_blend_rgba<blender_argb32, rendering_buffer> pixfmt_argb32;
2742     typedef pixfmt_alpha_blend_rgba<blender_abgr32, rendering_buffer> pixfmt_abgr32;
2743     typedef pixfmt_alpha_blend_rgba<blender_bgra32, rendering_buffer> pixfmt_bgra32;
2744 
2745     typedef pixfmt_alpha_blend_rgba<blender_srgba32, rendering_buffer> pixfmt_srgba32;
2746     typedef pixfmt_alpha_blend_rgba<blender_sargb32, rendering_buffer> pixfmt_sargb32;
2747     typedef pixfmt_alpha_blend_rgba<blender_sabgr32, rendering_buffer> pixfmt_sabgr32;
2748     typedef pixfmt_alpha_blend_rgba<blender_sbgra32, rendering_buffer> pixfmt_sbgra32;
2749 
2750     typedef pixfmt_alpha_blend_rgba<blender_rgba32_pre, rendering_buffer> pixfmt_rgba32_pre;
2751     typedef pixfmt_alpha_blend_rgba<blender_argb32_pre, rendering_buffer> pixfmt_argb32_pre;
2752     typedef pixfmt_alpha_blend_rgba<blender_abgr32_pre, rendering_buffer> pixfmt_abgr32_pre;
2753     typedef pixfmt_alpha_blend_rgba<blender_bgra32_pre, rendering_buffer> pixfmt_bgra32_pre;
2754 
2755     typedef pixfmt_alpha_blend_rgba<blender_srgba32_pre, rendering_buffer> pixfmt_srgba32_pre;
2756     typedef pixfmt_alpha_blend_rgba<blender_sargb32_pre, rendering_buffer> pixfmt_sargb32_pre;
2757     typedef pixfmt_alpha_blend_rgba<blender_sabgr32_pre, rendering_buffer> pixfmt_sabgr32_pre;
2758     typedef pixfmt_alpha_blend_rgba<blender_sbgra32_pre, rendering_buffer> pixfmt_sbgra32_pre;
2759 
2760     typedef pixfmt_alpha_blend_rgba<blender_rgba32_plain, rendering_buffer> pixfmt_rgba32_plain;
2761     typedef pixfmt_alpha_blend_rgba<blender_argb32_plain, rendering_buffer> pixfmt_argb32_plain;
2762     typedef pixfmt_alpha_blend_rgba<blender_abgr32_plain, rendering_buffer> pixfmt_abgr32_plain;
2763     typedef pixfmt_alpha_blend_rgba<blender_bgra32_plain, rendering_buffer> pixfmt_bgra32_plain;
2764 
2765     typedef pixfmt_alpha_blend_rgba<blender_srgba32_plain, rendering_buffer> pixfmt_srgba32_plain;
2766     typedef pixfmt_alpha_blend_rgba<blender_sargb32_plain, rendering_buffer> pixfmt_sargb32_plain;
2767     typedef pixfmt_alpha_blend_rgba<blender_sabgr32_plain, rendering_buffer> pixfmt_sabgr32_plain;
2768     typedef pixfmt_alpha_blend_rgba<blender_sbgra32_plain, rendering_buffer> pixfmt_sbgra32_plain;
2769 
2770     typedef pixfmt_alpha_blend_rgba<blender_rgba64, rendering_buffer> pixfmt_rgba64;
2771     typedef pixfmt_alpha_blend_rgba<blender_argb64, rendering_buffer> pixfmt_argb64;
2772     typedef pixfmt_alpha_blend_rgba<blender_abgr64, rendering_buffer> pixfmt_abgr64;
2773     typedef pixfmt_alpha_blend_rgba<blender_bgra64, rendering_buffer> pixfmt_bgra64;
2774 
2775     typedef pixfmt_alpha_blend_rgba<blender_rgba64_pre, rendering_buffer> pixfmt_rgba64_pre;
2776     typedef pixfmt_alpha_blend_rgba<blender_argb64_pre, rendering_buffer> pixfmt_argb64_pre;
2777     typedef pixfmt_alpha_blend_rgba<blender_abgr64_pre, rendering_buffer> pixfmt_abgr64_pre;
2778     typedef pixfmt_alpha_blend_rgba<blender_bgra64_pre, rendering_buffer> pixfmt_bgra64_pre;
2779 
2780 	typedef pixfmt_alpha_blend_rgba<blender_rgba64_plain, rendering_buffer> pixfmt_rgba64_plain;
2781 	typedef pixfmt_alpha_blend_rgba<blender_argb64_plain, rendering_buffer> pixfmt_argb64_plain;
2782 	typedef pixfmt_alpha_blend_rgba<blender_abgr64_plain, rendering_buffer> pixfmt_abgr64_plain;
2783 	typedef pixfmt_alpha_blend_rgba<blender_bgra64_plain, rendering_buffer> pixfmt_bgra64_plain;
2784 
2785 	typedef pixfmt_alpha_blend_rgba<blender_rgba128, rendering_buffer> pixfmt_rgba128;
2786     typedef pixfmt_alpha_blend_rgba<blender_argb128, rendering_buffer> pixfmt_argb128;
2787     typedef pixfmt_alpha_blend_rgba<blender_abgr128, rendering_buffer> pixfmt_abgr128;
2788     typedef pixfmt_alpha_blend_rgba<blender_bgra128, rendering_buffer> pixfmt_bgra128;
2789 
2790     typedef pixfmt_alpha_blend_rgba<blender_rgba128_pre, rendering_buffer> pixfmt_rgba128_pre;
2791     typedef pixfmt_alpha_blend_rgba<blender_argb128_pre, rendering_buffer> pixfmt_argb128_pre;
2792     typedef pixfmt_alpha_blend_rgba<blender_abgr128_pre, rendering_buffer> pixfmt_abgr128_pre;
2793     typedef pixfmt_alpha_blend_rgba<blender_bgra128_pre, rendering_buffer> pixfmt_bgra128_pre;
2794 
2795     typedef pixfmt_alpha_blend_rgba<blender_rgba128_plain, rendering_buffer> pixfmt_rgba128_plain;
2796     typedef pixfmt_alpha_blend_rgba<blender_argb128_plain, rendering_buffer> pixfmt_argb128_plain;
2797     typedef pixfmt_alpha_blend_rgba<blender_abgr128_plain, rendering_buffer> pixfmt_abgr128_plain;
2798     typedef pixfmt_alpha_blend_rgba<blender_bgra128_plain, rendering_buffer> pixfmt_bgra128_plain;
2799 
2800 }
2801 
2802 #endif
2803 
2804