summaryrefslogtreecommitdiff
path: root/third_party
diff options
context:
space:
mode:
authorTom Sepez <tsepez@chromium.org>2015-06-16 16:29:44 -0700
committerTom Sepez <tsepez@chromium.org>2015-06-16 16:29:44 -0700
commit2ca8fcbc8a7a3ef6adfac154c47068c1696205d0 (patch)
treede3f825c75b1b92908825f68af8a4e7146cf97fd /third_party
parentea44bd064a86679a47a7265020f997d6e3b88336 (diff)
downloadpdfium-chromium/2439.tar.xz
Separate agg-authored code from fx-authored code.chromium/2439chromium/2438chromium/2437chromium/2436chromium/2435
Creates a separate library so we can apply less-strict warnings to the code we can't change from upstream vs. the code we can change, reducing noise in the standalone build. Remove needless foo.{cpp,h} files that merely perform indirection via #include "some_other_path/foo.{cpp,h}". BUG=pdfium:166 R=brucedawson@chromium.org, thestig@chromium.org Review URL: https://codereview.chromium.org/1152743007.
Diffstat (limited to 'third_party')
-rw-r--r--third_party/BUILD.gn25
-rw-r--r--third_party/agg23/agg_array.h506
-rw-r--r--third_party/agg23/agg_basics.h282
-rw-r--r--third_party/agg23/agg_clip_liang_barsky.h125
-rw-r--r--third_party/agg23/agg_color_gray.h50
-rw-r--r--third_party/agg23/agg_conv_adaptor_vcgen.h138
-rw-r--r--third_party/agg23/agg_conv_dash.h61
-rw-r--r--third_party/agg23/agg_conv_stroke.h110
-rw-r--r--third_party/agg23/agg_curves.cpp109
-rw-r--r--third_party/agg23/agg_curves.h188
-rw-r--r--third_party/agg23/agg_math.h63
-rw-r--r--third_party/agg23/agg_math_stroke.h272
-rw-r--r--third_party/agg23/agg_path_storage.cpp98
-rw-r--r--third_party/agg23/agg_path_storage.h172
-rw-r--r--third_party/agg23/agg_pixfmt_gray.h177
-rw-r--r--third_party/agg23/agg_rasterizer_scanline_aa.cpp489
-rw-r--r--third_party/agg23/agg_rasterizer_scanline_aa.h472
-rw-r--r--third_party/agg23/agg_render_scanlines.h50
-rw-r--r--third_party/agg23/agg_renderer_base.h163
-rw-r--r--third_party/agg23/agg_renderer_scanline.h93
-rw-r--r--third_party/agg23/agg_rendering_buffer.h145
-rw-r--r--third_party/agg23/agg_scanline_u.h150
-rw-r--r--third_party/agg23/agg_shorten_path.h57
-rw-r--r--third_party/agg23/agg_vcgen_dash.cpp176
-rw-r--r--third_party/agg23/agg_vcgen_dash.h75
-rw-r--r--third_party/agg23/agg_vcgen_stroke.cpp214
-rw-r--r--third_party/agg23/agg_vcgen_stroke.h120
-rw-r--r--third_party/agg23/agg_vertex_sequence.h100
-rw-r--r--third_party/third_party.gyp27
29 files changed, 4707 insertions, 0 deletions
diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn
index 18baeb2eb5..bcb7cbabee 100644
--- a/third_party/BUILD.gn
+++ b/third_party/BUILD.gn
@@ -30,6 +30,31 @@ source_set("bigint") {
]
}
+source_set("fx_agg") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/pdfium:pdfium_config",
+ ]
+ sources = [
+ "agg23/agg_basics.h",
+ "agg23/agg_clip_liang_barsky.h",
+ "agg23/agg_conv_dash.h",
+ "agg23/agg_conv_stroke.h",
+ "agg23/agg_curves.cpp",
+ "agg23/agg_curves.h",
+ "agg23/agg_path_storage.cpp",
+ "agg23/agg_path_storage.h",
+ "agg23/agg_rasterizer_scanline_aa.cpp",
+ "agg23/agg_rasterizer_scanline_aa.h",
+ "agg23/agg_renderer_scanline.h",
+ "agg23/agg_rendering_buffer.h",
+ "agg23/agg_scanline_u.h",
+ "agg23/agg_vcgen_dash.cpp",
+ "agg23/agg_vcgen_stroke.cpp",
+ ]
+}
+
source_set("freetype") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
diff --git a/third_party/agg23/agg_array.h b/third_party/agg23/agg_array.h
new file mode 100644
index 0000000000..810eb4ef22
--- /dev/null
+++ b/third_party/agg23/agg_array.h
@@ -0,0 +1,506 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_ARRAY_INCLUDED
+#define AGG_ARRAY_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+template<class T> class pod_array
+{
+public:
+ typedef T value_type;
+ ~pod_array()
+ {
+ FX_Free(m_array);
+ }
+ pod_array() : m_size(0), m_capacity(0), m_array(0) {}
+ pod_array(unsigned cap, unsigned extra_tail = 0);
+ pod_array(const pod_array<T>&);
+ const pod_array<T>& operator = (const pod_array<T>&);
+ void capacity(unsigned cap, unsigned extra_tail = 0);
+ unsigned capacity() const
+ {
+ return m_capacity;
+ }
+ void allocate(unsigned size, unsigned extra_tail = 0);
+ void resize(unsigned new_size);
+ void zero()
+ {
+ FXSYS_memset(m_array, 0, sizeof(T) * m_size);
+ }
+ void add(const T& v)
+ {
+ m_array[m_size++] = v;
+ }
+ void inc_size(unsigned size)
+ {
+ m_size += size;
+ }
+ unsigned size() const
+ {
+ return m_size;
+ }
+ unsigned byte_size() const
+ {
+ return m_size * sizeof(T);
+ }
+ const T& operator [] (unsigned i) const
+ {
+ return m_array[i];
+ }
+ T& operator [] (unsigned i)
+ {
+ return m_array[i];
+ }
+ const T& at(unsigned i) const
+ {
+ return m_array[i];
+ }
+ T& at(unsigned i)
+ {
+ return m_array[i];
+ }
+ T value_at(unsigned i) const
+ {
+ return m_array[i];
+ }
+ const T* data() const
+ {
+ return m_array;
+ }
+ T* data()
+ {
+ return m_array;
+ }
+ void remove_all()
+ {
+ m_size = 0;
+ }
+ void cut_at(unsigned num)
+ {
+ if(num < m_size) {
+ m_size = num;
+ }
+ }
+private:
+ unsigned m_size;
+ unsigned m_capacity;
+ T* m_array;
+};
+template<class T>
+void pod_array<T>::capacity(unsigned cap, unsigned extra_tail)
+{
+ m_size = 0;
+ unsigned full_cap = cap + extra_tail;
+ if(full_cap < cap) {
+ FX_Free(m_array);
+ m_array = 0;
+ m_capacity = 0;
+ } else if(full_cap > m_capacity) {
+ FX_Free(m_array);
+ m_array = FX_Alloc(T, full_cap);
+ m_capacity = full_cap;
+ }
+}
+template<class T>
+void pod_array<T>::allocate(unsigned size, unsigned extra_tail)
+{
+ capacity(size, extra_tail);
+ m_size = size;
+}
+template<class T>
+void pod_array<T>::resize(unsigned new_size)
+{
+ if(new_size > m_size) {
+ if(new_size > m_capacity) {
+ T* data = FX_Alloc(T, new_size);
+ FXSYS_memcpy(data, m_array, m_size * sizeof(T));
+ FX_Free(m_array);
+ m_array = data;
+ }
+ } else {
+ m_size = new_size;
+ }
+}
+template<class T> pod_array<T>::pod_array(unsigned cap, unsigned extra_tail) :
+ m_size(0), m_capacity(cap + extra_tail), m_array(FX_Alloc(T, m_capacity)) {}
+template<class T> pod_array<T>::pod_array(const pod_array<T>& v) :
+ m_size(v.m_size),
+ m_capacity(v.m_capacity),
+ m_array(v.m_capacity ? FX_Alloc(T, v.m_capacity) : 0)
+{
+ FXSYS_memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
+}
+template<class T> const pod_array<T>&
+pod_array<T>::operator = (const pod_array<T>&v)
+{
+ allocate(v.m_size);
+ if(v.m_size) {
+ FXSYS_memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
+ }
+ return *this;
+}
+template<class T, unsigned S = 6> class pod_deque
+{
+public:
+ enum block_scale_e {
+ block_shift = S,
+ block_size = 1 << block_shift,
+ block_mask = block_size - 1
+ };
+ typedef T value_type;
+ ~pod_deque();
+ pod_deque();
+ pod_deque(unsigned block_ptr_inc);
+ pod_deque(const pod_deque<T, S>& v);
+ const pod_deque<T, S>& operator = (const pod_deque<T, S>& v);
+ void remove_all()
+ {
+ m_size = 0;
+ }
+ void free_all()
+ {
+ free_tail(0);
+ }
+ void free_tail(unsigned size);
+ void add(const T& val);
+ void modify_last(const T& val);
+ void remove_last();
+ int allocate_continuous_block(unsigned num_elements);
+ void add_array(const T* ptr, unsigned num_elem)
+ {
+ while(num_elem--) {
+ add(*ptr++);
+ }
+ }
+ template<class DataAccessor> void add_data(DataAccessor& data)
+ {
+ while(data.size()) {
+ add(*data);
+ ++data;
+ }
+ }
+ void cut_at(unsigned size)
+ {
+ if(size < m_size) {
+ m_size = size;
+ }
+ }
+ unsigned size() const
+ {
+ return m_size;
+ }
+ const T& operator [] (unsigned i) const
+ {
+ return m_blocks[i >> block_shift][i & block_mask];
+ }
+ T& operator [] (unsigned i)
+ {
+ return m_blocks[i >> block_shift][i & block_mask];
+ }
+ const T& at(unsigned i) const
+ {
+ return m_blocks[i >> block_shift][i & block_mask];
+ }
+ T& at(unsigned i)
+ {
+ return m_blocks[i >> block_shift][i & block_mask];
+ }
+ T value_at(unsigned i) const
+ {
+ return m_blocks[i >> block_shift][i & block_mask];
+ }
+ const T& curr(unsigned idx) const
+ {
+ return (*this)[idx];
+ }
+ T& curr(unsigned idx)
+ {
+ return (*this)[idx];
+ }
+ const T& prev(unsigned idx) const
+ {
+ return (*this)[(idx + m_size - 1) % m_size];
+ }
+ T& prev(unsigned idx)
+ {
+ return (*this)[(idx + m_size - 1) % m_size];
+ }
+ const T& next(unsigned idx) const
+ {
+ return (*this)[(idx + 1) % m_size];
+ }
+ T& next(unsigned idx)
+ {
+ return (*this)[(idx + 1) % m_size];
+ }
+ const T& last() const
+ {
+ return (*this)[m_size - 1];
+ }
+ T& last()
+ {
+ return (*this)[m_size - 1];
+ }
+ unsigned byte_size() const;
+ const T* block(unsigned nb) const
+ {
+ return m_blocks[nb];
+ }
+public:
+ void allocate_block(unsigned nb);
+ T* data_ptr();
+ unsigned m_size;
+ unsigned m_num_blocks;
+ unsigned m_max_blocks;
+ T** m_blocks;
+ unsigned m_block_ptr_inc;
+};
+template<class T, unsigned S> pod_deque<T, S>::~pod_deque()
+{
+ if(m_num_blocks) {
+ T** blk = m_blocks + m_num_blocks - 1;
+ while(m_num_blocks--) {
+ FX_Free(*blk);
+ --blk;
+ }
+ FX_Free(m_blocks);
+ }
+}
+template<class T, unsigned S>
+void pod_deque<T, S>::free_tail(unsigned size)
+{
+ if(size < m_size) {
+ unsigned nb = (size + block_mask) >> block_shift;
+ while(m_num_blocks > nb) {
+ FX_Free(m_blocks[--m_num_blocks]);
+ }
+ m_size = size;
+ }
+}
+template<class T, unsigned S> pod_deque<T, S>::pod_deque() :
+ m_size(0),
+ m_num_blocks(0),
+ m_max_blocks(0),
+ m_blocks(0),
+ m_block_ptr_inc(block_size)
+{
+}
+template<class T, unsigned S>
+pod_deque<T, S>::pod_deque(unsigned block_ptr_inc) :
+ m_size(0),
+ m_num_blocks(0),
+ m_max_blocks(0),
+ m_blocks(0),
+ m_block_ptr_inc(block_ptr_inc)
+{
+}
+template<class T, unsigned S>
+pod_deque<T, S>::pod_deque(const pod_deque<T, S>& v) :
+ m_size(v.m_size),
+ m_num_blocks(v.m_num_blocks),
+ m_max_blocks(v.m_max_blocks),
+ m_blocks(v.m_max_blocks ? FX_Alloc(T*, v.m_max_blocks) : 0),
+ m_block_ptr_inc(v.m_block_ptr_inc)
+{
+ unsigned i;
+ for(i = 0; i < v.m_num_blocks; ++i) {
+ m_blocks[i] = FX_Alloc(T, block_size);
+ FXSYS_memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
+ }
+}
+template<class T, unsigned S>
+const pod_deque<T, S>& pod_deque<T, S>::operator = (const pod_deque<T, S>& v)
+{
+ unsigned i;
+ for(i = m_num_blocks; i < v.m_num_blocks; ++i) {
+ allocate_block(i);
+ }
+ for(i = 0; i < v.m_num_blocks; ++i) {
+ FXSYS_memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
+ }
+ m_size = v.m_size;
+ return *this;
+}
+template<class T, unsigned S>
+void pod_deque<T, S>::allocate_block(unsigned nb)
+{
+ if(nb >= m_max_blocks) {
+ T** new_blocks = FX_Alloc(T*, m_max_blocks + m_block_ptr_inc);
+ if(m_blocks) {
+ FXSYS_memcpy(new_blocks,
+ m_blocks,
+ m_num_blocks * sizeof(T*));
+ FX_Free(m_blocks);
+ }
+ m_blocks = new_blocks;
+ m_max_blocks += m_block_ptr_inc;
+ }
+ m_blocks[nb] = FX_Alloc(T, block_size);
+ m_num_blocks++;
+}
+template<class T, unsigned S>
+inline T* pod_deque<T, S>::data_ptr()
+{
+ unsigned nb = m_size >> block_shift;
+ if(nb >= m_num_blocks) {
+ allocate_block(nb);
+ }
+ return m_blocks[nb] + (m_size & block_mask);
+}
+template<class T, unsigned S>
+inline void pod_deque<T, S>::add(const T& val)
+{
+ *data_ptr() = val;
+ ++m_size;
+}
+template<class T, unsigned S>
+inline void pod_deque<T, S>::remove_last()
+{
+ if(m_size) {
+ --m_size;
+ }
+}
+template<class T, unsigned S>
+void pod_deque<T, S>::modify_last(const T& val)
+{
+ remove_last();
+ add(val);
+}
+template<class T, unsigned S>
+int pod_deque<T, S>::allocate_continuous_block(unsigned num_elements)
+{
+ if(num_elements < block_size) {
+ data_ptr();
+ unsigned rest = block_size - (m_size & block_mask);
+ unsigned index;
+ if(num_elements <= rest) {
+ index = m_size;
+ m_size += num_elements;
+ return index;
+ }
+ m_size += rest;
+ data_ptr();
+ index = m_size;
+ m_size += num_elements;
+ return index;
+ }
+ return -1;
+}
+template<class T, unsigned S>
+unsigned pod_deque<T, S>::byte_size() const
+{
+ return m_size * sizeof(T);
+}
+class pod_allocator
+{
+public:
+ void remove_all()
+ {
+ if(m_num_blocks) {
+ int8u** blk = m_blocks + m_num_blocks - 1;
+ while(m_num_blocks--) {
+ FX_Free(*blk);
+ --blk;
+ }
+ FX_Free(m_blocks);
+ }
+ m_num_blocks = 0;
+ m_max_blocks = 0;
+ m_blocks = 0;
+ m_buf_ptr = 0;
+ m_rest = 0;
+ }
+ ~pod_allocator()
+ {
+ remove_all();
+ }
+ pod_allocator(unsigned block_size, unsigned block_ptr_inc = 256 - 8) :
+ m_block_size(block_size),
+ m_block_ptr_inc(block_ptr_inc),
+ m_num_blocks(0),
+ m_max_blocks(0),
+ m_blocks(0),
+ m_buf_ptr(0),
+ m_rest(0)
+ {
+ }
+ int8u* allocate(unsigned size, unsigned alignment = 1)
+ {
+ if(size == 0) {
+ return 0;
+ }
+ if(size <= m_rest) {
+ int8u* ptr = m_buf_ptr;
+ if(alignment > 1) {
+ unsigned align = (alignment - unsigned((size_t)ptr) % alignment) % alignment;
+ size += align;
+ ptr += align;
+ if(size <= m_rest) {
+ m_rest -= size;
+ m_buf_ptr += size;
+ return ptr;
+ }
+ allocate_block(size);
+ return allocate(size - align, alignment);
+ }
+ m_rest -= size;
+ m_buf_ptr += size;
+ return ptr;
+ }
+ allocate_block(size + alignment - 1);
+ return allocate(size, alignment);
+ }
+private:
+ void allocate_block(unsigned size)
+ {
+ if(size < m_block_size) {
+ size = m_block_size;
+ }
+ if(m_num_blocks >= m_max_blocks) {
+ int8u** new_blocks = FX_Alloc(int8u*, m_max_blocks + m_block_ptr_inc);
+ if(m_blocks) {
+ FXSYS_memcpy(new_blocks,
+ m_blocks,
+ m_num_blocks * sizeof(int8u*));
+ FX_Free(m_blocks);
+ }
+ m_blocks = new_blocks;
+ m_max_blocks += m_block_ptr_inc;
+ }
+ m_blocks[m_num_blocks] = m_buf_ptr = FX_Alloc(int8u, size);
+ m_num_blocks++;
+ m_rest = size;
+ }
+ unsigned m_block_size;
+ unsigned m_block_ptr_inc;
+ unsigned m_num_blocks;
+ unsigned m_max_blocks;
+ int8u** m_blocks;
+ int8u* m_buf_ptr;
+ unsigned m_rest;
+};
+enum quick_sort_threshold_e {
+ quick_sort_threshold = 9
+};
+template<class T> inline void swap_elements(T& a, T& b)
+{
+ T temp = a;
+ a = b;
+ b = temp;
+}
+}
+#endif
diff --git a/third_party/agg23/agg_basics.h b/third_party/agg23/agg_basics.h
new file mode 100644
index 0000000000..d2fad58feb
--- /dev/null
+++ b/third_party/agg23/agg_basics.h
@@ -0,0 +1,282 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_BASICS_INCLUDED
+#define AGG_BASICS_INCLUDED
+#ifndef AGG_INT8
+#define AGG_INT8 signed char
+#endif
+#ifndef AGG_INT8U
+#define AGG_INT8U unsigned char
+#endif
+#ifndef AGG_INT16
+#define AGG_INT16 short
+#endif
+#ifndef AGG_INT16U
+#define AGG_INT16U unsigned short
+#endif
+#ifndef AGG_INT32
+#define AGG_INT32 int
+#endif
+#ifndef AGG_INT32U
+#define AGG_INT32U unsigned
+#endif
+#ifndef AGG_INT64
+#define AGG_INT64 signed long long
+#endif
+#ifndef AGG_INT64U
+#define AGG_INT64U unsigned long long
+#endif
+#define AGG_INLINE inline
+namespace agg
+{
+typedef AGG_INT8 int8;
+typedef AGG_INT8U int8u;
+typedef AGG_INT16 int16;
+typedef AGG_INT16U int16u;
+typedef AGG_INT32 int32;
+typedef AGG_INT32U int32u;
+typedef AGG_INT64 int64;
+typedef AGG_INT64U int64u;
+typedef unsigned char cover_type;
+enum cover_scale_e {
+ cover_shift = 8,
+ cover_size = 1 << cover_shift,
+ cover_mask = cover_size - 1,
+ cover_none = 0,
+ cover_full = cover_mask
+};
+template<class T> struct rect_base {
+ typedef rect_base<T> self_type;
+ T x1;
+ T y1;
+ T x2;
+ T y2;
+ rect_base() {}
+ rect_base(T x1_, T y1_, T x2_, T y2_) :
+ x1(x1_), y1(y1_), x2(x2_), y2(y2_) {}
+ const self_type& normalize()
+ {
+ T t;
+ if(x1 > x2) {
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+ if(y1 > y2) {
+ t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+ return *this;
+ }
+ bool clip(const self_type& r)
+ {
+ if(x2 > r.x2) {
+ x2 = r.x2;
+ }
+ if(y2 > r.y2) {
+ y2 = r.y2;
+ }
+ if(x1 < r.x1) {
+ x1 = r.x1;
+ }
+ if(y1 < r.y1) {
+ y1 = r.y1;
+ }
+ return x1 <= x2 && y1 <= y2;
+ }
+ bool is_valid() const
+ {
+ return x1 <= x2 && y1 <= y2;
+ }
+};
+template<class Rect>
+inline Rect intersect_rectangles(const Rect& r1, const Rect& r2)
+{
+ Rect r = r1;
+ if(r.x2 > r2.x2) {
+ r.x2 = r2.x2;
+ }
+ if(r.y2 > r2.y2) {
+ r.y2 = r2.y2;
+ }
+ if(r.x1 < r2.x1) {
+ r.x1 = r2.x1;
+ }
+ if(r.y1 < r2.y1) {
+ r.y1 = r2.y1;
+ }
+ return r;
+}
+template<class Rect>
+inline Rect unite_rectangles(const Rect& r1, const Rect& r2)
+{
+ Rect r = r1;
+ if(r.x2 < r2.x2) {
+ r.x2 = r2.x2;
+ }
+ if(r.y2 < r2.y2) {
+ r.y2 = r2.y2;
+ }
+ if(r.x1 > r2.x1) {
+ r.x1 = r2.x1;
+ }
+ if(r.y1 > r2.y1) {
+ r.y1 = r2.y1;
+ }
+ return r;
+}
+typedef rect_base<int> rect;
+typedef rect_base<FX_FLOAT> rect_d;
+enum path_commands_e {
+ path_cmd_stop = 0,
+ path_cmd_move_to = 1,
+ path_cmd_line_to = 2,
+ path_cmd_curve3 = 3,
+ path_cmd_curve4 = 4,
+ path_cmd_curveN = 5,
+ path_cmd_catrom = 6,
+ path_cmd_ubspline = 7,
+ path_cmd_end_poly = 0x0F,
+ path_cmd_mask = 0x0F
+};
+enum path_flags_e {
+ path_flags_none = 0,
+ path_flags_ccw = 0x10,
+ path_flags_cw = 0x20,
+ path_flags_close = 0x40,
+ path_flags_jr = 0x80,
+ path_flags_mask = 0xF0
+};
+inline bool is_vertex(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c >= path_cmd_move_to && c < path_cmd_end_poly;
+}
+inline bool is_drawing(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c >= path_cmd_line_to && c < path_cmd_end_poly;
+}
+inline bool is_stop(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_stop;
+}
+inline bool is_move_to(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_move_to;
+}
+inline bool is_line_to(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_line_to;
+}
+inline bool is_curve(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_curve3 || c == path_cmd_curve4;
+}
+inline bool is_curve3(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_curve3;
+}
+inline bool is_curve4(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c == path_cmd_curve4;
+}
+inline bool is_end_poly(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & path_cmd_mask) == path_cmd_end_poly;
+}
+inline bool is_close(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & ~(path_flags_cw | path_flags_ccw)) ==
+ (path_cmd_end_poly | path_flags_close);
+}
+inline bool is_next_poly(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return is_stop(c) || is_move_to(c) || is_end_poly(c);
+}
+inline bool is_cw(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & path_flags_cw) != 0;
+}
+inline bool is_ccw(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & path_flags_ccw) != 0;
+}
+inline bool is_oriented(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & (path_flags_cw | path_flags_ccw)) != 0;
+}
+inline bool is_closed(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return (c & path_flags_close) != 0;
+}
+inline unsigned get_close_flag(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c & path_flags_close;
+}
+inline unsigned clear_orientation(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c & ~(path_flags_cw | path_flags_ccw);
+}
+inline unsigned get_orientation(unsigned c)
+{
+ c &= ~path_flags_jr;
+ return c & (path_flags_cw | path_flags_ccw);
+}
+inline unsigned set_orientation(unsigned c, unsigned o)
+{
+ c &= ~path_flags_jr;
+ return clear_orientation(c) | o;
+}
+struct point_type {
+ FX_FLOAT x, y;
+ unsigned flag;
+ point_type() {}
+ point_type(FX_FLOAT x_, FX_FLOAT y_, unsigned flag_ = 0) : x(x_), y(y_), flag(flag_) {}
+};
+struct point_type_flag : public point_type {
+ unsigned flag;
+ point_type_flag()
+ {
+ flag = 0;
+ }
+ point_type_flag(FX_FLOAT x_, FX_FLOAT y_, unsigned flag_ = 0) : point_type(x_, y_), flag(flag_) {}
+};
+struct vertex_type {
+ FX_FLOAT x, y;
+ unsigned cmd;
+ vertex_type() {}
+ vertex_type(FX_FLOAT x_, FX_FLOAT y_, unsigned cmd_) :
+ x(x_), y(y_), cmd(cmd_) {}
+};
+}
+#endif
diff --git a/third_party/agg23/agg_clip_liang_barsky.h b/third_party/agg23/agg_clip_liang_barsky.h
new file mode 100644
index 0000000000..cfc4c91f60
--- /dev/null
+++ b/third_party/agg23/agg_clip_liang_barsky.h
@@ -0,0 +1,125 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Liang-Barsky clipping
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED
+#define AGG_CLIP_LIANG_BARSKY_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+template<class T>
+inline unsigned clipping_flags(T x, T y, const rect_base<T>& clip_box)
+{
+ return (x > clip_box.x2) |
+ ((y > clip_box.y2) << 1) |
+ ((x < clip_box.x1) << 2) |
+ ((y < clip_box.y1) << 3);
+}
+template<class T>
+inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2,
+ const rect_base<T>& clip_box,
+ T* x, T* y)
+{
+ const FX_FLOAT nearzero = 1e-30f;
+ FX_FLOAT deltax = (FX_FLOAT)(x2 - x1);
+ FX_FLOAT deltay = (FX_FLOAT)(y2 - y1);
+ unsigned np = 0;
+ if(deltax == 0) {
+ deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
+ }
+ FX_FLOAT xin, xout;
+ if(deltax > 0) {
+ xin = (FX_FLOAT)clip_box.x1;
+ xout = (FX_FLOAT)clip_box.x2;
+ } else {
+ xin = (FX_FLOAT)clip_box.x2;
+ xout = (FX_FLOAT)clip_box.x1;
+ }
+ FX_FLOAT tinx = FXSYS_Div(xin - x1, deltax);
+ if(deltay == 0) {
+ deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
+ }
+ FX_FLOAT yin, yout;
+ if(deltay > 0) {
+ yin = (FX_FLOAT)clip_box.y1;
+ yout = (FX_FLOAT)clip_box.y2;
+ } else {
+ yin = (FX_FLOAT)clip_box.y2;
+ yout = (FX_FLOAT)clip_box.y1;
+ }
+ FX_FLOAT tiny = FXSYS_Div(yin - y1, deltay);
+ FX_FLOAT tin1, tin2;
+ if (tinx < tiny) {
+ tin1 = tinx;
+ tin2 = tiny;
+ } else {
+ tin1 = tiny;
+ tin2 = tinx;
+ }
+ if(tin1 <= 1.0f) {
+ if(0 < tin1) {
+ *x++ = (T)xin;
+ *y++ = (T)yin;
+ ++np;
+ }
+ if(tin2 <= 1.0f) {
+ FX_FLOAT toutx = FXSYS_Div(xout - x1, deltax);
+ FX_FLOAT touty = FXSYS_Div(yout - y1, deltay);
+ FX_FLOAT tout1 = (toutx < touty) ? toutx : touty;
+ if(tin2 > 0 || tout1 > 0) {
+ if(tin2 <= tout1) {
+ if(tin2 > 0) {
+ if(tinx > tiny) {
+ *x++ = (T)xin;
+ *y++ = (T)(y1 + FXSYS_Mul(deltay, tinx));
+ } else {
+ *x++ = (T)(x1 + FXSYS_Mul(deltax, tiny));
+ *y++ = (T)yin;
+ }
+ ++np;
+ }
+ if(tout1 < 1.0f) {
+ if(toutx < touty) {
+ *x++ = (T)xout;
+ *y++ = (T)(y1 + FXSYS_Mul(deltay, toutx));
+ } else {
+ *x++ = (T)(x1 + FXSYS_Mul(deltax, touty));
+ *y++ = (T)yout;
+ }
+ } else {
+ *x++ = x2;
+ *y++ = y2;
+ }
+ ++np;
+ } else {
+ if(tinx > tiny) {
+ *x++ = (T)xin;
+ *y++ = (T)yout;
+ } else {
+ *x++ = (T)xout;
+ *y++ = (T)yin;
+ }
+ ++np;
+ }
+ }
+ }
+ }
+ return np;
+}
+}
+#endif
diff --git a/third_party/agg23/agg_color_gray.h b/third_party/agg23/agg_color_gray.h
new file mode 100644
index 0000000000..5db7bcaf28
--- /dev/null
+++ b/third_party/agg23/agg_color_gray.h
@@ -0,0 +1,50 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Adaptation for high precision colors has been sponsored by
+// Liberty Technology Systems, Inc., visit http://lib-sys.com
+//
+// Liberty Technology Systems, Inc. is the provider of
+// PostScript and PDF technology for software developers.
+//
+//----------------------------------------------------------------------------
+//
+// color types gray8, gray16
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_COLOR_GRAY_INCLUDED
+#define AGG_COLOR_GRAY_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+struct gray8 {
+ typedef int8u value_type;
+ typedef int32u calc_type;
+ typedef int32 long_type;
+ enum base_scale_e {
+ base_shift = 8,
+ base_size = 1 << base_shift,
+ base_mask = base_size - 1
+ };
+ typedef gray8 self_type;
+ value_type v;
+ value_type a;
+ gray8() {}
+ gray8(unsigned v_, unsigned a_ = base_mask) :
+ v(int8u(v_)), a(int8u(a_)) {}
+};
+}
+#endif
diff --git a/third_party/agg23/agg_conv_adaptor_vcgen.h b/third_party/agg23/agg_conv_adaptor_vcgen.h
new file mode 100644
index 0000000000..0d8d6ff99e
--- /dev/null
+++ b/third_party/agg23/agg_conv_adaptor_vcgen.h
@@ -0,0 +1,138 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_CONV_ADAPTOR_VCGEN_INCLUDED
+#define AGG_CONV_ADAPTOR_VCGEN_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+struct null_markers {
+ void remove_all() {}
+ void add_vertex(FX_FLOAT, FX_FLOAT, unsigned) {}
+ void prepare_src() {}
+ void rewind(unsigned) {}
+ unsigned vertex(FX_FLOAT*, FX_FLOAT*)
+ {
+ return path_cmd_stop;
+ }
+};
+template<class VertexSource,
+ class Generator,
+ class Markers = null_markers> class conv_adaptor_vcgen
+{
+ enum status {
+ initial,
+ accumulate,
+ generate
+ };
+public:
+ conv_adaptor_vcgen(VertexSource& source) :
+ m_source(&source),
+ m_status(initial)
+ {}
+ void set_source(VertexSource& source)
+ {
+ m_source = &source;
+ }
+ Generator& generator()
+ {
+ return m_generator;
+ }
+ const Generator& generator() const
+ {
+ return m_generator;
+ }
+ Markers& markers()
+ {
+ return m_markers;
+ }
+ const Markers& markers() const
+ {
+ return m_markers;
+ }
+ void rewind(unsigned path_id)
+ {
+ m_source->rewind(path_id);
+ m_status = initial;
+ }
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y);
+private:
+ conv_adaptor_vcgen(const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
+ const conv_adaptor_vcgen<VertexSource, Generator, Markers>&
+ operator = (const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
+ VertexSource* m_source;
+ Generator m_generator;
+ Markers m_markers;
+ status m_status;
+ unsigned m_last_cmd;
+ FX_FLOAT m_start_x;
+ FX_FLOAT m_start_y;
+};
+template<class VertexSource, class Generator, class Markers>
+unsigned conv_adaptor_vcgen<VertexSource, Generator, Markers>::vertex(FX_FLOAT* x, FX_FLOAT* y)
+{
+ unsigned cmd = path_cmd_stop;
+ bool done = false;
+ while(!done) {
+ switch(m_status) {
+ case initial:
+ m_markers.remove_all();
+ m_last_cmd = m_source->vertex(&m_start_x, &m_start_y);
+ m_status = accumulate;
+ case accumulate:
+ if(is_stop(m_last_cmd)) {
+ return path_cmd_stop;
+ }
+ m_generator.remove_all();
+ m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
+ m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
+ for(;;) {
+ cmd = m_source->vertex(x, y);
+ if(is_vertex(cmd)) {
+ m_last_cmd = cmd;
+ if(is_move_to(cmd)) {
+ m_start_x = *x;
+ m_start_y = *y;
+ break;
+ }
+ m_generator.add_vertex(*x, *y, cmd);
+ m_markers.add_vertex(*x, *y, path_cmd_line_to);
+ } else {
+ if(is_stop(cmd)) {
+ m_last_cmd = path_cmd_stop;
+ break;
+ }
+ if(is_end_poly(cmd)) {
+ m_generator.add_vertex(*x, *y, cmd);
+ break;
+ }
+ }
+ }
+ m_generator.rewind(0);
+ m_status = generate;
+ case generate:
+ cmd = m_generator.vertex(x, y);
+ if(is_stop(cmd)) {
+ m_status = accumulate;
+ break;
+ }
+ done = true;
+ break;
+ }
+ }
+ return cmd;
+}
+}
+#endif
diff --git a/third_party/agg23/agg_conv_dash.h b/third_party/agg23/agg_conv_dash.h
new file mode 100644
index 0000000000..63b2019dde
--- /dev/null
+++ b/third_party/agg23/agg_conv_dash.h
@@ -0,0 +1,61 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// conv_dash
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_CONV_DASH_INCLUDED
+#define AGG_CONV_DASH_INCLUDED
+#include "agg_basics.h"
+#include "agg_vcgen_dash.h"
+#include "agg_conv_adaptor_vcgen.h"
+namespace agg
+{
+template<class VertexSource, class Markers = null_markers>
+struct conv_dash : public conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers> {
+ typedef Markers marker_type;
+ typedef conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers> base_type;
+ conv_dash(VertexSource& vs) :
+ conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers>(vs)
+ {
+ }
+ void remove_all_dashes()
+ {
+ base_type::generator().remove_all_dashes();
+ }
+ void add_dash(FX_FLOAT dash_len, FX_FLOAT gap_len)
+ {
+ base_type::generator().add_dash(dash_len, gap_len);
+ }
+ void dash_start(FX_FLOAT ds)
+ {
+ base_type::generator().dash_start(ds);
+ }
+ void shorten(FX_FLOAT s)
+ {
+ base_type::generator().shorten(s);
+ }
+ double shorten() const
+ {
+ return base_type::generator().shorten();
+ }
+private:
+ conv_dash(const conv_dash<VertexSource, Markers>&);
+ const conv_dash<VertexSource, Markers>&
+ operator = (const conv_dash<VertexSource, Markers>&);
+};
+}
+#endif
diff --git a/third_party/agg23/agg_conv_stroke.h b/third_party/agg23/agg_conv_stroke.h
new file mode 100644
index 0000000000..5a36bd73bb
--- /dev/null
+++ b/third_party/agg23/agg_conv_stroke.h
@@ -0,0 +1,110 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// conv_stroke
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_CONV_STROKE_INCLUDED
+#define AGG_CONV_STROKE_INCLUDED
+#include "agg_basics.h"
+#include "agg_vcgen_stroke.h"
+#include "agg_conv_adaptor_vcgen.h"
+namespace agg
+{
+template<class VertexSource, class Markers = null_markers>
+struct conv_stroke :
+ public conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers> {
+ typedef Markers marker_type;
+ typedef conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers> base_type;
+ conv_stroke(VertexSource& vs) :
+ conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>(vs)
+ {
+ }
+ void line_cap(line_cap_e lc)
+ {
+ base_type::generator().line_cap(lc);
+ }
+ void line_join(line_join_e lj)
+ {
+ base_type::generator().line_join(lj);
+ }
+ void inner_join(inner_join_e ij)
+ {
+ base_type::generator().inner_join(ij);
+ }
+ line_cap_e line_cap() const
+ {
+ return base_type::generator().line_cap();
+ }
+ line_join_e line_join() const
+ {
+ return base_type::generator().line_join();
+ }
+ inner_join_e inner_join() const
+ {
+ return base_type::generator().inner_join();
+ }
+ void width(FX_FLOAT w)
+ {
+ base_type::generator().width(w);
+ }
+ void miter_limit(FX_FLOAT ml)
+ {
+ base_type::generator().miter_limit(ml);
+ }
+ void miter_limit_theta(FX_FLOAT t)
+ {
+ base_type::generator().miter_limit_theta(t);
+ }
+ void inner_miter_limit(FX_FLOAT ml)
+ {
+ base_type::generator().inner_miter_limit(ml);
+ }
+ void approximation_scale(FX_FLOAT as)
+ {
+ base_type::generator().approximation_scale(as);
+ }
+ FX_FLOAT width() const
+ {
+ return base_type::generator().width();
+ }
+ FX_FLOAT miter_limit() const
+ {
+ return base_type::generator().miter_limit();
+ }
+ FX_FLOAT inner_miter_limit() const
+ {
+ return base_type::generator().inner_miter_limit();
+ }
+ FX_FLOAT approximation_scale() const
+ {
+ return base_type::generator().approximation_scale();
+ }
+ void shorten(FX_FLOAT s)
+ {
+ base_type::generator().shorten(s);
+ }
+ FX_FLOAT shorten() const
+ {
+ return base_type::generator().shorten();
+ }
+private:
+ conv_stroke(const conv_stroke<VertexSource, Markers>&);
+ const conv_stroke<VertexSource, Markers>&
+ operator = (const conv_stroke<VertexSource, Markers>&);
+};
+}
+#endif
diff --git a/third_party/agg23/agg_curves.cpp b/third_party/agg23/agg_curves.cpp
new file mode 100644
index 0000000000..5a2d5631d6
--- /dev/null
+++ b/third_party/agg23/agg_curves.cpp
@@ -0,0 +1,109 @@
+
+//----------------------------------------------------------------------------
+// XYQ: 2006-01-22 Copied from AGG project.
+// TODO: This file uses intensive floating point operations, so it's NOT suitable
+// for platforms like Symbian OS. We need to change to FIX format.
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#include "../../core/include/fxcrt/fx_basic.h"
+#include "agg_curves.h"
+#include "agg_math.h"
+namespace agg
+{
+const FX_FLOAT curve_collinearity_epsilon = 1e-30f;
+enum curve_recursion_limit_e { curve_recursion_limit = 16 };
+void curve4_div::init(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+{
+ m_points.remove_all();
+ m_distance_tolerance_square = 1.0f / 4;
+ m_distance_tolerance_manhattan = 1.0f * 4;
+ bezier(x1, y1, x2, y2, x3, y3, x4, y4);
+ m_count = 0;
+}
+void curve4_div::recursive_bezier(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4,
+ unsigned level)
+{
+ if(level > curve_recursion_limit) {
+ return;
+ }
+ FX_FLOAT x12 = (x1 + x2) / 2;
+ FX_FLOAT y12 = (y1 + y2) / 2;
+ FX_FLOAT x23 = (x2 + x3) / 2;
+ FX_FLOAT y23 = (y2 + y3) / 2;
+ FX_FLOAT x34 = (x3 + x4) / 2;
+ FX_FLOAT y34 = (y3 + y4) / 2;
+ FX_FLOAT x123 = (x12 + x23) / 2;
+ FX_FLOAT y123 = (y12 + y23) / 2;
+ FX_FLOAT x234 = (x23 + x34) / 2;
+ FX_FLOAT y234 = (y23 + y34) / 2;
+ FX_FLOAT x1234 = (x123 + x234) / 2;
+ FX_FLOAT y1234 = (y123 + y234) / 2;
+ FX_FLOAT dx = x4 - x1;
+ FX_FLOAT dy = y4 - y1;
+ FX_FLOAT d2 = FXSYS_fabs(FXSYS_Mul(x2 - x4, dy) - FXSYS_Mul(y2 - y4, dx));
+ FX_FLOAT d3 = FXSYS_fabs(FXSYS_Mul(x3 - x4, dy) - FXSYS_Mul(y3 - y4, dx));
+ switch((int(d2 > curve_collinearity_epsilon) << 1) +
+ int(d3 > curve_collinearity_epsilon)) {
+ case 0:
+ if(FXSYS_fabs(x1 + x3 - x2 - x2) +
+ FXSYS_fabs(y1 + y3 - y2 - y2) +
+ FXSYS_fabs(x2 + x4 - x3 - x3) +
+ FXSYS_fabs(y2 + y4 - y3 - y3) <= m_distance_tolerance_manhattan) {
+ m_points.add(point_type(x1234, y1234, path_flags_jr));
+ return;
+ }
+ break;
+ case 1:
+ if(FXSYS_Mul(d3, d3) <= FXSYS_Mul(m_distance_tolerance_square,
+ FXSYS_Mul(dx, dx) + FXSYS_Mul(dy, dy))) {
+ m_points.add(point_type(x23, y23, path_flags_jr));
+ return;
+ }
+ break;
+ case 2:
+ if(FXSYS_Mul(d2, d2) <= FXSYS_Mul(m_distance_tolerance_square,
+ FXSYS_Mul(dx, dx) + FXSYS_Mul(dy, dy))) {
+ m_points.add(point_type(x23, y23, path_flags_jr));
+ return;
+ }
+ break;
+ case 3:
+ if(FXSYS_Mul(d2 + d3, d2 + d3) <= FXSYS_Mul(m_distance_tolerance_square,
+ FXSYS_Mul(dx, dx) + FXSYS_Mul(dy, dy))) {
+ m_points.add(point_type(x23, y23, path_flags_jr));
+ return;
+ }
+ break;
+ }
+ recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
+ recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
+}
+void curve4_div::bezier(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+{
+ m_points.add(point_type(x1, y1));
+ recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0);
+ m_points.add(point_type(x4, y4));
+}
+}
diff --git a/third_party/agg23/agg_curves.h b/third_party/agg23/agg_curves.h
new file mode 100644
index 0000000000..495f7a6a8f
--- /dev/null
+++ b/third_party/agg23/agg_curves.h
@@ -0,0 +1,188 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+// Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_CURVES_INCLUDED
+#define AGG_CURVES_INCLUDED
+#include "agg_array.h"
+namespace agg
+{
+struct curve4_points {
+ FX_FLOAT cp[8];
+ curve4_points() {}
+ curve4_points(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+ {
+ cp[0] = x1;
+ cp[1] = y1;
+ cp[2] = x2;
+ cp[3] = y2;
+ cp[4] = x3;
+ cp[5] = y3;
+ cp[6] = x4;
+ cp[7] = y4;
+ }
+ void init(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+ {
+ cp[0] = x1;
+ cp[1] = y1;
+ cp[2] = x2;
+ cp[3] = y2;
+ cp[4] = x3;
+ cp[5] = y3;
+ cp[6] = x4;
+ cp[7] = y4;
+ }
+ FX_FLOAT operator [] (unsigned i) const
+ {
+ return cp[i];
+ }
+ FX_FLOAT& operator [] (unsigned i)
+ {
+ return cp[i];
+ }
+};
+class curve4_div
+{
+public:
+ curve4_div() :
+ m_count(0)
+ {}
+ curve4_div(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4) :
+ m_count(0)
+ {
+ init(x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+ curve4_div(const curve4_points& cp) :
+ m_count(0)
+ {
+ init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ }
+ void reset()
+ {
+ m_points.remove_all();
+ m_count = 0;
+ }
+ void init(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4);
+ void init(const curve4_points& cp)
+ {
+ init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ }
+ void rewind(unsigned)
+ {
+ m_count = 0;
+ }
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y)
+ {
+ if(m_count >= m_points.size()) {
+ return path_cmd_stop;
+ }
+ const point_type& p = m_points[m_count++];
+ *x = p.x;
+ *y = p.y;
+ return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
+ }
+ unsigned vertex_flag(FX_FLOAT* x, FX_FLOAT* y, int& flag)
+ {
+ if(m_count >= m_points.size()) {
+ return path_cmd_stop;
+ }
+ const point_type& p = m_points[m_count++];
+ *x = p.x;
+ *y = p.y;
+ flag = p.flag;
+ return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
+ }
+ int count()
+ {
+ return m_points.size();
+ }
+private:
+ void bezier(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4);
+ void recursive_bezier(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4,
+ unsigned level);
+ FX_FLOAT m_distance_tolerance_square;
+ FX_FLOAT m_distance_tolerance_manhattan;
+ unsigned m_count;
+ pod_deque<point_type> m_points;
+};
+class curve4
+{
+public:
+ curve4() {}
+ curve4(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+ {
+ init(x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+ curve4(const curve4_points& cp)
+ {
+ init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ }
+ void reset()
+ {
+ m_curve_div.reset();
+ }
+ void init(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x3, FX_FLOAT y3,
+ FX_FLOAT x4, FX_FLOAT y4)
+ {
+ m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+ void init(const curve4_points& cp)
+ {
+ init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ }
+ void rewind(unsigned path_id)
+ {
+ m_curve_div.rewind(path_id);
+ }
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y)
+ {
+ return m_curve_div.vertex(x, y);
+ }
+ unsigned vertex_curve_flag(FX_FLOAT* x, FX_FLOAT* y, int& flag)
+ {
+ return m_curve_div.vertex_flag(x, y, flag);
+ }
+ int count()
+ {
+ return m_curve_div.count();
+ }
+private:
+ curve4_div m_curve_div;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_math.h b/third_party/agg23/agg_math.h
new file mode 100644
index 0000000000..31e0daf3bb
--- /dev/null
+++ b/third_party/agg23/agg_math.h
@@ -0,0 +1,63 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+// Bessel function (besj) was adapted for use in AGG library by Andy Wilk
+// Contact: castor.vulgaris@gmail.com
+//----------------------------------------------------------------------------
+#ifndef AGG_MATH_INCLUDED
+#define AGG_MATH_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+const FX_FLOAT intersection_epsilon = 1.0e-30f;
+AGG_INLINE FX_FLOAT calc_point_location(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x, FX_FLOAT y)
+{
+ return FXSYS_Mul(x - x2, y2 - y1) - FXSYS_Mul(y - y2, x2 - x1);
+}
+AGG_INLINE FX_FLOAT calc_distance(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2)
+{
+ FX_FLOAT dx = x2 - x1;
+ FX_FLOAT dy = y2 - y1;
+ return FXSYS_sqrt2(dx, dy);
+}
+AGG_INLINE FX_FLOAT calc_line_point_distance(FX_FLOAT x1, FX_FLOAT y1,
+ FX_FLOAT x2, FX_FLOAT y2,
+ FX_FLOAT x, FX_FLOAT y)
+{
+ FX_FLOAT dx = x2 - x1;
+ FX_FLOAT dy = y2 - y1;
+ FX_FLOAT d = FXSYS_sqrt2(dx, dy);
+ if(d < intersection_epsilon) {
+ return calc_distance(x1, y1, x, y);
+ }
+ return FXSYS_MulDiv(x - x2, dy, d) - FXSYS_MulDiv(y - y2, dx, d);
+}
+AGG_INLINE bool calc_intersection(FX_FLOAT ax, FX_FLOAT ay, FX_FLOAT bx, FX_FLOAT by,
+ FX_FLOAT cx, FX_FLOAT cy, FX_FLOAT dx, FX_FLOAT dy,
+ FX_FLOAT* x, FX_FLOAT* y)
+{
+ FX_FLOAT num = FXSYS_Mul(ay - cy, dx - cx) - FXSYS_Mul(ax - cx, dy - cy);
+ FX_FLOAT den = FXSYS_Mul(bx - ax, dy - cy) - FXSYS_Mul(by - ay, dx - cx);
+ if (FXSYS_fabs(den) < intersection_epsilon) {
+ return false;
+ }
+ *x = ax + FXSYS_MulDiv(bx - ax, num, den);
+ *y = ay + FXSYS_MulDiv(by - ay, num, den);
+ return true;
+}
+}
+#endif
diff --git a/third_party/agg23/agg_math_stroke.h b/third_party/agg23/agg_math_stroke.h
new file mode 100644
index 0000000000..620d675312
--- /dev/null
+++ b/third_party/agg23/agg_math_stroke.h
@@ -0,0 +1,272 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Stroke math
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_STROKE_MATH_INCLUDED
+#define AGG_STROKE_MATH_INCLUDED
+#include "agg_math.h"
+#include "agg_vertex_sequence.h"
+namespace agg
+{
+enum line_cap_e {
+ butt_cap,
+ square_cap,
+ round_cap
+};
+enum line_join_e {
+ miter_join = 0,
+ miter_join_revert = 1,
+ miter_join_round = 4,
+ round_join = 2,
+ bevel_join = 3
+};
+enum inner_join_e {
+ inner_bevel,
+ inner_miter,
+ inner_jag,
+ inner_round
+};
+const FX_FLOAT stroke_theta = 1.0f / 1000.0f;
+template<class VertexConsumer>
+void stroke_calc_arc(VertexConsumer& out_vertices,
+ FX_FLOAT x, FX_FLOAT y,
+ FX_FLOAT dx1, FX_FLOAT dy1,
+ FX_FLOAT dx2, FX_FLOAT dy2,
+ FX_FLOAT width,
+ FX_FLOAT approximation_scale)
+{
+ typedef typename VertexConsumer::value_type coord_type;
+ FX_FLOAT a1 = FXSYS_atan2(dy1, dx1);
+ FX_FLOAT a2 = FXSYS_atan2(dy2, dx2);
+ FX_FLOAT da = a1 - a2;
+ bool ccw = da > 0 && da < FX_PI;
+ if(width < 0) {
+ width = -width;
+ }
+ da = FXSYS_acos(FXSYS_Div(width, width + FXSYS_Div(1.0f / 8, approximation_scale))) * 2;
+ out_vertices.add(coord_type(x + dx1, y + dy1));
+ if(!ccw) {
+ if(a1 > a2) {
+ a2 += 2 * FX_PI;
+ }
+ a2 -= da / 4;
+ a1 += da;
+ while(a1 < a2) {
+ out_vertices.add(coord_type(x + FXSYS_Mul(width, FXSYS_cos(a1)),
+ y + FXSYS_Mul(width, FXSYS_sin(a1))));
+ a1 += da;
+ }
+ } else {
+ if(a1 < a2) {
+ a2 -= 2 * FX_PI;
+ }
+ a2 += da / 4;
+ a1 -= da;
+ while(a1 > a2) {
+ out_vertices.add(coord_type(x + FXSYS_Mul(width, FXSYS_cos(a1)),
+ y + FXSYS_Mul(width, FXSYS_sin(a1))));
+ a1 -= da;
+ }
+ }
+ out_vertices.add(coord_type(x + dx2, y + dy2));
+}
+template<class VertexConsumer>
+void stroke_calc_miter(VertexConsumer& out_vertices,
+ const vertex_dist& v0,
+ const vertex_dist& v1,
+ const vertex_dist& v2,
+ FX_FLOAT dx1, FX_FLOAT dy1,
+ FX_FLOAT dx2, FX_FLOAT dy2,
+ FX_FLOAT width,
+ line_join_e line_join,
+ FX_FLOAT miter_limit,
+ FX_FLOAT approximation_scale)
+{
+ typedef typename VertexConsumer::value_type coord_type;
+ FX_FLOAT xi = v1.x;
+ FX_FLOAT yi = v1.y;
+ bool miter_limit_exceeded = true;
+ if(calc_intersection(v0.x + dx1, v0.y - dy1,
+ v1.x + dx1, v1.y - dy1,
+ v1.x + dx2, v1.y - dy2,
+ v2.x + dx2, v2.y - dy2,
+ &xi, &yi)) {
+ FX_FLOAT d1 = calc_distance(v1.x, v1.y, xi, yi);
+ FX_FLOAT lim = FXSYS_Mul(width, miter_limit);
+ if(d1 <= lim) {
+ out_vertices.add(coord_type(xi, yi));
+ miter_limit_exceeded = false;
+ }
+ } else {
+ FX_FLOAT x2 = v1.x + dx1;
+ FX_FLOAT y2 = v1.y - dy1;
+ if((FXSYS_Mul(x2 - v0.x, dy1) - FXSYS_Mul(v0.y - y2, dx1) < 0) !=
+ (FXSYS_Mul(x2 - v2.x, dy1) - FXSYS_Mul(v2.y - y2, dx1) < 0)) {
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ miter_limit_exceeded = false;
+ }
+ }
+ if(miter_limit_exceeded) {
+ switch(line_join) {
+ case miter_join_revert:
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
+ break;
+ case miter_join_round:
+ stroke_calc_arc(out_vertices,
+ v1.x, v1.y, dx1, -dy1, dx2, -dy2,
+ width, approximation_scale);
+ break;
+ default:
+ out_vertices.add(coord_type(v1.x + dx1 + FXSYS_Mul(dy1, miter_limit),
+ v1.y - dy1 + FXSYS_Mul(dx1, miter_limit)));
+ out_vertices.add(coord_type(v1.x + dx2 - FXSYS_Mul(dy2, miter_limit),
+ v1.y - dy2 - FXSYS_Mul(dx2, miter_limit)));
+ break;
+ }
+ }
+}
+template<class VertexConsumer>
+void stroke_calc_cap(VertexConsumer& out_vertices,
+ const vertex_dist& v0,
+ const vertex_dist& v1,
+ FX_FLOAT len,
+ line_cap_e line_cap,
+ FX_FLOAT width,
+ FX_FLOAT approximation_scale)
+{
+ typedef typename VertexConsumer::value_type coord_type;
+ out_vertices.remove_all();
+ FX_FLOAT dx1 = FXSYS_Div(v1.y - v0.y, len);
+ FX_FLOAT dy1 = FXSYS_Div(v1.x - v0.x, len);
+ FX_FLOAT dx2 = 0;
+ FX_FLOAT dy2 = 0;
+ dx1 = FXSYS_Mul(dx1, width);
+ dy1 = FXSYS_Mul(dy1, width);
+ if(line_cap != round_cap) {
+ if(line_cap == square_cap) {
+ dx2 = dy1;
+ dy2 = dx1;
+ }
+ out_vertices.add(coord_type(v0.x - dx1 - dx2, v0.y + dy1 - dy2));
+ out_vertices.add(coord_type(v0.x + dx1 - dx2, v0.y - dy1 - dy2));
+ } else {
+ FX_FLOAT a1 = FXSYS_atan2(dy1, -dx1);
+ FX_FLOAT a2 = a1 + FX_PI;
+ FX_FLOAT da = FXSYS_acos(FXSYS_Div(width, width +
+ FXSYS_Div(1.0f / 8, approximation_scale))) * 2;
+ out_vertices.add(coord_type(v0.x - dx1, v0.y + dy1));
+ a1 += da;
+ a2 -= da / 4;
+ while(a1 < a2) {
+ out_vertices.add(coord_type(v0.x + FXSYS_Mul(width, FXSYS_cos(a1)),
+ v0.y + FXSYS_Mul(width, FXSYS_sin(a1))));
+ a1 += da;
+ }
+ out_vertices.add(coord_type(v0.x + dx1, v0.y - dy1));
+ }
+}
+template<class VertexConsumer>
+void stroke_calc_join(VertexConsumer& out_vertices,
+ const vertex_dist& v0,
+ const vertex_dist& v1,
+ const vertex_dist& v2,
+ FX_FLOAT len1,
+ FX_FLOAT len2,
+ FX_FLOAT width,
+ line_join_e line_join,
+ inner_join_e inner_join,
+ FX_FLOAT miter_limit,
+ FX_FLOAT inner_miter_limit,
+ FX_FLOAT approximation_scale)
+{
+ typedef typename VertexConsumer::value_type coord_type;
+ FX_FLOAT dx1, dy1, dx2, dy2;
+ dx1 = FXSYS_MulDiv(width, v1.y - v0.y, len1);
+ dy1 = FXSYS_MulDiv(width, v1.x - v0.x, len1);
+ dx2 = FXSYS_MulDiv(width, v2.y - v1.y, len2);
+ dy2 = FXSYS_MulDiv(width, v2.x - v1.x, len2);
+ out_vertices.remove_all();
+ if(calc_point_location(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y) > 0) {
+ switch(inner_join) {
+ default:
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
+ break;
+ case inner_miter:
+ stroke_calc_miter(out_vertices,
+ v0, v1, v2, dx1, dy1, dx2, dy2,
+ width,
+ miter_join_revert,
+ inner_miter_limit,
+ 1.0f);
+ break;
+ case inner_jag:
+ case inner_round: {
+ FX_FLOAT d = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2);
+ if(d < len1 * len1 && d < len2 * len2) {
+ stroke_calc_miter(out_vertices,
+ v0, v1, v2, dx1, dy1, dx2, dy2,
+ width,
+ miter_join_revert,
+ inner_miter_limit,
+ 1.0f);
+ } else {
+ if(inner_join == inner_jag) {
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ out_vertices.add(coord_type(v1.x, v1.y ));
+ out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
+ } else {
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ out_vertices.add(coord_type(v1.x, v1.y ));
+ stroke_calc_arc(out_vertices,
+ v1.x, v1.y, dx2, -dy2, dx1, -dy1,
+ width, approximation_scale);
+ out_vertices.add(coord_type(v1.x, v1.y ));
+ out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
+ }
+ }
+ }
+ break;
+ }
+ } else {
+ switch(line_join) {
+ case miter_join:
+ case miter_join_revert:
+ case miter_join_round:
+ stroke_calc_miter(out_vertices,
+ v0, v1, v2, dx1, dy1, dx2, dy2,
+ width,
+ line_join,
+ miter_limit,
+ approximation_scale);
+ break;
+ case round_join:
+ stroke_calc_arc(out_vertices,
+ v1.x, v1.y, dx1, -dy1, dx2, -dy2,
+ width, approximation_scale);
+ break;
+ default:
+ out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
+ out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
+ break;
+ }
+ }
+}
+}
+#endif
diff --git a/third_party/agg23/agg_path_storage.cpp b/third_party/agg23/agg_path_storage.cpp
new file mode 100644
index 0000000000..f5c9843e58
--- /dev/null
+++ b/third_party/agg23/agg_path_storage.cpp
@@ -0,0 +1,98 @@
+
+//----------------------------------------------------------------------------
+// XYQ: 2006-01-22 Copied from AGG project.
+// TODO: This file uses intensive floating point operations, so it's NOT suitable
+// for platforms like Symbian OS. We need to change to FIX format.
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Class path_storage
+//
+//----------------------------------------------------------------------------
+#include "../../core/include/fxcrt/fx_basic.h"
+#include "agg_path_storage.h"
+#include "agg_math.h"
+namespace agg
+{
+path_storage::~path_storage()
+{
+ if(m_total_blocks) {
+ FX_FLOAT** coord_blk = m_coord_blocks + m_total_blocks - 1;
+ while(m_total_blocks--) {
+ FX_Free(*coord_blk);
+ --coord_blk;
+ }
+ FX_Free(m_coord_blocks);
+ }
+}
+path_storage::path_storage() :
+ m_total_vertices(0),
+ m_total_blocks(0),
+ m_max_blocks(0),
+ m_coord_blocks(0),
+ m_cmd_blocks(0),
+ m_iterator(0)
+{
+}
+void path_storage::allocate_block(unsigned nb)
+{
+ if(nb >= m_max_blocks) {
+ FX_FLOAT** new_coords =
+ FX_Alloc2D(FX_FLOAT*, m_max_blocks + block_pool, 2);
+ unsigned char** new_cmds =
+ (unsigned char**)(new_coords + m_max_blocks + block_pool);
+ if(m_coord_blocks) {
+ FXSYS_memcpy(new_coords,
+ m_coord_blocks,
+ m_max_blocks * sizeof(FX_FLOAT*));
+ FXSYS_memcpy(new_cmds,
+ m_cmd_blocks,
+ m_max_blocks * sizeof(unsigned char*));
+ FX_Free(m_coord_blocks);
+ }
+ m_coord_blocks = new_coords;
+ m_cmd_blocks = new_cmds;
+ m_max_blocks += block_pool;
+ }
+ m_coord_blocks[nb] =
+ FX_Alloc( FX_FLOAT, block_size * 2 +
+ block_size /
+ (sizeof(FX_FLOAT) / sizeof(unsigned char)));
+ m_cmd_blocks[nb] =
+ (unsigned char*)(m_coord_blocks[nb] + block_size * 2);
+ m_total_blocks++;
+}
+void path_storage::rewind(unsigned path_id)
+{
+ m_iterator = path_id;
+}
+void path_storage::curve4(FX_FLOAT x_ctrl1, FX_FLOAT y_ctrl1,
+ FX_FLOAT x_ctrl2, FX_FLOAT y_ctrl2,
+ FX_FLOAT x_to, FX_FLOAT y_to)
+{
+ add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
+ add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
+ add_vertex(x_to, y_to, path_cmd_curve4);
+}
+void path_storage::end_poly()
+{
+ if(m_total_vertices) {
+ if(is_vertex(command(m_total_vertices - 1))) {
+ add_vertex(0, 0, path_cmd_end_poly | path_flags_close);
+ }
+ }
+}
+}
diff --git a/third_party/agg23/agg_path_storage.h b/third_party/agg23/agg_path_storage.h
new file mode 100644
index 0000000000..dc13851d09
--- /dev/null
+++ b/third_party/agg23/agg_path_storage.h
@@ -0,0 +1,172 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_PATH_STORAGE_INCLUDED
+#define AGG_PATH_STORAGE_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+class path_storage
+{
+ enum block_scale_e {
+ block_shift = 8,
+ block_size = 1 << block_shift,
+ block_mask = block_size - 1,
+ block_pool = 256
+ };
+public:
+ class vertex_source
+ {
+ public:
+ vertex_source() {}
+ vertex_source(const path_storage& p) : m_path(&p), m_vertex_idx(0) {}
+ void rewind(unsigned path_id)
+ {
+ m_vertex_idx = path_id;
+ }
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y)
+ {
+ return (m_vertex_idx < m_path->total_vertices()) ?
+ m_path->vertex(m_vertex_idx++, x, y) :
+ path_cmd_stop;
+ }
+ private:
+ const path_storage* m_path;
+ unsigned m_vertex_idx;
+ };
+ ~path_storage();
+ path_storage();
+ unsigned last_vertex(FX_FLOAT* x, FX_FLOAT* y) const;
+ unsigned prev_vertex(FX_FLOAT* x, FX_FLOAT* y) const;
+ void move_to(FX_FLOAT x, FX_FLOAT y);
+ void line_to(FX_FLOAT x, FX_FLOAT y);
+ void curve4(FX_FLOAT x_ctrl1, FX_FLOAT y_ctrl1,
+ FX_FLOAT x_ctrl2, FX_FLOAT y_ctrl2,
+ FX_FLOAT x_to, FX_FLOAT y_to);
+ template<class VertexSource>
+ void add_path(VertexSource& vs,
+ unsigned path_id = 0,
+ bool solid_path = true)
+ {
+ FX_FLOAT x, y;
+ unsigned cmd;
+ vs.rewind(path_id);
+ while(!is_stop(cmd = vs.vertex(&x, &y))) {
+ if(is_move_to(cmd) && solid_path && m_total_vertices) {
+ cmd = path_cmd_line_to;
+ }
+ add_vertex(x, y, cmd);
+ }
+ }
+ template<class VertexSource>
+ void add_path_curve(VertexSource& vs,
+ unsigned path_id = 0,
+ bool solid_path = true)
+ {
+ FX_FLOAT x, y;
+ unsigned cmd;
+ int flag;
+ vs.rewind(path_id);
+ while(!is_stop(cmd = vs.vertex_curve_flag(&x, &y, flag))) {
+ if(is_move_to(cmd) && solid_path && m_total_vertices) {
+ cmd = path_cmd_line_to | flag;
+ }
+ add_vertex(x, y, cmd | flag);
+ }
+ }
+ unsigned total_vertices() const
+ {
+ return m_total_vertices;
+ }
+ unsigned vertex(unsigned idx, FX_FLOAT* x, FX_FLOAT* y) const
+ {
+ unsigned nb = idx >> block_shift;
+ const FX_FLOAT* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
+ *x = *pv++;
+ *y = *pv;
+ return m_cmd_blocks[nb][idx & block_mask];
+ }
+ unsigned command(unsigned idx) const
+ {
+ return m_cmd_blocks[idx >> block_shift][idx & block_mask];
+ }
+ unsigned getflag(unsigned idx) const
+ {
+ return m_cmd_blocks[idx >> block_shift][idx & block_mask] & path_flags_jr;
+ }
+ void rewind(unsigned path_id);
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y);
+ void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd);
+ void end_poly();
+private:
+ void allocate_block(unsigned nb);
+ unsigned char* storage_ptrs(FX_FLOAT** xy_ptr);
+private:
+ unsigned m_total_vertices;
+ unsigned m_total_blocks;
+ unsigned m_max_blocks;
+ FX_FLOAT** m_coord_blocks;
+ unsigned char** m_cmd_blocks;
+ unsigned m_iterator;
+};
+inline unsigned path_storage::vertex(FX_FLOAT* x, FX_FLOAT* y)
+{
+ if(m_iterator >= m_total_vertices) {
+ return path_cmd_stop;
+ }
+ return vertex(m_iterator++, x, y);
+}
+inline unsigned path_storage::prev_vertex(FX_FLOAT* x, FX_FLOAT* y) const
+{
+ if(m_total_vertices > 1) {
+ return vertex(m_total_vertices - 2, x, y);
+ }
+ return path_cmd_stop;
+}
+inline unsigned path_storage::last_vertex(FX_FLOAT* x, FX_FLOAT* y) const
+{
+ if(m_total_vertices) {
+ return vertex(m_total_vertices - 1, x, y);
+ }
+ return path_cmd_stop;
+}
+inline unsigned char* path_storage::storage_ptrs(FX_FLOAT** 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);
+}
+inline void path_storage::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
+{
+ FX_FLOAT* 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(FX_FLOAT x, FX_FLOAT y)
+{
+ add_vertex(x, y, path_cmd_move_to);
+}
+inline void path_storage::line_to(FX_FLOAT x, FX_FLOAT y)
+{
+ add_vertex(x, y, path_cmd_line_to);
+}
+}
+#endif
diff --git a/third_party/agg23/agg_pixfmt_gray.h b/third_party/agg23/agg_pixfmt_gray.h
new file mode 100644
index 0000000000..5a80935479
--- /dev/null
+++ b/third_party/agg23/agg_pixfmt_gray.h
@@ -0,0 +1,177 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Adaptation for high precision colors has been sponsored by
+// Liberty Technology Systems, Inc., visit http://lib-sys.com
+//
+// Liberty Technology Systems, Inc. is the provider of
+// PostScript and PDF technology for software developers.
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_PIXFMT_GRAY_INCLUDED
+#define AGG_PIXFMT_GRAY_INCLUDED
+#include "agg_basics.h"
+#include "agg_color_gray.h"
+#include "agg_rendering_buffer.h"
+namespace agg
+{
+template<class ColorT> struct blender_gray {
+ typedef ColorT color_type;
+ typedef typename color_type::value_type value_type;
+ typedef typename color_type::calc_type calc_type;
+ enum base_scale_e { base_shift = color_type::base_shift };
+ static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
+ unsigned alpha, unsigned cover = 0)
+ {
+ *p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift);
+ }
+};
+template<class Blender, unsigned Step = 1, unsigned Offset = 0>
+class pixel_formats_gray
+{
+public:
+ typedef rendering_buffer::row_data row_data;
+ typedef rendering_buffer::span_data span_data;
+ typedef typename Blender::color_type color_type;
+ typedef typename color_type::value_type value_type;
+ typedef typename color_type::calc_type calc_type;
+ enum base_scale_e {
+ base_shift = color_type::base_shift,
+ base_size = color_type::base_size,
+ base_mask = color_type::base_mask
+ };
+private:
+ static AGG_INLINE void copy_or_blend_pix(value_type* p,
+ const color_type& c,
+ unsigned cover)
+ {
+ if (c.a) {
+ calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
+ if(alpha == base_mask) {
+ *p = c.v;
+ } else {
+ Blender::blend_pix(p, c.v, alpha, cover);
+ }
+ }
+ }
+ static AGG_INLINE void copy_or_blend_pix(value_type* p,
+ const color_type& c)
+ {
+ if (c.a) {
+ if(c.a == base_mask) {
+ *p = c.v;
+ } else {
+ Blender::blend_pix(p, c.v, c.a);
+ }
+ }
+ }
+public:
+ pixel_formats_gray(rendering_buffer& rb) :
+ m_rbuf(&rb)
+ {}
+ AGG_INLINE unsigned width() const
+ {
+ return m_rbuf->width();
+ }
+ AGG_INLINE unsigned height() const
+ {
+ return m_rbuf->height();
+ }
+ AGG_INLINE color_type pixel(int x, int y) const
+ {
+ value_type* p = (value_type*)m_rbuf->row(y) + x * Step + Offset;
+ return color_type(*p);
+ }
+ row_data row(int x, int y) const
+ {
+ return row_data(x,
+ width() - 1,
+ m_rbuf->row(y) +
+ x * Step * sizeof(value_type) +
+ Offset * sizeof(value_type));
+ }
+ span_data span(int x, int y, unsigned len)
+ {
+ return span_data(x, len,
+ m_rbuf->row(y) +
+ x * Step * sizeof(value_type) +
+ Offset * sizeof(value_type));
+ }
+ AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
+ {
+ *((value_type*)m_rbuf->row(y) + x * Step + Offset) = c.v;
+ }
+ AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
+ {
+ copy_or_blend_pix((value_type*)m_rbuf->row(y) + x * Step + Offset, c, cover);
+ }
+ AGG_INLINE void copy_hline(int x, int y,
+ unsigned len,
+ const color_type& c)
+ {
+ value_type* p = (value_type*)m_rbuf->row(y) + x * Step + Offset;
+ do {
+ *p = c.v;
+ p += Step;
+ } while(--len);
+ }
+ void blend_hline(int x, int y,
+ unsigned len,
+ const color_type& c,
+ int8u cover)
+ {
+ if (c.a) {
+ value_type* p = (value_type*)m_rbuf->row(y) + x * Step + Offset;
+ calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
+ if(alpha == base_mask) {
+ do {
+ *p = c.v;
+ p += Step;
+ } while(--len);
+ } else {
+ do {
+ Blender::blend_pix(p, c.v, alpha, cover);
+ p += Step;
+ } while(--len);
+ }
+ }
+ }
+ void blend_solid_hspan(int x, int y,
+ unsigned len,
+ const color_type& c,
+ const int8u* covers)
+ {
+ if (c.a) {
+ value_type* p = (value_type*)m_rbuf->row(y) + x * Step + Offset;
+ do {
+ calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
+ if(alpha == base_mask) {
+ *p = c.v;
+ } else {
+ Blender::blend_pix(p, c.v, alpha, *covers);
+ }
+ p += Step;
+ ++covers;
+ } while(--len);
+ }
+ }
+private:
+ rendering_buffer* m_rbuf;
+};
+typedef blender_gray<gray8> blender_gray8;
+typedef pixel_formats_gray<blender_gray8, 1, 0> pixfmt_gray8;
+}
+#endif
diff --git a/third_party/agg23/agg_rasterizer_scanline_aa.cpp b/third_party/agg23/agg_rasterizer_scanline_aa.cpp
new file mode 100644
index 0000000000..8216e60221
--- /dev/null
+++ b/third_party/agg23/agg_rasterizer_scanline_aa.cpp
@@ -0,0 +1,489 @@
+
+//----------------------------------------------------------------------------
+// XYQ: 2006-01-22 Copied from AGG project.
+// This file uses only integer data, so it's suitable for all platforms.
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+//
+// The author gratefully acknowleges the support of David Turner,
+// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
+// libray - in producing this work. See http://www.freetype.org for details.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Adaptation for 32-bit screen coordinates has been sponsored by
+// Liberty Technology Systems, Inc., visit http://lib-sys.com
+//
+// Liberty Technology Systems, Inc. is the provider of
+// PostScript and PDF technology for software developers.
+//
+//----------------------------------------------------------------------------
+//
+// Class outline_aa - implementation.
+//
+// Initially the rendering algorithm was designed by David Turner and the
+// other authors of the FreeType library - see the above notice. I nearly
+// created a similar renderer, but still I was far from David's work.
+// I completely redesigned the original code and adapted it for Anti-Grain
+// ideas. Two functions - render_line and render_hline are the core of
+// the algorithm - they calculate the exact coverage of each pixel cell
+// of the polygon. I left these functions almost as is, because there's
+// no way to improve the perfection - hats off to David and his group!
+//
+// All other code is very different from the original.
+//
+//----------------------------------------------------------------------------
+#include "../../core/include/fxcrt/fx_ext.h"
+#include <limits.h>
+#include "agg_rasterizer_scanline_aa.h"
+namespace agg
+{
+AGG_INLINE void cell_aa::set_cover(int c, int a)
+{
+ cover = c;
+ area = a;
+}
+AGG_INLINE void cell_aa::add_cover(int c, int a)
+{
+ cover += c;
+ area += a;
+}
+AGG_INLINE void cell_aa::set_coord(int cx, int cy)
+{
+ x = cx;
+ y = cy;
+}
+AGG_INLINE void cell_aa::set(int cx, int cy, int c, int a)
+{
+ x = cx;
+ y = cy;
+ cover = c;
+ area = a;
+}
+outline_aa::~outline_aa()
+{
+ if(m_num_blocks) {
+ cell_aa** ptr = m_cells + m_num_blocks - 1;
+ while(m_num_blocks--) {
+ FX_Free(*ptr);
+ ptr--;
+ }
+ FX_Free(m_cells);
+ }
+}
+outline_aa::outline_aa() :
+ m_num_blocks(0),
+ m_max_blocks(0),
+ m_cur_block(0),
+ m_num_cells(0),
+ m_cells(0),
+ m_cur_cell_ptr(0),
+ m_cur_x(0),
+ m_cur_y(0),
+ m_min_x(0x7FFFFFFF),
+ m_min_y(0x7FFFFFFF),
+ m_max_x(-0x7FFFFFFF),
+ m_max_y(-0x7FFFFFFF),
+ m_sorted(false)
+{
+ m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
+}
+void outline_aa::reset()
+{
+ m_num_cells = 0;
+ m_cur_block = 0;
+ m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
+ m_sorted = false;
+ m_min_x = 0x7FFFFFFF;
+ m_min_y = 0x7FFFFFFF;
+ m_max_x = -0x7FFFFFFF;
+ m_max_y = -0x7FFFFFFF;
+}
+void outline_aa::allocate_block()
+{
+ if(m_cur_block >= m_num_blocks) {
+ if(m_num_blocks >= m_max_blocks) {
+ cell_aa** new_cells = FX_Alloc( cell_aa*, m_max_blocks + cell_block_pool);
+ if(m_cells) {
+ FXSYS_memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_aa*));
+ FX_Free(m_cells);
+ }
+ m_cells = new_cells;
+ m_max_blocks += cell_block_pool;
+ }
+ m_cells[m_num_blocks++] = FX_Alloc(cell_aa, cell_block_size);
+ }
+ m_cur_cell_ptr = m_cells[m_cur_block++];
+}
+AGG_INLINE void outline_aa::add_cur_cell()
+{
+ if(m_cur_cell.area | m_cur_cell.cover) {
+ if((m_num_cells & cell_block_mask) == 0) {
+ if(m_num_blocks >= cell_block_limit) {
+ return;
+ }
+ allocate_block();
+ }
+ *m_cur_cell_ptr++ = m_cur_cell;
+ ++m_num_cells;
+ }
+}
+AGG_INLINE void outline_aa::set_cur_cell(int x, int y)
+{
+ if(m_cur_cell.x != x || m_cur_cell.y != y) {
+ add_cur_cell();
+ m_cur_cell.set(x, y, 0, 0);
+ if(x < m_min_x) {
+ m_min_x = x;
+ }
+ if(x > m_max_x) {
+ m_max_x = x;
+ }
+ if(y < m_min_y) {
+ m_min_y = y;
+ }
+ if(y > m_max_y) {
+ m_max_y = y;
+ }
+ }
+}
+AGG_INLINE void outline_aa::render_hline(int ey, int x1, int y1, int x2, int y2)
+{
+ int ex1 = x1 >> poly_base_shift;
+ int ex2 = x2 >> poly_base_shift;
+ int fx1 = x1 & poly_base_mask;
+ int fx2 = x2 & poly_base_mask;
+ int delta, p, first, dx;
+ int incr, lift, mod, rem;
+ if(y1 == y2) {
+ set_cur_cell(ex2, ey);
+ return;
+ }
+ if(ex1 == ex2) {
+ delta = y2 - y1;
+ m_cur_cell.add_cover(delta, (fx1 + fx2) * delta);
+ return;
+ }
+ p = (poly_base_size - fx1) * (y2 - y1);
+ first = poly_base_size;
+ incr = 1;
+ dx = x2 - x1;
+ if(dx < 0) {
+ p = fx1 * (y2 - y1);
+ first = 0;
+ incr = -1;
+ dx = -dx;
+ }
+ delta = p / dx;
+ mod = p % dx;
+ if(mod < 0) {
+ delta--;
+ mod += dx;
+ }
+ m_cur_cell.add_cover(delta, (fx1 + first) * delta);
+ ex1 += incr;
+ set_cur_cell(ex1, ey);
+ y1 += delta;
+ if(ex1 != ex2) {
+ p = poly_base_size * (y2 - y1 + delta);
+ lift = p / dx;
+ rem = p % dx;
+ if (rem < 0) {
+ lift--;
+ rem += dx;
+ }
+ mod -= dx;
+ while (ex1 != ex2) {
+ delta = lift;
+ mod += rem;
+ if(mod >= 0) {
+ mod -= dx;
+ delta++;
+ }
+ m_cur_cell.add_cover(delta, (poly_base_size) * delta);
+ y1 += delta;
+ ex1 += incr;
+ set_cur_cell(ex1, ey);
+ }
+ }
+ delta = y2 - y1;
+ m_cur_cell.add_cover(delta, (fx2 + poly_base_size - first) * delta);
+}
+void outline_aa::render_line(int x1, int y1, int x2, int y2)
+{
+ enum dx_limit_e { dx_limit = 16384 << poly_base_shift };
+ int dx = x2 - x1;
+ if(dx >= dx_limit || dx <= -dx_limit) {
+ int cx = (x1 + x2) >> 1;
+ int cy = (y1 + y2) >> 1;
+ render_line(x1, y1, cx, cy);
+ render_line(cx, cy, x2, y2);
+ }
+ int dy = y2 - y1;
+ int ey1 = y1 >> poly_base_shift;
+ int ey2 = y2 >> poly_base_shift;
+ int fy1 = y1 & poly_base_mask;
+ int fy2 = y2 & poly_base_mask;
+ int x_from, x_to;
+ int p, rem, mod, lift, delta, first, incr;
+ if(ey1 == ey2) {
+ render_hline(ey1, x1, fy1, x2, fy2);
+ return;
+ }
+ incr = 1;
+ if(dx == 0) {
+ int ex = x1 >> poly_base_shift;
+ int two_fx = (x1 - (ex << poly_base_shift)) << 1;
+ int area;
+ first = poly_base_size;
+ if(dy < 0) {
+ first = 0;
+ incr = -1;
+ }
+ x_from = x1;
+ delta = first - fy1;
+ m_cur_cell.add_cover(delta, two_fx * delta);
+ ey1 += incr;
+ set_cur_cell(ex, ey1);
+ delta = first + first - poly_base_size;
+ area = two_fx * delta;
+ while(ey1 != ey2) {
+ m_cur_cell.set_cover(delta, area);
+ ey1 += incr;
+ set_cur_cell(ex, ey1);
+ }
+ delta = fy2 - poly_base_size + first;
+ m_cur_cell.add_cover(delta, two_fx * delta);
+ return;
+ }
+ p = (poly_base_size - fy1) * dx;
+ first = poly_base_size;
+ if(dy < 0) {
+ p = fy1 * dx;
+ first = 0;
+ incr = -1;
+ dy = -dy;
+ }
+ delta = p / dy;
+ mod = p % dy;
+ if(mod < 0) {
+ delta--;
+ mod += dy;
+ }
+ x_from = x1 + delta;
+ render_hline(ey1, x1, fy1, x_from, first);
+ ey1 += incr;
+ set_cur_cell(x_from >> poly_base_shift, ey1);
+ if(ey1 != ey2) {
+ p = poly_base_size * dx;
+ lift = p / dy;
+ rem = p % dy;
+ if(rem < 0) {
+ lift--;
+ rem += dy;
+ }
+ mod -= dy;
+ while(ey1 != ey2) {
+ delta = lift;
+ mod += rem;
+ if (mod >= 0) {
+ mod -= dy;
+ delta++;
+ }
+ x_to = x_from + delta;
+ render_hline(ey1, x_from, poly_base_size - first, x_to, first);
+ x_from = x_to;
+ ey1 += incr;
+ set_cur_cell(x_from >> poly_base_shift, ey1);
+ }
+ }
+ render_hline(ey1, x_from, poly_base_size - first, x2, fy2);
+}
+void outline_aa::move_to(int x, int y)
+{
+ if(m_sorted) {
+ reset();
+ }
+ set_cur_cell(x >> poly_base_shift, y >> poly_base_shift);
+ m_cur_x = x;
+ m_cur_y = y;
+}
+void outline_aa::line_to(int x, int y)
+{
+ render_line(m_cur_x, m_cur_y, x, y);
+ m_cur_x = x;
+ m_cur_y = y;
+ m_sorted = false;
+}
+template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
+{
+ T temp = *a;
+ *a = *b;
+ *b = temp;
+}
+enum {
+ qsort_threshold = 9
+};
+static void qsort_cells(cell_aa** start, unsigned num)
+{
+ cell_aa** stack[80];
+ cell_aa*** top;
+ cell_aa** limit;
+ cell_aa** base;
+ limit = start + num;
+ base = start;
+ top = stack;
+ for (;;) {
+ int len = int(limit - base);
+ cell_aa** i;
+ cell_aa** j;
+ cell_aa** pivot;
+ if(len > qsort_threshold) {
+ pivot = base + len / 2;
+ swap_cells(base, pivot);
+ i = base + 1;
+ j = limit - 1;
+ if((*j)->x < (*i)->x) {
+ swap_cells(i, j);
+ }
+ if((*base)->x < (*i)->x) {
+ swap_cells(base, i);
+ }
+ if((*j)->x < (*base)->x) {
+ swap_cells(base, j);
+ }
+ for(;;) {
+ int x = (*base)->x;
+ do {
+ i++;
+ } while( (*i)->x < x );
+ do {
+ j--;
+ } while( x < (*j)->x );
+ if(i > j) {
+ break;
+ }
+ swap_cells(i, j);
+ }
+ swap_cells(base, j);
+ if(j - base > limit - i) {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ } else {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ } else {
+ j = base;
+ i = j + 1;
+ for(; i < limit; j = i, i++) {
+ for(; j[1]->x < (*j)->x; j--) {
+ swap_cells(j + 1, j);
+ if (j == base) {
+ break;
+ }
+ }
+ }
+ if(top > stack) {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ } else {
+ break;
+ }
+ }
+ }
+}
+void outline_aa::sort_cells()
+{
+ if(m_sorted) {
+ return;
+ }
+ add_cur_cell();
+ if(m_num_cells == 0) {
+ return;
+ }
+ m_sorted_cells.allocate(m_num_cells, 16);
+ if (m_max_y > 0 && m_min_y < 0 && -m_min_y > INT_MAX - m_max_y) {
+ return;
+ }
+ unsigned size = m_max_y - m_min_y;
+ if (size + 1 < size) {
+ return;
+ }
+ size++;
+ m_sorted_y.allocate(size, 16);
+ m_sorted_y.zero();
+ cell_aa** block_ptr = m_cells;
+ cell_aa* cell_ptr = NULL;
+ unsigned nb = m_num_cells >> cell_block_shift;
+ unsigned i;
+ while(nb--) {
+ cell_ptr = *block_ptr++;
+ i = cell_block_size;
+ while(i--) {
+ m_sorted_y[cell_ptr->y - m_min_y].start++;
+ ++cell_ptr;
+ }
+ }
+ i = m_num_cells & cell_block_mask;
+ if (i) {
+ cell_ptr = *block_ptr++;
+ }
+ while(i--) {
+ m_sorted_y[cell_ptr->y - m_min_y].start++;
+ ++cell_ptr;
+ }
+ unsigned start = 0;
+ for(i = 0; i < m_sorted_y.size(); i++) {
+ unsigned v = m_sorted_y[i].start;
+ m_sorted_y[i].start = start;
+ start += v;
+ }
+ block_ptr = m_cells;
+ nb = m_num_cells >> cell_block_shift;
+ while(nb--) {
+ cell_ptr = *block_ptr++;
+ i = cell_block_size;
+ while(i--) {
+ sorted_y& cur_y = m_sorted_y[cell_ptr->y - m_min_y];
+ m_sorted_cells[cur_y.start + cur_y.num] = cell_ptr;
+ ++cur_y.num;
+ ++cell_ptr;
+ }
+ }
+ i = m_num_cells & cell_block_mask;
+ if (i) {
+ cell_ptr = *block_ptr++;
+ }
+ while(i--) {
+ sorted_y& cur_y = m_sorted_y[cell_ptr->y - m_min_y];
+ m_sorted_cells[cur_y.start + cur_y.num] = cell_ptr;
+ ++cur_y.num;
+ ++cell_ptr;
+ }
+ for(i = 0; i < m_sorted_y.size(); i++) {
+ const sorted_y& cur_y = m_sorted_y[i];
+ if(cur_y.num) {
+ qsort_cells(m_sorted_cells.data() + cur_y.start, cur_y.num);
+ }
+ }
+ m_sorted = true;
+}
+}
diff --git a/third_party/agg23/agg_rasterizer_scanline_aa.h b/third_party/agg23/agg_rasterizer_scanline_aa.h
new file mode 100644
index 0000000000..da1900d0dd
--- /dev/null
+++ b/third_party/agg23/agg_rasterizer_scanline_aa.h
@@ -0,0 +1,472 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+//
+// The author gratefully acknowleges the support of David Turner,
+// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
+// libray - in producing this work. See http://www.freetype.org for details.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Adaptation for 32-bit screen coordinates has been sponsored by
+// Liberty Technology Systems, Inc., visit http://lib-sys.com
+//
+// Liberty Technology Systems, Inc. is the provider of
+// PostScript and PDF technology for software developers.
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
+#define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
+#include "../../core/include/fxge/fx_ge.h"
+#include "agg_basics.h"
+#include "agg_math.h"
+#include "agg_array.h"
+#include "agg_clip_liang_barsky.h"
+#include "agg_render_scanlines.h"
+namespace agg
+{
+enum poly_base_scale_e {
+ poly_base_shift = 8,
+ poly_base_size = 1 << poly_base_shift,
+ poly_base_mask = poly_base_size - 1
+};
+inline int poly_coord(FX_FLOAT c)
+{
+ return int(c * poly_base_size);
+}
+struct cell_aa {
+ int x;
+ int y;
+ int cover;
+ int area;
+ void set(int x, int y, int c, int a);
+ void set_coord(int x, int y);
+ void set_cover(int c, int a);
+ void add_cover(int c, int a);
+};
+class outline_aa
+{
+ enum cell_block_scale_e {
+ cell_block_shift = 12,
+ cell_block_size = 1 << cell_block_shift,
+ cell_block_mask = cell_block_size - 1,
+ cell_block_pool = 256,
+ cell_block_limit = 1024
+ };
+ struct sorted_y {
+ unsigned start;
+ unsigned num;
+ };
+public:
+ ~outline_aa();
+ outline_aa();
+ void reset();
+ void move_to(int x, int y);
+ void line_to(int x, int y);
+ 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;
+ }
+ void sort_cells();
+ unsigned total_cells() const
+ {
+ return m_num_cells;
+ }
+ unsigned scanline_num_cells(unsigned y) const
+ {
+ return m_sorted_y[y - m_min_y].num;
+ }
+ const cell_aa* const* scanline_cells(unsigned y) const
+ {
+ return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
+ }
+ bool sorted() const
+ {
+ return m_sorted;
+ }
+private:
+ outline_aa(const outline_aa&);
+ const outline_aa& operator = (const outline_aa&);
+ void set_cur_cell(int x, int y);
+ void add_cur_cell();
+ void render_hline(int ey, int x1, int y1, int x2, int y2);
+ void render_line(int x1, int y1, int x2, int y2);
+ void allocate_block();
+private:
+ unsigned m_num_blocks;
+ unsigned m_max_blocks;
+ unsigned m_cur_block;
+ unsigned m_num_cells;
+ cell_aa** m_cells;
+ cell_aa* m_cur_cell_ptr;
+ pod_array<cell_aa*> m_sorted_cells;
+ pod_array<sorted_y> m_sorted_y;
+ cell_aa m_cur_cell;
+ int m_cur_x;
+ int m_cur_y;
+ int m_min_x;
+ int m_min_y;
+ int m_max_x;
+ int m_max_y;
+ bool m_sorted;
+};
+class scanline_hit_test
+{
+public:
+ scanline_hit_test(int x) : m_x(x), m_hit(false) {}
+ void reset_spans() {}
+ void finalize(int) {}
+ void add_cell(int x, int)
+ {
+ if(m_x == x) {
+ m_hit = true;
+ }
+ }
+ void add_span(int x, int len, int)
+ {
+ if(m_x >= x && m_x < x + len) {
+ m_hit = true;
+ }
+ }
+ unsigned num_spans() const
+ {
+ return 1;
+ }
+ bool hit() const
+ {
+ return m_hit;
+ }
+private:
+ int m_x;
+ bool m_hit;
+};
+enum filling_rule_e {
+ fill_non_zero,
+ fill_even_odd
+};
+class rasterizer_scanline_aa
+{
+ enum status {
+ status_initial,
+ status_line_to,
+ status_closed
+ };
+public:
+ enum aa_scale_e {
+ aa_num = 1 << 8,
+ aa_mask = aa_num - 1,
+ aa_2num = aa_num * 2,
+ aa_2mask = aa_2num - 1
+ };
+ rasterizer_scanline_aa() :
+ m_filling_rule(fill_non_zero),
+ m_clipped_start_x(0),
+ m_clipped_start_y(0),
+ m_status(status_initial),
+ m_clipping(false)
+ {
+ }
+ ~rasterizer_scanline_aa() {}
+ void filling_rule(filling_rule_e filling_rule)
+ {
+ m_filling_rule = filling_rule;
+ }
+ int min_x() const
+ {
+ return m_outline.min_x();
+ }
+ int min_y() const
+ {
+ return m_outline.min_y();
+ }
+ int max_x() const
+ {
+ return m_outline.max_x();
+ }
+ int max_y() const
+ {
+ return m_outline.max_y();
+ }
+ void reset()
+ {
+ m_outline.reset();
+ m_status = status_initial;
+ }
+ void clip_box(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2)
+ {
+ m_clip_box = rect(poly_coord(x1), poly_coord(y1),
+ poly_coord(x2), poly_coord(y2));
+ m_clip_box.normalize();
+ m_clipping = true;
+ }
+ void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
+ {
+ if(is_close(cmd)) {
+ close_polygon();
+ } else {
+ if(is_move_to(cmd)) {
+ move_to(poly_coord(x), poly_coord(y));
+ } else {
+ if(is_vertex(cmd)) {
+ line_to(poly_coord(x), poly_coord(y));
+ }
+ }
+ }
+ }
+ void move_to(int x, int y)
+ {
+ if(m_clipping) {
+ if(m_outline.sorted()) {
+ reset();
+ }
+ if(m_status == status_line_to) {
+ close_polygon();
+ }
+ m_prev_x = m_start_x = x;
+ m_prev_y = m_start_y = y;
+ m_status = status_initial;
+ m_prev_flags = clipping_flags(x, y, m_clip_box);
+ if(m_prev_flags == 0) {
+ move_to_no_clip(x, y);
+ }
+ } else {
+ move_to_no_clip(x, y);
+ }
+ }
+ void line_to(int x, int y)
+ {
+ if(m_clipping) {
+ clip_segment(x, y);
+ } else {
+ line_to_no_clip(x, y);
+ }
+ }
+ void close_polygon()
+ {
+ if (m_status != status_line_to) {
+ return;
+ }
+ if(m_clipping) {
+ clip_segment(m_start_x, m_start_y);
+ }
+ close_polygon_no_clip();
+ }
+ AGG_INLINE unsigned calculate_alpha(int area, bool no_smooth) const
+ {
+ int cover = area >> (poly_base_shift * 2 + 1 - 8);
+ if(cover < 0) {
+ cover = -cover;
+ }
+ if(m_filling_rule == fill_even_odd) {
+ cover &= aa_2mask;
+ if(cover > aa_num) {
+ cover = aa_2num - cover;
+ }
+ }
+ if (no_smooth) {
+ cover = cover > aa_mask / 2 ? aa_mask : 0;
+ }
+ if(cover > aa_mask) {
+ cover = aa_mask;
+ }
+ return cover;
+ }
+ AGG_INLINE void sort()
+ {
+ m_outline.sort_cells();
+ }
+ AGG_INLINE bool rewind_scanlines()
+ {
+ close_polygon();
+ m_outline.sort_cells();
+ if(m_outline.total_cells() == 0) {
+ return false;
+ }
+ m_cur_y = m_outline.min_y();
+ return true;
+ }
+ AGG_INLINE bool navigate_scanline(int y)
+ {
+ close_polygon();
+ m_outline.sort_cells();
+ if(m_outline.total_cells() == 0 ||
+ y < m_outline.min_y() ||
+ y > m_outline.max_y()) {
+ return false;
+ }
+ m_cur_y = y;
+ return true;
+ }
+ template<class Scanline> bool sweep_scanline(Scanline& sl, bool no_smooth)
+ {
+ for(;;) {
+ if(m_cur_y > m_outline.max_y()) {
+ return false;
+ }
+ sl.reset_spans();
+ unsigned num_cells = m_outline.scanline_num_cells(m_cur_y);
+ const cell_aa* const* cells = m_outline.scanline_cells(m_cur_y);
+ int cover = 0;
+ while(num_cells) {
+ const cell_aa* cur_cell = *cells;
+ int x = cur_cell->x;
+ int area = cur_cell->area;
+ unsigned alpha;
+ cover += cur_cell->cover;
+ while(--num_cells) {
+ cur_cell = *++cells;
+ if(cur_cell->x != x) {
+ break;
+ }
+ area += cur_cell->area;
+ cover += cur_cell->cover;
+ }
+ if(area) {
+ alpha = calculate_alpha((cover << (poly_base_shift + 1)) - area, no_smooth);
+ if(alpha) {
+ sl.add_cell(x, alpha);
+ }
+ x++;
+ }
+ if(num_cells && cur_cell->x > x) {
+ alpha = calculate_alpha(cover << (poly_base_shift + 1), no_smooth);
+ if(alpha) {
+ sl.add_span(x, cur_cell->x - x, alpha);
+ }
+ }
+ }
+ if(sl.num_spans()) {
+ break;
+ }
+ ++m_cur_y;
+ }
+ sl.finalize(m_cur_y);
+ ++m_cur_y;
+ return true;
+ }
+ template<class VertexSource>
+ void add_path(VertexSource& vs, unsigned path_id = 0)
+ {
+ FX_FLOAT x;
+ FX_FLOAT y;
+ unsigned cmd;
+ vs.rewind(path_id);
+ while(!is_stop(cmd = vs.vertex(&x, &y))) {
+ add_vertex(x, y, cmd);
+ }
+ }
+ template<class VertexSource>
+ void add_path_transformed(VertexSource& vs, const CFX_AffineMatrix* pMatrix, unsigned path_id = 0)
+ {
+ FX_FLOAT x;
+ FX_FLOAT y;
+ unsigned cmd;
+ vs.rewind(path_id);
+ while(!is_stop(cmd = vs.vertex(&x, &y))) {
+ if (pMatrix) {
+ pMatrix->Transform(x, y);
+ }
+ add_vertex(x, y, cmd);
+ }
+ }
+private:
+ rasterizer_scanline_aa(const rasterizer_scanline_aa&);
+ const rasterizer_scanline_aa&
+ operator = (const rasterizer_scanline_aa&);
+ void move_to_no_clip(int x, int y)
+ {
+ if(m_status == status_line_to) {
+ close_polygon_no_clip();
+ }
+ m_outline.move_to(x * 1, y);
+ m_clipped_start_x = x;
+ m_clipped_start_y = y;
+ m_status = status_line_to;
+ }
+ void line_to_no_clip(int x, int y)
+ {
+ if(m_status != status_initial) {
+ m_outline.line_to(x * 1, y);
+ m_status = status_line_to;
+ }
+ }
+ void close_polygon_no_clip()
+ {
+ if(m_status == status_line_to) {
+ m_outline.line_to(m_clipped_start_x * 1, m_clipped_start_y);
+ m_status = status_closed;
+ }
+ }
+ void clip_segment(int x, int y)
+ {
+ unsigned flags = clipping_flags(x, y, m_clip_box);
+ if(m_prev_flags == flags) {
+ if(flags == 0) {
+ if(m_status == status_initial) {
+ move_to_no_clip(x, y);
+ } else {
+ line_to_no_clip(x, y);
+ }
+ }
+ } else {
+ int cx[4];
+ int cy[4];
+ unsigned n = clip_liang_barsky(m_prev_x, m_prev_y,
+ x, y,
+ m_clip_box,
+ cx, cy);
+ const int* px = cx;
+ const int* py = cy;
+ while(n--) {
+ if(m_status == status_initial) {
+ move_to_no_clip(*px++, *py++);
+ } else {
+ line_to_no_clip(*px++, *py++);
+ }
+ }
+ }
+ m_prev_flags = flags;
+ m_prev_x = x;
+ m_prev_y = y;
+ }
+private:
+ outline_aa m_outline;
+ filling_rule_e m_filling_rule;
+ int m_clipped_start_x;
+ int m_clipped_start_y;
+ int m_start_x;
+ int m_start_y;
+ int m_prev_x;
+ int m_prev_y;
+ unsigned m_prev_flags;
+ unsigned m_status;
+ rect m_clip_box;
+ bool m_clipping;
+ int m_cur_y;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_render_scanlines.h b/third_party/agg23/agg_render_scanlines.h
new file mode 100644
index 0000000000..0dfd6d259f
--- /dev/null
+++ b/third_party/agg23/agg_render_scanlines.h
@@ -0,0 +1,50 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_RENDER_SCANLINES_INCLUDED
+#define AGG_RENDER_SCANLINES_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+template<class Rasterizer, class Scanline, class Renderer>
+void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren, bool no_smooth)
+{
+ if(ras.rewind_scanlines()) {
+ sl.reset(ras.min_x(), ras.max_x());
+ ren.prepare(unsigned(ras.max_x() - ras.min_x() + 2));
+ while(ras.sweep_scanline(sl, no_smooth)) {
+ ren.render(sl);
+ }
+ }
+}
+template<class Rasterizer, class Scanline, class Renderer,
+ class VertexSource, class ColorStorage, class PathId>
+void render_all_paths(Rasterizer& ras,
+ Scanline& sl,
+ Renderer& r,
+ VertexSource& vs,
+ const ColorStorage& as,
+ const PathId& path_id,
+ unsigned num_paths)
+{
+ for(unsigned i = 0; i < num_paths; i++) {
+ ras.reset();
+ ras.add_path(vs, path_id[i]);
+ r.color(as[i]);
+ render_scanlines(ras, sl, r);
+ }
+}
+}
+#endif
diff --git a/third_party/agg23/agg_renderer_base.h b/third_party/agg23/agg_renderer_base.h
new file mode 100644
index 0000000000..bd1b203b9a
--- /dev/null
+++ b/third_party/agg23/agg_renderer_base.h
@@ -0,0 +1,163 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// class renderer_base
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_RENDERER_BASE_INCLUDED
+#define AGG_RENDERER_BASE_INCLUDED
+#include "agg_basics.h"
+#include "agg_rendering_buffer.h"
+namespace agg
+{
+template<class PixelFormat> class renderer_base
+{
+public:
+ typedef PixelFormat pixfmt_type;
+ typedef typename pixfmt_type::color_type color_type;
+ typedef typename pixfmt_type::row_data row_data;
+ typedef typename pixfmt_type::span_data span_data;
+ renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {}
+ renderer_base(pixfmt_type& ren) :
+ m_ren(&ren),
+ m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
+ {}
+ void attach(pixfmt_type& ren)
+ {
+ m_ren = &ren;
+ m_clip_box = rect(0, 0, ren.width() - 1, ren.height() - 1);
+ }
+ const pixfmt_type& ren() const
+ {
+ return *m_ren;
+ }
+ pixfmt_type& ren()
+ {
+ return *m_ren;
+ }
+ unsigned width() const
+ {
+ return m_ren->width();
+ }
+ unsigned height() const
+ {
+ return m_ren->height();
+ }
+ void first_clip_box() {}
+ bool next_clip_box()
+ {
+ return false;
+ }
+ const rect& clip_box() const
+ {
+ return m_clip_box;
+ }
+ int xmin() const
+ {
+ return m_clip_box.x1;
+ }
+ int ymin() const
+ {
+ return m_clip_box.y1;
+ }
+ int xmax() const
+ {
+ return m_clip_box.x2;
+ }
+ int ymax() const
+ {
+ return m_clip_box.y2;
+ }
+ const rect& bounding_clip_box() const
+ {
+ return m_clip_box;
+ }
+ int bounding_xmin() const
+ {
+ return m_clip_box.x1;
+ }
+ int bounding_ymin() const
+ {
+ return m_clip_box.y1;
+ }
+ int bounding_xmax() const
+ {
+ return m_clip_box.x2;
+ }
+ int bounding_ymax() const
+ {
+ return m_clip_box.y2;
+ }
+ void blend_hline(int x1, int y, int x2,
+ const color_type& c, cover_type cover)
+ {
+ if(x1 > x2) {
+ int t = x2;
+ x2 = x1;
+ x1 = t;
+ }
+ if(y > ymax()) {
+ return;
+ }
+ if(y < ymin()) {
+ return;
+ }
+ if(x1 > xmax()) {
+ return;
+ }
+ if(x2 < xmin()) {
+ return;
+ }
+ if(x1 < xmin()) {
+ x1 = xmin();
+ }
+ if(x2 > xmax()) {
+ x2 = xmax();
+ }
+ m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
+ }
+ void blend_solid_hspan(int x, int y, int len,
+ const color_type& c,
+ const cover_type* covers)
+ {
+ if(y > ymax()) {
+ return;
+ }
+ if(y < ymin()) {
+ return;
+ }
+ if(x < xmin()) {
+ len -= xmin() - x;
+ if(len <= 0) {
+ return;
+ }
+ covers += xmin() - x;
+ x = xmin();
+ }
+ if(x + len > xmax()) {
+ len = xmax() - x + 1;
+ if(len <= 0) {
+ return;
+ }
+ }
+ m_ren->blend_solid_hspan(x, y, len, c, covers);
+ }
+private:
+ pixfmt_type* m_ren;
+ rect m_clip_box;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_renderer_scanline.h b/third_party/agg23/agg_renderer_scanline.h
new file mode 100644
index 0000000000..62d104f7f2
--- /dev/null
+++ b/third_party/agg23/agg_renderer_scanline.h
@@ -0,0 +1,93 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_RENDERER_SCANLINE_INCLUDED
+#define AGG_RENDERER_SCANLINE_INCLUDED
+#include "agg_basics.h"
+#include "agg_renderer_base.h"
+#include "agg_render_scanlines.h"
+namespace agg
+{
+template<class BaseRenderer, class SpanGenerator> class renderer_scanline_aa
+{
+public:
+ typedef BaseRenderer base_ren_type;
+ typedef SpanGenerator span_gen_type;
+ renderer_scanline_aa() : m_ren(0), m_span_gen(0) {}
+ renderer_scanline_aa(base_ren_type& ren, span_gen_type& span_gen) :
+ m_ren(&ren),
+ m_span_gen(&span_gen)
+ {}
+ void attach(base_ren_type& ren, span_gen_type& span_gen)
+ {
+ m_ren = &ren;
+ m_span_gen = &span_gen;
+ }
+ void prepare(unsigned max_span_len)
+ {
+ m_span_gen->prepare(max_span_len);
+ }
+ template<class Scanline> void render(const Scanline& sl)
+ {
+ int y = sl.y();
+ m_ren->first_clip_box();
+ do {
+ int xmin = m_ren->xmin();
+ int xmax = m_ren->xmax();
+ if(y >= m_ren->ymin() && y <= m_ren->ymax()) {
+ unsigned num_spans = sl.num_spans();
+ typename Scanline::const_iterator span = sl.begin();
+ for(;;) {
+ int x = span->x;
+ int len = span->len;
+ bool solid = false;
+ const typename Scanline::cover_type* covers = span->covers;
+ if(len < 0) {
+ solid = true;
+ len = -len;
+ }
+ if(x < xmin) {
+ len -= xmin - x;
+ if(!solid) {
+ covers += xmin - x;
+ }
+ x = xmin;
+ }
+ if(len > 0) {
+ if(x + len > xmax) {
+ len = xmax - x + 1;
+ }
+ if(len > 0) {
+ m_ren->blend_color_hspan_no_clip(
+ x, y, len,
+ m_span_gen->generate(x, y, len),
+ solid ? 0 : covers,
+ *covers);
+ }
+ }
+ if(--num_spans == 0) {
+ break;
+ }
+ ++span;
+ }
+ }
+ } while(m_ren->next_clip_box());
+ }
+private:
+ base_ren_type* m_ren;
+ SpanGenerator* m_span_gen;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_rendering_buffer.h b/third_party/agg23/agg_rendering_buffer.h
new file mode 100644
index 0000000000..9c1c0c6899
--- /dev/null
+++ b/third_party/agg23/agg_rendering_buffer.h
@@ -0,0 +1,145 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// class rendering_buffer
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_RENDERING_BUFFER_INCLUDED
+#define AGG_RENDERING_BUFFER_INCLUDED
+#include "agg_basics.h"
+namespace agg
+{
+class rendering_buffer
+{
+public:
+ struct row_data {
+ int x1, x2;
+ const int8u* ptr;
+ row_data() {}
+ row_data(int x1_, int x2_, const int8u* ptr_) :
+ x1(x1_), x2(x2_), ptr(ptr_) {}
+ };
+ struct span_data {
+ int x;
+ unsigned len;
+ int8u* ptr;
+ span_data() {}
+ span_data(int) : x(0), len(0), ptr(0) {}
+ span_data(int x_, unsigned len_, int8u* ptr_) :
+ x(x_), len(len_), ptr(ptr_) {}
+ };
+ ~rendering_buffer()
+ {
+ FX_Free(m_rows);
+ }
+ rendering_buffer() :
+ m_buf(0),
+ m_rows(0),
+ m_width(0),
+ m_height(0),
+ m_stride(0),
+ m_max_height(0)
+ {
+ }
+ rendering_buffer(int8u* buf, unsigned width, unsigned height, int stride) :
+ m_buf(0),
+ m_rows(0),
+ m_width(0),
+ m_height(0),
+ m_stride(0),
+ m_max_height(0)
+ {
+ attach(buf, width, height, stride);
+ }
+ void attach(int8u* buf, unsigned width, unsigned height, int stride)
+ {
+ m_buf = buf;
+ m_width = width;
+ m_height = height;
+ m_stride = stride;
+ if(height > m_max_height) {
+ FX_Free(m_rows);
+ m_rows = FX_Alloc(int8u*, m_max_height = height);
+ }
+ int8u* row_ptr = m_buf;
+ if(stride < 0) {
+ row_ptr = m_buf - int(height - 1) * stride;
+ }
+ int8u** rows = m_rows;
+ while(height--) {
+ *rows++ = row_ptr;
+ row_ptr += stride;
+ }
+ }
+ int8u* buf()
+ {
+ return m_buf;
+ }
+ const int8u* buf() const
+ {
+ return m_buf;
+ }
+ unsigned width() const
+ {
+ return m_width;
+ }
+ unsigned height() const
+ {
+ return m_height;
+ }
+ int stride() const
+ {
+ return m_stride;
+ }
+ unsigned stride_abs() const
+ {
+ return (m_stride < 0) ?
+ unsigned(-m_stride) :
+ unsigned(m_stride);
+ }
+ int8u* row(unsigned y)
+ {
+ return m_rows[y];
+ }
+ const int8u* row(unsigned y) const
+ {
+ return m_rows[y];
+ }
+ int8u* next_row(void* p)
+ {
+ return (int8u*)p + m_stride;
+ }
+ const int8u* next_row(const void* p) const
+ {
+ return (int8u*)p + m_stride;
+ }
+ int8u const* const* rows() const
+ {
+ return m_rows;
+ }
+private:
+ rendering_buffer(const rendering_buffer&);
+ const rendering_buffer& operator = (const rendering_buffer&);
+private:
+ int8u* m_buf;
+ int8u** m_rows;
+ unsigned m_width;
+ unsigned m_height;
+ int m_stride;
+ unsigned m_max_height;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_scanline_u.h b/third_party/agg23/agg_scanline_u.h
new file mode 100644
index 0000000000..2100115329
--- /dev/null
+++ b/third_party/agg23/agg_scanline_u.h
@@ -0,0 +1,150 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by
+// Liberty Technology Systems, Inc., visit http://lib-sys.com
+//
+// Liberty Technology Systems, Inc. is the provider of
+// PostScript and PDF technology for software developers.
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_SCANLINE_U_INCLUDED
+#define AGG_SCANLINE_U_INCLUDED
+#include "agg_array.h"
+namespace agg
+{
+template<class CoverT> class scanline_u
+{
+public:
+ typedef scanline_u<CoverT> self_type;
+ typedef CoverT cover_type;
+ typedef int16 coord_type;
+ struct span {
+ coord_type x;
+ coord_type len;
+ cover_type* covers;
+ };
+ typedef span* iterator;
+ typedef const span* const_iterator;
+ ~scanline_u()
+ {
+ FX_Free(m_spans);
+ FX_Free(m_covers);
+ }
+ scanline_u() :
+ m_min_x(0),
+ m_max_len(0),
+ m_last_x(0x7FFFFFF0),
+ m_covers(0),
+ m_spans(0),
+ m_cur_span(0)
+ {}
+ void reset(int min_x, int max_x)
+ {
+ unsigned max_len = max_x - min_x + 2;
+ if(max_len > m_max_len) {
+ FX_Free(m_spans);
+ FX_Free(m_covers);
+ m_covers = FX_Alloc( cover_type , max_len);
+ m_spans = FX_Alloc( span , max_len);
+ m_max_len = max_len;
+ }
+ m_last_x = 0x7FFFFFF0;
+ m_min_x = min_x;
+ m_cur_span = m_spans;
+ }
+ void add_cell(int x, unsigned cover)
+ {
+ x -= m_min_x;
+ m_covers[x] = (cover_type)cover;
+ if(x == m_last_x + 1) {
+ m_cur_span->len++;
+ } else {
+ m_cur_span++;
+ m_cur_span->x = (coord_type)(x + m_min_x);
+ m_cur_span->len = 1;
+ m_cur_span->covers = m_covers + x;
+ }
+ m_last_x = x;
+ }
+ void add_cells(int x, unsigned len, const CoverT* covers)
+ {
+ x -= m_min_x;
+ FXSYS_memcpy(m_covers + x, covers, len * sizeof(CoverT));
+ if(x == m_last_x + 1) {
+ m_cur_span->len += (coord_type)len;
+ } else {
+ m_cur_span++;
+ m_cur_span->x = (coord_type)(x + m_min_x);
+ m_cur_span->len = (coord_type)len;
+ m_cur_span->covers = m_covers + x;
+ }
+ m_last_x = x + len - 1;
+ }
+ void add_span(int x, unsigned len, unsigned cover)
+ {
+ x -= m_min_x;
+ FXSYS_memset(m_covers + x, cover, len);
+ if(x == m_last_x + 1) {
+ m_cur_span->len += (coord_type)len;
+ } else {
+ m_cur_span++;
+ m_cur_span->x = (coord_type)(x + m_min_x);
+ m_cur_span->len = (coord_type)len;
+ m_cur_span->covers = m_covers + x;
+ }
+ m_last_x = x + len - 1;
+ }
+ void finalize(int y)
+ {
+ m_y = y;
+ }
+ void reset_spans()
+ {
+ m_last_x = 0x7FFFFFF0;
+ m_cur_span = m_spans;
+ }
+ int y() const
+ {
+ return m_y;
+ }
+ unsigned num_spans() const
+ {
+ return unsigned(m_cur_span - m_spans);
+ }
+ const_iterator begin() const
+ {
+ return m_spans + 1;
+ }
+ iterator begin()
+ {
+ return m_spans + 1;
+ }
+private:
+ scanline_u(const self_type&);
+ const self_type& operator = (const self_type&);
+private:
+ int m_min_x;
+ unsigned m_max_len;
+ int m_last_x;
+ int m_y;
+ cover_type* m_covers;
+ span* m_spans;
+ span* m_cur_span;
+};
+typedef scanline_u<int8u> scanline_u8;
+}
+#endif
diff --git a/third_party/agg23/agg_shorten_path.h b/third_party/agg23/agg_shorten_path.h
new file mode 100644
index 0000000000..d7eb4be018
--- /dev/null
+++ b/third_party/agg23/agg_shorten_path.h
@@ -0,0 +1,57 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_SHORTEN_PATH_INCLUDED
+#define AGG_SHORTEN_PATH_INCLUDED
+#include "agg_basics.h"
+#include "agg_vertex_sequence.h"
+namespace agg
+{
+template<class VertexSequence>
+void shorten_path(VertexSequence& vs, FX_FLOAT s, unsigned closed = 0)
+{
+ typedef typename VertexSequence::value_type vertex_type;
+ if(s > 0 && vs.size() > 1) {
+ FX_FLOAT d;
+ int n = int(vs.size() - 2);
+ while(n) {
+ d = vs[n].dist;
+ if(d > s) {
+ break;
+ }
+ vs.remove_last();
+ s -= d;
+ --n;
+ }
+ if(vs.size() < 2) {
+ vs.remove_all();
+ } else {
+ n = vs.size() - 1;
+ vertex_type& prev = vs[n - 1];
+ vertex_type& last = vs[n];
+ d = (prev.dist - s) / prev.dist;
+ FX_FLOAT x = prev.x + (last.x - prev.x) * d;
+ FX_FLOAT y = prev.y + (last.y - prev.y) * d;
+ last.x = x;
+ last.y = y;
+ if(!prev(last)) {
+ vs.remove_last();
+ }
+ vs.close(closed != 0);
+ }
+ }
+}
+}
+#endif
diff --git a/third_party/agg23/agg_vcgen_dash.cpp b/third_party/agg23/agg_vcgen_dash.cpp
new file mode 100644
index 0000000000..43f8edf350
--- /dev/null
+++ b/third_party/agg23/agg_vcgen_dash.cpp
@@ -0,0 +1,176 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Line dash generator
+//
+//----------------------------------------------------------------------------
+#include "../../core/include/fxcrt/fx_basic.h"
+#include "agg_vcgen_dash.h"
+#include "agg_shorten_path.h"
+namespace agg
+{
+vcgen_dash::vcgen_dash() :
+ m_total_dash_len(0),
+ m_num_dashes(0),
+ m_dash_start(0),
+ m_shorten(0),
+ m_curr_dash_start(0),
+ m_curr_dash(0),
+ m_src_vertices(),
+ m_closed(0),
+ m_status(initial),
+ m_src_vertex(0)
+{
+}
+void vcgen_dash::remove_all_dashes()
+{
+ m_total_dash_len = 0;
+ m_num_dashes = 0;
+ m_curr_dash_start = 0;
+ m_curr_dash = 0;
+}
+void vcgen_dash::add_dash(FX_FLOAT dash_len, FX_FLOAT gap_len)
+{
+ if(m_num_dashes < max_dashes) {
+ m_total_dash_len += dash_len + gap_len;
+ m_dashes[m_num_dashes++] = dash_len;
+ m_dashes[m_num_dashes++] = gap_len;
+ }
+}
+void vcgen_dash::dash_start(FX_FLOAT ds)
+{
+ m_dash_start = ds;
+ calc_dash_start(FXSYS_fabs(ds));
+}
+void vcgen_dash::calc_dash_start(FX_FLOAT ds)
+{
+ m_curr_dash = 0;
+ m_curr_dash_start = 0;
+ while(ds > 0) {
+ if(ds > m_dashes[m_curr_dash]) {
+ ds -= m_dashes[m_curr_dash];
+ ++m_curr_dash;
+ m_curr_dash_start = 0;
+ if(m_curr_dash >= m_num_dashes) {
+ m_curr_dash = 0;
+ }
+ } else {
+ m_curr_dash_start = ds;
+ ds = 0;
+ }
+ }
+}
+void vcgen_dash::remove_all()
+{
+ m_status = initial;
+ m_src_vertices.remove_all();
+ m_closed = 0;
+}
+void vcgen_dash::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
+{
+ m_status = initial;
+ if(is_move_to(cmd)) {
+ m_src_vertices.modify_last(vertex_dist(x, y));
+ } else {
+ if(is_vertex(cmd)) {
+ m_src_vertices.add(vertex_dist(x, y));
+ } else {
+ m_closed = get_close_flag(cmd);
+ }
+ }
+}
+void vcgen_dash::rewind(unsigned)
+{
+ if(m_status == initial) {
+ m_src_vertices.close(m_closed != 0);
+ shorten_path(m_src_vertices, m_shorten, m_closed);
+ }
+ m_status = ready;
+ m_src_vertex = 0;
+}
+unsigned vcgen_dash::vertex(FX_FLOAT* x, FX_FLOAT* y)
+{
+ unsigned cmd = path_cmd_move_to;
+ while(!is_stop(cmd)) {
+ switch(m_status) {
+ case initial:
+ rewind(0);
+ case ready:
+ if(m_num_dashes < 2 || m_src_vertices.size() < 2) {
+ cmd = path_cmd_stop;
+ break;
+ }
+ m_status = polyline;
+ m_src_vertex = 1;
+ m_v1 = &m_src_vertices[0];
+ m_v2 = &m_src_vertices[1];
+ m_curr_rest = m_v1->dist;
+ *x = m_v1->x;
+ *y = m_v1->y;
+ if(m_dash_start >= 0) {
+ calc_dash_start(m_dash_start);
+ }
+ return path_cmd_move_to;
+ case polyline: {
+ FX_FLOAT dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start;
+ unsigned cmd = (m_curr_dash & 1) ?
+ path_cmd_move_to :
+ path_cmd_line_to;
+ if(m_curr_rest > dash_rest) {
+ m_curr_rest -= dash_rest;
+ ++m_curr_dash;
+ if(m_curr_dash >= m_num_dashes) {
+ m_curr_dash = 0;
+ }
+ m_curr_dash_start = 0;
+ *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist;
+ *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist;
+ } else {
+ m_curr_dash_start += m_curr_rest;
+ *x = m_v2->x;
+ *y = m_v2->y;
+ ++m_src_vertex;
+ m_v1 = m_v2;
+ m_curr_rest = m_v1->dist;
+ if(m_closed) {
+ if(m_src_vertex > m_src_vertices.size()) {
+ m_status = stop;
+ } else {
+ m_v2 = &m_src_vertices
+ [
+ (m_src_vertex >= m_src_vertices.size()) ? 0 :
+ m_src_vertex
+ ];
+ }
+ } else {
+ if(m_src_vertex >= m_src_vertices.size()) {
+ m_status = stop;
+ } else {
+ m_v2 = &m_src_vertices[m_src_vertex];
+ }
+ }
+ }
+ return cmd;
+ }
+ break;
+ case stop:
+ cmd = path_cmd_stop;
+ break;
+ }
+ }
+ return path_cmd_stop;
+}
+}
diff --git a/third_party/agg23/agg_vcgen_dash.h b/third_party/agg23/agg_vcgen_dash.h
new file mode 100644
index 0000000000..9c3aa630c2
--- /dev/null
+++ b/third_party/agg23/agg_vcgen_dash.h
@@ -0,0 +1,75 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Line dash generator
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_VCGEN_DASH_INCLUDED
+#define AGG_VCGEN_DASH_INCLUDED
+#include "agg_basics.h"
+#include "agg_vertex_sequence.h"
+namespace agg
+{
+class vcgen_dash
+{
+ enum max_dashes_e {
+ max_dashes = 32
+ };
+ enum status_e {
+ initial,
+ ready,
+ polyline,
+ stop
+ };
+public:
+ typedef vertex_sequence<vertex_dist, 6> vertex_storage;
+ vcgen_dash();
+ void remove_all_dashes();
+ void add_dash(FX_FLOAT dash_len, FX_FLOAT gap_len);
+ void dash_start(FX_FLOAT ds);
+ void shorten(FX_FLOAT s)
+ {
+ m_shorten = s;
+ }
+ double shorten() const
+ {
+ return m_shorten;
+ }
+ void remove_all();
+ void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd);
+ void rewind(unsigned path_id);
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y);
+private:
+ vcgen_dash(const vcgen_dash&);
+ const vcgen_dash& operator = (const vcgen_dash&);
+ void calc_dash_start(FX_FLOAT ds);
+ FX_FLOAT m_dashes[max_dashes];
+ FX_FLOAT m_total_dash_len;
+ unsigned m_num_dashes;
+ FX_FLOAT m_dash_start;
+ FX_FLOAT m_shorten;
+ FX_FLOAT m_curr_dash_start;
+ unsigned m_curr_dash;
+ FX_FLOAT m_curr_rest;
+ const vertex_dist* m_v1;
+ const vertex_dist* m_v2;
+ vertex_storage m_src_vertices;
+ unsigned m_closed;
+ status_e m_status;
+ unsigned m_src_vertex;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_vcgen_stroke.cpp b/third_party/agg23/agg_vcgen_stroke.cpp
new file mode 100644
index 0000000000..9b8cb66fd9
--- /dev/null
+++ b/third_party/agg23/agg_vcgen_stroke.cpp
@@ -0,0 +1,214 @@
+
+//----------------------------------------------------------------------------
+// XYQ: 2006-01-22 Copied from AGG project.
+// TODO: This file uses intensive floating point operations, so it's NOT suitable
+// for platforms like Symbian OS. We need to change to FIX format.
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// Stroke generator
+//
+//----------------------------------------------------------------------------
+#include "../../core/include/fxcrt/fx_basic.h"
+#include "agg_vcgen_stroke.h"
+namespace agg
+{
+
+vcgen_stroke::vcgen_stroke() :
+ m_src_vertices(),
+ m_out_vertices(),
+ m_width(0.5f),
+ m_miter_limit(4 * 1.0f),
+ m_inner_miter_limit(1.0f + 1.0f / 100),
+ m_approx_scale(1.0f),
+ m_line_cap(butt_cap),
+ m_line_join(miter_join),
+ m_inner_join(inner_miter),
+ m_closed(0),
+ m_status(initial),
+ m_src_vertex(0),
+ m_out_vertex(0)
+{
+}
+void vcgen_stroke::remove_all()
+{
+ m_src_vertices.remove_all();
+ m_closed = 0;
+ m_status = initial;
+}
+void vcgen_stroke::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
+{
+ m_status = initial;
+ if(is_move_to(cmd)) {
+ m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd));
+ } else {
+ if(is_vertex(cmd)) {
+ m_src_vertices.add(vertex_dist_cmd(x, y, cmd));
+ } else {
+ m_closed = get_close_flag(cmd);
+ }
+ }
+}
+static inline void calc_butt_cap(FX_FLOAT* cap,
+ const vertex_dist& v0,
+ const vertex_dist& v1,
+ FX_FLOAT len,
+ FX_FLOAT width)
+{
+ FX_FLOAT dx = FXSYS_MulDiv(v1.y - v0.y, width, len);
+ FX_FLOAT dy = FXSYS_MulDiv(v1.x - v0.x, width, len);
+ cap[0] = v0.x - dx;
+ cap[1] = v0.y + dy;
+ cap[2] = v0.x + dx;
+ cap[3] = v0.y - dy;
+}
+void vcgen_stroke::rewind(unsigned)
+{
+ if(m_status == initial) {
+ m_src_vertices.close(m_closed != 0);
+ if(m_src_vertices.size() < 3) {
+ m_closed = 0;
+ }
+ }
+ m_status = ready;
+ m_src_vertex = 0;
+ m_out_vertex = 0;
+}
+unsigned vcgen_stroke::vertex(FX_FLOAT* x, FX_FLOAT* y)
+{
+ unsigned cmd = path_cmd_line_to;
+ line_join_e curj;
+ while(!is_stop(cmd)) {
+ switch(m_status) {
+ case initial:
+ rewind(0);
+ case ready:
+ if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) {
+ cmd = path_cmd_stop;
+ break;
+ }
+ m_status = m_closed ? outline1 : cap1;
+ cmd = path_cmd_move_to;
+ m_src_vertex = 0;
+ m_out_vertex = 0;
+ break;
+ case cap1:
+ stroke_calc_cap(m_out_vertices,
+ m_src_vertices[0],
+ m_src_vertices[1],
+ m_src_vertices[0].dist,
+ m_line_cap,
+ m_width,
+ m_approx_scale);
+ m_src_vertex = 1;
+ m_prev_status = outline1;
+ m_status = out_vertices;
+ m_out_vertex = 0;
+ break;
+ case cap2:
+ stroke_calc_cap(m_out_vertices,
+ m_src_vertices[m_src_vertices.size() - 1],
+ m_src_vertices[m_src_vertices.size() - 2],
+ m_src_vertices[m_src_vertices.size() - 2].dist,
+ m_line_cap,
+ m_width,
+ m_approx_scale);
+ m_prev_status = outline2;
+ m_status = out_vertices;
+ m_out_vertex = 0;
+ break;
+ case outline1:
+ if(m_closed) {
+ if(m_src_vertex >= m_src_vertices.size()) {
+ m_prev_status = close_first;
+ m_status = end_poly1;
+ break;
+ }
+ } else {
+ if(m_src_vertex >= m_src_vertices.size() - 1) {
+ m_status = cap2;
+ break;
+ }
+ }
+ curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
+ stroke_calc_join(m_out_vertices,
+ m_src_vertices.prev(m_src_vertex),
+ m_src_vertices.curr(m_src_vertex),
+ m_src_vertices.next(m_src_vertex),
+ m_src_vertices.prev(m_src_vertex).dist,
+ m_src_vertices.curr(m_src_vertex).dist,
+ m_width,
+ curj,
+ m_inner_join,
+ m_miter_limit,
+ m_inner_miter_limit,
+ m_approx_scale);
+ ++m_src_vertex;
+ m_prev_status = m_status;
+ m_status = out_vertices;
+ m_out_vertex = 0;
+ break;
+ case close_first:
+ m_status = outline2;
+ cmd = path_cmd_move_to;
+ case outline2:
+ if(m_src_vertex <= unsigned(m_closed == 0)) {
+ m_status = end_poly2;
+ m_prev_status = stop;
+ break;
+ }
+ --m_src_vertex;
+ curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
+ stroke_calc_join(m_out_vertices,
+ m_src_vertices.next(m_src_vertex),
+ m_src_vertices.curr(m_src_vertex),
+ m_src_vertices.prev(m_src_vertex),
+ m_src_vertices.curr(m_src_vertex).dist,
+ m_src_vertices.prev(m_src_vertex).dist,
+ m_width,
+ curj,
+ m_inner_join,
+ m_miter_limit,
+ m_inner_miter_limit,
+ m_approx_scale);
+ m_prev_status = m_status;
+ m_status = out_vertices;
+ m_out_vertex = 0;
+ break;
+ case out_vertices:
+ if(m_out_vertex >= m_out_vertices.size()) {
+ m_status = m_prev_status;
+ } else {
+ const point_type& c = m_out_vertices[m_out_vertex++];
+ *x = c.x;
+ *y = c.y;
+ return cmd;
+ }
+ break;
+ case end_poly1:
+ m_status = m_prev_status;
+ return path_cmd_end_poly | path_flags_close | path_flags_ccw;
+ case end_poly2:
+ m_status = m_prev_status;
+ return path_cmd_end_poly | path_flags_close | path_flags_cw;
+ case stop:
+ cmd = path_cmd_stop;
+ break;
+ }
+ }
+ return cmd;
+}
+}
diff --git a/third_party/agg23/agg_vcgen_stroke.h b/third_party/agg23/agg_vcgen_stroke.h
new file mode 100644
index 0000000000..84fadd6ed8
--- /dev/null
+++ b/third_party/agg23/agg_vcgen_stroke.h
@@ -0,0 +1,120 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+#ifndef AGG_VCGEN_STROKE_INCLUDED
+#define AGG_VCGEN_STROKE_INCLUDED
+#include "agg_math_stroke.h"
+namespace agg
+{
+class vcgen_stroke
+{
+ enum status_e {
+ initial,
+ ready,
+ cap1,
+ cap2,
+ outline1,
+ close_first,
+ outline2,
+ out_vertices,
+ end_poly1,
+ end_poly2,
+ stop
+ };
+public:
+ typedef vertex_sequence<vertex_dist_cmd, 6> vertex_storage;
+ typedef pod_deque<point_type, 6> coord_storage;
+ vcgen_stroke();
+ void line_cap(line_cap_e lc)
+ {
+ m_line_cap = lc;
+ }
+ void line_join(line_join_e lj)
+ {
+ m_line_join = lj;
+ }
+ void inner_join(inner_join_e ij)
+ {
+ m_inner_join = ij;
+ }
+ line_cap_e line_cap() const
+ {
+ return m_line_cap;
+ }
+ line_join_e line_join() const
+ {
+ return m_line_join;
+ }
+ inner_join_e inner_join() const
+ {
+ return m_inner_join;
+ }
+ void width(FX_FLOAT w)
+ {
+ m_width = w / 2;
+ }
+ void miter_limit(FX_FLOAT ml)
+ {
+ m_miter_limit = ml;
+ }
+ void miter_limit_theta(FX_FLOAT t);
+ void inner_miter_limit(FX_FLOAT ml)
+ {
+ m_inner_miter_limit = ml;
+ }
+ void approximation_scale(FX_FLOAT as)
+ {
+ m_approx_scale = as;
+ }
+ FX_FLOAT width() const
+ {
+ return m_width * 2;
+ }
+ FX_FLOAT miter_limit() const
+ {
+ return m_miter_limit;
+ }
+ FX_FLOAT inner_miter_limit() const
+ {
+ return m_inner_miter_limit;
+ }
+ FX_FLOAT approximation_scale() const
+ {
+ return m_approx_scale;
+ }
+ void remove_all();
+ void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd);
+ void rewind(unsigned path_id);
+ unsigned vertex(FX_FLOAT* x, FX_FLOAT* y);
+private:
+ vcgen_stroke(const vcgen_stroke&);
+ const vcgen_stroke& operator = (const vcgen_stroke&);
+ vertex_storage m_src_vertices;
+ coord_storage m_out_vertices;
+ FX_FLOAT m_width;
+ FX_FLOAT m_miter_limit;
+ FX_FLOAT m_inner_miter_limit;
+ FX_FLOAT m_approx_scale;
+ line_cap_e m_line_cap;
+ line_join_e m_line_join;
+ inner_join_e m_inner_join;
+ unsigned m_closed;
+ status_e m_status;
+ status_e m_prev_status;
+ unsigned m_src_vertex;
+ unsigned m_out_vertex;
+};
+}
+#endif
diff --git a/third_party/agg23/agg_vertex_sequence.h b/third_party/agg23/agg_vertex_sequence.h
new file mode 100644
index 0000000000..6600bf2085
--- /dev/null
+++ b/third_party/agg23/agg_vertex_sequence.h
@@ -0,0 +1,100 @@
+
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.3
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//----------------------------------------------------------------------------
+//
+// vertex_sequence container and vertex_dist struct
+//
+//----------------------------------------------------------------------------
+#ifndef AGG_VERTEX_SEQUENCE_INCLUDED
+#define AGG_VERTEX_SEQUENCE_INCLUDED
+#include "agg_basics.h"
+#include "agg_array.h"
+#include "agg_math.h"
+namespace agg
+{
+template<class T, unsigned S = 6>
+class vertex_sequence : public pod_deque<T, S>
+{
+public:
+ typedef pod_deque<T, S> base_type;
+ void add(const T& val);
+ void modify_last(const T& val);
+ void close(bool remove_flag);
+};
+template<class T, unsigned S>
+void vertex_sequence<T, S>::add(const T& val)
+{
+ if(base_type::size() > 1) {
+ if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) {
+ base_type::remove_last();
+ }
+ }
+ base_type::add(val);
+}
+template<class T, unsigned S>
+void vertex_sequence<T, S>::modify_last(const T& val)
+{
+ base_type::remove_last();
+ add(val);
+}
+template<class T, unsigned S>
+void vertex_sequence<T, S>::close(bool closed)
+{
+ while(base_type::size() > 1) {
+ if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) {
+ break;
+ }
+ T t = (*this)[base_type::size() - 1];
+ base_type::remove_last();
+ modify_last(t);
+ }
+ if(closed) {
+ while(base_type::size() > 1) {
+ if((*this)[base_type::size() - 1]((*this)[0])) {
+ break;
+ }
+ base_type::remove_last();
+ }
+ }
+}
+const FX_FLOAT vertex_dist_epsilon = 1e-14f;
+struct vertex_dist {
+ FX_FLOAT x;
+ FX_FLOAT y;
+ FX_FLOAT dist;
+ vertex_dist() {}
+ vertex_dist(FX_FLOAT x_, FX_FLOAT y_) :
+ x(x_),
+ y(y_),
+ dist(0)
+ {
+ }
+ bool operator () (const vertex_dist& val)
+ {
+ bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon;
+ return ret;
+ }
+};
+struct vertex_dist_cmd : public vertex_dist {
+ unsigned cmd;
+ vertex_dist_cmd() {}
+ vertex_dist_cmd(FX_FLOAT x_, FX_FLOAT y_, unsigned cmd_) :
+ vertex_dist(x_, y_),
+ cmd(cmd_)
+ {
+ }
+};
+}
+#endif
diff --git a/third_party/third_party.gyp b/third_party/third_party.gyp
index b6978658dd..8538001e7f 100644
--- a/third_party/third_party.gyp
+++ b/third_party/third_party.gyp
@@ -21,6 +21,33 @@
],
},
{
+ 'target_name': 'fx_agg',
+ 'type': 'static_library',
+ 'sources': [
+ 'agg23/agg_basics.h',
+ 'agg23/agg_clip_liang_barsky.h',
+ 'agg23/agg_conv_dash.h',
+ 'agg23/agg_conv_stroke.h',
+ 'agg23/agg_curves.cpp',
+ 'agg23/agg_curves.h',
+ 'agg23/agg_path_storage.cpp',
+ 'agg23/agg_path_storage.h',
+ 'agg23/agg_rasterizer_scanline_aa.cpp',
+ 'agg23/agg_rasterizer_scanline_aa.h',
+ 'agg23/agg_renderer_scanline.h',
+ 'agg23/agg_rendering_buffer.h',
+ 'agg23/agg_scanline_u.h',
+ 'agg23/agg_vcgen_dash.cpp',
+ 'agg23/agg_vcgen_stroke.cpp',
+ ],
+ 'conditions': [
+ ['os_posix==1', {
+ # library contains several enum vs non-enum conditionals.
+ 'cflags': [ '-Wno-extra', ],
+ }],
+ ],
+ },
+ {
'target_name': 'freetype',
'type': 'static_library',
'defines': [