//----------------------------------------------------------------------------
// Anti-Grain Geometry (AGG) - Version 2.5
// A high quality rendering engine for C++
// Copyright (C) 2002-2006 Maxim Shemanarev
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://antigrain.com
// 
// AGG is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// AGG is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with AGG; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
// MA 02110-1301, USA.
//----------------------------------------------------------------------------
//
// Adaptation for high precision colors has been sponsored by 
// Liberty Technology Systems, Inc., visit http://lib-sys.com
//
// Liberty Technology Systems, Inc. is the provider of
// PostScript and PDF technology for software developers.
// 
//----------------------------------------------------------------------------

#ifndef AGG_PIXFMT_RGBA_INCLUDED
#define AGG_PIXFMT_RGBA_INCLUDED

#include <string.h>
#include <math.h>
#include "agg_basics.h"
#include "agg_color_rgba.h"
#include "agg_rendering_buffer.h"

namespace agg
{

    //=========================================================multiplier_rgba
    template<class ColorT, class Order> struct multiplier_rgba
    {
        typedef typename ColorT::value_type value_type;
        typedef typename ColorT::calc_type calc_type;

        //--------------------------------------------------------------------
        static AGG_INLINE void premultiply(value_type* p)
        {
            calc_type a = p[Order::A];
            if(a < ColorT::base_mask)
            {
                if(a == 0)
                {
                    p[Order::R] = p[Order::G] = p[Order::B] = 0;
                    return;
                }
                p[Order::R] = value_type((p[Order::R] * a + ColorT::base_mask) >> ColorT::base_shift);
                p[Order::G] = value_type((p[Order::G] * a + ColorT::base_mask) >> ColorT::base_shift);
                p[Order::B] = value_type((p[Order::B] * a + ColorT::base_mask) >> ColorT::base_shift);
            }
        }


        //--------------------------------------------------------------------
        static AGG_INLINE void demultiply(value_type* p)
        {
            calc_type a = p[Order::A];
            if(a < ColorT::base_mask)
            {
                if(a == 0)
                {
                    p[Order::R] = p[Order::G] = p[Order::B] = 0;
                    return;
                }
                calc_type r = (calc_type(p[Order::R]) * ColorT::base_mask) / a;
                calc_type g = (calc_type(p[Order::G]) * ColorT::base_mask) / a;
                calc_type b = (calc_type(p[Order::B]) * ColorT::base_mask) / a;
                p[Order::R] = value_type((r > ColorT::base_mask) ? ColorT::base_mask : r);
                p[Order::G] = value_type((g > ColorT::base_mask) ? ColorT::base_mask : g);
                p[Order::B] = value_type((b > ColorT::base_mask) ? ColorT::base_mask : b);
            }
        }
    };

    //=====================================================apply_gamma_dir_rgba
    template<class ColorT, class Order, class GammaLut> class apply_gamma_dir_rgba
    {
    public:
        typedef typename ColorT::value_type value_type;

        apply_gamma_dir_rgba(const GammaLut& gamma) : m_gamma(gamma) {}

        AGG_INLINE void operator () (value_type* p)
        {
            p[Order::R] = m_gamma.dir(p[Order::R]);
            p[Order::G] = m_gamma.dir(p[Order::G]);
            p[Order::B] = m_gamma.dir(p[Order::B]);
        }

    private:
        const GammaLut& m_gamma;
    };

    //=====================================================apply_gamma_inv_rgba
    template<class ColorT, class Order, class GammaLut> class apply_gamma_inv_rgba
    {
    public:
        typedef typename ColorT::value_type value_type;

        apply_gamma_inv_rgba(const GammaLut& gamma) : m_gamma(gamma) {}

        AGG_INLINE void operator () (value_type* p)
        {
            p[Order::R] = m_gamma.inv(p[Order::R]);
            p[Order::G] = m_gamma.inv(p[Order::G]);
            p[Order::B] = m_gamma.inv(p[Order::B]);
        }

    private:
        const GammaLut& m_gamma;
    };


    







    //=============================================================blender_rgba
    template<class ColorT, class Order> struct blender_rgba
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e 
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        //--------------------------------------------------------------------
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned cr, unsigned cg, unsigned cb,
                                         unsigned alpha, 
                                         unsigned cover=0)
        {
            calc_type r = p[Order::R];
            calc_type g = p[Order::G];
            calc_type b = p[Order::B];
            calc_type a = p[Order::A];
            p[Order::R] = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift);
            p[Order::G] = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift);
            p[Order::B] = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift);
            p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift));
        }
    };

    //=========================================================blender_rgba_pre
    template<class ColorT, class Order> struct blender_rgba_pre
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        //--------------------------------------------------------------------
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned cr, unsigned cg, unsigned cb,
                                         unsigned alpha,
                                         unsigned cover)
        {
            alpha = color_type::base_mask - alpha;
            cover = (cover + 1) << (base_shift - 8);
            p[Order::R] = (value_type)((p[Order::R] * alpha + cr * cover) >> base_shift);
            p[Order::G] = (value_type)((p[Order::G] * alpha + cg * cover) >> base_shift);
            p[Order::B] = (value_type)((p[Order::B] * alpha + cb * cover) >> base_shift);
            p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift));
        }

        //--------------------------------------------------------------------
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned cr, unsigned cg, unsigned cb,
                                         unsigned alpha)
        {
            alpha = color_type::base_mask - alpha;
            p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr);
            p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg);
            p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb);
            p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift));
        }
    };

    //======================================================blender_rgba_plain
    template<class ColorT, class Order> struct blender_rgba_plain
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e { base_shift = color_type::base_shift };

        //--------------------------------------------------------------------
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned cr, unsigned cg, unsigned cb,
                                         unsigned alpha,
                                         unsigned cover=0)
        {
            if(alpha == 0) return;
            calc_type a = p[Order::A];
            calc_type r = p[Order::R] * a;
            calc_type g = p[Order::G] * a;
            calc_type b = p[Order::B] * a;
            a = ((alpha + a) << base_shift) - alpha * a;
            p[Order::A] = (value_type)(a >> base_shift);
            p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a);
            p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a);
            p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a);
        }
    };











    //=========================================================comp_op_rgba_clear
    template<class ColorT, class Order> struct comp_op_rgba_clear
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned, unsigned, unsigned, unsigned,
                                         unsigned cover)
        {
            if(cover < 255)
            {
                cover = 255 - cover;
                p[Order::R] = (value_type)((p[Order::R] * cover + 255) >> 8);
                p[Order::G] = (value_type)((p[Order::G] * cover + 255) >> 8);
                p[Order::B] = (value_type)((p[Order::B] * cover + 255) >> 8);
                p[Order::A] = (value_type)((p[Order::A] * cover + 255) >> 8);
            }
            else
            {
                p[0] = p[1] = p[2] = p[3] = 0; 
            }
        }
    };

    //===========================================================comp_op_rgba_src
    template<class ColorT, class Order> struct comp_op_rgba_src
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;

        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                unsigned alpha = 255 - cover;
                p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8));
                p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8));
                p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8));
                p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8));
            }
            else
            {
                p[Order::R] = sr;
                p[Order::G] = sg;
                p[Order::B] = sb;
                p[Order::A] = sa;
            }
        }
    };

    //===========================================================comp_op_rgba_dst
    template<class ColorT, class Order> struct comp_op_rgba_dst
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;

        static AGG_INLINE void blend_pix(value_type*, 
                                         unsigned, unsigned, unsigned, 
                                         unsigned, unsigned)
        {
        }
    };

    //======================================================comp_op_rgba_src_over
    template<class ColorT, class Order> struct comp_op_rgba_src_over
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        //   Dca' = Sca + Dca.(1 - Sa)
        //   Da'  = Sa + Da - Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            calc_type s1a = base_mask - sa;
            p[Order::R] = (value_type)(sr + ((p[Order::R] * s1a + base_mask) >> base_shift));
            p[Order::G] = (value_type)(sg + ((p[Order::G] * s1a + base_mask) >> base_shift));
            p[Order::B] = (value_type)(sb + ((p[Order::B] * s1a + base_mask) >> base_shift));
            p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
        }
    };

    //======================================================comp_op_rgba_dst_over
    template<class ColorT, class Order> struct comp_op_rgba_dst_over
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Dca + Sca.(1 - Da)
        // Da'  = Sa + Da - Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            calc_type d1a = base_mask - p[Order::A];
            p[Order::R] = (value_type)(p[Order::R] + ((sr * d1a + base_mask) >> base_shift));
            p[Order::G] = (value_type)(p[Order::G] + ((sg * d1a + base_mask) >> base_shift));
            p[Order::B] = (value_type)(p[Order::B] + ((sb * d1a + base_mask) >> base_shift));
            p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
        }
    };

    //======================================================comp_op_rgba_src_in
    template<class ColorT, class Order> struct comp_op_rgba_src_in
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca.Da
        // Da'  = Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            calc_type da = p[Order::A];
            if(cover < 255)
            {
                unsigned alpha = 255 - cover;
                p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8));
            }
            else
            {
                p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift);
                p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift);
                p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift);
                p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift);
            }
        }
    };

    //======================================================comp_op_rgba_dst_in
    template<class ColorT, class Order> struct comp_op_rgba_dst_in
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Dca.Sa
        // Da'  = Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned, unsigned, unsigned, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sa = base_mask - ((cover * (base_mask - sa) + 255) >> 8);
            }
            p[Order::R] = (value_type)((p[Order::R] * sa + base_mask) >> base_shift);
            p[Order::G] = (value_type)((p[Order::G] * sa + base_mask) >> base_shift);
            p[Order::B] = (value_type)((p[Order::B] * sa + base_mask) >> base_shift);
            p[Order::A] = (value_type)((p[Order::A] * sa + base_mask) >> base_shift);
        }
    };

    //======================================================comp_op_rgba_src_out
    template<class ColorT, class Order> struct comp_op_rgba_src_out
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca.(1 - Da)
        // Da'  = Sa.(1 - Da) 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            calc_type da = base_mask - p[Order::A];
            if(cover < 255)
            {
                unsigned alpha = 255 - cover;
                p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8));
                p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8));
            }
            else
            {
                p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift);
                p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift);
                p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift);
                p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift);
            }
        }
    };

    //======================================================comp_op_rgba_dst_out
    template<class ColorT, class Order> struct comp_op_rgba_dst_out
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Dca.(1 - Sa) 
        // Da'  = Da.(1 - Sa) 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned, unsigned, unsigned, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sa = (sa * cover + 255) >> 8;
            }
            sa = base_mask - sa;
            p[Order::R] = (value_type)((p[Order::R] * sa + base_shift) >> base_shift);
            p[Order::G] = (value_type)((p[Order::G] * sa + base_shift) >> base_shift);
            p[Order::B] = (value_type)((p[Order::B] * sa + base_shift) >> base_shift);
            p[Order::A] = (value_type)((p[Order::A] * sa + base_shift) >> base_shift);
        }
    };

    //=====================================================comp_op_rgba_src_atop
    template<class ColorT, class Order> struct comp_op_rgba_src_atop
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca.Da + Dca.(1 - Sa)
        // Da'  = Da
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            calc_type da = p[Order::A];
            sa = base_mask - sa;
            p[Order::R] = (value_type)((sr * da + p[Order::R] * sa + base_mask) >> base_shift);
            p[Order::G] = (value_type)((sg * da + p[Order::G] * sa + base_mask) >> base_shift);
            p[Order::B] = (value_type)((sb * da + p[Order::B] * sa + base_mask) >> base_shift);
        }
    };

    //=====================================================comp_op_rgba_dst_atop
    template<class ColorT, class Order> struct comp_op_rgba_dst_atop
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Dca.Sa + Sca.(1 - Da)
        // Da'  = Sa 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            calc_type da = base_mask - p[Order::A];
            if(cover < 255)
            {
                unsigned alpha = 255 - cover;
                sr = (p[Order::R] * sa + sr * da + base_mask) >> base_shift;
                sg = (p[Order::G] * sa + sg * da + base_mask) >> base_shift;
                sb = (p[Order::B] * sa + sb * da + base_mask) >> base_shift;
                p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8));
                p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8));
                p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8));
                p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8));

            }
            else
            {
                p[Order::R] = (value_type)((p[Order::R] * sa + sr * da + base_mask) >> base_shift);
                p[Order::G] = (value_type)((p[Order::G] * sa + sg * da + base_mask) >> base_shift);
                p[Order::B] = (value_type)((p[Order::B] * sa + sb * da + base_mask) >> base_shift);
                p[Order::A] = (value_type)sa;
            }
        }
    };

    //=========================================================comp_op_rgba_xor
    template<class ColorT, class Order> struct comp_op_rgba_xor
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
        // Da'  = Sa + Da - 2.Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type s1a = base_mask - sa;
                calc_type d1a = base_mask - p[Order::A];
                p[Order::R] = (value_type)((p[Order::R] * s1a + sr * d1a + base_mask) >> base_shift);
                p[Order::G] = (value_type)((p[Order::G] * s1a + sg * d1a + base_mask) >> base_shift);
                p[Order::B] = (value_type)((p[Order::B] * s1a + sb * d1a + base_mask) >> base_shift);
                p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask/2) >> (base_shift - 1)));
            }
        }
    };

    //=========================================================comp_op_rgba_plus
    template<class ColorT, class Order> struct comp_op_rgba_plus
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca + Dca
        // Da'  = Sa + Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type dr = p[Order::R] + sr;
                calc_type dg = p[Order::G] + sg;
                calc_type db = p[Order::B] + sb;
                calc_type da = p[Order::A] + sa;
                p[Order::R] = (dr > base_mask) ? (value_type)base_mask : dr;
                p[Order::G] = (dg > base_mask) ? (value_type)base_mask : dg;
                p[Order::B] = (db > base_mask) ? (value_type)base_mask : db;
                p[Order::A] = (da > base_mask) ? (value_type)base_mask : da;
            }
        }
    };

    //========================================================comp_op_rgba_minus
    template<class ColorT, class Order> struct comp_op_rgba_minus
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Dca - Sca
        // Da' = 1 - (1 - Sa).(1 - Da)
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type dr = p[Order::R] - sr;
                calc_type dg = p[Order::G] - sg;
                calc_type db = p[Order::B] - sb;
                p[Order::R] = (dr > base_mask) ? 0 : dr;
                p[Order::G] = (dg > base_mask) ? 0 : dg;
                p[Order::B] = (db > base_mask) ? 0 : db;
                p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
                //p[Order::A] = (value_type)(base_mask - (((base_mask - sa) * (base_mask - p[Order::A]) + base_mask) >> base_shift));
            }
        }
    };

    //=====================================================comp_op_rgba_multiply
    template<class ColorT, class Order> struct comp_op_rgba_multiply
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
        // Da'  = Sa + Da - Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type s1a = base_mask - sa;
                calc_type d1a = base_mask - p[Order::A];
                calc_type dr = p[Order::R];
                calc_type dg = p[Order::G];
                calc_type db = p[Order::B];
                p[Order::R] = (value_type)((sr * dr + sr * d1a + dr * s1a + base_mask) >> base_shift);
                p[Order::G] = (value_type)((sg * dg + sg * d1a + dg * s1a + base_mask) >> base_shift);
                p[Order::B] = (value_type)((sb * db + sb * d1a + db * s1a + base_mask) >> base_shift);
                p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
            }
        }
    };

    //=====================================================comp_op_rgba_screen
    template<class ColorT, class Order> struct comp_op_rgba_screen
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // Dca' = Sca + Dca - Sca.Dca
        // Da'  = Sa + Da - Sa.Da 
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type dr = p[Order::R];
                calc_type dg = p[Order::G];
                calc_type db = p[Order::B];
                calc_type da = p[Order::A];
                p[Order::R] = (value_type)(sr + dr - ((sr * dr + base_mask) >> base_shift));
                p[Order::G] = (value_type)(sg + dg - ((sg * dg + base_mask) >> base_shift));
                p[Order::B] = (value_type)(sb + db - ((sb * db + base_mask) >> base_shift));
                p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
            }
        }
    };

    //=====================================================comp_op_rgba_overlay
    template<class ColorT, class Order> struct comp_op_rgba_overlay
    {
        typedef ColorT color_type;
        typedef Order order_type;
        typedef typename color_type::value_type value_type;
        typedef typename color_type::calc_type calc_type;
        enum base_scale_e
        { 
            base_shift = color_type::base_shift,
            base_mask  = color_type::base_mask
        };

        // if 2.Dca < Da
        //   Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
        // otherwise
        //   Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
        // 
        // Da' = Sa + Da - Sa.Da
        static AGG_INLINE void blend_pix(value_type* p, 
                                         unsigned sr, unsigned sg, unsigned sb, 
                                         unsigned sa, unsigned cover)
        {
            if(cover < 255)
            {
                sr = (sr * cover + 255) >> 8;
                sg = (sg * cover + 255) >> 8;
                sb = (sb * cover + 255) >> 8;
                sa = (sa * cover + 255) >> 8;
            }
            if(sa)
            {
                calc_type d1a  = base_mask - p[Order::A];
                calc_type s1a  = base_mask - sa;
                calc_type dr   = p[Order::R];
                calc_type dg   = p[Order::G];
                calc_type db   = p[Order::B];
                calc_type da