diff options
author | John Abd-El-Malek <jabdelmalek@google.com> | 2014-05-17 22:33:34 -0700 |
---|---|---|
committer | John Abd-El-Malek <jabdelmalek@google.com> | 2014-05-17 22:33:34 -0700 |
commit | 5110c4743751145c4ae1934cd1d83bc6c55bb43f (patch) | |
tree | b141608096b73163182764c25b895d3df4b2c182 /core/src/fxge/agg/agg23 | |
parent | 76b563d2feed92ed328afb1f15e3466a9536b11b (diff) | |
download | pdfium-5110c4743751145c4ae1934cd1d83bc6c55bb43f.tar.xz |
Initial commit.
Diffstat (limited to 'core/src/fxge/agg/agg23')
28 files changed, 6310 insertions, 0 deletions
diff --git a/core/src/fxge/agg/agg23/agg_array.h b/core/src/fxge/agg/agg23/agg_array.h new file mode 100644 index 0000000000..f5680d90fe --- /dev/null +++ b/core/src/fxge/agg/agg23/agg_array.h @@ -0,0 +1,510 @@ + +//---------------------------------------------------------------------------- +// 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 CFX_Object +{ +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 = 0; + m_capacity = 0; + m_array = FX_Alloc(T, full_cap); + if (m_array) { + 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 CFX_Object +{ +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 CFX_Object +{ +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/core/src/fxge/agg/agg23/agg_basics.h b/core/src/fxge/agg/agg23/agg_basics.h new file mode 100644 index 0000000000..a78fed8c23 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object { + 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 : public CFX_Object { + 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 : public CFX_Object { + 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/core/src/fxge/agg/agg23/agg_clip_liang_barsky.h b/core/src/fxge/agg/agg23/agg_clip_liang_barsky.h new file mode 100644 index 0000000000..cfc4c91f60 --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_color_gray.h b/core/src/fxge/agg/agg23/agg_color_gray.h new file mode 100644 index 0000000000..5db7bcaf28 --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_conv_adaptor_vcgen.h b/core/src/fxge/agg/agg23/agg_conv_adaptor_vcgen.h new file mode 100644 index 0000000000..1cf817a1c7 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object { + 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 : public CFX_Object +{ + 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/core/src/fxge/agg/agg23/agg_conv_dash.h b/core/src/fxge/agg/agg23/agg_conv_dash.h new file mode 100644 index 0000000000..63b2019dde --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_conv_stroke.h b/core/src/fxge/agg/agg23/agg_conv_stroke.h new file mode 100644 index 0000000000..5a36bd73bb --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_curves.h b/core/src/fxge/agg/agg23/agg_curves.h new file mode 100644 index 0000000000..5719cbf508 --- /dev/null +++ b/core/src/fxge/agg/agg23/agg_curves.h @@ -0,0 +1,191 @@ + +//---------------------------------------------------------------------------- +// 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 : public CFX_Object { + 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 CFX_Object +{ +public: + curve4_div() : + m_cusp_limit(0), + 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_cusp_limit(0), + 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; + FX_FLOAT m_cusp_limit; + unsigned m_count; + pod_deque<point_type> m_points; +}; +class curve4 : public CFX_Object +{ +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/core/src/fxge/agg/agg23/agg_math.h b/core/src/fxge/agg/agg23/agg_math.h new file mode 100644 index 0000000000..31e0daf3bb --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_math_stroke.h b/core/src/fxge/agg/agg23/agg_math_stroke.h new file mode 100644 index 0000000000..620d675312 --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_path_storage.h b/core/src/fxge/agg/agg23/agg_path_storage.h new file mode 100644 index 0000000000..64ea0b4753 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object +{ + 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 CFX_Object + { + 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/core/src/fxge/agg/agg23/agg_pixfmt_gray.h b/core/src/fxge/agg/agg23/agg_pixfmt_gray.h new file mode 100644 index 0000000000..052a2e35d8 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object { + 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 CFX_Object +{ +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/core/src/fxge/agg/agg23/agg_rasterizer_scanline_aa.h b/core/src/fxge/agg/agg23/agg_rasterizer_scanline_aa.h new file mode 100644 index 0000000000..e9f0defbe8 --- /dev/null +++ b/core/src/fxge/agg/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 "../../../../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 : public CFX_Object { + 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 : public CFX_Object +{ + 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 : public CFX_Object { + 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 CFX_Object +{ +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 : public CFX_Object +{ + 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/core/src/fxge/agg/agg23/agg_render_scanlines.h b/core/src/fxge/agg/agg23/agg_render_scanlines.h new file mode 100644 index 0000000000..0dfd6d259f --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_renderer_base.h b/core/src/fxge/agg/agg23/agg_renderer_base.h new file mode 100644 index 0000000000..3e20a6d408 --- /dev/null +++ b/core/src/fxge/agg/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 CFX_Object +{ +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/core/src/fxge/agg/agg23/agg_renderer_scanline.h b/core/src/fxge/agg/agg23/agg_renderer_scanline.h new file mode 100644 index 0000000000..b02b6b5f66 --- /dev/null +++ b/core/src/fxge/agg/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 CFX_Object +{ +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/core/src/fxge/agg/agg23/agg_rendering_buffer.h b/core/src/fxge/agg/agg23/agg_rendering_buffer.h new file mode 100644 index 0000000000..5a8681b537 --- /dev/null +++ b/core/src/fxge/agg/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 CFX_Object +{ +public: + struct row_data : public CFX_Object { + 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 : public CFX_Object { + 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/core/src/fxge/agg/agg23/agg_scanline_u.h b/core/src/fxge/agg/agg23/agg_scanline_u.h new file mode 100644 index 0000000000..f99feef91c --- /dev/null +++ b/core/src/fxge/agg/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 CFX_Object +{ +public: + typedef scanline_u<CoverT> self_type; + typedef CoverT cover_type; + typedef int16 coord_type; + struct span : public CFX_Object { + 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_memset8(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/core/src/fxge/agg/agg23/agg_shorten_path.h b/core/src/fxge/agg/agg23/agg_shorten_path.h new file mode 100644 index 0000000000..d7eb4be018 --- /dev/null +++ b/core/src/fxge/agg/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/core/src/fxge/agg/agg23/agg_vcgen_dash.h b/core/src/fxge/agg/agg23/agg_vcgen_dash.h new file mode 100644 index 0000000000..961da2d718 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object +{ + 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/core/src/fxge/agg/agg23/agg_vcgen_stroke.h b/core/src/fxge/agg/agg23/agg_vcgen_stroke.h new file mode 100644 index 0000000000..38fe1fc25d --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object +{ + 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/core/src/fxge/agg/agg23/agg_vertex_sequence.h b/core/src/fxge/agg/agg23/agg_vertex_sequence.h new file mode 100644 index 0000000000..29486d4787 --- /dev/null +++ b/core/src/fxge/agg/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 : public CFX_Object { + 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/core/src/fxge/agg/agg23/fx_agg_curves.cpp b/core/src/fxge/agg/agg23/fx_agg_curves.cpp new file mode 100644 index 0000000000..861320ee70 --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_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 "../../../../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/core/src/fxge/agg/agg23/fx_agg_driver.cpp b/core/src/fxge/agg/agg23/fx_agg_driver.cpp new file mode 100644 index 0000000000..557f134205 --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_agg_driver.cpp @@ -0,0 +1,1636 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../../include/fxge/fx_ge.h" +#include "../../dib/dib_int.h" +#include "../../ge/text_int.h" +#include "../../../../include/fxcodec/fx_codec.h" +#include "agg_pixfmt_gray.h" +#include "agg_path_storage.h" +#include "agg_scanline_u.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_curves.h" +#include "agg_conv_stroke.h" +#include "agg_conv_dash.h" +using namespace agg; +#include "../include/fx_agg_driver.h" +void _HardClip(FX_FLOAT& x, FX_FLOAT& y) +{ + if (x > 50000) { + x = 50000; + } + if (x < -50000) { + x = -50000; + } + if (y > 50000) { + y = 50000; + } + if (y < -50000) { + y = -50000; + } +} +void CAgg_PathData::BuildPath(const CFX_PathData* pPathData, const CFX_AffineMatrix* pObject2Device) +{ + int nPoints = pPathData->GetPointCount(); + FX_PATHPOINT* pPoints = pPathData->GetPoints(); + for (int i = 0; i < nPoints; i ++) { + FX_FLOAT x = pPoints[i].m_PointX, y = pPoints[i].m_PointY; + if (pObject2Device) { + pObject2Device->Transform(x, y); + } + _HardClip(x, y); + int point_type = pPoints[i].m_Flag & FXPT_TYPE; + if (point_type == FXPT_MOVETO) { + m_PathData.move_to(x, y); + } else if (point_type == FXPT_LINETO) { + if (pPoints[i - 1].m_Flag == FXPT_MOVETO && (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) && + pPoints[i].m_PointX == pPoints[i - 1].m_PointX && pPoints[i].m_PointY == pPoints[i - 1].m_PointY) { + x += 1; + } + m_PathData.line_to(x, y); + } else if (point_type == FXPT_BEZIERTO) { + FX_FLOAT x0 = pPoints[i - 1].m_PointX, y0 = pPoints[i - 1].m_PointY; + FX_FLOAT x2 = pPoints[i + 1].m_PointX, y2 = pPoints[i + 1].m_PointY; + FX_FLOAT x3 = pPoints[i + 2].m_PointX, y3 = pPoints[i + 2].m_PointY; + if (pObject2Device) { + pObject2Device->Transform(x0, y0); + pObject2Device->Transform(x2, y2); + pObject2Device->Transform(x3, y3); + } + curve4 curve(x0, y0, x, y, x2, y2, x3, y3); + i += 2; + m_PathData.add_path_curve(curve); + } + if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) { + m_PathData.end_poly(); + } + } +} +namespace agg +{ +template<class BaseRenderer> class renderer_scanline_aa_offset +{ +public: + typedef BaseRenderer base_ren_type; + typedef typename base_ren_type::color_type color_type; + renderer_scanline_aa_offset(base_ren_type& ren, unsigned left, unsigned top) : + m_ren(&ren), m_left(left), m_top(top) + {} + void color(const color_type& c) + { + m_color = c; + } + const color_type& color() const + { + return m_color; + } + void prepare(unsigned) {} + template<class Scanline> void render(const Scanline& sl) + { + int y = sl.y(); + unsigned num_spans = sl.num_spans(); + typename Scanline::const_iterator span = sl.begin(); + for(;;) { + int x = span->x; + if(span->len > 0) { + m_ren->blend_solid_hspan(x - m_left, y - m_top, (unsigned)span->len, + m_color, + span->covers); + } else { + m_ren->blend_hline(x - m_left, y - m_top, (unsigned)(x - span->len - 1), + m_color, + *(span->covers)); + } + if(--num_spans == 0) { + break; + } + ++span; + } + } +private: + base_ren_type* m_ren; + color_type m_color; + unsigned m_left, m_top; +}; +} +static void RasterizeStroke(rasterizer_scanline_aa& rasterizer, path_storage& path_data, + const CFX_AffineMatrix* pObject2Device, + const CFX_GraphStateData* pGraphState, FX_FLOAT scale = 1.0f, + FX_BOOL bStrokeAdjust = FALSE, FX_BOOL bTextMode = FALSE) +{ + line_cap_e cap; + switch (pGraphState->m_LineCap) { + case CFX_GraphStateData::LineCapRound: + cap = round_cap; + break; + case CFX_GraphStateData::LineCapSquare: + cap = square_cap; + break; + default: + cap = butt_cap; + break; + } + line_join_e join; + switch (pGraphState->m_LineJoin) { + case CFX_GraphStateData::LineJoinRound: + join = round_join; + break; + case CFX_GraphStateData::LineJoinBevel: + join = bevel_join; + break; + default: + join = miter_join_revert; + break; + } + FX_FLOAT width = pGraphState->m_LineWidth * scale; + FX_FLOAT unit = 1.f; + if (pObject2Device) { + unit = FXSYS_Div(1.0f, (pObject2Device->GetXUnit() + pObject2Device->GetYUnit()) / 2); + } + if (width < unit) { + width = unit; + } + if (pGraphState->m_DashArray == NULL) { + conv_stroke<path_storage> stroke(path_data); + stroke.line_join(join); + stroke.line_cap(cap); + stroke.miter_limit(pGraphState->m_MiterLimit); + stroke.width(width); + rasterizer.add_path_transformed(stroke, pObject2Device); + } else { + typedef conv_dash<path_storage> dash_converter; + dash_converter dash(path_data); + for (int i = 0; i < (pGraphState->m_DashCount + 1) / 2; i ++) { + FX_FLOAT on = pGraphState->m_DashArray[i * 2]; + if (on <= 0.000001f) { + on = 1.0f / 10; + } + FX_FLOAT off = i * 2 + 1 == pGraphState->m_DashCount ? on : + pGraphState->m_DashArray[i * 2 + 1]; + if (off < 0) { + off = 0; + } + dash.add_dash(on * scale, off * scale); + } + dash.dash_start(pGraphState->m_DashPhase * scale); + typedef conv_stroke<dash_converter> dash_stroke; + dash_stroke stroke(dash); + stroke.line_join(join); + stroke.line_cap(cap); + stroke.miter_limit(pGraphState->m_MiterLimit); + stroke.width(width); + rasterizer.add_path_transformed(stroke, pObject2Device); + } +} +IFX_RenderDeviceDriver* IFX_RenderDeviceDriver::CreateFxgeDriver(CFX_DIBitmap* pBitmap, FX_BOOL bRgbByteOrder, CFX_DIBitmap* pOriDevice, FX_BOOL bGroupKnockout) +{ + return FX_NEW CFX_AggDeviceDriver(pBitmap, 0, bRgbByteOrder, pOriDevice, bGroupKnockout); +} +CFX_AggDeviceDriver::CFX_AggDeviceDriver(CFX_DIBitmap* pBitmap, int dither_bits, FX_BOOL bRgbByteOrder, CFX_DIBitmap* pOriDevice, FX_BOOL bGroupKnockout) +{ + m_pBitmap = pBitmap; + m_DitherBits = dither_bits; + m_pClipRgn = NULL; + m_pPlatformBitmap = NULL; + m_pPlatformGraphics = NULL; + m_pDwRenderTartget = NULL; + m_bRgbByteOrder = bRgbByteOrder; + m_pOriDevice = pOriDevice; + m_bGroupKnockout = bGroupKnockout; + m_FillFlags = 0; + InitPlatform(); +} +CFX_AggDeviceDriver::~CFX_AggDeviceDriver() +{ + if (m_pClipRgn) { + delete m_pClipRgn; + } + for (int i = 0; i < m_StateStack.GetSize(); i ++) + if (m_StateStack[i]) { + delete (CFX_ClipRgn*)m_StateStack[i]; + } + DestroyPlatform(); +} +#if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_)) +void CFX_AggDeviceDriver::InitPlatform() +{ +} +void CFX_AggDeviceDriver::DestroyPlatform() +{ +} +FX_BOOL CFX_AggDeviceDriver::DrawDeviceText(int nChars, const FXTEXT_CHARPOS* pCharPos, CFX_Font* pFont, + CFX_FontCache* pCache, const CFX_AffineMatrix* pObject2Device, FX_FLOAT font_size, FX_DWORD color, + int alpha_flag, void* pIccTransform) +{ + return FALSE; +} +#endif +int CFX_AggDeviceDriver::GetDeviceCaps(int caps_id) +{ + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return FXDC_DISPLAY; + case FXDC_PIXEL_WIDTH: + return m_pBitmap->GetWidth(); + case FXDC_PIXEL_HEIGHT: + return m_pBitmap->GetHeight(); + case FXDC_BITS_PIXEL: + return m_pBitmap->GetBPP(); + case FXDC_HORZ_SIZE: + case FXDC_VERT_SIZE: + return 0; + case FXDC_RENDER_CAPS: { + int flags = FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | FXRC_BLEND_MODE | FXRC_SOFT_CLIP; + if (m_pBitmap->HasAlpha()) { + flags |= FXRC_ALPHA_OUTPUT; + } else if (m_pBitmap->IsAlphaMask()) { + if (m_pBitmap->GetBPP() == 1) { + flags |= FXRC_BITMASK_OUTPUT; + } else { + flags |= FXRC_BYTEMASK_OUTPUT; + } + } + if (m_pBitmap->IsCmykImage()) { + flags |= FXRC_CMYK_OUTPUT; + } + return flags; + } + case FXDC_DITHER_BITS: + return m_DitherBits; + } + return 0; +} +void CFX_AggDeviceDriver::SaveState() +{ + void* pClip = NULL; + if (m_pClipRgn) { + pClip = FX_NEW CFX_ClipRgn(*m_pClipRgn); + if (!pClip) { + return; + } + } + m_StateStack.Add(pClip); +} +void CFX_AggDeviceDriver::RestoreState(FX_BOOL bKeepSaved) +{ + if (m_StateStack.GetSize() == 0) { + if (m_pClipRgn) { + delete m_pClipRgn; + m_pClipRgn = NULL; + } + return; + } + CFX_ClipRgn* pSavedClip = (CFX_ClipRgn*)m_StateStack[m_StateStack.GetSize() - 1]; + if (m_pClipRgn) { + delete m_pClipRgn; + m_pClipRgn = NULL; + } + if (bKeepSaved) { + if (pSavedClip) { + m_pClipRgn = FX_NEW CFX_ClipRgn(*pSavedClip); + } + } else { + m_StateStack.RemoveAt(m_StateStack.GetSize() - 1); + m_pClipRgn = pSavedClip; + } +} +void CFX_AggDeviceDriver::SetClipMask(rasterizer_scanline_aa& rasterizer) +{ + FX_RECT path_rect(rasterizer.min_x(), rasterizer.min_y(), + rasterizer.max_x() + 1, rasterizer.max_y() + 1); + path_rect.Intersect(m_pClipRgn->GetBox()); + CFX_DIBitmapRef mask; + CFX_DIBitmap* pThisLayer = mask.New(); + if (!pThisLayer) { + return; + } + pThisLayer->Create(path_rect.Width(), path_rect.Height(), FXDIB_8bppMask); + pThisLayer->Clear(0); + rendering_buffer raw_buf(pThisLayer->GetBuffer(), pThisLayer->GetWidth(), pThisLayer->GetHeight(), pThisLayer->GetPitch()); + pixfmt_gray8 pixel_buf(raw_buf); + renderer_base<pixfmt_gray8> base_buf(pixel_buf); + renderer_scanline_aa_offset<renderer_base<pixfmt_gray8> > final_render(base_buf, path_rect.left, path_rect.top); + final_render.color(gray8(255)); + scanline_u8 scanline; + render_scanlines(rasterizer, scanline, final_render, (m_FillFlags & FXFILL_NOPATHSMOOTH) != 0); + m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top, mask); +} +FX_BOOL CFX_AggDeviceDriver::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_AffineMatrix* pObject2Device, + int fill_mode + ) +{ + m_FillFlags = fill_mode; + if (m_pClipRgn == NULL) { + m_pClipRgn = FX_NEW CFX_ClipRgn(GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + if (!m_pClipRgn) { + return FALSE; + } + } + if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) { + CFX_FloatRect rectf; + if (pPathData->IsRect(pObject2Device, &rectf)) { + rectf.Intersect(CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + FX_RECT rect = rectf.GetOutterRect(); + m_pClipRgn->IntersectRect(rect); + return TRUE; + } + } + CAgg_PathData path_data; + path_data.BuildPath(pPathData, pObject2Device); + path_data.m_PathData.end_poly(); + rasterizer_scanline_aa rasterizer; + rasterizer.clip_box(0.0f, 0.0f, (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_WIDTH)), (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + rasterizer.add_path(path_data.m_PathData); + rasterizer.filling_rule((fill_mode & 3) == FXFILL_WINDING ? fill_non_zero : fill_even_odd); + SetClipMask(rasterizer); + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_AffineMatrix* pObject2Device, + const CFX_GraphStateData* pGraphState + ) +{ + if (m_pClipRgn == NULL) { + m_pClipRgn = FX_NEW CFX_ClipRgn(GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + if (!m_pClipRgn) { + return FALSE; + } + } + CAgg_PathData path_data; + path_data.BuildPath(pPathData, NULL); + rasterizer_scanline_aa rasterizer; + rasterizer.clip_box(0.0f, 0.0f, (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_WIDTH)), (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + RasterizeStroke(rasterizer, path_data.m_PathData, pObject2Device, pGraphState); + rasterizer.filling_rule(fill_non_zero); + SetClipMask(rasterizer); + return TRUE; +} +class CFX_Renderer : public CFX_Object +{ +private: + int m_Alpha, + m_Red, + m_Green, + m_Blue, + m_Gray; + FX_DWORD m_Color; + FX_BOOL m_bFullCover; + FX_BOOL m_bRgbByteOrder; + CFX_DIBitmap* m_pOriDevice; + FX_RECT m_ClipBox; + const CFX_DIBitmap* m_pClipMask; + CFX_DIBitmap* m_pDevice; + const CFX_ClipRgn* m_pClipRgn; + void (CFX_Renderer::*composite_span)(FX_LPBYTE, int, int, int, FX_LPBYTE, int, int, FX_LPBYTE, FX_LPBYTE); +public: + void prepare(unsigned) {} + void CompositeSpan(FX_LPBYTE dest_scan, FX_LPBYTE ori_scan, int Bpp, FX_BOOL bDestAlpha, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan) + { + ASSERT(!m_pDevice->IsCmykImage()); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + if (Bpp) { + dest_scan += col_start * Bpp; + ori_scan += col_start * Bpp; + } else { + dest_scan += col_start / 8; + ori_scan += col_start / 8; + } + if (m_bRgbByteOrder) { + if (Bpp == 4 && bDestAlpha) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + FX_BYTE dest_alpha = ori_scan[3] + src_alpha - ori_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (m_bFullCover) { + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, alpha_ratio); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, alpha_ratio); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, alpha_ratio); + dest_scan++; + ori_scan++; + } else { + int r = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, alpha_ratio); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, alpha_ratio); + int b = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, alpha_ratio); + ori_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE( *dest_scan, r, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]); + dest_scan += 2; + } + } + return; + } else if (Bpp == 3 || Bpp == 4) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255 ; + } else { + src_alpha = m_Alpha; + } + int r = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, src_alpha); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + int b = FXDIB_ALPHA_MERGE(*ori_scan, m_Blue, src_alpha); + ori_scan += Bpp - 2; + *dest_scan = FXDIB_ALPHA_MERGE( *dest_scan, r, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]); + dest_scan += Bpp - 2; + } + } + return; + } + if (Bpp == 4 && bDestAlpha) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + int src_alpha_covered = src_alpha * cover_scan[col] / 255; + if (src_alpha_covered == 0) { + dest_scan += 4; + continue; + } + if (cover_scan[col] == 255) { + dest_scan[3] = src_alpha_covered; + *dest_scan ++ = m_Blue; + *dest_scan ++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } else { + if (dest_scan[3] == 0) { + dest_scan[3] = src_alpha_covered; + *dest_scan ++ = m_Blue; + *dest_scan ++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } + FX_BYTE cover = cover_scan[col]; + dest_scan[3] = FXDIB_ALPHA_MERGE(dest_scan[3], src_alpha, cover); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, cover); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, cover); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, cover); + dest_scan += 2; + } + } + return; + } else if (Bpp == 3 || Bpp == 4) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + if (m_bFullCover) { + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, src_alpha); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*ori_scan, m_Red, src_alpha); + dest_scan += Bpp - 2; + ori_scan += Bpp - 2; + continue; + } + int b = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, src_alpha); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + int r = FXDIB_ALPHA_MERGE(*ori_scan, m_Red, src_alpha); + ori_scan += Bpp - 2; + *dest_scan = FXDIB_ALPHA_MERGE( *dest_scan, b, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]); + dest_scan += Bpp - 2; + continue; + } + return; + } else if (Bpp == 1) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + if (m_bFullCover) { + *dest_scan = FXDIB_ALPHA_MERGE(*ori_scan++, m_Gray, src_alpha); + } else { + int gray = FXDIB_ALPHA_MERGE(*ori_scan++, m_Gray, src_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, cover_scan[col]); + dest_scan++; + } + } + } else { + int index = 0; + if (m_pDevice->GetPalette() == NULL) { + index = ((FX_BYTE)m_Color == 0xff) ? 1 : 0; + } else { + for (int i = 0; i < 2; i ++) + if (FXARGB_TODIB(m_pDevice->GetPalette()[i]) == m_Color) { + index = i; + } + } + FX_LPBYTE dest_scan1 = dest_scan; + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (!index) { + *dest_scan1 &= ~(1 << (7 - (col + span_left) % 8)); + } else { + *dest_scan1 |= 1 << (7 - (col + span_left) % 8); + } + } + dest_scan1 = dest_scan + (span_left % 8 + col - col_start + 1) / 8; + } + } + } + void CompositeSpan1bpp(FX_LPBYTE dest_scan, int Bpp, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan, + FX_LPBYTE dest_extra_alpha_scan) + { + ASSERT(!m_bRgbByteOrder); + ASSERT(!m_pDevice->IsCmykImage()); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + dest_scan += col_start / 8; + int index = 0; + if (m_pDevice->GetPalette() == NULL) { + index = ((FX_BYTE)m_Color == 0xff) ? 1 : 0; + } else { + for (int i = 0; i < 2; i ++) + if (FXARGB_TODIB(m_pDevice->GetPalette()[i]) == m_Color) { + index = i; + } + } + FX_LPBYTE dest_scan1 = dest_scan; + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (!index) { + *dest_scan1 &= ~(1 << (7 - (col + span_left) % 8)); + } else { + *dest_scan1 |= 1 << (7 - (col + span_left) % 8); + } + } + dest_scan1 = dest_scan + (span_left % 8 + col - col_start + 1) / 8; + } + } + void CompositeSpanGray(FX_LPBYTE dest_scan, int Bpp, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan, + FX_LPBYTE dest_extra_alpha_scan) + { + ASSERT(!m_bRgbByteOrder); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + dest_scan += col_start; + Bpp; + if (dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan = m_Gray; + *dest_extra_alpha_scan = m_Alpha; + } else { + FX_BYTE dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, alpha_ratio); + dest_scan ++; + continue; + } + } + dest_extra_alpha_scan ++; + dest_scan ++; + } + } else { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan = m_Gray; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, src_alpha); + } + } + dest_scan ++; + } + } + } + void CompositeSpanARGB(FX_LPBYTE dest_scan, int Bpp, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan, + FX_LPBYTE dest_extra_alpha_scan) + { + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + dest_scan += col_start * Bpp; + if (m_bRgbByteOrder) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_DWORD*)dest_scan = m_Color; + } else { + FX_BYTE dest_alpha = dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan += 2; + continue; + } + } + dest_scan += 4; + } + return; + } + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_DWORD*)dest_scan = m_Color; + } else { + if (dest_scan[3] == 0) { + dest_scan[3] = src_alpha; + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } + FX_BYTE dest_alpha = dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan += 2; + continue; + } + } + dest_scan += Bpp; + } + } + void CompositeSpanRGB(FX_LPBYTE dest_scan, int Bpp, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan, + FX_LPBYTE dest_extra_alpha_scan) + { + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + dest_scan += col_start * Bpp; + if (m_bRgbByteOrder) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + if (Bpp == 4) { + *(FX_DWORD*)dest_scan = m_Color; + } else if (Bpp == 3) { + *dest_scan++ = m_Red; + *dest_scan++ = m_Green; + *dest_scan++ = m_Blue; + continue; + } + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan += Bpp - 2; + continue; + } + } + dest_scan += Bpp; + } + return; + } + if (Bpp == 3 && dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan++ = (FX_BYTE)m_Blue; + *dest_scan++ = (FX_BYTE)m_Green; + *dest_scan++ = (FX_BYTE)m_Red; + *dest_extra_alpha_scan++ = (FX_BYTE)m_Alpha; + continue; + } else { + FX_BYTE dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan ++; + continue; + } + } + dest_extra_alpha_scan++; + dest_scan += Bpp; + } + } else { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + if (Bpp == 4) { + *(FX_DWORD*)dest_scan = m_Color; + } else if (Bpp == 3) { + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan++ = m_Red; + continue; + } + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan += Bpp - 2; + continue; + } + } + dest_scan += Bpp; + } + } + } + void CompositeSpanCMYK(FX_LPBYTE dest_scan, int Bpp, + int span_left, int span_len, FX_LPBYTE cover_scan, + int clip_left, int clip_right, FX_LPBYTE clip_scan, + FX_LPBYTE dest_extra_alpha_scan) + { + ASSERT(!m_bRgbByteOrder); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right ? span_len : (clip_right - span_left); + dest_scan += col_start * 4; + Bpp; + if (dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_CMYK*)dest_scan = m_Color; + *dest_extra_alpha_scan = (FX_BYTE)m_Alpha; + } else { + FX_BYTE dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, alpha_ratio); + dest_scan ++; + continue; + } + } + dest_extra_alpha_scan++; + dest_scan += 4; + } + } else { + for (int col = col_start; col < col_end; col ++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_CMYK*)dest_scan = m_Color; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan ++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, src_alpha); + dest_scan ++; + continue; + } + } + dest_scan += 4; + } + } + } + template<class Scanline> void render(const Scanline& sl) + { + if (m_pOriDevice == NULL && composite_span == NULL) { + return; + } + int y = sl.y(); + if (y < m_ClipBox.top || y >= m_ClipBox.bottom) { + return; + } + FX_LPBYTE dest_scan = m_pDevice->GetBuffer() + m_pDevice->GetPitch() * y; + FX_LPBYTE dest_scan_extra_alpha = NULL; + CFX_DIBitmap* pAlphaMask = m_pDevice->m_pAlphaMask; + if (pAlphaMask) { + dest_scan_extra_alpha = pAlphaMask->GetBuffer() + pAlphaMask->GetPitch() * y; + } + FX_LPBYTE ori_scan = NULL; + if (m_pOriDevice) { + ori_scan = m_pOriDevice->GetBuffer() + m_pOriDevice->GetPitch() * y; + } + int Bpp = m_pDevice->GetBPP() / 8; + FX_BOOL bDestAlpha = m_pDevice->HasAlpha() || m_pDevice->IsAlphaMask(); + unsigned num_spans = sl.num_spans(); + typename Scanline::const_iterator span = sl.begin(); + while (1) { + int x = span->x; + ASSERT(span->len > 0); + FX_LPBYTE dest_pos = NULL; + FX_LPBYTE dest_extra_alpha_pos = NULL; + FX_LPBYTE ori_pos = NULL; + if (Bpp) { + ori_pos = ori_scan ? ori_scan + x * Bpp : NULL; + dest_pos = dest_scan + x * Bpp; + dest_extra_alpha_pos = dest_scan_extra_alpha ? dest_scan_extra_alpha + x : NULL; + } else { + dest_pos = dest_scan + x / 8; + ori_pos = ori_scan ? ori_scan + x / 8 : NULL; + } + FX_LPBYTE clip_pos = NULL; + if (m_pClipMask) { + clip_pos = m_pClipMask->GetBuffer() + (y - m_ClipBox.top) * m_pClipMask->GetPitch() + x - m_ClipBox.left; + } + if (ori_pos) { + CompositeSpan(dest_pos, ori_pos, Bpp, bDestAlpha, x, span->len, span->covers, m_ClipBox.left, m_ClipBox.right, clip_pos); + } else { + (this->*composite_span)(dest_pos, Bpp, x, span->len, span->covers, m_ClipBox.left, m_ClipBox.right, clip_pos, dest_extra_alpha_pos); + } + if(--num_spans == 0) { + break; + } + ++span; + } + } + + FX_BOOL Init(CFX_DIBitmap* pDevice, CFX_DIBitmap* pOriDevice, const CFX_ClipRgn* pClipRgn, FX_DWORD color, FX_BOOL bFullCover, FX_BOOL bRgbByteOrder, + int alpha_flag = 0, void* pIccTransform = NULL) + { + m_pDevice = pDevice; + m_pClipRgn = pClipRgn; + composite_span = NULL; + m_bRgbByteOrder = bRgbByteOrder; + m_pOriDevice = pOriDevice; + if (m_pClipRgn) { + m_ClipBox = m_pClipRgn->GetBox(); + } else { + m_ClipBox.left = m_ClipBox.top = 0; + m_ClipBox.right = m_pDevice->GetWidth(); + m_ClipBox.bottom = m_pDevice->GetHeight(); + } + m_pClipMask = NULL; + if (m_pClipRgn && m_pClipRgn->GetType() == CFX_ClipRgn::MaskF) { + m_pClipMask = m_pClipRgn->GetMask(); + } + m_bFullCover = bFullCover; + FX_BOOL bObjectCMYK = FXGETFLAG_COLORTYPE(alpha_flag); + FX_BOOL bDeviceCMYK = pDevice->IsCmykImage(); + m_Alpha = bObjectCMYK ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color); + ICodec_IccModule* pIccModule = NULL; + if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } else { + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + } + if (m_pDevice->GetBPP() == 8) { + ASSERT(!m_bRgbByteOrder); + composite_span = &CFX_Renderer::CompositeSpanGray; + if (m_pDevice->IsAlphaMask()) { + m_Gray = 255; + } else { + if (pIccTransform) { + FX_BYTE gray; + color = bObjectCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, &gray, (FX_LPCBYTE)&color, 1); + m_Gray = gray; + } else { + if (bObjectCMYK) { + FX_BYTE r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), FXSYS_GetYValue(color), FXSYS_GetKValue(color), + r, g, b); + m_Gray = FXRGB2GRAY(r, g, b); + } else { + m_Gray = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color)); + } + } + } + return TRUE; + } + if (bDeviceCMYK) { + ASSERT(!m_bRgbByteOrder); + composite_span = &CFX_Renderer::CompositeSpanCMYK; + if (bObjectCMYK) { + m_Color = FXCMYK_TODIB(color); + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&m_Color, (FX_LPCBYTE)&m_Color, 1); + } + } else { + if (!pIccTransform) { + return FALSE; + } + color = FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&m_Color, (FX_LPCBYTE)&color, 1); + } + m_Red = ((FX_LPBYTE)&m_Color)[0]; + m_Green = ((FX_LPBYTE)&m_Color)[1]; + m_Blue = ((FX_LPBYTE)&m_Color)[2]; + m_Gray = ((FX_LPBYTE)&m_Color)[3]; + } else { + composite_span = (pDevice->GetFormat() == FXDIB_Argb) ? &CFX_Renderer::CompositeSpanARGB : &CFX_Renderer::CompositeSpanRGB; + if (pIccTransform) { + color = bObjectCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&m_Color, (FX_LPCBYTE)&color, 1); + ((FX_LPBYTE)&m_Color)[3] = m_Alpha; + m_Red = ((FX_LPBYTE)&m_Color)[2]; + m_Green = ((FX_LPBYTE)&m_Color)[1]; + m_Blue = ((FX_LPBYTE)&m_Color)[0]; + if (m_bRgbByteOrder) { + m_Color = FXARGB_TODIB(m_Color); + m_Color = FXARGB_TOBGRORDERDIB(m_Color); + } + } else { + if (bObjectCMYK) { + FX_BYTE r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), FXSYS_GetYValue(color), FXSYS_GetKValue(color), + r, g, b); + m_Color = FXARGB_MAKE(m_Alpha, r, g, b); + if (m_bRgbByteOrder) { + m_Color = FXARGB_TOBGRORDERDIB(m_Color); + } else { + m_Color = FXARGB_TODIB(m_Color); + } + m_Red = r; + m_Green = g; + m_Blue = b; + } else { + if (m_bRgbByteOrder) { + m_Color = FXARGB_TOBGRORDERDIB(color); + } else { + m_Color = FXARGB_TODIB(color); + } + ArgbDecode(color, m_Alpha, m_Red, m_Green, m_Blue); + } + } + } + if (m_pDevice->GetBPP() == 1) { + composite_span = &CFX_Renderer::CompositeSpan1bpp; + } + return TRUE; + } +}; +FX_BOOL CFX_AggDeviceDriver::RenderRasterizer(rasterizer_scanline_aa& rasterizer, FX_DWORD color, FX_BOOL bFullCover, FX_BOOL bGroupKnockout, + int alpha_flag, void* pIccTransform) +{ + CFX_DIBitmap* pt = bGroupKnockout ? m_pOriDevice : NULL; + CFX_Renderer render; + if (!render.Init(m_pBitmap, pt, m_pClipRgn, color, bFullCover, m_bRgbByteOrder, alpha_flag, pIccTransform)) { + return FALSE; + } + scanline_u8 scanline; + render_scanlines(rasterizer, scanline, render, (m_FillFlags & FXFILL_NOPATHSMOOTH) != 0); + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::DrawPath(const CFX_PathData* pPathData, + const CFX_AffineMatrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type + ) +{ + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + if (GetBuffer() == NULL) { + return TRUE; + } + m_FillFlags = fill_mode; + if ((fill_mode & 3) && fill_color) { + CAgg_PathData path_data; + path_data.BuildPath(pPathData, pObject2Device); + rasterizer_scanline_aa rasterizer; + rasterizer.clip_box(0.0f, 0.0f, (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_WIDTH)), (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + rasterizer.add_path(path_data.m_PathData); + rasterizer.filling_rule((fill_mode & 3) == FXFILL_WINDING ? fill_non_zero : fill_even_odd); + if (!RenderRasterizer(rasterizer, fill_color, fill_mode & FXFILL_FULLCOVER, FALSE, alpha_flag, pIccTransform)) { + return FALSE; + } + } + int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_STROKE(alpha_flag) : FXARGB_A(stroke_color); + if (pGraphState && stroke_alpha) { + if (fill_mode & FX_ZEROAREA_FILL) { + CAgg_PathData path_data; + path_data.BuildPath(pPathData, pObject2Device); + rasterizer_scanline_aa rasterizer; + rasterizer.clip_box(0.0f, 0.0f, (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_WIDTH)), (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + RasterizeStroke(rasterizer, path_data.m_PathData, NULL, pGraphState, 1, FALSE, fill_mode & FX_STROKE_TEXT_MODE); + int fill_flag = FXGETFLAG_COLORTYPE(alpha_flag) << 8 | FXGETFLAG_ALPHA_STROKE(alpha_flag); + if (!RenderRasterizer(rasterizer, stroke_color, fill_mode & FXFILL_FULLCOVER, m_bGroupKnockout, fill_flag, pIccTransform)) { + return FALSE; + } + return TRUE; + } + CFX_AffineMatrix matrix1, matrix2; + if (pObject2Device) { + matrix1.a = FX_MAX(FXSYS_fabs(pObject2Device->a), FXSYS_fabs(pObject2Device->b)); + matrix1.d = matrix1.a; + matrix2.Set(pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a, + pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d, + 0, 0); + CFX_AffineMatrix mtRervese; + mtRervese.SetReverse(matrix2); + matrix1 = *pObject2Device; + matrix1.Concat(mtRervese); + } + CAgg_PathData path_data; + path_data.BuildPath(pPathData, &matrix1); + rasterizer_scanline_aa rasterizer; + rasterizer.clip_box(0.0f, 0.0f, (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_WIDTH)), (FX_FLOAT)(GetDeviceCaps(FXDC_PIXEL_HEIGHT))); + RasterizeStroke(rasterizer, path_data.m_PathData, &matrix2, pGraphState, matrix1.a, FALSE, fill_mode & FX_STROKE_TEXT_MODE); + int fill_flag = FXGETFLAG_COLORTYPE(alpha_flag) << 8 | FXGETFLAG_ALPHA_STROKE(alpha_flag); + if (!RenderRasterizer(rasterizer, stroke_color, fill_mode & FXFILL_FULLCOVER, m_bGroupKnockout, fill_flag, pIccTransform)) { + return FALSE; + } + } + return TRUE; +} +void RgbByteOrderSetPixel(CFX_DIBitmap* pBitmap, int x, int y, FX_DWORD argb) +{ + if (x < 0 || x >= pBitmap->GetWidth() || y < 0 || y >= pBitmap->GetHeight()) { + return; + } + FX_LPBYTE pos = (FX_BYTE*)pBitmap->GetBuffer() + y * pBitmap->GetPitch() + x * pBitmap->GetBPP() / 8; + if (pBitmap->GetFormat() == FXDIB_Argb) { + FXARGB_SETRGBORDERDIB(pos, ArgbGamma(argb)); + } else { + int alpha = FXARGB_A(argb); + pos[0] = (FXARGB_R(argb) * alpha + pos[0] * (255 - alpha)) / 255; + pos[1] = (FXARGB_G(argb) * alpha + pos[1] * (255 - alpha)) / 255; + pos[2] = (FXARGB_B(argb) * alpha + pos[2] * (255 - alpha)) / 255; + } +} +void RgbByteOrderCompositeRect(CFX_DIBitmap* pBitmap, int left, int top, int width, int height, FX_ARGB argb) +{ + int src_alpha = FXARGB_A(argb); + if (src_alpha == 0) { + return; + } + FX_RECT rect(left, top, left + width, top + height); + rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); + width = rect.Width(); + int src_r = FXARGB_R(argb), src_g = FXARGB_G(argb), src_b = FXARGB_B(argb); + int Bpp = pBitmap->GetBPP() / 8; + FX_BOOL bAlpha = pBitmap->HasAlpha(); + int dib_argb = FXARGB_TOBGRORDERDIB(argb); + FX_BYTE* pBuffer = pBitmap->GetBuffer(); + if (src_alpha == 255) { + for (int row = rect.top; row < rect.bottom; row ++) { + FX_LPBYTE dest_scan = pBuffer + row * pBitmap->GetPitch() + rect.left * Bpp; + if (Bpp == 4) { + FX_DWORD* scan = (FX_DWORD*)dest_scan; + for (int col = 0; col < width; col ++) { + *scan ++ = dib_argb; + } + } else { + for (int col = 0; col < width; col ++) { + *dest_scan ++ = src_r; + *dest_scan ++ = src_g; + *dest_scan ++ = src_b; + } + } + } + return; + } + src_r = FX_GAMMA(src_r); + src_g = FX_GAMMA(src_g); + src_b = FX_GAMMA(src_b); + for (int row = rect.top; row < rect.bottom; row ++) { + FX_LPBYTE dest_scan = pBuffer + row * pBitmap->GetPitch() + rect.left * Bpp; + if (bAlpha) { + for (int col = 0; col < width; col ++) { + FX_BYTE back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + dest_scan += 4; + continue; + } + FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan += 2; + } + } else { + for (int col = 0; col < width; col ++) { + *dest_scan = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(*dest_scan), src_r, src_alpha)); + dest_scan++; + *dest_scan = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(*dest_scan), src_g, src_alpha)); + dest_scan++; + *dest_scan = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(*dest_scan), src_b, src_alpha)); + dest_scan++; + if (Bpp == 4) { + dest_scan++; + } + } + } + } +} +void RgbByteOrderTransferBitmap(CFX_DIBitmap* pBitmap, int dest_left, int dest_top, int width, int height, + const CFX_DIBSource* pSrcBitmap, int src_left, int src_top) +{ + if (pBitmap == NULL) { + return; + } + pBitmap->GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left, src_top, NULL); + if (width == 0 || height == 0) { + return; + } + int Bpp = pBitmap->GetBPP() / 8; + FXDIB_Format dest_format = pBitmap->GetFormat(); + FXDIB_Format src_format = pSrcBitmap->GetFormat(); + int pitch = pBitmap->GetPitch(); + FX_BYTE* buffer = pBitmap->GetBuffer(); + if (dest_format == src_format) { + for (int row = 0; row < height; row ++) { + FX_LPBYTE dest_scan = buffer + (dest_top + row) * pitch + dest_left * Bpp; + FX_LPBYTE src_scan = (FX_LPBYTE)pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp; + if (Bpp == 4) { + for (int col = 0; col < width; col ++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_scan[3], src_scan[0], src_scan[1], src_scan[2])); + dest_scan += 4; + src_scan += 4; + } + } else { + for (int col = 0; col < width; col ++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = src_scan[0]; + src_scan += 3; + } + } + } + return; + } + int src_pitch = pSrcBitmap->GetPitch(); + FX_ARGB* src_pal = pSrcBitmap->GetPalette(); + FX_LPBYTE dest_buf = buffer + dest_top * pitch + dest_left * Bpp; + if (dest_format == FXDIB_Rgb) { + if (src_format == FXDIB_Rgb32) { + for (int row = 0; row < height; row ++) { + FX_LPBYTE dest_scan = dest_buf + row * pitch; + FX_LPBYTE src_scan = (FX_BYTE*)pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col ++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = src_scan[0]; + src_scan += 4; + } + } + } else { + ASSERT(FALSE); + } + } else if (dest_format == FXDIB_Argb || dest_format == FXDIB_Rgb32) { + if (src_format == FXDIB_Rgb) { + for (int row = 0; row < height; row ++) { + FX_BYTE* dest_scan = (FX_BYTE*)(dest_buf + row * pitch); + FX_LPBYTE src_scan = (FX_BYTE*)pSrcBitmap->GetScanline(src_top + row) + src_left * 3; + if (src_format == FXDIB_Argb) { + for (int col = 0; col < width; col ++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, FX_GAMMA(src_scan[0]), FX_GAMMA(src_scan[1]), FX_GAMMA(src_scan[2]))); + dest_scan += 4; + src_scan += 3; + } + } else { + for (int col = 0; col < width; col ++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1], src_scan[2])); + dest_scan += 4; + src_scan += 3; + } + } + } + } else if (src_format == FXDIB_Rgb32) { + ASSERT(dest_format == FXDIB_Argb); + for (int row = 0; row < height; row ++) { + FX_LPBYTE dest_scan = dest_buf + row * pitch; + FX_LPBYTE src_scan = (FX_LPBYTE)(pSrcBitmap->GetScanline(src_top + row) + src_left * 4); + for (int col = 0; col < width; col++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1], src_scan[2])); + src_scan += 4; + dest_scan += 4; + } + } + } + } else { + ASSERT(FALSE); + } +} +FX_ARGB _DefaultCMYK2ARGB(FX_CMYK cmyk, FX_BYTE alpha) +{ + FX_BYTE r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk), + r, g, b); + return ArgbEncode(alpha, r, g, b); +} +FX_BOOL _DibSetPixel(CFX_DIBitmap* pDevice, int x, int y, FX_DWORD color, int alpha_flag, void* pIccTransform) +{ + FX_BOOL bObjCMYK = FXGETFLAG_COLORTYPE(alpha_flag); + int alpha = bObjCMYK ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color); + if (pIccTransform) { + ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + color = bObjCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&color, (FX_LPBYTE)&color, 1); + color = bObjCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + if (!pDevice->IsCmykImage()) { + color = (color & 0xffffff) | (alpha << 24); + } + } else { + if (pDevice->IsCmykImage()) { + if (!bObjCMYK) { + return FALSE; + } + } else { + if (bObjCMYK) { + color = _DefaultCMYK2ARGB(color, alpha); + } + } + } + pDevice->SetPixel(x, y, color); + if (pDevice->m_pAlphaMask) { + pDevice->m_pAlphaMask->SetPixel(x, y, alpha << 24); + } + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::SetPixel(int x, int y, FX_DWORD color, int alpha_flag, void* pIccTransform) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + if (m_pClipRgn == NULL) { + if (m_bRgbByteOrder) { + RgbByteOrderSetPixel(m_pBitmap, x, y, color); + } else { + return _DibSetPixel(m_pBitmap, x, y, color, alpha_flag, pIccTransform); + } + } else if (m_pClipRgn->GetBox().Contains(x, y)) { + if (m_pClipRgn->GetType() == CFX_ClipRgn::RectI) { + if (m_bRgbByteOrder) { + RgbByteOrderSetPixel(m_pBitmap, x, y, color); + } else { + return _DibSetPixel(m_pBitmap, x, y, color, alpha_flag, pIccTransform); + } + } else if (m_pClipRgn->GetType() == CFX_ClipRgn::MaskF) { + const CFX_DIBitmap* pMask = m_pClipRgn->GetMask(); + FX_BOOL bCMYK = FXGETFLAG_COLORTYPE(alpha_flag); + int new_alpha = bCMYK ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color); + new_alpha = new_alpha * pMask->GetScanline(y)[x] / 255; + if (m_bRgbByteOrder) { + RgbByteOrderSetPixel(m_pBitmap, x, y, (color & 0xffffff) | (new_alpha << 24)); + return TRUE; + } + if (bCMYK) { + FXSETFLAG_ALPHA_FILL(alpha_flag, new_alpha); + } else { + color = (color & 0xffffff) | (new_alpha << 24); + } + return _DibSetPixel(m_pBitmap, x, y, color, alpha_flag, pIccTransform); + } + } + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::FillRect(const FX_RECT* pRect, FX_DWORD fill_color, int alpha_flag, void* pIccTransform, int blend_type) +{ + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + FX_RECT clip_rect; + GetClipBox(&clip_rect); + FX_RECT draw_rect = clip_rect; + if (pRect) { + draw_rect.Intersect(*pRect); + } + if (draw_rect.IsEmpty()) { + return TRUE; + } + if (m_pClipRgn == NULL || m_pClipRgn->GetType() == CFX_ClipRgn::RectI) { + if (m_bRgbByteOrder) { + RgbByteOrderCompositeRect(m_pBitmap, draw_rect.left, draw_rect.top, draw_rect.Width(), draw_rect.Height(), fill_color); + } else { + m_pBitmap->CompositeRect(draw_rect.left, draw_rect.top, draw_rect.Width(), draw_rect.Height(), fill_color, alpha_flag, pIccTransform); + } + return TRUE; + } + m_pBitmap->CompositeMask(draw_rect.left, draw_rect.top, draw_rect.Width(), draw_rect.Height(), (const CFX_DIBitmap*)m_pClipRgn->GetMask(), + fill_color, draw_rect.left - clip_rect.left, draw_rect.top - clip_rect.top, FXDIB_BLEND_NORMAL, NULL, m_bRgbByteOrder, alpha_flag, pIccTransform); + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::GetClipBox(FX_RECT* pRect) +{ + if (m_pClipRgn == NULL) { + pRect->left = pRect->top = 0; + pRect->right = GetDeviceCaps(FXDC_PIXEL_WIDTH); + pRect->bottom = GetDeviceCaps(FXDC_PIXEL_HEIGHT); + return TRUE; + } + *pRect = m_pClipRgn->GetBox(); + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top, void* pIccTransform, FX_BOOL bDEdge) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + if (bDEdge) { + if (m_bRgbByteOrder) { + RgbByteOrderTransferBitmap(pBitmap, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight(), m_pBitmap, left, top); + } else { + return pBitmap->TransferBitmap(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight(), m_pBitmap, left, top, pIccTransform); + } + return TRUE; + } + FX_RECT rect(left, top, left + pBitmap->GetWidth(), top + pBitmap->GetHeight()); + CFX_DIBitmap *pBack = NULL; + if (m_pOriDevice) { + pBack = m_pOriDevice->Clone(&rect); + if (!pBack) { + return TRUE; + } + pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(), m_pBitmap, 0, 0); + } else { + pBack = m_pBitmap->Clone(&rect); + } + if (!pBack) { + return TRUE; + } + FX_BOOL bRet = TRUE; + left = left >= 0 ? 0 : left; + top = top >= 0 ? 0 : top; + if (m_bRgbByteOrder) { + RgbByteOrderTransferBitmap(pBitmap, 0, 0, rect.Width(), rect.Height(), pBack, left, top); + } else { + bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack, left, top, pIccTransform); + } + delete pBack; + return bRet; +} +FX_BOOL CFX_AggDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, FX_DWORD argb, const FX_RECT* pSrcRect, int left, int top, int blend_type, + int alpha_flag, void* pIccTransform) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + if (pBitmap->IsAlphaMask()) + return m_pBitmap->CompositeMask(left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, argb, + pSrcRect->left, pSrcRect->top, blend_type, m_pClipRgn, m_bRgbByteOrder, alpha_flag, pIccTransform); + return m_pBitmap->CompositeBitmap(left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, + pSrcRect->left, pSrcRect->top, blend_type, m_pClipRgn, m_bRgbByteOrder, pIccTransform); +} +FX_BOOL CFX_AggDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, FX_DWORD argb, int dest_left, int dest_top, + int dest_width, int dest_height, const FX_RECT* pClipRect, FX_DWORD flags, + int alpha_flag, void* pIccTransform, int blend_type) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + if (dest_width == pSource->GetWidth() && dest_height == pSource->GetHeight()) { + FX_RECT rect(0, 0, dest_width, dest_height); + return SetDIBits(pSource, argb, &rect, dest_left, dest_top, blend_type, alpha_flag, pIccTransform); + } + FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width, dest_top + dest_height); + dest_rect.Normalize(); + FX_RECT dest_clip = dest_rect; + dest_clip.Intersect(*pClipRect); + CFX_BitmapComposer composer; + composer.Compose(m_pBitmap, m_pClipRgn, 255, argb, dest_clip, FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag, pIccTransform, blend_type); + dest_clip.Offset(-dest_rect.left, -dest_rect.top); + CFX_ImageStretcher stretcher; + if (stretcher.Start(&composer, pSource, dest_width, dest_height, dest_clip, flags)) { + stretcher.Continue(NULL); + } + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, int bitmap_alpha, FX_DWORD argb, + const CFX_AffineMatrix* pMatrix, FX_DWORD render_flags, FX_LPVOID& handle, + int alpha_flag, void* pIccTransform, int blend_type) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + CFX_ImageRenderer* pRenderer = FX_NEW CFX_ImageRenderer; + if (!pRenderer) { + return FALSE; + } + pRenderer->Start(m_pBitmap, m_pClipRgn, pSource, bitmap_alpha, argb, pMatrix, render_flags, m_bRgbByteOrder, alpha_flag, pIccTransform); + handle = pRenderer; + return TRUE; +} +FX_BOOL CFX_AggDeviceDriver::ContinueDIBits(FX_LPVOID pHandle, IFX_Pause* pPause) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return TRUE; + } + return ((CFX_ImageRenderer*)pHandle)->Continue(pPause); +} +void CFX_AggDeviceDriver::CancelDIBits(FX_LPVOID pHandle) +{ + if (m_pBitmap->GetBuffer() == NULL) { + return; + } + delete (CFX_ImageRenderer*)pHandle; +} +CFX_FxgeDevice::CFX_FxgeDevice() +{ + m_bOwnedBitmap = FALSE; +} +FX_BOOL CFX_FxgeDevice::Attach(CFX_DIBitmap* pBitmap, int dither_bits, FX_BOOL bRgbByteOrder, CFX_DIBitmap* pOriDevice, FX_BOOL bGroupKnockout) +{ + if (pBitmap == NULL) { + return FALSE; + } + SetBitmap(pBitmap); + IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_AggDeviceDriver(pBitmap, dither_bits, bRgbByteOrder, pOriDevice, bGroupKnockout); + if (!pDriver) { + return FALSE; + } + SetDeviceDriver(pDriver); + return TRUE; +} +FX_BOOL CFX_FxgeDevice::Create(int width, int height, FXDIB_Format format, int dither_bits, CFX_DIBitmap* pOriDevice) +{ + m_bOwnedBitmap = TRUE; + CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap; + if (!pBitmap) { + return FALSE; + } + if (!pBitmap->Create(width, height, format)) { + delete pBitmap; + return FALSE; + } + SetBitmap(pBitmap); + IFX_RenderDeviceDriver* pDriver = FX_NEW CFX_AggDeviceDriver(pBitmap, dither_bits, FALSE, pOriDevice, FALSE); + if (!pDriver) { + return FALSE; + } + SetDeviceDriver(pDriver); + return TRUE; +} +CFX_FxgeDevice::~CFX_FxgeDevice() +{ + if (m_bOwnedBitmap && GetBitmap()) { + delete GetBitmap(); + } +} diff --git a/core/src/fxge/agg/agg23/fx_agg_path_storage.cpp b/core/src/fxge/agg/agg23/fx_agg_path_storage.cpp new file mode 100644 index 0000000000..8c4b701ebe --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_agg_path_storage.cpp @@ -0,0 +1,104 @@ + +//---------------------------------------------------------------------------- +// 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 "../../../../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_Alloc( FX_FLOAT*, (m_max_blocks + block_pool) * 2); + if (!new_coords) { + return; + } + unsigned char** new_cmds = + (unsigned char**)(new_coords + m_max_blocks + block_pool); + if(m_coord_blocks) { + FXSYS_memcpy32(new_coords, + m_coord_blocks, + m_max_blocks * sizeof(FX_FLOAT*)); + FXSYS_memcpy32(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))); + if (!m_coord_blocks[nb]) { + return; + } + 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/core/src/fxge/agg/agg23/fx_agg_rasterizer_scanline_aa.cpp b/core/src/fxge/agg/agg23/fx_agg_rasterizer_scanline_aa.cpp new file mode 100644 index 0000000000..634d10a3be --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_agg_rasterizer_scanline_aa.cpp @@ -0,0 +1,495 @@ + +//---------------------------------------------------------------------------- +// 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 "../../../../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 (!new_cells) { + return; + } + if(m_cells) { + FXSYS_memcpy32(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); + if (!m_cells[m_num_blocks - 1]) { + return; + } + } + 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/core/src/fxge/agg/agg23/fx_agg_vcgen_dash.cpp b/core/src/fxge/agg/agg23/fx_agg_vcgen_dash.cpp new file mode 100644 index 0000000000..0b6c29051b --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_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 "../../../../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/core/src/fxge/agg/agg23/fx_agg_vcgen_stroke.cpp b/core/src/fxge/agg/agg23/fx_agg_vcgen_stroke.cpp new file mode 100644 index 0000000000..425ac45aca --- /dev/null +++ b/core/src/fxge/agg/agg23/fx_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 "../../../../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; +} +} |