incubator-ooo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r1184758 [4/17] - in /incubator/ooo/trunk/main: ./ agg/inc/ agg/source/ solenv/config/
Date Sun, 16 Oct 2011 04:13:21 GMT
Modified: incubator/ooo/trunk/main/agg/inc/agg_path_storage.h
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/agg/inc/agg_path_storage.h?rev=1184758&r1=1184757&r2=1184758&view=diff
==============================================================================
--- incubator/ooo/trunk/main/agg/inc/agg_path_storage.h (original)
+++ incubator/ooo/trunk/main/agg/inc/agg_path_storage.h Sun Oct 16 04:13:16 2011
@@ -1,5 +1,5 @@
 //----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.3
+// Anti-Grain Geometry - Version 2.4
 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 //
 // Permission to copy, use, modify, sell and distribute this software 
@@ -16,349 +16,1530 @@
 #ifndef AGG_PATH_STORAGE_INCLUDED
 #define AGG_PATH_STORAGE_INCLUDED
 
-#include "agg_basics.h"
+#include <string.h>
+#include <math.h>
+#include "agg_math.h"
+#include "agg_array.h"
+#include "agg_bezier_arc.h"
 
 namespace agg
 {
 
-    //------------------------------------------------------------path_storage
-    // A container to store vertices with their flags. 
-    // A path consists of a number of contours separated with "move_to" 
-    // commands. The path storage can keep and maintain more than one
-    // path. 
-    // To navigate to the beginning of a particular path, use rewind(path_id);
-    // Where path_id is what start_new_path() returns. So, when you call
-    // start_new_path() you need to store its return value somewhere else
-    // to navigate to the path afterwards.
-    //
-    // See Implementation: agg_path_storage.cpp 
-    // See also: vertex_source concept
-    //------------------------------------------------------------------------
-    class path_storage
+
+    //----------------------------------------------------vertex_block_storage
+    template<class T, unsigned BlockShift=8, unsigned BlockPool=256>
+    class vertex_block_storage
     {
+    public:
         // Allocation parameters
-        enum
+        enum block_scale_e
         {
-            block_shift = 8,
+            block_shift = BlockShift,
             block_size  = 1 << block_shift,
             block_mask  = block_size - 1,
-            block_pool  = 256
+            block_pool  = BlockPool
         };
 
-    public:
-
-        //--------------------------------------------------------------------
-        class const_iterator
-        {
-            void vertex()
-            {
-                if(m_vertex_idx < m_path->total_vertices()) 
-                {
-                    m_vertex.cmd = m_path->vertex(m_vertex_idx, &m_vertex.x, &m_vertex.y);
-                }
-                else
-                {
-                    m_vertex.cmd = path_cmd_stop;
-                    m_vertex.x = m_vertex.y = 0.0;
-                }
-            }
+        typedef T value_type;
+        typedef vertex_block_storage<T, BlockShift, BlockPool> self_type;
 
-        public:
-            const_iterator() {}
-            const_iterator(unsigned cmd) { m_vertex.cmd = cmd; }
-            const_iterator(const const_iterator& i) : 
-                m_path(i.m_path),
-                m_vertex_idx(i.m_vertex_idx),
-                m_vertex(i.m_vertex) 
-            {
-            }
+        ~vertex_block_storage();
+        vertex_block_storage();
+        vertex_block_storage(const self_type& v);
+        const self_type& operator = (const self_type& ps);
 
-            const_iterator(const path_storage& p, unsigned id) : 
-                m_path(&p),
-                m_vertex_idx(id)
-            {
-                vertex();
-            }
+        void remove_all();
+        void free_all();
 
-            const_iterator& operator++() 
-            {
-                ++m_vertex_idx;
-                vertex();
-                return *this;
-            }
+        void add_vertex(double x, double y, unsigned cmd);
+        void modify_vertex(unsigned idx, double x, double y);
+        void modify_vertex(unsigned idx, double x, double y, unsigned cmd);
+        void modify_command(unsigned idx, unsigned cmd);
+        void swap_vertices(unsigned v1, unsigned v2);
 
-            const vertex_type& operator*() const { return m_vertex; }
-            const vertex_type* operator->() const { return &m_vertex; }
+        unsigned last_command() const;
+        unsigned last_vertex(double* x, double* y) const;
+        unsigned prev_vertex(double* x, double* y) const;
 
-            bool operator != (const const_iterator& i) 
-            { 
-                return m_vertex.cmd != i.m_vertex.cmd; 
-            }
+        double last_x() const;
+        double last_y() const;
 
-        private:
-            const path_storage* m_path;
-            unsigned            m_vertex_idx;
-            vertex_type         m_vertex;
-        };
+        unsigned total_vertices() const;
+        unsigned vertex(unsigned idx, double* x, double* y) const;
+        unsigned command(unsigned idx) const;
 
-        ~path_storage();
-        path_storage();
-        path_storage(const path_storage& ps);
+    private:
+        void   allocate_block(unsigned nb);
+        int8u* storage_ptrs(T** xy_ptr);
 
-        void remove_all();
+    private:
+        unsigned m_total_vertices;
+        unsigned m_total_blocks;
+        unsigned m_max_blocks;
+        T**      m_coord_blocks;
+        int8u**  m_cmd_blocks;
+    };
 
-        unsigned last_vertex(double* x, double* y) const;
-        unsigned prev_vertex(double* x, double* y) const;
 
-        void rel_to_abs(double* x, double* y) const;
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    void vertex_block_storage<T,S,P>::free_all()
+    {
+        if(m_total_blocks)
+        {
+            T** coord_blk = m_coord_blocks + m_total_blocks - 1;
+            while(m_total_blocks--)
+            {
+                pod_allocator<T>::deallocate(
+                    *coord_blk,
+                    block_size * 2 + 
+                    block_size / (sizeof(T) / sizeof(unsigned char)));
+                --coord_blk;
+            }
+            pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2);
+            m_total_blocks   = 0;
+            m_max_blocks     = 0;
+            m_coord_blocks   = 0;
+            m_cmd_blocks     = 0;
+            m_total_vertices = 0;
+        }
+    }
 
-        void move_to(double x, double y);
-        void move_rel(double dx, double dy);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    vertex_block_storage<T,S,P>::~vertex_block_storage()
+    {
+        free_all();
+    }
 
-        void line_to(double x, double y);
-        void line_rel(double dx, double dy);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    vertex_block_storage<T,S,P>::vertex_block_storage() :
+        m_total_vertices(0),
+        m_total_blocks(0),
+        m_max_blocks(0),
+        m_coord_blocks(0),
+        m_cmd_blocks(0)
+    {
+    }
 
-        void arc_to(double rx, double ry,
-                    double angle,
-                    bool large_arc_flag,
-                    bool sweep_flag,
-                    double x, double y);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    vertex_block_storage<T,S,P>::vertex_block_storage(const vertex_block_storage<T,S,P>& v) :
+        m_total_vertices(0),
+        m_total_blocks(0),
+        m_max_blocks(0),
+        m_coord_blocks(0),
+        m_cmd_blocks(0)
+    {
+        *this = v;
+    }
 
-        void arc_rel(double rx, double ry,
-                     double angle,
-                     bool large_arc_flag,
-                     bool sweep_flag,
-                     double dx, double dy);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    const vertex_block_storage<T,S,P>& 
+    vertex_block_storage<T,S,P>::operator = (const vertex_block_storage<T,S,P>& v)
+    {
+        remove_all();
+        unsigned i;
+        for(i = 0; i < v.total_vertices(); i++)
+        {
+            double x, y;
+            unsigned cmd = v.vertex(i, &x, &y);
+            add_vertex(x, y, cmd);
+        }
+	    return *this;
+    }
 
-        void curve3(double x_ctrl, double y_ctrl, 
-                    double x_to,   double y_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::remove_all()
+    {
+        m_total_vertices = 0;
+    }
 
-        void curve3_rel(double dx_ctrl, double dy_ctrl, 
-                        double dx_to,   double dy_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::add_vertex(double x, double y, 
+                                                        unsigned cmd)
+    {
+        T* coord_ptr = 0;
+        *storage_ptrs(&coord_ptr) = (int8u)cmd;
+        coord_ptr[0] = T(x);
+        coord_ptr[1] = T(y);
+        m_total_vertices++;
+    }
 
-        void curve3(double x_to, double y_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 
+                                                           double x, double y)
+    {
+        T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
+        pv[0] = T(x);
+        pv[1] = T(y);
+    }
 
-        void curve3_rel(double dx_to, double dy_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 
+                                                           double x, double y, 
+                                                           unsigned cmd)
+    {
+        unsigned block = idx >> block_shift;
+        unsigned offset = idx & block_mask;
+        T* pv = m_coord_blocks[block] + (offset << 1);
+        pv[0] = T(x);
+        pv[1] = T(y);
+        m_cmd_blocks[block][offset] = (int8u)cmd;
+    }
 
-        void curve4(double x_ctrl1, double y_ctrl1, 
-                    double x_ctrl2, double y_ctrl2, 
-                    double x_to,    double y_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::modify_command(unsigned idx, 
+                                                            unsigned cmd)
+    {
+        m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd;
+    }
 
-        void curve4_rel(double dx_ctrl1, double dy_ctrl1, 
-                        double dx_ctrl2, double dy_ctrl2, 
-                        double dx_to,    double dy_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline void vertex_block_storage<T,S,P>::swap_vertices(unsigned v1, unsigned v2)
+    {
+        unsigned b1 = v1 >> block_shift;
+        unsigned b2 = v2 >> block_shift;
+        unsigned o1 = v1 & block_mask;
+        unsigned o2 = v2 & block_mask;
+        T* pv1 = m_coord_blocks[b1] + (o1 << 1);
+        T* pv2 = m_coord_blocks[b2] + (o2 << 1);
+        T  val;
+        val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val;
+        val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val;
+        int8u cmd = m_cmd_blocks[b1][o1];
+        m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2];
+        m_cmd_blocks[b2][o2] = cmd;
+    }
 
-        void curve4(double x_ctrl2, double y_ctrl2, 
-                    double x_to,    double y_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::last_command() const
+    {
+        if(m_total_vertices) return command(m_total_vertices - 1);
+        return path_cmd_stop;
+    }
 
-        void curve4_rel(double x_ctrl2, double y_ctrl2, 
-                        double x_to,    double y_to);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::last_vertex(double* x, double* y) const
+    {
+        if(m_total_vertices) return vertex(m_total_vertices - 1, x, y);
+        return path_cmd_stop;
+    }
 
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::prev_vertex(double* x, double* y) const
+    {
+        if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y);
+        return path_cmd_stop;
+    }
 
-        void end_poly(unsigned flags = path_flags_close);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline double vertex_block_storage<T,S,P>::last_x() const
+    {
+        if(m_total_vertices)
+        {
+            unsigned idx = m_total_vertices - 1;
+            return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1];
+        }
+        return 0.0;
+    }
 
-        void close_polygon(unsigned flags = path_flags_none)
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline double vertex_block_storage<T,S,P>::last_y() const
+    {
+        if(m_total_vertices)
         {
-            end_poly(path_flags_close | flags);
+            unsigned idx = m_total_vertices - 1;
+            return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1];
         }
+        return 0.0;
+    }
 
-        void add_poly(const double* vertices, unsigned num, 
-                      bool solid_path = false,
-                      unsigned end_flags = path_flags_none);
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::total_vertices() const
+    {
+        return m_total_vertices;
+    }
 
-        template<class VertexSource> 
-        void add_path(VertexSource& vs, 
-                      unsigned path_id = 0, 
-                      bool solid_path = true)
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::vertex(unsigned idx, 
+                                                        double* x, double* y) const
+    {
+        unsigned nb = idx >> block_shift;
+        const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
+        *x = pv[0];
+        *y = pv[1];
+        return m_cmd_blocks[nb][idx & block_mask];
+    }
+
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    inline unsigned vertex_block_storage<T,S,P>::command(unsigned idx) const
+    {
+        return m_cmd_blocks[idx >> block_shift][idx & block_mask];
+    }
+
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    void vertex_block_storage<T,S,P>::allocate_block(unsigned nb)
+    {
+        if(nb >= m_max_blocks) 
         {
-            double x, y;
-            unsigned cmd;
-            vs.rewind(path_id);
-            while(!is_stop(cmd = vs.vertex(&x, &y)))
+            T** new_coords = 
+                pod_allocator<T*>::allocate((m_max_blocks + block_pool) * 2);
+
+            unsigned char** new_cmds = 
+                (unsigned char**)(new_coords + m_max_blocks + block_pool);
+
+            if(m_coord_blocks)
             {
-                if(is_move_to(cmd) && solid_path && m_total_vertices) 
-                {
-                    cmd = path_cmd_line_to;
-                }
-                add_vertex(x, y, cmd);
+                memcpy(new_coords, 
+                       m_coord_blocks, 
+                       m_max_blocks * sizeof(T*));
+
+                memcpy(new_cmds, 
+                       m_cmd_blocks, 
+                       m_max_blocks * sizeof(unsigned char*));
+
+                pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2);
             }
+            m_coord_blocks = new_coords;
+            m_cmd_blocks   = new_cmds;
+            m_max_blocks  += block_pool;
         }
+        m_coord_blocks[nb] = 
+            pod_allocator<T>::allocate(block_size * 2 + 
+                   block_size / (sizeof(T) / sizeof(unsigned char)));
 
-        unsigned start_new_path();
+        m_cmd_blocks[nb]  = 
+            (unsigned char*)(m_coord_blocks[nb] + block_size * 2);
 
-        void copy_from(const path_storage& ps);
-        const path_storage& operator = (const path_storage& ps)
+        m_total_blocks++;
+    }
+
+    //------------------------------------------------------------------------
+    template<class T, unsigned S, unsigned P>
+    int8u* vertex_block_storage<T,S,P>::storage_ptrs(T** xy_ptr)
+    {
+        unsigned nb = m_total_vertices >> block_shift;
+        if(nb >= m_total_blocks)
         {
-            copy_from(ps);
-            return *this;
+            allocate_block(nb);
         }
+        *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
+        return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
+    }
 
 
-        unsigned total_vertices() const { return m_total_vertices; }
-        unsigned vertex(unsigned idx, double* x, double* y) const
+
+
+    //-----------------------------------------------------poly_plain_adaptor
+    template<class T> class poly_plain_adaptor
+    {
+    public:
+        typedef T value_type;
+
+        poly_plain_adaptor() : 
+            m_data(0), 
+            m_ptr(0),
+            m_end(0),
+            m_closed(false),
+            m_stop(false)
+        {}
+
+        poly_plain_adaptor(const T* data, unsigned num_points, bool closed) :
+            m_data(data), 
+            m_ptr(data),
+            m_end(data + num_points * 2),
+            m_closed(closed),
+            m_stop(false)
+        {}
+
+        void init(const T* data, unsigned num_points, bool closed)
         {
-            unsigned nb = idx >> block_shift;
-            const double* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
-            *x = *pv++;
-            *y = *pv;
-            return m_cmd_blocks[nb][idx & block_mask];
+            m_data = data;
+            m_ptr = data;
+            m_end = data + num_points * 2;
+            m_closed = closed;
+            m_stop = false;
         }
-        unsigned command(unsigned idx) const
+
+        void rewind(unsigned)
         {
-            return m_cmd_blocks[idx >> block_shift][idx & block_mask];
+            m_ptr = m_data;
+            m_stop = false;
         }
 
-        void     rewind(unsigned path_id);
-        unsigned vertex(double* x, double* y);
+        unsigned vertex(double* x, double* y)
+        {
+            if(m_ptr < m_end)
+            {
+                bool first = m_ptr == m_data;
+                *x = *m_ptr++;
+                *y = *m_ptr++;
+                return first ? path_cmd_move_to : path_cmd_line_to;
+            }
+            *x = *y = 0.0;
+            if(m_closed && !m_stop)
+            {
+                m_stop = true;
+                return path_cmd_end_poly | path_flags_close;
+            }
+            return path_cmd_stop;
+        }
 
-        const_iterator begin(unsigned id) const { return const_iterator(*this, id); }
-        const_iterator begin()            const { return const_iterator(*this, 0); }
-        const_iterator end()              const { return const_iterator(path_cmd_stop); }
-
-        // Arrange the orientation of all the polygons. After calling this
-        // method all the polygons will have the same orientation
-        // determined by the new_orientation flag, i.e., 
-        // path_flags_cw or path_flags_ccw
-        unsigned arrange_orientations(unsigned path_id, path_flags_e new_orientation);
-        void arrange_orientations_all_paths(path_flags_e new_orientation);
+    private:
+        const T* m_data;
+        const T* m_ptr;
+        const T* m_end;
+        bool     m_closed;
+        bool     m_stop;
+    };
 
-        // Flip all the vertices horizontally or vertically
-        void flip_x(double x1, double x2);
-        void flip_y(double y1, double y2);
-        
-        // This function adds a vertex with its flags directly. Since there's no 
-        // checking for errors, keeping proper path integrity is the responsibility
-        // of the caller. It can be said the function is "not very public". 
-        void add_vertex(double x, double y, unsigned cmd);
 
-        // Allows you to modify vertex coordinates. The caller must know 
-        // the index of the vertex. 
-        void modify_vertex(unsigned idx, double x, double y)
+
+
+
+    //-------------------------------------------------poly_container_adaptor
+    template<class Container> class poly_container_adaptor
+    {
+    public:
+        typedef typename Container::value_type vertex_type;
+
+        poly_container_adaptor() : 
+            m_container(0), 
+            m_index(0),
+            m_closed(false),
+            m_stop(false)
+        {}
+
+        poly_container_adaptor(const Container& data, bool closed) :
+            m_container(&data), 
+            m_index(0),
+            m_closed(closed),
+            m_stop(false)
+        {}
+
+        void init(const Container& data, bool closed)
         {
-            double* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
-            *pv++ = x;
-            *pv   = y;
+            m_container = &data;
+            m_index = 0;
+            m_closed = closed;
+            m_stop = false;
         }
 
-        // Allows you to modify vertex command. The caller must know 
-        // the index of the vertex. 
-        void modify_command(unsigned idx, unsigned cmd)
+        void rewind(unsigned)
         {
-            m_cmd_blocks[idx >> block_shift][idx & block_mask] = (unsigned char)cmd;
+            m_index = 0;
+            m_stop = false;
         }
 
+        unsigned vertex(double* x, double* y)
+        {
+            if(m_index < m_container->size())
+            {
+                bool first = m_index == 0;
+                const vertex_type& v = (*m_container)[m_index++];
+                *x = v.x;
+                *y = v.y;
+                return first ? path_cmd_move_to : path_cmd_line_to;
+            }
+            *x = *y = 0.0;
+            if(m_closed && !m_stop)
+            {
+                m_stop = true;
+                return path_cmd_end_poly | path_flags_close;
+            }
+            return path_cmd_stop;
+        }
 
     private:
-        void allocate_block(unsigned nb);
-        unsigned char* storage_ptrs(double** xy_ptr);
-        unsigned perceive_polygon_orientation(unsigned idx, 
-                                              double xs, double ys,
-                                              unsigned* orientation);
-        void reverse_polygon(unsigned start, unsigned end);
-
-    private:
-        unsigned        m_total_vertices;
-        unsigned        m_total_blocks;
-        unsigned        m_max_blocks;
-        double**        m_coord_blocks;
-        unsigned char** m_cmd_blocks;
-        unsigned        m_iterator;
+        const Container* m_container;
+        unsigned m_index;
+        bool     m_closed;
+        bool     m_stop;
     };
 
 
-    //------------------------------------------------------------------------
-    inline unsigned path_storage::vertex(double* x, double* y)
-    {
-        if(m_iterator >= m_total_vertices) return path_cmd_stop;
-        return vertex(m_iterator++, x, y);
-    }
 
-    //------------------------------------------------------------------------
-    inline unsigned path_storage::prev_vertex(double* x, double* y) const
+    //-----------------------------------------poly_container_reverse_adaptor
+    template<class Container> class poly_container_reverse_adaptor
     {
-        if(m_total_vertices > 1)
+    public:
+        typedef typename Container::value_type vertex_type;
+
+        poly_container_reverse_adaptor() : 
+            m_container(0), 
+            m_index(-1),
+            m_closed(false),
+            m_stop(false)
+        {}
+
+        poly_container_reverse_adaptor(const Container& data, bool closed) :
+            m_container(&data), 
+            m_index(-1),
+            m_closed(closed),
+            m_stop(false)
+        {}
+
+        void init(const Container& data, bool closed)
         {
-            return vertex(m_total_vertices - 2, x, y);
+            m_container = &data;
+            m_index = m_container->size() - 1;
+            m_closed = closed;
+            m_stop = false;
         }
-        return path_cmd_stop;
-    }
 
-    //------------------------------------------------------------------------
-    inline unsigned path_storage::last_vertex(double* x, double* y) const
-    {
-        if(m_total_vertices)
+        void rewind(unsigned)
         {
-            return vertex(m_total_vertices - 1, x, y);
+            m_index = m_container->size() - 1;
+            m_stop = false;
         }
-        return path_cmd_stop;
-    }
 
-    //------------------------------------------------------------------------
-    inline void path_storage::rel_to_abs(double* x, double* y) const
-    {
-        if(m_total_vertices)
+        unsigned vertex(double* x, double* y)
         {
-            double x2;
-            double y2;
-            if(is_vertex(vertex(m_total_vertices - 1, &x2, &y2)))
+            if(m_index >= 0)
             {
-                *x += x2;
-                *y += y2;
+                bool first = m_index == int(m_container->size() - 1);
+                const vertex_type& v = (*m_container)[m_index--];
+                *x = v.x;
+                *y = v.y;
+                return first ? path_cmd_move_to : path_cmd_line_to;
             }
+            *x = *y = 0.0;
+            if(m_closed && !m_stop)
+            {
+                m_stop = true;
+                return path_cmd_end_poly | path_flags_close;
+            }
+            return path_cmd_stop;
         }
-    }
 
-    //------------------------------------------------------------------------
-    inline unsigned char* path_storage::storage_ptrs(double** xy_ptr)
-    {
-        unsigned nb = m_total_vertices >> block_shift;
-        if(nb >= m_total_blocks)
-        {
-            allocate_block(nb);
-        }
-        *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
-        return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
-    }
+    private:
+        const Container* m_container;
+        int  m_index;
+        bool m_closed;
+        bool m_stop;
+    };
 
 
-    //------------------------------------------------------------------------
-    inline void path_storage::add_vertex(double x, double y, unsigned cmd)
-    {
-        double* coord_ptr = 0;
-        unsigned char* cmd_ptr = storage_ptrs(&coord_ptr);
-        *cmd_ptr = (unsigned char)cmd;
-        *coord_ptr++ = x;
-        *coord_ptr   = y;
-        m_total_vertices++;
-    }
 
-    //------------------------------------------------------------------------
-    inline void path_storage::move_to(double x, double y)
-    {
-        add_vertex(x, y, path_cmd_move_to);
-    }
 
-    //------------------------------------------------------------------------
-    inline void path_storage::move_rel(double dx, double dy)
+
+    //--------------------------------------------------------line_adaptor
+    class line_adaptor
+    {
+    public:
+        typedef double value_type;
+
+        line_adaptor() : m_line(m_coord, 2, false) {}
+        line_adaptor(double x1, double y1, double x2, double y2) :
+            m_line(m_coord, 2, false)
+        {
+            m_coord[0] = x1;
+            m_coord[1] = y1;
+            m_coord[2] = x2;
+            m_coord[3] = y2;
+        }
+        
+        void init(double x1, double y1, double x2, double y2)
+        {
+            m_coord[0] = x1;
+            m_coord[1] = y1;
+            m_coord[2] = x2;
+            m_coord[3] = y2;
+            m_line.rewind(0);
+        }
+
+        void rewind(unsigned)
+        {
+            m_line.rewind(0);
+        }
+
+        unsigned vertex(double* x, double* y)
+        {
+            return m_line.vertex(x, y);
+        }
+
+    private:
+        double                     m_coord[4];
+        poly_plain_adaptor<double> m_line;
+    };
+
+
+
+
+
+
+
+
+
+
+
+
+
+    //---------------------------------------------------------------path_base
+    // A container to store vertices with their flags. 
+    // A path consists of a number of contours separated with "move_to" 
+    // commands. The path storage can keep and maintain more than one
+    // path. 
+    // To navigate to the beginning of a particular path, use rewind(path_id);
+    // Where path_id is what start_new_path() returns. So, when you call
+    // start_new_path() you need to store its return value somewhere else
+    // to navigate to the path afterwards.
+    //
+    // See also: vertex_source concept
+    //------------------------------------------------------------------------
+    template<class VertexContainer> class path_base
+    {
+    public:
+        typedef VertexContainer            container_type;
+        typedef path_base<VertexContainer> self_type;
+
+        //--------------------------------------------------------------------
+        path_base() : m_vertices(), m_iterator(0) {}
+        void remove_all() { m_vertices.remove_all(); m_iterator = 0; }
+        void free_all()   { m_vertices.free_all();   m_iterator = 0; }
+
+        // Make path functions
+        //--------------------------------------------------------------------
+        unsigned start_new_path();
+
+        void move_to(double x, double y);
+        void move_rel(double dx, double dy);
+
+        void line_to(double x, double y);
+        void line_rel(double dx, double dy);
+
+        void hline_to(double x);
+        void hline_rel(double dx);
+
+        void vline_to(double y);
+        void vline_rel(double dy);
+
+        void arc_to(double rx, double ry,
+                    double angle,
+                    bool large_arc_flag,
+                    bool sweep_flag,
+                    double x, double y);
+
+        void arc_rel(double rx, double ry,
+                     double angle,
+                     bool large_arc_flag,
+                     bool sweep_flag,
+                     double dx, double dy);
+
+        void curve3(double x_ctrl, double y_ctrl, 
+                    double x_to,   double y_to);
+
+        void curve3_rel(double dx_ctrl, double dy_ctrl, 
+                        double dx_to,   double dy_to);
+
+        void curve3(double x_to, double y_to);
+
+        void curve3_rel(double dx_to, double dy_to);
+
+        void curve4(double x_ctrl1, double y_ctrl1, 
+                    double x_ctrl2, double y_ctrl2, 
+                    double x_to,    double y_to);
+
+        void curve4_rel(double dx_ctrl1, double dy_ctrl1, 
+                        double dx_ctrl2, double dy_ctrl2, 
+                        double dx_to,    double dy_to);
+
+        void curve4(double x_ctrl2, double y_ctrl2, 
+                    double x_to,    double y_to);
+
+        void curve4_rel(double x_ctrl2, double y_ctrl2, 
+                        double x_to,    double y_to);
+
+
+        void end_poly(unsigned flags = path_flags_close);
+        void close_polygon(unsigned flags = path_flags_none);
+
+        // Accessors
+        //--------------------------------------------------------------------
+        const container_type& vertices() const { return m_vertices; } 
+              container_type& vertices()       { return m_vertices; } 
+
+        unsigned total_vertices() const;
+
+        void rel_to_abs(double* x, double* y) const;
+
+        unsigned last_vertex(double* x, double* y) const;
+        unsigned prev_vertex(double* x, double* y) const;
+
+        double last_x() const;
+        double last_y() const;
+
+        unsigned vertex(unsigned idx, double* x, double* y) const;
+        unsigned command(unsigned idx) const;
+
+        void modify_vertex(unsigned idx, double x, double y);
+        void modify_vertex(unsigned idx, double x, double y, unsigned cmd);
+        void modify_command(unsigned idx, unsigned cmd);
+
+        // VertexSource interface
+        //--------------------------------------------------------------------
+        void     rewind(unsigned path_id);
+        unsigned vertex(double* x, double* y);
+
+        // Arrange the orientation of a polygon, all polygons in a path, 
+        // or in all paths. After calling arrange_orientations() or 
+        // arrange_orientations_all_paths(), all the polygons will have 
+        // the same orientation, i.e. path_flags_cw or path_flags_ccw
+        //--------------------------------------------------------------------
+        unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation);
+        unsigned arrange_orientations(unsigned path_id, path_flags_e orientation);
+        void     arrange_orientations_all_paths(path_flags_e orientation);
+        void     invert_polygon(unsigned start);
+
+        // Flip all vertices horizontally or vertically, 
+        // between x1 and x2, or between y1 and y2 respectively
+        //--------------------------------------------------------------------
+        void flip_x(double x1, double x2);
+        void flip_y(double y1, double y2);
+
+        // Concatenate path. The path is added as is.
+        //--------------------------------------------------------------------
+        template<class VertexSource> 
+        void concat_path(VertexSource& vs, unsigned path_id = 0)
+        {
+            double x, y;
+            unsigned cmd;
+            vs.rewind(path_id);
+            while(!is_stop(cmd = vs.vertex(&x, &y)))
+            {
+                m_vertices.add_vertex(x, y, cmd);
+            }
+        }
+
+        //--------------------------------------------------------------------
+        // Join path. The path is joined with the existing one, that is, 
+        // it behaves as if the pen of a plotter was always down (drawing)
+        template<class VertexSource> 
+        void join_path(VertexSource& vs, unsigned path_id = 0)
+        {
+            double x, y;
+            unsigned cmd;
+            vs.rewind(path_id);
+            cmd = vs.vertex(&x, &y);
+            if(!is_stop(cmd))
+            {
+                if(is_vertex(cmd))
+                {
+                    double x0, y0;
+                    unsigned cmd0 = last_vertex(&x0, &y0);
+                    if(is_vertex(cmd0))
+                    {
+                        if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon)
+                        {
+                            if(is_move_to(cmd)) cmd = path_cmd_line_to;
+                            m_vertices.add_vertex(x, y, cmd);
+                        }
+                    }
+                    else
+                    {
+                        if(is_stop(cmd0))
+                        {
+                            cmd = path_cmd_move_to;
+                        }
+                        else
+                        {
+                            if(is_move_to(cmd)) cmd = path_cmd_line_to;
+                        }
+                        m_vertices.add_vertex(x, y, cmd);
+                    }
+                }
+                while(!is_stop(cmd = vs.vertex(&x, &y)))
+                {
+                    m_vertices.add_vertex(x, y, is_move_to(cmd) ? 
+                                                    unsigned(path_cmd_line_to) : 
+                                                    cmd);
+                }
+            }
+        }
+
+        // Concatenate polygon/polyline. 
+        //--------------------------------------------------------------------
+        template<class T> void concat_poly(const T* data, 
+                                           unsigned num_points,
+                                           bool closed)
+        {
+            poly_plain_adaptor<T> poly(data, num_points, closed);
+            concat_path(poly);
+        }
+
+        // Join polygon/polyline continuously.
+        //--------------------------------------------------------------------
+        template<class T> void join_poly(const T* data, 
+                                         unsigned num_points,
+                                         bool closed)
+        {
+            poly_plain_adaptor<T> poly(data, num_points, closed);
+            join_path(poly);
+        }
+
+        //--------------------------------------------------------------------
+        void translate(double dx, double dy, unsigned path_id=0);
+        void translate_all_paths(double dx, double dy);
+
+        //--------------------------------------------------------------------
+        template<class Trans>
+        void transform(const Trans& trans, unsigned path_id=0)
+        {
+            unsigned num_ver = m_vertices.total_vertices();
+            for(; path_id < num_ver; path_id++)
+            {
+                double x, y;
+                unsigned cmd = m_vertices.vertex(path_id, &x, &y);
+                if(is_stop(cmd)) break;
+                if(is_vertex(cmd))
+                {
+                    trans.transform(&x, &y);
+                    m_vertices.modify_vertex(path_id, x, y);
+                }
+            }
+        }
+
+        //--------------------------------------------------------------------
+        template<class Trans>
+        void transform_all_paths(const Trans& trans)
+        {
+            unsigned idx;
+            unsigned num_ver = m_vertices.total_vertices();
+            for(idx = 0; idx < num_ver; idx++)
+            {
+                double x, y;
+                if(is_vertex(m_vertices.vertex(idx, &x, &y)))
+                {
+                    trans.transform(&x, &y);
+                    m_vertices.modify_vertex(idx, x, y);
+                }
+            }
+        }
+
+
+
+    private:
+        unsigned perceive_polygon_orientation(unsigned start, unsigned end);
+        void     invert_polygon(unsigned start, unsigned end);
+
+        VertexContainer m_vertices;
+        unsigned        m_iterator;
+    };
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    unsigned path_base<VC>::start_new_path()
+    {
+        if(!is_stop(m_vertices.last_command()))
+        {
+            m_vertices.add_vertex(0.0, 0.0, path_cmd_stop);
+        }
+        return m_vertices.total_vertices();
+    }
+
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::rel_to_abs(double* x, double* y) const
+    {
+        if(m_vertices.total_vertices())
+        {
+            double x2;
+            double y2;
+            if(is_vertex(m_vertices.last_vertex(&x2, &y2)))
+            {
+                *x += x2;
+                *y += y2;
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::move_to(double x, double y)
+    {
+        m_vertices.add_vertex(x, y, path_cmd_move_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::move_rel(double dx, double dy)
     {
         rel_to_abs(&dx, &dy);
-        add_vertex(dx, dy, path_cmd_move_to);
+        m_vertices.add_vertex(dx, dy, path_cmd_move_to);
     }
 
     //------------------------------------------------------------------------
-    inline void path_storage::line_to(double x, double y)
+    template<class VC> 
+    inline void path_base<VC>::line_to(double x, double y)
     {
-        add_vertex(x, y, path_cmd_line_to);
+        m_vertices.add_vertex(x, y, path_cmd_line_to);
     }
 
     //------------------------------------------------------------------------
-    inline void path_storage::line_rel(double dx, double dy)
+    template<class VC> 
+    inline void path_base<VC>::line_rel(double dx, double dy)
     {
         rel_to_abs(&dx, &dy);
-        add_vertex(dx, dy, path_cmd_line_to);
+        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::hline_to(double x)
+    {
+        m_vertices.add_vertex(x, last_y(), path_cmd_line_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::hline_rel(double dx)
+    {
+        double dy = 0;
+        rel_to_abs(&dx, &dy);
+        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::vline_to(double y)
+    {
+        m_vertices.add_vertex(last_x(), y, path_cmd_line_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::vline_rel(double dy)
+    {
+        double dx = 0;
+        rel_to_abs(&dx, &dy);
+        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::arc_to(double rx, double ry,
+                               double angle,
+                               bool large_arc_flag,
+                               bool sweep_flag,
+                               double x, double y)
+    {
+        if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command()))
+        {
+            const double epsilon = 1e-30;
+            double x0 = 0.0;
+            double y0 = 0.0;
+            m_vertices.last_vertex(&x0, &y0);
+
+            rx = fabs(rx);
+            ry = fabs(ry);
+
+            // Ensure radii are valid
+            //-------------------------
+            if(rx < epsilon || ry < epsilon) 
+            {
+                line_to(x, y);
+                return;
+            }
+
+            if(calc_distance(x0, y0, x, y) < epsilon)
+            {
+                // If the endpoints (x, y) and (x0, y0) are identical, then this
+                // is equivalent to omitting the elliptical arc segment entirely.
+                return;
+            }
+            bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
+            if(a.radii_ok())
+            {
+                join_path(a);
+            }
+            else
+            {
+                line_to(x, y);
+            }
+        }
+        else
+        {
+            move_to(x, y);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::arc_rel(double rx, double ry,
+                                double angle,
+                                bool large_arc_flag,
+                                bool sweep_flag,
+                                double dx, double dy)
+    {
+        rel_to_abs(&dx, &dy);
+        arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve3(double x_ctrl, double y_ctrl, 
+                               double x_to,   double y_to)
+    {
+        m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3);
+        m_vertices.add_vertex(x_to,   y_to,   path_cmd_curve3);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve3_rel(double dx_ctrl, double dy_ctrl, 
+                                   double dx_to,   double dy_to)
+    {
+        rel_to_abs(&dx_ctrl, &dy_ctrl);
+        rel_to_abs(&dx_to,   &dy_to);
+        m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3);
+        m_vertices.add_vertex(dx_to,   dy_to,   path_cmd_curve3);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve3(double x_to, double y_to)
+    {
+        double x0;
+        double y0;
+        if(is_vertex(m_vertices.last_vertex(&x0, &y0)))
+        {
+            double x_ctrl;
+            double y_ctrl; 
+            unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl);
+            if(is_curve(cmd))
+            {
+                x_ctrl = x0 + x0 - x_ctrl;
+                y_ctrl = y0 + y0 - y_ctrl;
+            }
+            else
+            {
+                x_ctrl = x0;
+                y_ctrl = y0;
+            }
+            curve3(x_ctrl, y_ctrl, x_to, y_to);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve3_rel(double dx_to, double dy_to)
+    {
+        rel_to_abs(&dx_to, &dy_to);
+        curve3(dx_to, dy_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve4(double x_ctrl1, double y_ctrl1, 
+                               double x_ctrl2, double y_ctrl2, 
+                               double x_to,    double y_to)
+    {
+        m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
+        m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
+        m_vertices.add_vertex(x_to,    y_to,    path_cmd_curve4);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve4_rel(double dx_ctrl1, double dy_ctrl1, 
+                                   double dx_ctrl2, double dy_ctrl2, 
+                                   double dx_to,    double dy_to)
+    {
+        rel_to_abs(&dx_ctrl1, &dy_ctrl1);
+        rel_to_abs(&dx_ctrl2, &dy_ctrl2);
+        rel_to_abs(&dx_to,    &dy_to);
+        m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4);
+        m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4);
+        m_vertices.add_vertex(dx_to,    dy_to,    path_cmd_curve4);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve4(double x_ctrl2, double y_ctrl2, 
+                               double x_to,    double y_to)
+    {
+        double x0;
+        double y0;
+        if(is_vertex(last_vertex(&x0, &y0)))
+        {
+            double x_ctrl1;
+            double y_ctrl1; 
+            unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1);
+            if(is_curve(cmd))
+            {
+                x_ctrl1 = x0 + x0 - x_ctrl1;
+                y_ctrl1 = y0 + y0 - y_ctrl1;
+            }
+            else
+            {
+                x_ctrl1 = x0;
+                y_ctrl1 = y0;
+            }
+            curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::curve4_rel(double dx_ctrl2, double dy_ctrl2, 
+                                   double dx_to,    double dy_to)
+    {
+        rel_to_abs(&dx_ctrl2, &dy_ctrl2);
+        rel_to_abs(&dx_to,    &dy_to);
+        curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::end_poly(unsigned flags)
+    {
+        if(is_vertex(m_vertices.last_command()))
+        {
+            m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::close_polygon(unsigned flags)
+    {
+        end_poly(path_flags_close | flags);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::total_vertices() const
+    {
+        return m_vertices.total_vertices();
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::last_vertex(double* x, double* y) const
+    {
+        return m_vertices.last_vertex(x, y);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::prev_vertex(double* x, double* y) const
+    {
+        return m_vertices.prev_vertex(x, y);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline double path_base<VC>::last_x() const
+    {
+        return m_vertices.last_x();
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline double path_base<VC>::last_y() const
+    {
+        return m_vertices.last_y();
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::vertex(unsigned idx, double* x, double* y) const
+    {
+        return m_vertices.vertex(idx, x, y);
+    }
+ 
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::command(unsigned idx) const
+    {
+        return m_vertices.command(idx);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::modify_vertex(unsigned idx, double x, double y)
+    {
+        m_vertices.modify_vertex(idx, x, y);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::modify_vertex(unsigned idx, double x, double y, unsigned cmd)
+    {
+        m_vertices.modify_vertex(idx, x, y, cmd);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::modify_command(unsigned idx, unsigned cmd)
+    {
+        m_vertices.modify_command(idx, cmd);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline void path_base<VC>::rewind(unsigned path_id)
+    {
+        m_iterator = path_id;
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    inline unsigned path_base<VC>::vertex(double* x, double* y)
+    {
+        if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop;
+        return m_vertices.vertex(m_iterator++, x, y);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    unsigned path_base<VC>::perceive_polygon_orientation(unsigned start,
+                                                         unsigned end)
+    {
+        // Calculate signed area (double area to be exact)
+        //---------------------
+        unsigned np = end - start;
+        double area = 0.0;
+        unsigned i;
+        for(i = 0; i < np; i++)
+        {
+            double x1, y1, x2, y2;
+            m_vertices.vertex(start + i,            &x1, &y1);
+            m_vertices.vertex(start + (i + 1) % np, &x2, &y2);
+            area += x1 * y2 - y1 * x2;
+        }
+        return (area < 0.0) ? path_flags_cw : path_flags_ccw;
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::invert_polygon(unsigned start, unsigned end)
+    {
+        unsigned i;
+        unsigned tmp_cmd = m_vertices.command(start);
+        
+        --end; // Make "end" inclusive
+
+        // Shift all commands to one position
+        for(i = start; i < end; i++)
+        {
+            m_vertices.modify_command(i, m_vertices.command(i + 1));
+        }
+
+        // Assign starting command to the ending command
+        m_vertices.modify_command(end, tmp_cmd);
+
+        // Reverse the polygon
+        while(end > start)
+        {
+            m_vertices.swap_vertices(start++, end--);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::invert_polygon(unsigned start)
+    {
+        // Skip all non-vertices at the beginning
+        while(start < m_vertices.total_vertices() && 
+              !is_vertex(m_vertices.command(start))) ++start;
+
+        // Skip all insignificant move_to
+        while(start+1 < m_vertices.total_vertices() && 
+              is_move_to(m_vertices.command(start)) &&
+              is_move_to(m_vertices.command(start+1))) ++start;
+
+        // Find the last vertex
+        unsigned end = start + 1;
+        while(end < m_vertices.total_vertices() && 
+              !is_next_poly(m_vertices.command(end))) ++end;
+
+        invert_polygon(start, end);
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    unsigned path_base<VC>::arrange_polygon_orientation(unsigned start, 
+                                                        path_flags_e orientation)
+    {
+        if(orientation == path_flags_none) return start;
+        
+        // Skip all non-vertices at the beginning
+        while(start < m_vertices.total_vertices() && 
+              !is_vertex(m_vertices.command(start))) ++start;
+
+        // Skip all insignificant move_to
+        while(start+1 < m_vertices.total_vertices() && 
+              is_move_to(m_vertices.command(start)) &&
+              is_move_to(m_vertices.command(start+1))) ++start;
+
+        // Find the last vertex
+        unsigned end = start + 1;
+        while(end < m_vertices.total_vertices() && 
+              !is_next_poly(m_vertices.command(end))) ++end;
+
+        if(end - start > 2)
+        {
+            if(perceive_polygon_orientation(start, end) != unsigned(orientation))
+            {
+                // Invert polygon, set orientation flag, and skip all end_poly
+                invert_polygon(start, end);
+                unsigned cmd;
+                while(end < m_vertices.total_vertices() && 
+                      is_end_poly(cmd = m_vertices.command(end)))
+                {
+                    m_vertices.modify_command(end++, set_orientation(cmd, orientation));
+                }
+            }
+        }
+        return end;
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    unsigned path_base<VC>::arrange_orientations(unsigned start, 
+                                                 path_flags_e orientation)
+    {
+        if(orientation != path_flags_none)
+        {
+            while(start < m_vertices.total_vertices())
+            {
+                start = arrange_polygon_orientation(start, orientation);
+                if(is_stop(m_vertices.command(start)))
+                {
+                    ++start;
+                    break;
+                }
+            }
+        }
+        return start;
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::arrange_orientations_all_paths(path_flags_e orientation)
+    {
+        if(orientation != path_flags_none)
+        {
+            unsigned start = 0;
+            while(start < m_vertices.total_vertices())
+            {
+                start = arrange_orientations(start, orientation);
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::flip_x(double x1, double x2)
+    {
+        unsigned i;
+        double x, y;
+        for(i = 0; i < m_vertices.total_vertices(); i++)
+        {
+            unsigned cmd = m_vertices.vertex(i, &x, &y);
+            if(is_vertex(cmd))
+            {
+                m_vertices.modify_vertex(i, x2 - x + x1, y);
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::flip_y(double y1, double y2)
+    {
+        unsigned i;
+        double x, y;
+        for(i = 0; i < m_vertices.total_vertices(); i++)
+        {
+            unsigned cmd = m_vertices.vertex(i, &x, &y);
+            if(is_vertex(cmd))
+            {
+                m_vertices.modify_vertex(i, x, y2 - y + y1);
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::translate(double dx, double dy, unsigned path_id)
+    {
+        unsigned num_ver = m_vertices.total_vertices();
+        for(; path_id < num_ver; path_id++)
+        {
+            double x, y;
+            unsigned cmd = m_vertices.vertex(path_id, &x, &y);
+            if(is_stop(cmd)) break;
+            if(is_vertex(cmd))
+            {
+                x += dx;
+                y += dy;
+                m_vertices.modify_vertex(path_id, x, y);
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    template<class VC> 
+    void path_base<VC>::translate_all_paths(double dx, double dy)
+    {
+        unsigned idx;
+        unsigned num_ver = m_vertices.total_vertices();
+        for(idx = 0; idx < num_ver; idx++)
+        {
+            double x, y;
+            if(is_vertex(m_vertices.vertex(idx, &x, &y)))
+            {
+                x += dx;
+                y += dy;
+                m_vertices.modify_vertex(idx, x, y);
+            }
+        }
     }
+
+    //-----------------------------------------------------vertex_stl_storage
+    template<class Container> class vertex_stl_storage
+    {
+    public:
+        typedef typename Container::value_type vertex_type;
+        typedef typename vertex_type::value_type value_type;
+
+        void remove_all() { m_vertices.clear(); }
+        void free_all()   { m_vertices.clear(); }
+
+        void add_vertex(double x, double y, unsigned cmd)
+        {
+            m_vertices.push_back(vertex_type(value_type(x), 
+                                             value_type(y), 
+                                             int8u(cmd)));
+        }
+
+        void modify_vertex(unsigned idx, double x, double y)
+        {
+            vertex_type& v = m_vertices[idx];
+            v.x = value_type(x);
+            v.y = value_type(y);
+        }
+
+        void modify_vertex(unsigned idx, double x, double y, unsigned cmd)
+        {
+            vertex_type& v = m_vertices[idx];
+            v.x   = value_type(x);
+            v.y   = value_type(y);
+            v.cmd = int8u(cmd);
+        }
+
+        void modify_command(unsigned idx, unsigned cmd)
+        {
+            m_vertices[idx].cmd = int8u(cmd);
+        }
+
+        void swap_vertices(unsigned v1, unsigned v2)
+        {
+            vertex_type t = m_vertices[v1];
+            m_vertices[v1] = m_vertices[v2];
+            m_vertices[v2] = t;
+        }
+
+        unsigned last_command() const
+        {
+            return m_vertices.size() ? 
+                m_vertices[m_vertices.size() - 1].cmd : 
+                path_cmd_stop;
+        }
+
+        unsigned last_vertex(double* x, double* y) const
+        {
+            if(m_vertices.size() == 0)
+            {
+                *x = *y = 0.0;
+                return path_cmd_stop;
+            }
+            return vertex(m_vertices.size() - 1, x, y);
+        }
+
+        unsigned prev_vertex(double* x, double* y) const
+        {
+            if(m_vertices.size() < 2)
+            {
+                *x = *y = 0.0;
+                return path_cmd_stop;
+            }
+            return vertex(m_vertices.size() - 2, x, y);
+        }
+
+        double last_x() const
+        {
+            return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0;
+        }
+
+        double last_y() const
+        {
+            return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0;
+        }
+
+        unsigned total_vertices() const
+        {
+            return m_vertices.size();
+        }
+
+        unsigned vertex(unsigned idx, double* x, double* y) const
+        {
+            const vertex_type& v = m_vertices[idx];
+            *x = v.x;
+            *y = v.y;
+            return v.cmd;
+        }
+
+        unsigned command(unsigned idx) const
+        {
+            return m_vertices[idx].cmd;
+        }
+
+    private:
+        Container m_vertices;
+    };
+
+    //-----------------------------------------------------------path_storage
+    typedef path_base<vertex_block_storage<double> > path_storage;
+
+    // Example of declarations path_storage with pod_bvector as a container
+    //-----------------------------------------------------------------------
+    //typedef path_base<vertex_stl_storage<pod_bvector<vertex_d> > > path_storage;
+
 }
 
 
 
+// Example of declarations path_storage with std::vector as a container
+//---------------------------------------------------------------------------
+//#include <vector>
+//namespace agg
+//{
+//    typedef path_base<vertex_stl_storage<std::vector<vertex_d> > > stl_path_storage; 
+//}
+
+
+
+
 #endif

Modified: incubator/ooo/trunk/main/agg/inc/agg_path_storage_integer.h
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/agg/inc/agg_path_storage_integer.h?rev=1184758&r1=1184757&r2=1184758&view=diff
==============================================================================
--- incubator/ooo/trunk/main/agg/inc/agg_path_storage_integer.h (original)
+++ incubator/ooo/trunk/main/agg/inc/agg_path_storage_integer.h Sun Oct 16 04:13:16 2011
@@ -1,5 +1,5 @@
 //----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.3
+// Anti-Grain Geometry - Version 2.4
 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 //
 // Permission to copy, use, modify, sell and distribute this software 
@@ -21,7 +21,6 @@
 
 namespace agg
 {
-
     //---------------------------------------------------------vertex_integer
     template<class T, unsigned CoordShift=6> struct vertex_integer
     {
@@ -33,10 +32,10 @@ namespace agg
             cmd_curve4  = 3
         };
 
-        enum
+        enum coord_scale_e
         {
             coord_shift = CoordShift,
-            coord_mult  = 1 << coord_shift
+            coord_scale  = 1 << coord_shift
         };
 
         T x,y;
@@ -49,8 +48,8 @@ namespace agg
                         double dx=0, double dy=0,
                         double scale=1.0) const
         {
-            *x_ = dx + (double(x >> 1) / coord_mult) * scale;
-            *y_ = dy + (double(y >> 1) / coord_mult) * scale;
+            *x_ = dx + (double(x >> 1) / coord_scale) * scale;
+            *y_ = dy + (double(y >> 1) / coord_scale) * scale;
             switch(((y & 1) << 1) | (x & 1))
             {
                 case cmd_move_to: return path_cmd_move_to;
@@ -67,6 +66,7 @@ namespace agg
     template<class T, unsigned CoordShift=6> class path_storage_integer
     {
     public:
+        typedef T value_type;
         typedef vertex_integer<T, CoordShift> vertex_integer_type;
 
         //--------------------------------------------------------------------
@@ -110,12 +110,9 @@ namespace agg
 
         //--------------------------------------------------------------------
         unsigned size() const { return m_storage.size(); }
-        unsigned vertex(unsigned idx, T* x, T* y) const
+        unsigned vertex(unsigned idx, double* x, double* y) const
         {
-            const vertex_integer_type& v = m_storage[idx];
-            *x = v.x >> 1;
-            *y = v.y >> 1;
-            return ((v.y & 1) << 1) | (v.x & 1);
+            return m_storage[idx].vertex(x, y);
         }
 
         //--------------------------------------------------------------------
@@ -130,7 +127,6 @@ namespace agg
             }
         }
 
-
         //--------------------------------------------------------------------
         void rewind(unsigned) 
         { 
@@ -191,11 +187,10 @@ namespace agg
             return bounds;
         }
 
-
     private:
-        pod_deque<vertex_integer_type, 6> m_storage;
-        unsigned                          m_vertex_idx;
-        bool                              m_closed;
+        pod_bvector<vertex_integer_type, 6> m_storage;
+        unsigned                            m_vertex_idx;
+        bool                                m_closed;
     };
 
 

Modified: incubator/ooo/trunk/main/agg/inc/agg_pattern_filters_rgba.h
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/agg/inc/agg_pattern_filters_rgba.h?rev=1184758&r1=1184757&r2=1184758&view=diff
==============================================================================
--- incubator/ooo/trunk/main/agg/inc/agg_pattern_filters_rgba.h (original)
+++ incubator/ooo/trunk/main/agg/inc/agg_pattern_filters_rgba.h Sun Oct 16 04:13:16 2011
@@ -1,5 +1,5 @@
 //----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.3
+// Anti-Grain Geometry - Version 2.4
 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 //
 // Permission to copy, use, modify, sell and distribute this software 
@@ -67,7 +67,7 @@ namespace agg
                                               color_type* p, int x, int y)
         {
             calc_type r, g, b, a;
-            r = g = b = a = line_subpixel_size * line_subpixel_size / 2;
+            r = g = b = a = line_subpixel_scale * line_subpixel_scale / 2;
 
             calc_type weight;
             int x_lr = x >> line_subpixel_shift;
@@ -77,8 +77,8 @@ namespace agg
             y &= line_subpixel_mask;
             const color_type* ptr = buf[y_lr] + x_lr;
 
-            weight = (line_subpixel_size - x) * 
-                     (line_subpixel_size - y);
+            weight = (line_subpixel_scale - x) * 
+                     (line_subpixel_scale - y);
             r += weight * ptr->r;
             g += weight * ptr->g;
             b += weight * ptr->b;
@@ -86,7 +86,7 @@ namespace agg
 
             ++ptr;
 
-            weight = x * (line_subpixel_size - y);
+            weight = x * (line_subpixel_scale - y);
             r += weight * ptr->r;
             g += weight * ptr->g;
             b += weight * ptr->b;
@@ -94,7 +94,7 @@ namespace agg
 
             ptr = buf[y_lr + 1] + x_lr;
 
-            weight = (line_subpixel_size - x) * y;
+            weight = (line_subpixel_scale - x) * y;
             r += weight * ptr->r;
             g += weight * ptr->g;
             b += weight * ptr->b;

Modified: incubator/ooo/trunk/main/agg/inc/agg_pixfmt_amask_adaptor.h
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/agg/inc/agg_pixfmt_amask_adaptor.h?rev=1184758&r1=1184757&r2=1184758&view=diff
==============================================================================
--- incubator/ooo/trunk/main/agg/inc/agg_pixfmt_amask_adaptor.h (original)
+++ incubator/ooo/trunk/main/agg/inc/agg_pixfmt_amask_adaptor.h Sun Oct 16 04:13:16 2011
@@ -1,5 +1,5 @@
 //----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.3
+// Anti-Grain Geometry - Version 2.4
 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 //
 // Permission to copy, use, modify, sell and distribute this software 
@@ -18,6 +18,7 @@
 
 
 #include <string.h>
+#include "agg_array.h"
 #include "agg_rendering_buffer.h"
 
 
@@ -29,47 +30,50 @@ namespace agg
     public:
         typedef PixFmt pixfmt_type;
         typedef typename pixfmt_type::color_type color_type;
+        typedef typename pixfmt_type::row_data row_data;
         typedef AlphaMask amask_type;
         typedef typename amask_type::cover_type cover_type;
 
     private:
-        enum { span_extra_tail = 256 };
+        enum span_extra_tail_e { span_extra_tail = 256 };
 
         void realloc_span(unsigned len)
         {
-            if(len > m_max_len)
+            if(len > m_span.size())
             {
-                delete [] m_span;
-                m_span = new cover_type[m_max_len = len + span_extra_tail];
+                m_span.resize(len + span_extra_tail);
             }
         }
 
         void init_span(unsigned len)
         {
             realloc_span(len);
-
-            // ATTN! May work incorrectly if cover_type is more that one byte
-            memset(m_span, amask_type::cover_full, len * sizeof(cover_type));
+            memset(&m_span[0], amask_type::cover_full, len * sizeof(cover_type));
         }
 
         void init_span(unsigned len, const cover_type* covers)
         {
             realloc_span(len);
-            memcpy(m_span, covers, len * sizeof(cover_type));
+            memcpy(&m_span[0], covers, len * sizeof(cover_type));
         }
 
 
     public:
-        ~pixfmt_amask_adaptor() { delete [] m_span; }
-
         pixfmt_amask_adaptor(pixfmt_type& pixf, const amask_type& mask) :
-            m_pixf(&pixf), m_mask(&mask), m_span(0), m_max_len(0)
+            m_pixf(&pixf), m_mask(&mask), m_span()
         {}
 
         void attach_pixfmt(pixfmt_type& pixf)          { m_pixf = &pixf; }
         void attach_alpha_mask(const amask_type& mask) { m_mask = &mask; }
 
         //--------------------------------------------------------------------
+        template<class PixFmt2>
+        bool attach_pixfmt(PixFmt2& pixf, int x1, int y1, int x2, int y2)
+        {
+            return m_pixf->attach(pixf, x1, y1, x2, y2);
+        }
+
+        //--------------------------------------------------------------------
         unsigned width()  const { return m_pixf->width();  }
         unsigned height() const { return m_pixf->height(); }
 
@@ -97,8 +101,8 @@ namespace agg
                         const color_type& c)
         {
             realloc_span(len);
-            m_mask->fill_hspan(x, y, m_span, len);
-            m_pixf->blend_solid_hspan(x, y, len, c, m_span);
+            m_mask->fill_hspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]);
         }
 
         //--------------------------------------------------------------------
@@ -108,8 +112,8 @@ namespace agg
                          cover_type cover)
         {
             init_span(len);
-            m_mask->combine_hspan(x, y, m_span, len);
-            m_pixf->blend_solid_hspan(x, y, len, c, m_span);
+            m_mask->combine_hspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]);
         }
 
         //--------------------------------------------------------------------
@@ -118,8 +122,8 @@ namespace agg
                         const color_type& c)
         {
             realloc_span(len);
-            m_mask->fill_vspan(x, y, m_span, len);
-            m_pixf->blend_solid_vspan(x, y, len, c, m_span);
+            m_mask->fill_vspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]);
         }
 
         //--------------------------------------------------------------------
@@ -129,8 +133,8 @@ namespace agg
                          cover_type cover)
         {
             init_span(len);
-            m_mask->combine_vspan(x, y, m_span, len);
-            m_pixf->blend_solid_vspan(x, y, len, c, m_span);
+            m_mask->combine_vspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]);
         }
 
         //--------------------------------------------------------------------
@@ -150,8 +154,8 @@ namespace agg
                                const cover_type* covers)
         {
             init_span(len, covers);
-            m_mask->combine_hspan(x, y, m_span, len);
-            m_pixf->blend_solid_hspan(x, y, len, c, m_span);
+            m_mask->combine_hspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]);
         }
 
 
@@ -162,10 +166,26 @@ namespace agg
                                const cover_type* covers)
         {
             init_span(len, covers);
-            m_mask->combine_vspan(x, y, m_span, len);
-            m_pixf->blend_solid_vspan(x, y, len, c, m_span);
+            m_mask->combine_vspan(x, y, &m_span[0], len);
+            m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]);
+        }
+
+
+        //--------------------------------------------------------------------
+        void copy_color_hspan(int x, int y, unsigned len, const color_type* colors)
+        {
+            realloc_span(len);
+            m_mask->fill_hspan(x, y, &m_span[0], len);
+            m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover_full);
         }
 
+        //--------------------------------------------------------------------
+        void copy_color_vspan(int x, int y, unsigned len, const color_type* colors)
+        {
+            realloc_span(len);
+            m_mask->fill_vspan(x, y, &m_span[0], len);
+            m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover_full);
+        }
 
         //--------------------------------------------------------------------
         void blend_color_hspan(int x, int y,
@@ -177,14 +197,14 @@ namespace agg
             if(covers) 
             {
                 init_span(len, covers);
-                m_mask->combine_hspan(x, y, m_span, len);
+                m_mask->combine_hspan(x, y, &m_span[0], len);
             }
             else
             {
                 realloc_span(len);
-                m_mask->fill_hspan(x, y, m_span, len);
+                m_mask->fill_hspan(x, y, &m_span[0], len);
             }
-            m_pixf->blend_color_hspan(x, y, len, colors, m_span, cover);
+            m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover);
         }
 
 
@@ -198,65 +218,20 @@ namespace agg
             if(covers) 
             {
                 init_span(len, covers);
-                m_mask->combine_vspan(x, y, m_span, len);
-            }
-            else
-            {
-                realloc_span(len);
-                m_mask->fill_vspan(x, y, m_span, len);
-            }
-            m_pixf->blend_color_vspan(x, y, len, colors, m_span, cover);
-        }
-
-
-        //--------------------------------------------------------------------
-        void blend_opaque_color_hspan(int x, int y,
-                                      unsigned len, 
-                                      const color_type* colors,
-                                      const cover_type* covers,
-                                      cover_type cover = cover_full)
-        {
-            if(covers) 
-            {
-                init_span(len, covers);
-                m_mask->combine_hspan(x, y, m_span, len);
-            }
-            else
-            {
-                realloc_span(len);
-                m_mask->fill_hspan(x, y, m_span, len);
-            }
-            m_pixf->blend_opaque_color_hspan(x, y, len, colors, m_span, cover);
-        }
-
-
-        //--------------------------------------------------------------------
-        void blend_opaque_color_vspan(int x, int y,
-                                      unsigned len, 
-                                      const color_type* colors,
-                                      const cover_type* covers,
-                                      cover_type cover = cover_full)
-        {
-            if(covers) 
-            {
-                init_span(len, covers);
-                m_mask->combine_vspan(x, y, m_span, len);
+                m_mask->combine_vspan(x, y, &m_span[0], len);
             }
             else
             {
                 realloc_span(len);
-                m_mask->fill_vspan(x, y, m_span, len);
+                m_mask->fill_vspan(x, y, &m_span[0], len);
             }
-            m_pixf->blend_opaque_color_vspan(x, y, len, colors, m_span, cover);
+            m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover);
         }
 
-
     private:
-        pixfmt_type*      m_pixf;
-        const amask_type* m_mask;
-
-        cover_type*       m_span;
-        unsigned          m_max_len;
+        pixfmt_type*          m_pixf;
+        const amask_type*     m_mask;
+        pod_array<cover_type> m_span;
     };
 
 }



Mime
View raw message