root/src/servers/app/drawing/Painter/agg_scanline_storage_subpix.h
/*
 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
 * All rights reserved. Distributed under the terms of the MIT License.
 *
 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
 *
 *
 * Class scanline_storage_subpix, a slightly modified version of
 * scanline_storage customized to store 3 covers per pixel
 *
 */

#ifndef AGG_SCANLINE_STORAGE_SUBPIX_INCLUDED
#define AGG_SCANLINE_STORAGE_SUBPIX_INCLUDED

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "agg_array.h"
#include "agg_scanline_storage_aa.h"


namespace agg
{
        //--------------------------------------------scanline_storage_subpix
        template<class T> class scanline_storage_subpix
        {
        public:
                typedef T cover_type;

                //---------------------------------------------------------------
                struct span_data
                {
                        int32 x;
                        int32 len;               // If negative, it's a solid span, covers is valid
                        int       covers_id; // The index of the cells in the scanline_cell_storage
                };

                //---------------------------------------------------------------
                struct scanline_data
                {
                        int              y;
                        unsigned num_spans;
                        unsigned start_span;
                };


                //---------------------------------------------------------------
                class embedded_scanline
                {
                public:

                        //-----------------------------------------------------------
                        class const_iterator
                        {
                        public:
                                struct span
                                {
                                        int32    x;
                                        int32    len; // If negative, it's a solid span, covers is valid
                                        const T* covers;
                                };

                                const_iterator() : m_storage(0) {}
                                const_iterator(const embedded_scanline& sl) :
                                        m_storage(sl.m_storage),
                                        m_span_idx(sl.m_scanline.start_span)
                                {
                                        init_span();
                                }

                                const span& operator*()  const { return m_span;  }
                                const span* operator->() const { return &m_span; }

                                void operator ++ ()
                                {
                                        ++m_span_idx;
                                        init_span();
                                }

                        private:
                                void init_span()
                                {
                                        const span_data& s = m_storage->span_by_index(m_span_idx);
                                        m_span.x          = s.x;
                                        m_span.len        = s.len;
                                        m_span.covers = m_storage->covers_by_index(s.covers_id);
                                }

                                const scanline_storage_subpix* m_storage;
                                unsigned                                   m_span_idx;
                                span                                       m_span;
                        };

                        friend class const_iterator;


                        //-----------------------------------------------------------
                        embedded_scanline(const scanline_storage_subpix& storage) :
                                m_storage(&storage)
                        {
                                init(0);
                        }

                        //-----------------------------------------------------------
                        void     reset(int, int)         {}
                        unsigned num_spans()   const { return m_scanline.num_spans;      }
                        int              y()               const { return m_scanline.y;                  }
                        const_iterator begin() const { return const_iterator(*this); }

                        //-----------------------------------------------------------
                        void init(unsigned scanline_idx)
                        {
                                m_scanline_idx = scanline_idx;
                                m_scanline = m_storage->scanline_by_index(m_scanline_idx);
                        }

                private:
                        const scanline_storage_subpix* m_storage;
                        scanline_data                      m_scanline;
                        unsigned                                   m_scanline_idx;
                };


                //---------------------------------------------------------------
                scanline_storage_subpix() :
                        m_covers(),
                        m_spans(256-2),                 // Block increment size
                        m_scanlines(),
                        m_min_x( 0x7FFFFFFF),
                        m_min_y( 0x7FFFFFFF),
                        m_max_x(-0x7FFFFFFF),
                        m_max_y(-0x7FFFFFFF),
                        m_cur_scanline(0)
                {
                        m_fake_scanline.y = 0;
                        m_fake_scanline.num_spans = 0;
                        m_fake_scanline.start_span = 0;
                        m_fake_span.x = 0;
                        m_fake_span.len = 0;
                        m_fake_span.covers_id = 0;
                }

                // Renderer Interface
                //---------------------------------------------------------------
                void prepare()
                {
                        m_covers.remove_all();
                        m_scanlines.remove_all();
                        m_spans.remove_all();
                        m_min_x =  0x7FFFFFFF;
                        m_min_y =  0x7FFFFFFF;
                        m_max_x = -0x7FFFFFFF;
                        m_max_y = -0x7FFFFFFF;
                        m_cur_scanline = 0;
                }

                //---------------------------------------------------------------
                template<class Scanline> void render(const Scanline& sl)
                {
                        scanline_data sl_this;

                        int y = sl.y();
                        if(y < m_min_y) m_min_y = y;
                        if(y > m_max_y) m_max_y = y;

                        sl_this.y = y;
                        sl_this.num_spans = sl.num_spans();
                        sl_this.start_span = m_spans.size();
                        typename Scanline::const_iterator span_iterator = sl.begin();

                        unsigned num_spans = sl_this.num_spans;
                        for(;;)
                        {
                                span_data sp;

                                sp.x             = span_iterator->x;
                                sp.len           = span_iterator->len;
                                int len          = abs(int(sp.len));
                                sp.covers_id =
                                        m_covers.add_cells(span_iterator->covers,
                                                                           (unsigned(len)));
                                m_spans.add(sp);
                                int x1 = sp.x;
                                int x2 = sp.x + len/3 - 1;
                                if(x1 < m_min_x) m_min_x = x1;
                                if(x2 > m_max_x) m_max_x = x2;
                                if(--num_spans == 0) break;
                                ++span_iterator;
                        }
                        m_scanlines.add(sl_this);
                }


                //---------------------------------------------------------------
                // Iterate scanlines interface
                int min_x() const { return m_min_x; }
                int min_y() const { return m_min_y; }
                int max_x() const { return m_max_x; }
                int max_y() const { return m_max_y; }

                //---------------------------------------------------------------
                bool rewind_scanlines()
                {
                        m_cur_scanline = 0;
                        return m_scanlines.size() > 0;
                }


                //---------------------------------------------------------------
                template<class Scanline> bool sweep_scanline(Scanline& sl)
                {
                        sl.reset_spans();
                        for(;;)
                        {
                                if(m_cur_scanline >= m_scanlines.size()) return false;
                                const scanline_data& sl_this = m_scanlines[m_cur_scanline];

                                unsigned num_spans = sl_this.num_spans;
                                unsigned span_idx  = sl_this.start_span;
                                do
                                {
                                        const span_data& sp = m_spans[span_idx++];
                                        const T* covers = covers_by_index(sp.covers_id);
                                        if(sp.len < 0)
                                        {
                                                sl.add_span(sp.x, unsigned(-sp.len), *covers);
                                        }
                                        else
                                        {
                                                sl.add_cells(sp.x, sp.len, covers);
                                        }
                                }
                                while(--num_spans);
                                ++m_cur_scanline;
                                if(sl.num_spans())
                                {
                                        sl.finalize(sl_this.y);
                                        break;
                                }
                        }
                        return true;
                }


                //---------------------------------------------------------------
                // Specialization for embedded_scanline
                bool sweep_scanline(embedded_scanline& sl)
                {
                        do
                        {
                                if(m_cur_scanline >= m_scanlines.size()) return false;
                                sl.init(m_cur_scanline);
                                ++m_cur_scanline;
                        }
                        while(sl.num_spans() == 0);
                        return true;
                }

                //---------------------------------------------------------------
                unsigned byte_size() const
                {
                        unsigned i;
                        unsigned size = sizeof(int32) * 4; // min_x, min_y, max_x, max_y

                        for(i = 0; i < m_scanlines.size(); ++i)
                        {
                                size += sizeof(int32) * 3; // scanline size in bytes

                                const scanline_data& sl_this = m_scanlines[i];

                                unsigned num_spans = sl_this.num_spans;
                                unsigned span_idx  = sl_this.start_span;
                                do
                                {
                                        const span_data& sp = m_spans[span_idx++];

                                        size += sizeof(int32) * 2;                                // X, span_len
                                        if(sp.len < 0)
                                        {
                                                size += sizeof(T);                                        // cover
                                        }
                                        else
                                        {
                                                size += sizeof(T) * unsigned(sp.len); // covers
                                        }
                                }
                                while(--num_spans);
                        }
                        return size;
                }


                //---------------------------------------------------------------
                static void write_int32(int8u* dst, int32 val)
                {
                        dst[0] = ((const int8u*)&val)[0];
                        dst[1] = ((const int8u*)&val)[1];
                        dst[2] = ((const int8u*)&val)[2];
                        dst[3] = ((const int8u*)&val)[3];
                }


                //---------------------------------------------------------------
                void serialize(int8u* data) const
                {
                        unsigned i;

                        write_int32(data, min_x()); // min_x
                        data += sizeof(int32);
                        write_int32(data, min_y()); // min_y
                        data += sizeof(int32);
                        write_int32(data, max_x()); // max_x
                        data += sizeof(int32);
                        write_int32(data, max_y()); // max_y
                        data += sizeof(int32);

                        for(i = 0; i < m_scanlines.size(); ++i)
                        {
                                const scanline_data& sl_this = m_scanlines[i];

                                int8u* size_ptr = data;
                                data += sizeof(int32);  // Reserve space for scanline size in bytes

                                write_int32(data, sl_this.y);                    // Y
                                data += sizeof(int32);

                                write_int32(data, sl_this.num_spans);    // num_spans
                                data += sizeof(int32);

                                unsigned num_spans = sl_this.num_spans;
                                unsigned span_idx  = sl_this.start_span;
                                do
                                {
                                        const span_data& sp = m_spans[span_idx++];
                                        const T* covers = covers_by_index(sp.covers_id);

                                        write_int32(data, sp.x);                        // X
                                        data += sizeof(int32);

                                        write_int32(data, sp.len);                      // span_len
                                        data += sizeof(int32);

                                        if(sp.len < 0)
                                        {
                                                memcpy(data, covers, sizeof(T));
                                                data += sizeof(T);
                                        }
                                        else
                                        {
                                                memcpy(data, covers, unsigned(sp.len) * sizeof(T));
                                                data += sizeof(T) * unsigned(sp.len);
                                        }
                                }
                                while(--num_spans);
                                write_int32(size_ptr, int32(unsigned(data - size_ptr)));
                        }
                }


                //---------------------------------------------------------------
                const scanline_data& scanline_by_index(unsigned i) const
                {
                        return (i < m_scanlines.size()) ? m_scanlines[i] : m_fake_scanline;
                }

                //---------------------------------------------------------------
                const span_data& span_by_index(unsigned i) const
                {
                        return (i < m_spans.size()) ? m_spans[i] : m_fake_span;
                }

                //---------------------------------------------------------------
                const T* covers_by_index(int i) const
                {
                        return m_covers[i];
                }

        private:
                scanline_cell_storage<T>          m_covers;
                pod_bvector<span_data, 10>        m_spans;
                pod_bvector<scanline_data, 8> m_scanlines;
                span_data         m_fake_span;
                scanline_data m_fake_scanline;
                int                       m_min_x;
                int                       m_min_y;
                int                       m_max_x;
                int                       m_max_y;
                unsigned          m_cur_scanline;
        };


        typedef scanline_storage_subpix<int8u>  scanline_storage_subpix8;  //--------scanline_storage_subpix8
        typedef scanline_storage_subpix<int16u> scanline_storage_subpix16; //--------scanline_storage_subpix16
        typedef scanline_storage_subpix<int32u> scanline_storage_subpix32; //--------scanline_storage_subpix32


        //--------------------------------------serialized_scanlines_adaptor_subpix
        template<class T> class serialized_scanlines_adaptor_subpix
        {
        public:
                typedef T cover_type;

                //---------------------------------------------------------------------
                class embedded_scanline
                {
                public:
                        typedef T cover_type;

                        //-----------------------------------------------------------------
                        class const_iterator
                        {
                        public:
                                struct span
                                {
                                        int32    x;
                                        int32    len; // If negative, it's a solid span, "covers" is valid
                                        const T* covers;
                                };

                                const_iterator() : m_ptr(0) {}
                                const_iterator(const embedded_scanline& sl) :
                                        m_ptr(sl.m_ptr),
                                        m_dx(sl.m_dx)
                                {
                                        init_span();
                                }

                                const span& operator*()  const { return m_span;  }
                                const span* operator->() const { return &m_span; }

                                void operator ++ ()
                                {
                                        if(m_span.len < 0)
                                        {
                                                m_ptr += sizeof(T);
                                        }
                                        else
                                        {
                                                m_ptr += m_span.len * sizeof(T);
                                        }
                                        init_span();
                                }

                        private:
                                int read_int32()
                                {
                                        int32 val;
                                        ((int8u*)&val)[0] = *m_ptr++;
                                        ((int8u*)&val)[1] = *m_ptr++;
                                        ((int8u*)&val)[2] = *m_ptr++;
                                        ((int8u*)&val)[3] = *m_ptr++;
                                        return val;
                                }

                                void init_span()
                                {
                                        m_span.x          = read_int32() + m_dx;
                                        m_span.len        = read_int32();
                                        m_span.covers = m_ptr;
                                }

                                const int8u* m_ptr;
                                span             m_span;
                                int                      m_dx;
                        };

                        friend class const_iterator;


                        //-----------------------------------------------------------------
                        embedded_scanline() : m_ptr(0), m_y(0), m_num_spans(0) {}

                        //-----------------------------------------------------------------
                        void     reset(int, int)         {}
                        unsigned num_spans()   const { return m_num_spans;      }
                        int              y()               const { return m_y;                  }
                        const_iterator begin() const { return const_iterator(*this); }


                private:
                        //-----------------------------------------------------------------
                        int read_int32()
                        {
                                int32 val;
                                ((int8u*)&val)[0] = *m_ptr++;
                                ((int8u*)&val)[1] = *m_ptr++;
                                ((int8u*)&val)[2] = *m_ptr++;
                                ((int8u*)&val)[3] = *m_ptr++;
                                return val;
                        }

                public:
                        //-----------------------------------------------------------------
                        void init(const int8u* ptr, int dx, int dy)
                        {
                                m_ptr           = ptr;
                                m_y                     = read_int32() + dy;
                                m_num_spans = unsigned(read_int32());
                                m_dx            = dx;
                        }

                private:
                        const int8u* m_ptr;
                        int                      m_y;
                        unsigned         m_num_spans;
                        int                      m_dx;
                };



        public:
                //--------------------------------------------------------------------
                serialized_scanlines_adaptor_subpix() :
                        m_data(0),
                        m_end(0),
                        m_ptr(0),
                        m_dx(0),
                        m_dy(0),
                        m_min_x(0x7FFFFFFF),
                        m_min_y(0x7FFFFFFF),
                        m_max_x(-0x7FFFFFFF),
                        m_max_y(-0x7FFFFFFF)
                {}

                //--------------------------------------------------------------------
                serialized_scanlines_adaptor_subpix(const int8u* data, unsigned size,
                                                                                double dx, double dy) :
                        m_data(data),
                        m_end(data + size),
                        m_ptr(data),
                        m_dx(iround(dx)),
                        m_dy(iround(dy)),
                        m_min_x(0x7FFFFFFF),
                        m_min_y(0x7FFFFFFF),
                        m_max_x(-0x7FFFFFFF),
                        m_max_y(-0x7FFFFFFF)
                {}

                //--------------------------------------------------------------------
                void init(const int8u* data, unsigned size, double dx, double dy)
                {
                        m_data  = data;
                        m_end   = data + size;
                        m_ptr   = data;
                        m_dx    = iround(dx);
                        m_dy    = iround(dy);
                        m_min_x = 0x7FFFFFFF;
                        m_min_y = 0x7FFFFFFF;
                        m_max_x = -0x7FFFFFFF;
                        m_max_y = -0x7FFFFFFF;
                }

        private:
                //--------------------------------------------------------------------
                int read_int32()
                {
                        int32 val;
                        ((int8u*)&val)[0] = *m_ptr++;
                        ((int8u*)&val)[1] = *m_ptr++;
                        ((int8u*)&val)[2] = *m_ptr++;
                        ((int8u*)&val)[3] = *m_ptr++;
                        return val;
                }

                //--------------------------------------------------------------------
                unsigned read_int32u()
                {
                        int32u val;
                        ((int8u*)&val)[0] = *m_ptr++;
                        ((int8u*)&val)[1] = *m_ptr++;
                        ((int8u*)&val)[2] = *m_ptr++;
                        ((int8u*)&val)[3] = *m_ptr++;
                        return val;
                }

        public:
                // Iterate scanlines interface
                //--------------------------------------------------------------------
                bool rewind_scanlines()
                {
                        m_ptr = m_data;
                        if(m_ptr < m_end)
                        {
                                m_min_x = read_int32() + m_dx;
                                m_min_y = read_int32() + m_dy;
                                m_max_x = read_int32() + m_dx;
                                m_max_y = read_int32() + m_dy;
                        }
                        return m_ptr < m_end;
                }

                //--------------------------------------------------------------------
                int min_x() const { return m_min_x; }
                int min_y() const { return m_min_y; }
                int max_x() const { return m_max_x; }
                int max_y() const { return m_max_y; }

                //--------------------------------------------------------------------
                template<class Scanline> bool sweep_scanline(Scanline& sl)
                {
                        sl.reset_spans();
                        for(;;)
                        {
                                if(m_ptr >= m_end) return false;

                                read_int32();      // Skip scanline size in bytes
                                int y = read_int32() + m_dy;
                                unsigned num_spans = read_int32();

                                do
                                {
                                        int x = read_int32() + m_dx;
                                        int len = read_int32();

                                        if(len < 0)
                                        {
                                                sl.add_span(x, unsigned(-len), *m_ptr);
                                                m_ptr += sizeof(T);
                                        }
                                        else
                                        {
                                                sl.add_cells(x, len, m_ptr);
                                                m_ptr += len * sizeof(T);
                                        }
                                }
                                while(--num_spans);

                                if(sl.num_spans())
                                {
                                        sl.finalize(y);
                                        break;
                                }
                        }
                        return true;
                }


                //--------------------------------------------------------------------
                // Specialization for embedded_scanline
                bool sweep_scanline(embedded_scanline& sl)
                {
                        do
                        {
                                if(m_ptr >= m_end) return false;

                                unsigned byte_size = read_int32u();
                                sl.init(m_ptr, m_dx, m_dy);
                                m_ptr += byte_size - sizeof(int32);
                        }
                        while(sl.num_spans() == 0);
                        return true;
                }

        private:
                const int8u* m_data;
                const int8u* m_end;
                const int8u* m_ptr;
                int                      m_dx;
                int                      m_dy;
                int                      m_min_x;
                int                      m_min_y;
                int                      m_max_x;
                int                      m_max_y;
        };



        typedef serialized_scanlines_adaptor_subpix<int8u>
        serialized_scanlines_adaptor_subpix8; //serialized_scanlines_adaptor_subpix8

        typedef serialized_scanlines_adaptor_subpix<int16u>
        serialized_scanlines_adaptor_subpix16; //serialized_scanlines_adaptor_subpix16

        typedef serialized_scanlines_adaptor_subpix<int32u>
        serialized_scanlines_adaptor_subpix32; //serialized_scanlines_adaptor_subpix32

}


#endif