git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@61952 954022d7-b5bf-4e40-9824-e11837661b57
This commit is contained in:
Elen.Subbotina
2015-04-07 14:57:37 +00:00
committed by Alexander Trofimov
parent 858ab0bb93
commit b858608c6b
599 changed files with 141998 additions and 0 deletions

View File

@ -0,0 +1,211 @@
#ifndef AGG_SVG_ASSOC_POD_ARRAY_INCLUDE
#define AGG_SVG_ASSOC_POD_ARRAY_INCLUDE
//-----------------------------------------------------------------------------
#pragma warning(disable:4786)
#include <algorithm>
#include <functional>
#include <vector>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
enum sort_state_e {off,on};
//-------------------------------------------------------------------------
template<class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
pair() : first(T1()), second(T2()) {}
pair(const T1& v1, const T2& v2) : first(v1), second(v2) {}
T1 first;
T2 second;
};
//-------------------------------------------------------------------------
template<class KeyT, class T, class CompareT = std::less<KeyT> >
class assoc_pod_array : private std::vector<pair<KeyT, T> >
{
public:
//---------------------------------------------------------------------
typedef std::vector<pair<KeyT, T> > base_type;
//---------------------------------------------------------------------
typedef typename base_type::value_type value_type;
//---------------------------------------------------------------------
typedef KeyT key_type;
typedef T mapped_type;
typedef CompareT key_compare;
//---------------------------------------------------------------------
typedef base_type::iterator iterator;
typedef base_type::const_iterator const_iterator;
//---------------------------------------------------------------------
iterator begin()
{
return base_type::begin();
}
//---------------------------------------------------------------------
const_iterator begin() const
{
return base_type::begin();
}
//---------------------------------------------------------------------
iterator end()
{
return base_type::end();
}
//---------------------------------------------------------------------
const_iterator end() const
{
return base_type::end();
}
//---------------------------------------------------------------------
class value_compare
{
//-----------------------------------------------------------------
friend class assoc_pod_array;
//private:
public:
//-----------------------------------------------------------------
CompareT m_comp;
//-----------------------------------------------------------------
value_compare(CompareT c) : m_comp(c) {}
public:
//-----------------------------------------------------------------
template <class T>
bool operator()(const value_type& x, const T& y) const
{
return m_comp(x.first, y);
}
//-----------------------------------------------------------------
template <class T>
bool operator()(const T& x, const value_type& y) const
{
return m_comp(x, y.first);
}
//-----------------------------------------------------------------
bool operator()(const value_type& x, const typename value_type::first_type& y) const
{
return m_comp(x.first, y);
}
//-----------------------------------------------------------------
bool operator()(const typename value_type::first_type& x, const value_type& y) const
{
return m_comp(x, y.first);
}
//-----------------------------------------------------------------
bool operator()(const value_type& x, const value_type& y) const
{
return m_comp(x.first, y.first);
}
};
//---------------------------------------------------------------------
class value_compare_for_sort
{
//-----------------------------------------------------------------
friend class assoc_pod_array;
//private:
public:
//-----------------------------------------------------------------
CompareT m_comp;
//-----------------------------------------------------------------
value_compare_for_sort(CompareT c) : m_comp(c) {}
public:
//-----------------------------------------------------------------
bool operator()(const value_type& x, const typename value_type::first_type& y) const
{
return m_comp(x.first, y);
}
//-----------------------------------------------------------------
bool operator()(const typename value_type::first_type& x, const value_type& y) const
{
return m_comp(x, y.first);
}
//-----------------------------------------------------------------
bool operator()(const value_type& x, const value_type& y) const
{
return m_comp(x.first, y.first);
}
};
//-----------------------------------------------------------------
explicit assoc_pod_array(const CompareT& comp = key_compare())
: m_sort_state(off), m_compare(comp)
{
}
//-----------------------------------------------------------------
void sort_state(sort_state_e state)
{
m_sort_state = state;
if (m_sort_state == on)
{
std::sort(begin(), end(), value_compare_for_sort(m_compare));
}
}
//-----------------------------------------------------------------
unsigned size() const
{
return base_type::size();
}
//---------------------------------------------------------------------
void clear()
{
m_sort_state = off;
base_type::clear();
}
//---------------------------------------------------------------------
// Inserts val if and only if there is no element in the container with
// key equivalent to the key.
// return value indicates indicates whether the insertion takes place
bool insert(KeyT const & key, T const & val)
{
bool find(false);
if (m_sort_state == off)
{
//base_type::add(value_type(key, val));
base_type::push_back(value_type(key, val));
}
else
{
iterator it = std::lower_bound(begin(), end(),
key,value_compare(m_compare));
if (it == end())
{
base_type::insert(it, value_type(key, val));
}
else
if (!(!m_compare(it->first,key) && !m_compare(key,it->first)))
{
base_type::insert(it, value_type(key, val));
}
else
{
find = true;
}
}
return !find;
}
//---------------------------------------------------------------------
template <class Key>
iterator find(const Key& key)
{
assert(m_sort_state == on);
std::pair<iterator, iterator> p = std::equal_range(begin(), end(),
key, value_compare(m_compare));
return p.first != p.second ? p.first : end();
}
//-----------------------------------------------------------------------------
private:
sort_state_e m_sort_state;
CompareT m_compare;
};
}
}
#endif

View File

@ -0,0 +1,167 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_ATTRIBUTE_SOURCE_INCLUDED
#define AGG_SVG_ATTRIBUTE_SOURCE_INCLUDED
//-----------------------------------------------------------------------------
#include <cstring> // for memcpy
#include "agg_svg_basics.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class attribute_byte
{
public:
//---------------------------------------------------------------------
attribute_byte(attr_e attr, agg::int8u data)
{
m_storage[0] = tag_attribute_bin_byte;
m_storage[1] = attr;
m_storage[2] = data;
}
//---------------------------------------------------------------------
const agg::int8u* head() const { return m_storage; }
//---------------------------------------------------------------------
agg::int32u head_size() const { return buf_size - 1; }
//---------------------------------------------------------------------
const agg::int8u* data() const { return &m_storage[2]; }
//---------------------------------------------------------------------
agg::int32u data_size() const { return 1; }
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
enum
{
buf_size = 1 // tag
+ 1 // attr_e
+ 1 // data
};
//---------------------------------------------------------------------
agg::int8u m_storage[buf_size];
};
//-------------------------------------------------------------------------
class attribute_bin
{
public:
//---------------------------------------------------------------------
attribute_bin(attr_e attr,
const void * data,
agg::int32u size)
: m_data(static_cast<const agg::int8u*>(data)),
m_size(size),
m_with_type(false)
{
fill_head(attr);
}
//---------------------------------------------------------------------
attribute_bin(attr_e attr,
agg::int8u type,
const void * data,
agg::int32u size)
: m_data(static_cast<const agg::int8u*>(data)),
m_size(size + 1),
m_with_type(true)
{
fill_head(attr);
m_storage[2 + sizeof(agg::int32u)] = type;
--m_size;
}
//---------------------------------------------------------------------
const agg::int8u* head() const { return m_storage; }
//---------------------------------------------------------------------
agg::int32u head_size() const
{
return m_with_type ? buf_size : buf_size - 1;
}
//---------------------------------------------------------------------
const agg::int8u* data() const { return m_data; }
//---------------------------------------------------------------------
agg::int32u data_size() const { return m_size; }
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
void fill_head(attr_e attr)
{
m_storage[0] = tag_attribute_bin;
m_storage[1] = attr;
memcpy(&m_storage[2], &m_size, sizeof(agg::int32u));
}
//---------------------------------------------------------------------
enum
{
buf_size = 1 // tag
+ 1 // attr_e
+ sizeof(agg::int32u) // size
+ 1 // type
};
//---------------------------------------------------------------------
agg::int8u m_storage[buf_size];
const agg::int8u* m_data;
agg::int32u m_size;
bool m_with_type;
};
//-------------------------------------------------------------------------
class attribute_bin_short
{
public:
//---------------------------------------------------------------------
attribute_bin_short(attr_e attr, const void* data, agg::int8u size)
: m_data(static_cast<const agg::int8u*>(data)),
m_size(size),
m_with_type(false)
{
fill_head(attr);
}
//---------------------------------------------------------------------
attribute_bin_short(attr_e attr, agg::int8u type, const void* data, agg::int8u size)
: m_data(static_cast<const agg::int8u*>(data)),
m_size(size + 1),
m_with_type(true)
{
fill_head(attr);
m_storage[3] = type;
--m_size;
}
//---------------------------------------------------------------------
const agg::int8u* head() const { return m_storage; }
//---------------------------------------------------------------------
agg::int32u head_size() const
{
return m_with_type ? buf_size : buf_size - 1;
}
//---------------------------------------------------------------------
const agg::int8u* data() const { return m_data; }
//---------------------------------------------------------------------
agg::int32u data_size() const { return m_size; }
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
void fill_head(attr_e attr)
{
m_storage[0] = tag_attribute_bin_short;
m_storage[1] = attr;
m_storage[2] = m_size;
}
//---------------------------------------------------------------------
enum
{
buf_size = 1 // tag
+ 1 // attr_e
+ 1 // size
+ 1 // type
};
//---------------------------------------------------------------------
agg::int8u m_storage[buf_size];
const agg::int8u* m_data;
agg::int32u m_size;
bool m_with_type;
};
//-------------------------------------------------------------------------
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_ATTRIBUTE_SOURCE_INCLUDED

View File

@ -0,0 +1,480 @@
//-----------------------------------------------------------------------------
#include "agg_svg_attributes.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//---------------------------------------------------------------------------------
agg::line_join_e g_stroke_linejoin_lut[] =
{
agg::miter_join_revert,
agg::round_join,
agg::bevel_join
};
//---------------------------------------------------------------------------------
agg::line_cap_e g_stroke_linecap_lut[] =
{
agg::butt_cap,
agg::round_cap,
agg::square_cap
};
//---------------------------------------------------------------------------------
agg::filling_rule_e g_fill_rule_lut[] =
{
agg::fill_non_zero,
agg::fill_even_odd
};
//--------------------------------------------------------------------
agg::int8u* attr_stack::push_attribute(unsigned type, unsigned size)
{
if(m_sessions.size())
{
session& s = m_sessions.last();
agg::int8u* data = 0;
if(size < attr_heap_block_size)
{
int i = m_heap.allocate_continuous_block(size);
if(i >= 0)
{
data = &m_heap[i];
}
}
else
{
data = new agg::int8u[size];
type |= large_block_flag;
}
if(data)
{
m_attributes.add(attr(type, data, size));
s.set_saved_attribute(type);
++s.num_attributes;
return data;
}
}
return 0;
}
//--------------------------------------------------------------------
void attr_stack::end_session()
{
const session& s = m_sessions.last();
for(int i = (int)num_attributes() - 1; i >= 0; --i)
{
attr& a = m_attributes[s.start_attr_index + i];
if(a.type & large_block_flag)
{
delete [] a.data;
}
}
m_heap.free_tail(s.start_attr_heap);
m_attributes.free_tail(s.start_attr_index);
m_sessions.remove_last();
}
//--------------------------------------------------------------------
attributes::attributes(const global_settings& settings)
: m_stack()
, m_settings(&settings)
, m_values()
{}
//--------------------------------------------------------------------
struct affine_serializer_adaptor
{
transformer& m_trans;
affine_serializer_adaptor(transformer& trans) : m_trans(trans) {}
unsigned byte_size() const { return m_trans.byte_size_affine(); }
void serialize(agg::int8u* ptr) const { m_trans.serialize_affine(ptr); }
void deserialize(const agg::int8u* ptr) { m_trans.deserialize_affine(ptr); }
};
//--------------------------------------------------------------------
void attributes::end_session()
{
// Restore saved attributes
//-------------------------
int i = int(m_stack.num_attributes()) - 1;
for(; i >= 0; --i)
{
const attr_stack::attr* a = m_stack.attribute(i);
if(a)
{
switch(a->attr_type())
{
case attr_transform: { affine_serializer_adaptor (m_values.transformer).deserialize(a->data); } break;
case attr_viewBox: restore_attribute(m_values.transformer, a->data); break;
case attr_color: restore_attribute(m_values.color, a->data); break;
case attr_opacity: restore_attribute(m_values.opacity, a->data); break;
case attr_fill: restore_attribute(m_values.fill_type, a->data); break;
case attr_fill_color: restore_attribute(m_values.fill_color, a->data); break;
case attr_fill_gradient: restore_serializable(m_values.fill_gradient_id,a->data, a->size); break;
case attr_fill_opacity: restore_attribute(m_values.fill_opacity, a->data); break;
case attr_stroke: restore_attribute(m_values.stroke_type, a->data); break;
case attr_stroke_color: restore_attribute(m_values.stroke_color, a->data); break;
case attr_stroke_gradient: restore_serializable(m_values.stroke_gradient_id, a->data, a->size); break;
case attr_stroke_opacity: restore_attribute(m_values.stroke_opacity, a->data); break;
case attr_fill_rule: restore_attribute(m_values.fill_rule, a->data); break;
case attr_stroke_linejoin: restore_attribute(m_values.stroke_linejoin, a->data); break;
case attr_stroke_linecap: restore_attribute(m_values.stroke_linecap, a->data); break;
case attr_stroke_miterlimit: restore_attribute(m_values.stroke_miterlimit, a->data); break;
case attr_stroke_width: restore_attribute(m_values.stroke_width, a->data); break;
}
}
}
// Pop all attributes from stack
//--------------------------
m_stack.end_session();
}
//--------------------------------------------------------------------
void attributes::reset_all()
{
m_values = values();
}
//--------------------------------------------------------------------
void attributes::window(int x1, int y1, int x2, int y2)
{
m_values.transformer.window(x1, y1, x2, y2);
update_zoom();
}
//--------------------------------------------------------------------
void attributes::set_zoom(double x1, double y1, double x2, double y2)
{
zoom_data zoom;
zoom.sx1 = window_x1();
zoom.sy1 = window_y1();
zoom.sx2 = window_x2();
zoom.sy2 = window_y2();
zoom.wx1 = x1;
zoom.wy1 = y1;
zoom.wx2 = x2;
zoom.wy2 = y2;
m_zoom_stack.add(zoom);
update_zoom();
}
//--------------------------------------------------------------------
void attributes::initial_zoom()
{
m_zoom_stack.remove_all();
update_zoom();
}
//--------------------------------------------------------------------
void attributes::update_zoom()
{
unsigned i;
m_values.transformer.zoom(window_x1(), window_y1(), window_x2(), window_y2(),
window_x1(), window_y1(), window_x2(), window_y2());
for(i = 0; i < m_zoom_stack.size(); i++)
{
const zoom_data& zoom = m_zoom_stack[i];
double zoom_wx1 = zoom.wx1;
double zoom_wy1 = zoom.wy1;
double zoom_wx2 = zoom.wx2;
double zoom_wy2 = zoom.wy2;
m_values.transformer.zoom().inverse_transform(&zoom_wx1, &zoom_wy1);
m_values.transformer.zoom().inverse_transform(&zoom_wx2, &zoom_wy2);
m_values.transformer.zoom(zoom_wx1, zoom_wy1, zoom_wx2, zoom_wy2,
zoom.sx1, zoom.sy1, zoom.sx2, zoom.sy2);
}
}
//--------------------------------------------------------------------
void attributes::viewBox(double scx, double scy, double scw, double sch,
double vbx, double vby, double vbw, double vbh,
uniform_scaling_e align_type,
window_fit_logic_e meet_or_slice,
bool separate_window)
{
save_attribute(attr_viewBox, m_values.transformer);
m_values.transformer.viewBox(scx, scy, scw, sch,
vbx, vby, vbw, vbh,
align_type, meet_or_slice, separate_window);
}
//--------------------------------------------------------------------
void attributes::opacity(double op)
{
save_attribute(attr_opacity, m_values.opacity);
m_values.opacity = op;
}
//--------------------------------------------------------------------
void attributes::color(const color_type& c)
{
save_attribute(attr_color, m_values.color);
m_values.color = gamma_color(c);
}
//--------------------------------------------------------------------
void attributes::color(unsigned c)
{
color(agg::rgb8_packed(c));
}
//--------------------------------------------------------------------
void attributes::fill_none()
{
save_attribute(attr_fill, m_values.fill_type);
m_values.fill_type = paint_none;
}
//--------------------------------------------------------------------
void attributes::fill_currentColor()
{
save_attribute(attr_fill, m_values.fill_type);
m_values.fill_type = paint_currentColor;
}
//--------------------------------------------------------------------
void attributes::fill(const color_type& c)
{
save_attribute(attr_fill, m_values.fill_type);
save_attribute(attr_fill_color, m_values.fill_color);
m_values.fill_type = paint_color;
m_values.fill_color = gamma_color(c);
}
//--------------------------------------------------------------------
void attributes::fill(unsigned c)
{
fill(agg::rgb8_packed(c));
}
//--------------------------------------------------------------------
color_type attributes::fill_color() const
{
color_type c = (m_values.fill_type == paint_color) ? m_values.fill_color : m_values.color;
c.a = (color_type::value_type)(c.a * fill_opacity() + 0.5);
return c;
}
//--------------------------------------------------------------------
void attributes::fill_opacity(double op)
{
save_attribute(attr_fill_opacity, m_values.fill_opacity);
m_values.fill_opacity = op;
}
//--------------------------------------------------------------------
void attributes::stroke_none()
{
save_attribute(attr_stroke, m_values.stroke_type);
m_values.stroke_type = paint_none;
}
//--------------------------------------------------------------------
void attributes::stroke_currentColor()
{
save_attribute(attr_stroke, m_values.stroke_type);
m_values.stroke_type = paint_currentColor;
}
//--------------------------------------------------------------------
void attributes::stroke(const color_type& c)
{
save_attribute(attr_stroke, m_values.stroke_type);
save_attribute(attr_stroke_color, m_values.stroke_color);
m_values.stroke_type = paint_color;
m_values.stroke_color = gamma_color(c);
}
//--------------------------------------------------------------------
void attributes::stroke(unsigned c)
{
stroke(agg::rgb8_packed(c));
}
//--------------------------------------------------------------------
color_type attributes::stroke_color() const
{
color_type c = (m_values.stroke_type == paint_color) ? m_values.stroke_color : m_values.color;
c.a = (color_type::value_type)(c.a * stroke_opacity() + 0.5);
return c;
}
//--------------------------------------------------------------------
void attributes::stroke_opacity(double op)
{
save_attribute(attr_stroke_opacity, m_values.stroke_opacity);
m_values.stroke_opacity = op;
}
//--------------------------------------------------------------------
void attributes::fill_rule(fill_rule_e fe)
{
save_attribute(attr_fill_rule, m_values.fill_rule);
m_values.fill_rule = fe;
}
//--------------------------------------------------------------------
void attributes::stroke_linejoin(stroke_linejoin_e lj)
{
save_attribute(attr_stroke_linejoin, m_values.stroke_linejoin);
m_values.stroke_linejoin = lj;
}
//--------------------------------------------------------------------
void attributes::stroke_linecap(stroke_linecap_e lc)
{
save_attribute(attr_stroke_linecap, m_values.stroke_linecap);
m_values.stroke_linecap = lc;
}
//--------------------------------------------------------------------
void attributes::stroke_miterlimit(double ml)
{
save_attribute(attr_stroke_miterlimit, m_values.stroke_miterlimit);
m_values.stroke_miterlimit = ml;
}
//--------------------------------------------------------------------
void attributes::stroke_width(double sw)
{
save_attribute(attr_stroke_width, m_values.stroke_width);
m_values.stroke_width = sw;
if(sw <= 1e-30)
{
stroke_none();
}
}
//--------------------------------------------------------------------
void attributes::object_bbox(double x1, double y1, double x2, double y2)
{
save_attribute(attr_object_bbox, m_values.object_bbox);
m_values.object_bbox[0] = x1;
m_values.object_bbox[1] = y1;
m_values.object_bbox[2] = x2;
m_values.object_bbox[3] = y2;
}
//--------------------------------------------------------------------
void attributes::object_bbox(const rectangle& bbox)
{
object_bbox(bbox.x1, bbox.y1, bbox.x2, bbox.y2);
}
//--------------------------------------------------------------------
void attributes::transform(const agg::trans_affine& mtx)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.transform(mtx);
}
//--------------------------------------------------------------------
void attributes::transform(double a0, double a1, double a2,
double a3, double a4, double a5)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.transform(a0, a1, a2, a3, a4, a5);
}
//--------------------------------------------------------------------
void attributes::translate(double dx, double dy)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.translate(dx, dy);
}
//--------------------------------------------------------------------
void attributes::rotate(double angle)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.rotate(angle);
}
//--------------------------------------------------------------------
void attributes::rotate(double angle, double cx, double cy)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.rotate(angle, cx, cy);
}
//--------------------------------------------------------------------
void attributes::scale(double s)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.scale(s);
}
//--------------------------------------------------------------------
void attributes::scale(double sx, double sy)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.scale(sx, sy);
}
//--------------------------------------------------------------------
void attributes::skew(double sx, double sy)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.skew(sx, sy);
}
//--------------------------------------------------------------------
void attributes::skew_x(double s)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.skew_x(s);
}
//--------------------------------------------------------------------
void attributes::skew_y(double s)
{
save_serializable(attr_transform, affine_serializer_adaptor(m_values.transformer));
m_values.transformer.skew_y(s);
}
//---------------------------------------------------------------------------------
double attributes::percent2pix(double percent) const
{
double w = window_x2() - window_x1();
double h = window_y2() - window_y1();
if(m_values.transformer.viewBox_level())
{
double x1, y1, x2, y2;
m_values.transformer.world_viewport(&x1, &y1, &x2, &y2);
w = x2 - x1;
h = y2 - y1;
}
return percent * sqrt(w*w + h*h) * 0.0070710678118654752440084436210485;
}
//---------------------------------------------------------------------------------
double attributes::percent2pix_x(double percent) const
{
double w = window_x2() - window_x1();
if(m_values.transformer.viewBox_level())
{
double x1, y1, x2, y2;
m_values.transformer.world_viewport(&x1, &y1, &x2, &y2);
w = x2 - x1;
}
return percent * 0.01 * w;
}
//---------------------------------------------------------------------------------
double attributes::percent2pix_y(double percent) const
{
double h = window_y2() - window_y1();
if(m_values.transformer.viewBox_level())
{
double x1, y1, x2, y2;
m_values.transformer.world_viewport(&x1, &y1, &x2, &y2);
h = y2 - y1;
}
return percent * 0.01 * h;
}
//---------------------------------------------------------------------------------
double attributes::conv_units(double v, units2_e u) const
{
switch(u)
{
default: break;
case units_em: return v; // don't supported
case units_ex: return v; // don't supported
case units_pt:
case units_pt_x: return m_settings->pt2pix_x(v);
case units_pt_y: return m_settings->pt2pix_y(v);
case units_pc:
case units_pc_x: return m_settings->pc2pix_x(v);
case units_pc_y: return m_settings->pc2pix_y(v);
case units_cm:
case units_cm_x: return m_settings->cm2pix_x(v);
case units_cm_y: return m_settings->cm2pix_y(v);
case units_mm:
case units_mm_x: return m_settings->mm2pix_x(v);
case units_mm_y: return m_settings->mm2pix_y(v);
case units_in:
case units_in_x: return m_settings->in2pix_x(v);
case units_in_y: return m_settings->in2pix_y(v);
case units_percent: return percent2pix(v);
case units_percent_x: return percent2pix_x(v);
case units_percent_y: return percent2pix_y(v);
case units_deg: return v * agg::pi / 180.0;
case units_grad: return v * agg::pi / 200.0;
case units_rad: return v;
}
return v;
}
}
}

View File

@ -0,0 +1,590 @@
#ifndef AGG_SVG_ATTRIBUTES_INCLUDED
#define AGG_SVG_ATTRIBUTES_INCLUDED
#include "agg_conv_stroke.h"
#include "agg_gamma_lut.h"
#include "agg_svg_basics.h"
#include "agg_svg_defines.h"
#include "agg_svg_transformer.h"
#include "agg_svg_frame_buffer_rgba.h"
#include "agg_svg_gradient_lut_cache.h"
#include <string>
namespace agg
{
namespace svg
{
extern agg::line_join_e g_stroke_linejoin_lut[];
extern agg::line_cap_e g_stroke_linecap_lut[];
extern agg::filling_rule_e g_fill_rule_lut[];
class global_settings
{
public:
typedef agg::gamma_lut<color_type::value_type,
color_type::value_type,
color_type::base_shift,
color_type::base_shift> gamma_lut_type;
global_settings()
: m_gamma()
, m_dpi_x(96.0)
, m_dpi_y(96.0)
{}
// Metrics
//-----------------------------------------------------------------------
void dpi(double v) { m_dpi_x = m_dpi_y = v; }
void dpi_x(double v) { m_dpi_x = v; }
void dpi_y(double v) { m_dpi_y = v; }
double dpi() const { return (m_dpi_x + m_dpi_y) / 2; }
static double pt2pix(double pt, double dpi) { return pt * dpi / 72.0; }
static double pc2pix(double pc, double dpi) { return pc * dpi / 6.0; }
static double cm2pix(double cm, double dpi) { return cm * dpi / 2.54; }
static double mm2pix(double mm, double dpi) { return mm * dpi / 25.4; }
static double in2pix(double in, double dpi) { return in * dpi; }
double pt2pix_x(double pt) const { return pt2pix(pt, m_dpi_x); }
double pt2pix_y(double pt) const { return pt2pix(pt, m_dpi_y); }
double pc2pix_x(double pc) const { return pc2pix(pc, m_dpi_x); }
double pc2pix_y(double pc) const { return pc2pix(pc, m_dpi_y); }
double cm2pix_x(double cm) const { return cm2pix(cm, m_dpi_x); }
double cm2pix_y(double cm) const { return cm2pix(cm, m_dpi_y); }
double mm2pix_x(double mm) const { return mm2pix(mm, m_dpi_x); }
double mm2pix_y(double mm) const { return mm2pix(mm, m_dpi_y); }
double in2pix_x(double in) const { return in2pix(in, m_dpi_x); }
double in2pix_y(double in) const { return in2pix(in, m_dpi_y); }
double pt2pix(double pt) const { return pt2pix(pt, m_dpi_x); }
double pc2pix(double pc) const { return pc2pix(pc, m_dpi_x); }
double cm2pix(double cm) const { return cm2pix(cm, m_dpi_x); }
double mm2pix(double mm) const { return mm2pix(mm, m_dpi_x); }
double in2pix(double in) const { return in2pix(in, m_dpi_x); }
// Full color gamma correction
//-----------------------------------------------------------------------
void gamma(double g) { m_gamma.gamma(g); }
double gamma() const { return m_gamma.gamma(); }
const gamma_lut_type& gamma_lut() const { return m_gamma; }
unsigned gamma_dir(unsigned v) const { return m_gamma.dir(v); }
unsigned gamma_inv(unsigned v) const { return m_gamma.inv(v); }
private:
gamma_lut_type m_gamma;
double m_dpi_x;
double m_dpi_y;
};
//-------------------------------------------------------------------------
// Class attr_stack is used to save and restore different attributes.
//
// USAGE:
//
// 1. When the SVG command comes (startElement event), call
// begin_session();
//
// 2. When the attribute comes, you do the following:
// if(!stack.attribute_saved(attr.type()))
// {
// int8u* ptr = stack.push_attribute(attr.type(), attr.size());
// if(ptr) attr.serialize(ptr);
// }
// attr.set_new_value(attr_value);
//
// 3. When processing of the command is done (endElement event)
// you restore all saved attributes and call end_session():
//
// for(i = 0; i < stack.num_attributes(); ++i)
// {
// const attr_stack::attr* a = stack.attribute(i);
// if(a)
// {
// attr.deserialize(a->data, a->size);
// }
// }
// end_session();
//
//---------------------------------------------------------------------------
class attr_stack
{
public:
//-----------------------------------------------------------------------
enum
{
attr_heap_block_shift = 16,
attr_heap_block_size = 1 << attr_heap_block_shift,
attr_heap_block_mask = attr_heap_block_size - 1,
large_block_flag = (1 << 16)
};
//-----------------------------------------------------------------------
struct attr
{
unsigned type;
unsigned size;
agg::int8u* data;
attr() {}
attr(unsigned t, agg::int8u* d, unsigned s) :
type(t), size(s), data(d)
{}
unsigned attr_type() const { return type & (~large_block_flag); }
};
//-----------------------------------------------------------------------
attr_stack() :
m_heap(256-4),
m_attributes(),
m_sessions()
{}
//-----------------------------------------------------------------------
unsigned num_sessions() const
{
return m_sessions.size();
}
//-----------------------------------------------------------------------
void begin_session()
{
m_sessions.add(session(m_attributes.size(), m_heap.size()));
}
//-----------------------------------------------------------------------
bool attribute_saved(unsigned type) const
{
return m_sessions.last().attribute_saved(type) != 0;
}
//-----------------------------------------------------------------------
agg::int8u* push_attribute(unsigned type, unsigned size);
//-----------------------------------------------------------------------
unsigned num_attributes() const
{
return m_sessions.last().num_attributes;
}
//-----------------------------------------------------------------------
const attr* attribute(unsigned idx) const
{
return &m_attributes[m_sessions.last().start_attr_index + idx];
}
//-----------------------------------------------------------------------
void end_session();
//-----------------------------------------------------------------------
void clear()
{
m_heap.free_all();
m_attributes.free_all();
m_sessions.free_all();
}
private:
//-----------------------------------------------------------------------
struct session
{
enum
{
num_flag_bytes = 512/8
};
unsigned start_attr_index;
unsigned num_attributes;
unsigned start_attr_heap;
agg::int8u saved_attributes[num_flag_bytes];
session() {}
session(unsigned start_attr, unsigned start_heap) :
start_attr_index(start_attr),
num_attributes(0),
start_attr_heap(start_heap)
{
memset(saved_attributes, 0, sizeof(saved_attributes));
}
void set_saved_attribute(unsigned attr_type)
{
attr_type &= ~large_block_flag;
saved_attributes[attr_type >> 3] |= 1 << (attr_type & 7);
}
unsigned attribute_saved(unsigned attr_type) const
{
attr_type &= ~large_block_flag;
return saved_attributes[attr_type >> 3] & (1 << (attr_type & 7));
}
};
//-----------------------------------------------------------------------
agg::pod_bvector<agg::int8u, attr_heap_block_shift> m_heap;
agg::pod_bvector<attr, 8> m_attributes;
agg::pod_bvector<session, 6> m_sessions;
};
//-------------------------------------------------------------------------
class attr_string
{
std::string m_value;
public:
const char_type* data()const { return m_value.c_str(); }
unsigned byte_size()const {return (unsigned)m_value.size(); }
template <class DataAccessor>
const attr_string& assign_from(DataAccessor str)
{
unsigned len = str.size();
m_value.clear();
m_value.reserve(len + 1);
for(unsigned i = 0; str.size();)
{
m_value += str.read_value();
}
return *this;
}
void serialize(agg::int8u* ptr)const
{
memcpy(ptr, m_value.data(), m_value.size());
}
void deserialize(const agg::int8u* data, unsigned size)
{
m_value.assign(data, data + size);
}
};
//-------------------------------------------------------------------------
// This class is a container for all known SVG attributes. It uses
// attr_stack inside.
//
//---------------------------------------------------------------------------
class attributes
{
private:
struct zoom_data
{
double wx1, wy1, wx2, wy2;
double sx1, sy1, sx2, sy2;
};
typedef global_settings::gamma_lut_type gamma_lut_type;
// prevent copy
attributes(const attributes& attr);
const attributes& operator = (const attributes& attr);
struct values
{
double opacity;
color_type color;
paint_type_e fill_type;
color_type fill_color;
attr_string fill_gradient_id;
double fill_opacity;
fill_rule_e fill_rule;
paint_type_e stroke_type;
color_type stroke_color;
attr_string stroke_gradient_id;
double stroke_opacity;
double stroke_width;
stroke_linejoin_e stroke_linejoin;
stroke_linecap_e stroke_linecap;
double stroke_miterlimit;
agg::svg::transformer transformer;
double object_bbox[4];
values() :
opacity(1.0),
color(color_type(0,0,0)),
fill_type(paint_color),
fill_color(color_type(0, 0, 0)),
fill_gradient_id(),
fill_opacity(1.0),
fill_rule(fill_rule_nonzero),
stroke_type(paint_none),
stroke_color(color_type(0,0,0)),
stroke_gradient_id(),
stroke_opacity(1.0),
stroke_width(1.0),
stroke_linejoin(stroke_linejoin_miter),
stroke_linecap(stroke_linecap_butt),
stroke_miterlimit(4.0),
transformer()
{
object_bbox[0] = 0;
object_bbox[1] = 0;
object_bbox[2] = 1;
object_bbox[3] = 1;
}
};
public:
explicit attributes(const global_settings& settings);
// Global Settings
//-----------------------------------------------------------------------
const global_settings& settings() const { return *m_settings; }
double gamma() const { return m_settings->gamma(); }
const gamma_lut_type& gamma_lut() const { return m_settings->gamma_lut(); }
color_type gamma_color(color_type c) const
{
c.r = m_settings->gamma_dir(c.r);
c.g = m_settings->gamma_dir(c.g);
c.b = m_settings->gamma_dir(c.b);
return c;
}
// Sessions
//-----------------------------------------------------------------------
void begin_session() { m_stack.begin_session(); }
void end_session();
unsigned num_sessions() const { return m_stack.num_sessions(); }
//-----------------------------------------------------------------------
void reset_all();
void clear()
{
m_stack.clear();
reset_all();
}
//-----------------------------------------------------------------------
void window(int x1, int y1, int x2, int y2);
void set_zoom(double x1, double y1, double x2, double y2);
void initial_zoom();
// General attributes and properties
//-----------------------------------------------------------------------
void viewBox(double scx, double scy, double scw, double sch,
double vbx, double vby, double vbw, double vbh,
uniform_scaling_e align_type,
window_fit_logic_e meet_or_slice,
bool separate_window);
void opacity(double op);
void color(const color_type& c);
void color(unsigned c);
void fill_none();
void fill_currentColor();
void fill(const color_type& c);
void fill(unsigned c);
template<class DataAccessor>
void fill_gradient_id(DataAccessor gradient_id)
{
save_attribute(attr_fill, m_values.fill_type);
save_serializable(attr_fill_gradient, m_values.fill_gradient_id);
m_values.fill_type = paint_gradient;
m_values.fill_gradient_id.assign_from(gradient_id);
}
void fill_opacity(double op);
void stroke_none();
void stroke_currentColor();
void stroke(const color_type& c);
void stroke(unsigned c);
template<class DataAccessor>
void stroke_gradient_id(DataAccessor gradient_id)
{
save_attribute(attr_stroke, m_values.stroke_type);
save_serializable(attr_stroke_gradient, m_values.stroke_gradient_id);
m_values.stroke_type = paint_gradient;
m_values.stroke_gradient_id.assign_from(gradient_id);
}
void stroke_opacity(double op);
void fill_rule(fill_rule_e fe);
void stroke_linejoin(stroke_linejoin_e lj);
void stroke_linecap(stroke_linecap_e lc);
void stroke_miterlimit(double ml);
void stroke_width(double sw);
void object_bbox(double x1, double y1, double x2, double y2);
void object_bbox(const rectangle& bbox);
void transform(const agg::trans_affine& mtx);
void transform(double a0, double a1, double a2,
double a3, double a4, double a5);
void translate(double dx, double dy);
void rotate(double angle);
void rotate(double angle, double cx, double cy);
void scale(double s);
void scale(double sx, double sy);
void skew(double sx, double sy);
void skew_x(double s);
void skew_y(double s);
// Accessors
//-----------------------------------------------------------------------
double opacity() const { return m_values.opacity; }
paint_type_e fill_type() const { return m_values.fill_type; }
color_type fill_color() const;
double fill_opacity() const { return m_values.fill_opacity * opacity(); }
const char_type* fill_gradient_id() const { return m_values.fill_gradient_id.data(); }
fill_rule_e fill_rule() const { return m_values.fill_rule; }
paint_type_e stroke_type() const { return m_values.stroke_type; }
color_type stroke_color() const;
double stroke_opacity() const { return m_values.stroke_opacity * opacity(); }
const char_type* stroke_gradient_id() const { return m_values.stroke_gradient_id.data(); }
double stroke_width() const { return m_values.stroke_width; }
stroke_linejoin_e stroke_linejoin() const { return m_values.stroke_linejoin; }
stroke_linecap_e stroke_linecap() const { return m_values.stroke_linecap; }
double stroke_miterlimit() const { return m_values.stroke_miterlimit; }
const transformer& transform() const { return m_values.transformer; }
transformer& transform() { return m_values.transformer; }
double scale() const { return m_values.transformer.scale(); }
double object_x1() const { return m_values.object_bbox[0]; }
double object_y1() const { return m_values.object_bbox[1]; }
double object_x2() const { return m_values.object_bbox[2]; }
double object_y2() const { return m_values.object_bbox[3]; }
int window_x1() const { return m_values.transformer.window_x1(); }
int window_y1() const { return m_values.transformer.window_y1(); }
int window_x2() const { return m_values.transformer.window_x2(); }
int window_y2() const { return m_values.transformer.window_y2(); }
double clip_x1() const { return m_values.transformer.clip_x1(); }
double clip_y1() const { return m_values.transformer.clip_y1(); }
double clip_x2() const { return m_values.transformer.clip_x2(); }
double clip_y2() const { return m_values.transformer.clip_y2(); }
int buffer_x1() const { return m_values.transformer.buffer_x1(); }
int buffer_y1() const { return m_values.transformer.buffer_y1(); }
int buffer_x2() const { return m_values.transformer.buffer_x2(); }
int buffer_y2() const { return m_values.transformer.buffer_y2(); }
bool viewBox_is_valid() const { return m_values.transformer.is_valid(); }
bool is_visible(double x1, double y1, double x2, double y2) const
{
return m_values.transformer.is_visible(x1, y1, x2, y2);
}
// Metrics
//-----------------------------------------------------------------------
double percent2pix(double percent) const;
double percent2pix_x(double percent) const;
double percent2pix_y(double percent) const;
double conv_units(double v, units2_e u) const;
private:
template<class Serializer>
void save_serializable(unsigned attr, const Serializer& serializer)
{
if(!m_stack.attribute_saved(attr))
{
agg::int8u* ptr = m_stack.push_attribute(attr, serializer.byte_size());
serializer.serialize(ptr);
}
}
template<class Serializer>
void restore_serializable(Serializer& serializer,
const agg::int8u* data,
unsigned size)
{
serializer.deserialize(data, size);
}
template<class T>
void save_attribute(attr_e attr, const T& data)
{
if(!m_stack.attribute_saved(attr))
{
agg::int8u* ptr = m_stack.push_attribute(attr, sizeof(T));
memcpy(ptr, &data, sizeof(T));
}
}
template<class T1, class T2>
void save_attribute(unsigned attr, const T1& data1, const T2& data2)
{
if(!m_stack.attribute_saved(attr))
{
agg::int8u* ptr = m_stack.push_attribute(attr, sizeof(T1) + sizeof(T2));
memcpy(ptr, &data1, sizeof(T1));
memcpy(ptr + sizeof(T1), &data2, sizeof(T2));
}
}
template<class T>
void restore_attribute(T& attr, const agg::int8u* data)
{
memcpy(&attr, data, sizeof(T));
}
template<class T1, class T2>
void restore_attribute(T1& attr1, T2& attr2, const agg::int8u* data)
{
memcpy(&attr1, data, sizeof(T1));
memcpy(&attr2, data + sizeof(T1), sizeof(T2));
}
template<class ArrayType, class UnitsArrayAccessor>
void deserialize_units_array(unsigned start,
ArrayType& array,
UnitsArrayAccessor data)
{
if(start == 0) array.remove_all();
while(array.size() < start)
{
array.add(0.0);
}
for(unsigned i = 0; data.size(); i++)
{
double v = data.read_units_value(*this);
if(start + i < array.size())
{
array.at(start + i) = v;
}
else
{
array.add(v);
}
}
}
void update_zoom();
attr_stack m_stack;
const global_settings* m_settings;
agg::pod_bvector<zoom_data> m_zoom_stack;
values m_values;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_ATTRIBUTES_INCLUDED

View File

@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
#include "agg_svg_attributes_map.h"
#include "agg_svg_utils.h"
#include "agg_svg_basics.h"
#include "member_comparer.h"
#include <vector>
#include <utility>
#include <algorithm>
#include <cassert>
#include <cstring>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
namespace
{
typedef std::vector<std::pair<const char*, attr_e> > map_type;
map_type m_map;
unsigned m_names_positions[end_of_attr];
}
#define ADD_ATTR(name, value) \
m_map.push_back(map_type::value_type(name, value));
//-------------------------------------------------------------------------
attributes_map::attributes_map()
{
memset(m_names_positions, 0, sizeof(unsigned)*end_of_attr);
m_map.reserve(end_of_attr);
int index = 0;
ADD_ATTR( "color", attr_color );
ADD_ATTR( "cx", attr_cx );
ADD_ATTR( "cy", attr_cy );
ADD_ATTR( "d", attr_d );
ADD_ATTR( "fill", attr_fill );
ADD_ATTR( "fill-opacity", attr_fill_opacity );
ADD_ATTR( "fill-rule", attr_fill_rule );
ADD_ATTR( "fx", attr_fx );
ADD_ATTR( "fy", attr_fy );
ADD_ATTR( "gradientTransform", attr_gradientTransform );
ADD_ATTR( "gradientUnits", attr_gradientUnits );
ADD_ATTR( "height", attr_height );
ADD_ATTR( "id", attr_id );
ADD_ATTR( "offset", attr_offset );
ADD_ATTR( "opacity", attr_opacity );
ADD_ATTR( "points", attr_points );
ADD_ATTR( "preserveAspectRatio", attr_preserveAspectRatio );
ADD_ATTR( "r", attr_r );
ADD_ATTR( "rx", attr_rx );
ADD_ATTR( "ry", attr_ry );
ADD_ATTR( "spreadMethod", attr_spreadMethod );
ADD_ATTR( "stop-color", attr_stop_color );
ADD_ATTR( "stop-opacity", attr_stop_opacity );
ADD_ATTR( "stroke", attr_stroke );
ADD_ATTR( "stroke-linecap", attr_stroke_linecap );
ADD_ATTR( "stroke-linejoin", attr_stroke_linejoin );
ADD_ATTR( "stroke-miterlimit", attr_stroke_miterlimit );
ADD_ATTR( "stroke-opacity", attr_stroke_opacity );
ADD_ATTR( "stroke-width", attr_stroke_width );
ADD_ATTR( "style", attr_style );
ADD_ATTR( "transform", attr_transform );
ADD_ATTR( "viewBox", attr_viewBox );
ADD_ATTR( "width", attr_width );
ADD_ATTR( "x", attr_x );
ADD_ATTR( "x1", attr_x1 );
ADD_ATTR( "x2", attr_x2 );
ADD_ATTR( "xlink:href", attr_xlink_href );
ADD_ATTR( "y", attr_y );
ADD_ATTR( "y1", attr_y1 );
ADD_ATTR( "y2", attr_y2 );
//--------------------------------------
std::sort(m_map.begin(),
m_map.end(),
make_comparer
(
&map_type::value_type::first,
string_comparer()
)
);
map_type::iterator it = m_map.begin();
map_type::iterator end = m_map.end();
for (unsigned i = 0; it != end; ++it)
m_names_positions[it->second] = i++;
}
#undef ADD_ATTR
//-------------------------------------------------------------------------
attr_e attributes_map::get_type(const char * name)
{
typedef std::pair<const char*, attr_e>* iterator;
std::pair<map_type::iterator,map_type::iterator> range;
range = std::equal_range(m_map.begin(), m_map.end(), name,
make_comparer
(
&std::pair<const char*, attr_e>::first,
string_comparer()
));
return range.first != range.second ? range.first->second : end_of_attr;
}
//-------------------------------------------------------------------------
const char * attributes_map::get_name(unsigned attr)
{
assert(attr >= 0);
assert(attr < end_of_attr);
return m_map[m_names_positions[attr]].first;
}
} // namespace svg
} // namespace agg

View File

@ -0,0 +1,24 @@
#ifndef AGG_SVG_ATTRIBUTES_MAP
#define AGG_SVG_ATTRIBUTES_MAP
//-----------------------------------------------------------------------------
#include "agg_svg_defines.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
class attributes_map
{
public:
//---------------------------------------------------------------------
attributes_map();
//---------------------------------------------------------------------
attr_e get_type(const char * name);
//---------------------------------------------------------------------
const char * get_name(unsigned attr);
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_ATTRIBUTES_MAP

View File

@ -0,0 +1,274 @@
//-----------------------------------------------------------------------------
#include "agg_svg_attributes_setter.h"
#include "agg_svg_attributes.h"
#include "agg_svg_rendering_interpreter.h"
#include <string>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
attributes_setter::attributes_setter(attributes& at)
: m_attributes(at)
, m_interpreter(0)
{
}
//-------------------------------------------------------------------------
void attributes_setter::set_interpreter(rendering_interpreter* rin)
{
m_interpreter = rin;
}
//-------------------------------------------------------------------------
void attributes_setter::set_xlink_attributes(attr_data* attr,
unsigned num_attr)
{
element_e element;
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed) switch (attr[i].code)
{
case attr_xlink_href:
assert(attr[i].data.size() > 0);
element = m_interpreter->current_element();
if (element == elem_linearGradient ||
element == elem_radialGradient )
{
m_interpreter->process_xlink_href(attr[i].data);
}
attr[i].processed = true;
break;
}
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_paint_attributes(attr_data* attr, unsigned num_attr)
{
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed) switch (attr[i].code)
{
case attr_color:
assert(attr[i].data.size() == sizeof(agg::rgba8));
m_attributes.color(attr[i].data.color_at(0));
attr[i].processed = true;
break;
case attr_fill:
set_fill(attr[i].data);
attr[i].processed = true;
break;
case attr_fill_rule:
assert(attr[i].data.size() == 1);
m_attributes.fill_rule(fill_rule_e(*attr[i].data));
attr[i].processed = true;
break;
case attr_stroke:
set_stroke(attr[i].data);
attr[i].processed = true;
break;
case attr_stroke_linecap:
assert(attr[i].data.size() == 1);
m_attributes.stroke_linecap(stroke_linecap_e(*attr[i].data));
attr[i].processed = true;
break;
case attr_stroke_linejoin:
assert(attr[i].data.size() == 1);
m_attributes.stroke_linejoin(stroke_linejoin_e(*attr[i].data));
attr[i].processed = true;
break;
case attr_stroke_miterlimit:
assert(attr[i].data.size() == sizeof(coord_type));
m_attributes.stroke_miterlimit(attr[i].data.coord_at(0));
attr[i].processed = true;
break;
case attr_stroke_width:
assert(attr[i].data.size() == sizeof(coord_type) + 1);
m_attributes.stroke_width(attr[i].data.units_value(m_attributes));
attr[i].processed = true;
break;
}
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_color_attributes(attr_data* attr,
unsigned num_attr)
{
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed && attr[i].code == attr_color)
{
assert(attr[i].data.size() == sizeof(agg::rgba8));
m_attributes.color(attr[i].data.color_at(0));
attr[i].processed = true;
}
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_opacity_attributes(attr_data* attr,
unsigned num_attr)
{
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed) switch (attr[i].code)
{
case attr_opacity:
assert(attr[i].data.size() == sizeof(coord_type));
m_attributes.opacity(attr[i].data.coord_at(0) * m_attributes.opacity());
attr[i].processed = true;
break;
case attr_stroke_opacity:
assert(attr[i].data.size() == sizeof(coord_type));
m_attributes.stroke_opacity(attr[i].data.coord_at(0));
attr[i].processed = true;
break;
case attr_fill_opacity:
assert(attr[i].data.size() == sizeof(coord_type));
m_attributes.fill_opacity(attr[i].data.coord_at(0));
attr[i].processed = true;
break;
}
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_transform_attributes(attr_data* attr,
unsigned num_attr)
{
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed && attr[i].code == attr_transform)
{
set_transform(m_attributes, attr[i].data);
attr[i].processed = true;
}
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_presentation_attributes(attr_data* attr,
unsigned num_attr)
{
set_paint_attributes (attr, num_attr);
set_color_attributes (attr, num_attr);
set_opacity_attributes (attr, num_attr);
set_xlink_attributes (attr, num_attr);
}
//-------------------------------------------------------------------------
void attributes_setter::set_basic_shapes_common_attributes(
attr_data* attr,
unsigned num_attr)
{
set_paint_attributes (attr, num_attr);
set_color_attributes (attr, num_attr);
set_opacity_attributes (attr, num_attr);
set_transform_attributes (attr, num_attr);
}
//-------------------------------------------------------------------------
void attributes_setter::set_stroke_for_id(data_accessor_type data)
{
++data; // skip paint type
switch (m_interpreter->interpret_element(data))
{
case elem_linearGradient:
case elem_radialGradient:
m_attributes.stroke_gradient_id(data);
break;
default:
m_attributes.stroke_none();
assert(false);
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_fill_for_id(data_accessor_type data)
{
++data; // skip paint type
switch (m_interpreter->interpret_element(data))
{
case elem_linearGradient:
case elem_radialGradient:
m_attributes.fill_gradient_id(data);
break;
default:
m_attributes.fill_none();
assert(false);
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_fill(const data_accessor_type& data)
{
assert(data.size() >= 1);
paint_type_e p = paint_type_e(*data);
switch (p)
{
//---------------------------------------------------------------------
case paint_none:
assert(data.size() == 1);
m_attributes.fill_none();
break;
//---------------------------------------------------------------------
case paint_currentColor:
assert(data.size() == 1);
m_attributes.fill_currentColor();
break;
//---------------------------------------------------------------------
case paint_color:
assert(data.size() == 1 + sizeof(agg::rgba8));
m_attributes.fill(data.color_at(1));
break;
//---------------------------------------------------------------------
case paint_id:
set_fill_for_id(data);
break;
//---------------------------------------------------------------------
case paint_gradient:
assert(false);
//---------------------------------------------------------------------
default:
assert(false);
}
}
//-------------------------------------------------------------------------
void attributes_setter::set_stroke(const data_accessor_type& data)
{
assert(data.size() >= 1);
paint_type_e p = paint_type_e(*data);
switch (p)
{
//---------------------------------------------------------------------
case paint_none:
assert(data.size() == 1);
m_attributes.stroke_none();
break;
//---------------------------------------------------------------------
case paint_currentColor:
assert(data.size() == 1);
m_attributes.stroke_currentColor();
break;
//---------------------------------------------------------------------
case paint_color:
assert(data.size() == sizeof(agg::rgba8) + 1);
m_attributes.stroke(data.color_at(1));
break;
//---------------------------------------------------------------------
case paint_id:
set_stroke_for_id(data);
break;
//---------------------------------------------------------------------
case paint_gradient:
assert(false);
//---------------------------------------------------------------------
default:
assert(false);
}
}
//-------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,119 @@
#ifndef AGG_SVG_ATTRIBUTES_SETTER_INCLUDE
#define AGG_SVG_ATTRIBUTES_SETTER_INCLUDE
//-----------------------------------------------------------------------------
#include "agg_svg_dom_storage.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class attributes;
class rendering_interpreter;
//-------------------------------------------------------------------------
class attributes_setter
{
public:
//---------------------------------------------------------------------
attributes_setter(attributes&);
//---------------------------------------------------------------------
void set_interpreter(rendering_interpreter*);
//---------------------------------------------------------------------
void set_paint_attributes (attr_data*, unsigned);
void set_color_attributes (attr_data*, unsigned);
void set_opacity_attributes (attr_data*, unsigned);
void set_transform_attributes (attr_data*, unsigned);
void set_basic_shapes_common_attributes(attr_data*, unsigned);
void set_presentation_attributes (attr_data*, unsigned);
void set_xlink_attributes (attr_data*, unsigned);
//---------------------------------------------------------------------
template <class Consumer>
void set_transform(Consumer& cons, const data_accessor_type& data)
{
assert(data.size() >= 1);
transform_e t = transform_e(*data);
switch (t)
{
//-----------------------------------------------------------------
case transform_matrix:
assert(data.size() == 1 + 6 * sizeof(coord_type));
cons.transform(data.coord_at(1),
data.coord_at(1 + sizeof(coord_type)),
data.coord_at(1 + sizeof(coord_type) * 2),
data.coord_at(1 + sizeof(coord_type) * 3),
data.coord_at(1 + sizeof(coord_type) * 4),
data.coord_at(1 + sizeof(coord_type) * 5));
break;
//-----------------------------------------------------------------
case transform_translate:
assert(data.size() == 1 + 2 * sizeof(coord_type));
cons.translate(data.coord_at(1),
data.coord_at(1 + sizeof(coord_type)));
break;
//-----------------------------------------------------------------
case transform_rotate:
assert(data.size() >= 1 + sizeof(coord_type));
if (data.size() - 1 == sizeof(coord_type))
{
cons.rotate(data.coord_at(1));
}
else
{
assert(data.size() == 1 + 3 * sizeof(coord_type));
cons.rotate(data.coord_at(1),
data.coord_at(1 + sizeof(coord_type)),
data.coord_at(1 + sizeof(coord_type) * 2));
}
break;
//-----------------------------------------------------------------
case transform_scale:
assert(data.size() >= 1 + sizeof(coord_type));
if (data.size() - 1 == sizeof(coord_type))
{
cons.scale(data.coord_at(1));
}
else
{
assert(data.size() == 1 + 2 * sizeof(coord_type));
cons.scale(data.coord_at(1),
data.coord_at(1 + sizeof(coord_type)));
}
break;
//-----------------------------------------------------------------
case transform_skew_x:
assert(data.size() == 1 + sizeof(coord_type));
cons.skew_x(data.coord_at(1));
break;
//-----------------------------------------------------------------
case transform_skew_y:
assert(data.size() == 1 + sizeof(coord_type));
cons.skew_y(data.coord_at(1));
break;
//-----------------------------------------------------------------
default:
assert(false);
}
}
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
void set_fill (const data_accessor_type&);
//---------------------------------------------------------------------
void set_stroke(const data_accessor_type&);
//---------------------------------------------------------------------
void set_fill_for_id (data_accessor_type);
void set_stroke_for_id(data_accessor_type);
//---------------------------------------------------------------------
private:
attributes& m_attributes;
rendering_interpreter* m_interpreter;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_ATTRIBUTES_SETTER_INCLUDE

View File

@ -0,0 +1,72 @@
#ifndef AGG_SVG_BASICS_INCLUDED
#define AGG_SVG_BASICS_INCLUDED
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <string>
#include "agg_array.h"
#include "agg_pixfmt_rgba.h"
#include "platform/agg_platform_support.h"
#include "agg_svg_defines.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// The main container used to store binary SVG data
typedef agg::pod_bvector<agg::int8u,14> data_container;
//-------------------------------------------------------------------------
template<class Container> class data_accessor;
//-------------------------------------------------------------------------
typedef data_accessor<data_container> data_accessor_type;
//-------------------------------------------------------------------------
typedef double coord_type;
//-------------------------------------------------------------------------
typedef char char_type;
//-------------------------------------------------------------------------
const pix_format_e pix_format = agg::pix_format_bgra32;
//-------------------------------------------------------------------------
typedef agg::rgba8 color_type;
typedef agg::pixel32_type pixel_type;
typedef agg::order_bgra component_order;
typedef agg::rect_d rectangle;
//-------------------------------------------------------------------------
struct length
{
coord_type value;
units2_e unit;
};
//-------------------------------------------------------------------------
typedef length coordinate;
//-------------------------------------------------------------------------
typedef agg::pod_auto_array<color_type, 256> gradient_lut_type;
//-------------------------------------------------------------------------
struct string_comparer
{
bool operator()(const char* lhs, const char* rhs) const
{
using namespace std;
return strcmp(lhs, rhs) < 0;
}
};
//-------------------------------------------------------------------------
struct string_n_comparer
{
string_n_comparer(unsigned len) : m_len(len) {}
bool operator()(const char* lhs, const char* rhs) const
{
using namespace std;
return strncmp(lhs, rhs, m_len) < 0;
}
unsigned m_len;
};
} // namespace svg
} // namespace agg
#endif // ifndef AGG_SVG_BASICS_INCLUDED

View File

@ -0,0 +1,573 @@
//-----------------------------------------------------------------------------
#include "agg_svg_color_parser.h"
#include "agg_svg_utils.h"
#include <cstdlib> // for wcstombs
#include <cstring>
#include "agg_svg_basics.h"
#include "agg_svg_exception.h"
#include "member_comparer.h"
#include <utility>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
VEC_COLOR_RGBA color_parser::m_colors_to_rgba;
VEC_ULONG_COLOR color_parser::m_ulong_to_colors;
//-------------------------------------------------------------------------
const char* color_parser::m_input_str = init();
//-------------------------------------------------------------------------
namespace
{
//---------------------------------------------------------------------
inline unsigned long make_color(unsigned char r,
unsigned char g,
unsigned char b)
{
return (unsigned long)(r) |
(unsigned long)(g) << 8 |
(unsigned long)(b) << 16;
}
//---------------------------------------------------------------------
template <class T>
struct find_result
{
typedef std::pair<typename T::iterator, typename T::iterator> type;
};
}
//-------------------------------------------------------------------------
#define ADD_COLOR( COLOR, R, G, B )\
m_colors_to_rgba.push_back( VEC_COLOR_RGBA::value_type(COLOR,agg::rgba8(R,G,B)) );\
m_ulong_to_colors.push_back(VEC_ULONG_COLOR::value_type(make_color(R, G, B), COLOR));
//-------------------------------------------------------------------------
const char* color_parser::init()
{
m_colors_to_rgba.reserve( 150 );
m_ulong_to_colors.reserve( 150 );
ADD_COLOR( "aliceblue", 240, 248, 255);
ADD_COLOR( "antiquewhite", 250, 235, 215);
ADD_COLOR( "aqua", 0, 255, 255);
ADD_COLOR( "aquamarine", 127, 255, 212);
ADD_COLOR( "azure", 240, 255, 255);
ADD_COLOR( "beige", 245, 245, 220);
ADD_COLOR( "bisque", 255, 228, 196);
ADD_COLOR( "black", 0, 0, 0);
ADD_COLOR( "blanchedalmond", 255, 235, 205);
ADD_COLOR( "blue", 0, 0, 255);
ADD_COLOR( "blueviolet", 138, 43, 226);
ADD_COLOR( "brown", 165, 42, 42);
ADD_COLOR( "burlywood", 222, 184, 135);
ADD_COLOR( "cadetblue", 95, 158, 160);
ADD_COLOR( "chartreuse", 127, 255, 0);
ADD_COLOR( "chocolate", 210, 105, 30);
ADD_COLOR( "coral", 255, 127, 80);
ADD_COLOR( "cornflowerblue", 100, 149, 237);
ADD_COLOR( "cornsilk", 255, 248, 220);
ADD_COLOR( "crimson", 220, 20, 60);
ADD_COLOR( "cyan", 0, 255, 255);
ADD_COLOR( "darkblue", 0, 0, 139);
ADD_COLOR( "darkcyan", 0, 139, 139);
ADD_COLOR( "darkgoldenrod", 184, 134, 11);
ADD_COLOR( "darkgray", 169, 169, 169);
ADD_COLOR( "darkgreen", 0, 100, 0);
ADD_COLOR( "darkgrey", 169, 169, 169);
ADD_COLOR( "darkkhaki", 189, 183, 107);
ADD_COLOR( "darkmagenta", 139, 0, 139);
ADD_COLOR( "darkolivegreen", 85, 107, 47);
ADD_COLOR( "darkorange", 255, 140, 0);
ADD_COLOR( "darkorchid", 153, 50, 204);
ADD_COLOR( "darkred", 139, 0, 0);
ADD_COLOR( "darksalmon", 233, 150, 122);
ADD_COLOR( "darkseagreen", 143, 188, 143);
ADD_COLOR( "darkslateblue", 72, 61, 139);
ADD_COLOR( "darkslategray", 47, 79, 79);
ADD_COLOR( "darkslategrey", 47, 79, 79);
ADD_COLOR( "darkturquoise", 0, 206, 209);
ADD_COLOR( "darkviolet", 148, 0, 211);
ADD_COLOR( "deeppink", 255, 20, 147);
ADD_COLOR( "deepskyblue", 0, 191, 255);
ADD_COLOR( "dimgray", 105, 105, 105);
ADD_COLOR( "dimgrey", 105, 105, 105);
ADD_COLOR( "dodgerblue", 30, 144, 255);
ADD_COLOR( "firebrick", 178, 34, 34);
ADD_COLOR( "floralwhite", 255, 250, 240);
ADD_COLOR( "forestgreen", 34, 139, 34);
ADD_COLOR( "fuchsia", 255, 0, 255);
ADD_COLOR( "gainsboro", 220, 220, 220);
ADD_COLOR( "ghostwhite", 248, 248, 255);
ADD_COLOR( "gold", 255, 215, 0);
ADD_COLOR( "goldenrod", 218, 165, 32);
ADD_COLOR( "gray", 128, 128, 128);
ADD_COLOR( "grey", 128, 128, 128);
ADD_COLOR( "green", 0, 128, 0);
ADD_COLOR( "greenyellow", 173, 255, 47);
ADD_COLOR( "honeydew", 240, 255, 240);
ADD_COLOR( "hotpink", 255, 105, 180);
ADD_COLOR( "indianred", 205, 92, 92);
ADD_COLOR( "indigo", 75, 0, 130);
ADD_COLOR( "ivory", 255, 255, 240);
ADD_COLOR( "khaki", 240, 230, 140);
ADD_COLOR( "lavender", 230, 230, 250);
ADD_COLOR( "lavenderblush", 255, 240, 245);
ADD_COLOR( "lawngreen", 124, 252, 0);
ADD_COLOR( "lemonchiffon", 255, 250, 205);
ADD_COLOR( "lightblue", 173, 216, 230);
ADD_COLOR( "lightcoral", 240, 128, 128);
ADD_COLOR( "lightcyan", 224, 255, 255);
ADD_COLOR( "lightgoldenrodyellow", 250, 250, 210);
ADD_COLOR( "lightgray", 211, 211, 211);
ADD_COLOR( "lightgreen", 144, 238, 144);
ADD_COLOR( "lightgrey", 211, 211, 211);
ADD_COLOR( "lightpink", 255, 182, 193);
ADD_COLOR( "lightsalmon", 255, 160, 122);
ADD_COLOR( "lightseagreen", 32, 178, 170);
ADD_COLOR( "lightskyblue", 135, 206, 250);
ADD_COLOR( "lightslategray", 119, 136, 153);
ADD_COLOR( "lightslategrey", 119, 136, 153);
ADD_COLOR( "lightsteelblue", 176, 196, 222);
ADD_COLOR( "lightyellow", 255, 255, 224);
ADD_COLOR( "lime", 0, 255, 0);
ADD_COLOR( "limegreen", 50, 205, 50);
ADD_COLOR( "linen", 250, 240, 230);
ADD_COLOR( "magenta", 255, 0, 255);
ADD_COLOR( "maroon", 128, 0, 0);
ADD_COLOR( "mediumaquamarine", 102, 205, 170);
ADD_COLOR( "mediumblue", 0, 0, 205);
ADD_COLOR( "mediumorchid", 186, 85, 211);
ADD_COLOR( "mediumpurple", 147, 112, 219);
ADD_COLOR( "mediumseagreen", 60, 179, 113);
ADD_COLOR( "mediumslateblue", 123, 104, 238);
ADD_COLOR( "mediumspringgreen", 0, 250, 154);
ADD_COLOR( "mediumturquoise", 72, 209, 204);
ADD_COLOR( "mediumvioletred", 199, 21, 133);
ADD_COLOR( "midnightblue", 25, 25, 112);
ADD_COLOR( "mintcream", 245, 255, 250);
ADD_COLOR( "mistyrose", 255, 228, 225);
ADD_COLOR( "moccasin", 255, 228, 181);
ADD_COLOR( "navajowhite", 255, 222, 173);
ADD_COLOR( "navy", 0, 0, 128);
ADD_COLOR( "oldlace", 253, 245, 230);
ADD_COLOR( "olive", 128, 128, 0);
ADD_COLOR( "olivedrab", 107, 142, 35);
ADD_COLOR( "orange", 255, 165, 0);
ADD_COLOR( "orangered", 255, 69, 0);
ADD_COLOR( "orchid", 218, 112, 214);
ADD_COLOR( "palegoldenrod", 238, 232, 170);
ADD_COLOR( "palegreen", 152, 251, 152);
ADD_COLOR( "paleturquoise", 175, 238, 238);
ADD_COLOR( "palevioletred", 219, 112, 147);
ADD_COLOR( "papayawhip", 255, 239, 213);
ADD_COLOR( "peachpuff", 255, 218, 185);
ADD_COLOR( "peru", 205, 133, 63);
ADD_COLOR( "pink", 255, 192, 203);
ADD_COLOR( "plum", 221, 160, 221);
ADD_COLOR( "powderblue", 176, 224, 230);
ADD_COLOR( "purple", 128, 0, 128);
ADD_COLOR( "red", 255, 0, 0);
ADD_COLOR( "rosybrown", 188, 143, 143);
ADD_COLOR( "royalblue", 65, 105, 225);
ADD_COLOR( "paddlebrown", 139, 69, 19);
ADD_COLOR( "palmon", 250, 128, 114);
ADD_COLOR( "pandybrown", 244, 164, 96);
ADD_COLOR( "peagreen", 46, 139, 87);
ADD_COLOR( "peashell", 255, 245, 238);
ADD_COLOR( "pienna", 160, 82, 45);
ADD_COLOR( "pilver", 192, 192, 192);
ADD_COLOR( "pkyblue", 135, 206, 235);
ADD_COLOR( "plateblue", 106, 90, 205);
ADD_COLOR( "plategray", 112, 128, 144);
ADD_COLOR( "plategrey", 112, 128, 144);
ADD_COLOR( "pnow", 255, 250, 250);
ADD_COLOR( "ppringgreen", 0, 255, 127);
ADD_COLOR( "pteelblue", 70, 130, 180);
ADD_COLOR( "tan", 210, 180, 140);
ADD_COLOR( "teal", 0, 128, 128);
ADD_COLOR( "thistle", 216, 191, 216);
ADD_COLOR( "tomato", 255, 99, 71);
ADD_COLOR( "turquoise", 64, 224, 208);
ADD_COLOR( "violet", 238, 130, 238);
ADD_COLOR( "wheat", 245, 222, 179);
ADD_COLOR( "white", 255, 255, 255);
ADD_COLOR( "whitesmoke", 245, 245, 245);
ADD_COLOR( "yellow", 255, 255, 0);
ADD_COLOR( "yellowgreen", 154, 205, 50);
//--------------------------------------
std::sort(
m_colors_to_rgba.begin(),
m_colors_to_rgba.end(),
make_comparer(&VEC_COLOR_RGBA::value_type::first, string_comparer()));
//--------------------------------------
std::sort(
m_ulong_to_colors.begin(),
m_ulong_to_colors.end(),
make_comparer(&VEC_ULONG_COLOR::value_type::first));
//--------------------------------------
return 0;
}
//-- parses color string represented in hex format ( for ex. #FFF or #FFFFFF )
//-- return value - position where parser stopped
const char* color_parser::parse_color_hex(const char* str, agg::rgba8& color)
{
unsigned c = 0u;
unsigned r = 0u;
unsigned g = 0u;
unsigned b = 0u;
color.a = 255;
//-- find the length hex-color in input str( i.e. find_first_not_of )
int len = static_cast<int>(strspn( str, "#0123456789abcdefABCDEF" ));
switch( len )
{
case 7: //-- format #FFFFFF consists of 7 chars
sscanf( str+1, "%6x", &c );
color = agg::rgb8_packed(c);
return str+7;
case 4: //-- format #FFF consists of 4 chars
sscanf( str+1, "%1x", &r );
sscanf( str+2, "%1x", &g );
sscanf( str+3, "%1x", &b );
//-- convert format #FFF to #FFFFFF (every digit should be doubled)
color.r = (16 * r) + r;
color.g = (16 * g) + g;
color.b = (16 * b) + b;
return str+4;
default:
// Output an error and return str+len as we cannot read it
throw exception("[%s] is an invalid hex color format (expected '#FFF' or '#FFFFFF')", str);
}//switch
}
//-- parses color string represented in rgb format ( for ex. rgba(255,255,255,1.0) )
//-- return value - position where parser stopped
const char* color_parser::parse_color_rgb( const char* str, agg::rgba8& color )
{
bool rgba_format = false;
//-- check 'rgba' syntax
if( str[ RGB_KEYWORD_LEN ] == 'a' && str[ RGB_KEYWORD_LEN + 1] == '(' )
rgba_format = true;
//-- check 'rgb(' syntax
if( !rgba_format && str[ RGB_KEYWORD_LEN ] != '(' )
{
throw exception("[%s] has a wrong syntax at position %i", str, RGB_KEYWORD_LEN+1);
return 0;
}
//pos to begin search
str += ( rgba_format ? RGB_KEYWORD_LEN + 2 : RGB_KEYWORD_LEN + 1 );
color.r = get_next_rgb_value( str, ',' );
color.g = get_next_rgb_value( str, ',' );
if( rgba_format )
{
color.b = get_next_rgb_value( str, ',' );
color.a = static_cast<unsigned char>( 255 * get_opacity_value(str) + 0.5 );
}
else
{
color.b = get_next_rgb_value( str, ')' );
color.a = 255;
}
return str;
}
//--reads next RGB value from str, using stop_sign as delimiter
unsigned char color_parser::get_next_rgb_value( const char*& str, char stop_sign )
{
bool value_is_percent = false;
int value = extract_next_value( str, stop_sign, value_is_percent, 0 );
if( value_is_percent )
value = value * 255/100; //--handle percents
if( value < 0 || value > 255 )
{
throw exception("[%s] - the value %i is out of range [0,255]", m_input_str, value);
return 0;
}
return value;
}
//--reads opacity value from str
//--returns value in range [ 0.0 - 1.0 ]
float color_parser::get_opacity_value( const char*& str )
{
bool value_is_percent = false;
float fValue = extract_next_value( str, ')', value_is_percent, 0.0f, "%3f" );
if( value_is_percent )
{
throw exception("[%s] - percents are not allowed in opacity values [%f%%]", m_input_str, fValue);
return 1.0;
}
//-- check bounds
if( fValue < 0.0f ) fValue = 0.0f;
if( fValue > 1.0f ) fValue = 1.0f;
return fValue;
}
//-- parses input string and fills rgba structure.
//-- returns pointer where the parser stopped.
const char* color_parser::parse_color( const char* str, agg::rgba8& color )
{
assert( str != 0 );
m_input_str = str;
left_trim( str );
//if( strlen(str) < 4 ) // at least 4 signs in #FFF format ( all other formats are longer )
// throw exception( "[%s]- wrong syntax : too short input string", str );
if( str_starts(str, '#') )
return parse_color_hex( str, color );
if( str_starts(str,RGB_KEYWORD) ) //-- check if string begins with "rgb"
return parse_color_rgb( str, color );
//-- assume that we have keyword i.e. named color
//-- find where is the end of keyword in input str(i.e. find_first_not_of)
int pos = static_cast<int>(strspn( str, "abcdefghigklmnopqrstuvwxyz" ));
if( pos == 0 )
{
throw exception("[%s] is an unknown color or value or can not be parsed", str);
return 0;
}
// lets try to find this color in named colors vector
VEC_COLOR_RGBA::iterator it;
it = std::lower_bound(m_colors_to_rgba.begin(),
m_colors_to_rgba.end(),
str,
make_comparer
(
&VEC_COLOR_RGBA::value_type::first,
string_n_comparer(pos)
));
if( it == m_colors_to_rgba.end() )
{
throw exception("[%s] is an unknown color name (lowercase?)", str);
return 0;
}
color = it->second;
return str + pos;
}
//-- parses input string and fills rgba structure.
//-- returns pointer where the parser stopped.
const wchar_t* color_parser::parse_color( const wchar_t* wstr, agg::rgba8& color )
{
using namespace std;
char szBuf[ 256 ];
size_t nLen = wcslen(wstr);
if( nLen != wcstombs( szBuf, wstr, nLen + 1 ) )
{
throw exception("[%s] is an invalid color string", to_str(wstr).c_str());
return 0;
}
return wstr + ( parse_color(szBuf, color) - szBuf );
}
agg::rgba8 color_parser::parse_str( const char* str )
{
agg::rgba8 color(0, 0, 0, 0);
parse_color( str, color );
return color;
}
//-- extracts next value from string ( R , G, B or Opacity )
template<class T>
T color_parser::extract_next_value(
const char*& str, char stop_sign, bool& value_is_percent,
T dummy, const char* fmt )
{
using namespace std;
//STATIC_ASSERT(
assert( sizeof(T) == sizeof(int) || sizeof(T) == sizeof(float) );
// Extract_next_value_supports_only_int_and_float )
value_is_percent = false;
//--find value start position ( find_first_of )
int pos_value_begin = static_cast<int>(strcspn( str, " -0123456789" ));
if( pos_value_begin != 0 )
{
throw exception("[%s] has a wrong syntax at position %i", m_input_str, str-m_input_str+1);
return 0;
}
left_trim( str );//-- skip leading spaces
//--find value stop position
const char * p = strchr( str, stop_sign );
if( p == 0 )
{
throw exception("[%s] found, [%c] expected", m_input_str, stop_sign);
return 0;
}
if( *(p-1) == '%' ) //if value is a percent
value_is_percent = true;
T value;
int res = sscanf( str, fmt, &value );
if( res != 1 )
{
throw exception("[%s] - value [%s] can not be converted", m_input_str, str);
return 0;
}
str = p+1; //--go to next value in str
return value;
}
//-------------------------------------------------------------------------
//-- from given numbers (r,g,b,a) composes the ASCII-string of the color
std::string color_parser::compose_color_string(unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a)
{
float fOpacity = 0.01f * ( 0.5f + (a / 255.0f) * 100.f);
if (a != 255)
{
// !EVC FIX: No std::ostringstream on WindowsCe
char buf[1024];
unsigned r_ = r;
unsigned g_ = g;
unsigned b_ = b;
sprintf(buf, "rgba(%d,%d,%d,%.1f)", r_, g_, b_, fOpacity);
return std::string(buf);
/*
std::ostringstream oss;
oss << "rgba(" << (int)r << "," << (int)g << "," << (int)b << "," << fOpacity << ")";
return oss.str();
*/
}
unsigned long ulColor = ((unsigned long)(r) | (unsigned long)(g) << 8 | (unsigned long)(b) << 16 );
// lets try to find this color in color keywords vector
std::pair<VEC_ULONG_COLOR::iterator, VEC_ULONG_COLOR::iterator>
result =
std::equal_range(m_ulong_to_colors.begin(),
m_ulong_to_colors.end(),
ulColor,
make_comparer
(
&VEC_ULONG_COLOR::value_type::first,
std::less<VEC_ULONG_COLOR::value_type::first_type>()
));
if (result.first != result.second)
return result.first->second;
char szColor[8];
//-- if we have double digits like #FFFFFF - we should
//-- return string in short hex format( #FFF )
if( (r & 0x0F) == (r >> 4) && (g & 0x0F) == (g >> 4) && (b & 0x0F) == (b >> 4) )
{
r = (r >> 4);
g = (g >> 4);
b = (b >> 4);
int ret = sprintf( szColor, "#%x%x%x" , r,g,b );
assert( 4 == ret );
}else
{
int ret = sprintf( szColor, "#%02x%02x%02x" , r,g,b );
assert( 7 == ret);
}
return std::string( szColor );
}
//-------------------------------------------------------------------------
//-- from given numbers (r,g,b,a) composes the ASCII-string of the color
std::string color_parser::compose_color_string(unsigned char r,
unsigned char g,
unsigned char b)
{
unsigned long color = make_color(r, g, b);
// lets try to find this color in color keywords vector
find_result<VEC_ULONG_COLOR>::type result;
result = std::equal_range
(
m_ulong_to_colors.begin(),
m_ulong_to_colors.end(),
color,
make_comparer
(
&VEC_ULONG_COLOR::value_type::first,
std::less<VEC_ULONG_COLOR::value_type::first_type>()
)
);
if (result.first != result.second)
return result.first->second;
char buf[1024];
unsigned r_ = r;
unsigned g_ = g;
unsigned b_ = b;
sprintf(buf, "rgb(%d,%d,%d)", r_, g_, b_);
return std::string(buf);
}
} // namespace svg
}

View File

@ -0,0 +1,80 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_COLOR_PARSER_INCLUDED
#define AGG_SVG_COLOR_PARSER_INCLUDED
//-----------------------------------------------------------------------------
#if defined(_MSC_VER) && _MSC_VER < 1300
#pragma warning( disable : 4786 ) // ident trunc to '255' chars in debug info
#endif
//-----------------------------------------------------------------------------
#include "agg_svg_basics.h"
#include <string>
#include <vector>
#include <cassert>
#include <utility>
//-----------------------------------------------------------------------------
#define RGB_KEYWORD "rgb"
#define RGB_KEYWORD_LEN sizeof(RGB_KEYWORD)-1
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
typedef std::vector<std::pair<const char*,agg::rgba8> > VEC_COLOR_RGBA;
typedef std::vector<std::pair<unsigned long,const char*> > VEC_ULONG_COLOR;
//-------------------------------------------------------------------------
class color_parser
{
public:
static agg::rgba8 parse_str(const char* str);
//-- parses input string and fills agg::rgba8 structure.
//-- returns pointer where the parser stopped.
static const char* parse_color( const char* str, agg::rgba8& color );
static const wchar_t* parse_color( const wchar_t* str, agg::rgba8& color );
//-- from given numbers (r,g,b,a) composes the ASCII-string of the color
static std::string compose_color_string(unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a);
//-- from given numbers (r,g,b,a) composes the ASCII-string of the color
static std::string compose_color_string(unsigned char r,
unsigned char g,
unsigned char b);
private:
//-- parses color string represented in hex format ( #FFF or #FFFFFF )
static const char* parse_color_hex( const char* str, agg::rgba8& color );
//-- parses color string represented in rgb format( ex: rgba(255,255,255,1.0) )
static const char* parse_color_rgb( const char* str, agg::rgba8& color );
//-- reads next RGB value from str, using stop_sign as delimiter
static unsigned char get_next_rgb_value( const char*& str, char stop_sign );
//-- reads opacity value from str
static float get_opacity_value( const char*& str );
//-- extracts next value from str ( R, G, B or Opacity )
template<class T>
static T extract_next_value(
const char*& str, char stop_sign, bool& value_is_percent,
T dummy, const char* fmt="%3d" );
static const char* init();
private:
static const char* m_input_str;
static VEC_COLOR_RGBA m_colors_to_rgba;
static VEC_ULONG_COLOR m_ulong_to_colors;
};//color_parser class
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_COLOR_PARSER_INCLUDED

View File

@ -0,0 +1,222 @@
#ifndef AGG_SVG_DATA_ACCESSOR_INCLUDED
#define AGG_SVG_DATA_ACCESSOR_INCLUDED
#include "agg_svg_basics.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// Data accessor. An analog of a simple const pointer or an iterator used with
// plain arrays or standard containers.
template<class Container> class data_accessor
{
public:
typedef Container container_type;
typedef typename container_type::value_type value_type;
//------------------------------------------------------------------------
data_accessor() : m_container(0), m_pos(0), m_size(0) {}
data_accessor(const container_type& c) :
m_container(&c), m_pos(0), m_size(c.size()) {}
data_accessor(const container_type& c, unsigned pos, unsigned size_) :
m_container(&c), m_pos(pos), m_size(size_) {}
void reset()
{
m_container = 0;
m_pos = 0;
m_size = 0;
}
void init(const container_type& c)
{
m_container = &c;
m_pos = 0;
m_size = c.size();
}
void init(const container_type& c, unsigned pos, unsigned size_)
{
m_container = &c;
m_pos = pos;
m_size = size_;
}
//------------------------------------------------------------------------
const container_type* container() const { return m_container; }
unsigned pos() const { return m_pos; }
unsigned size() const { return m_size; }
value_type value() const { return m_container->value_at(m_pos); }
value_type operator * () const { return m_container->value_at(m_pos); }
value_type operator [] (unsigned i) const
{
return m_container->value_at(m_pos + i);
}
value_type at(unsigned i) const
{
return m_container->value_at(m_pos + i);
}
void inc()
{
++m_pos;
--m_size;
}
void operator ++ ()
{
++m_pos;
--m_size;
}
void operator += (unsigned n)
{
m_pos += n;
m_size -= n;
}
value_type read_value()
{
--m_size;
return m_container->value_at(m_pos++);
}
//------------------------------------------------------------------------
template <class T>
double units_value(const T& attr) const
{
return attr.conv_units(double(coord_at(0)),
units2_e(int8u_at(sizeof(coord_type))));
}
//------------------------------------------------------------------------
void value_at(unsigned i, char* v) const
{
*v = (char)at(i);
}
void value_at(unsigned i, agg::int8* v) const
{
*v = (agg::int8)at(i);
}
void value_at(unsigned i, agg::int8u* v) const
{
*v = (agg::int8u)at(i);
}
void value_at(unsigned i, agg::int16* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
}
void value_at(unsigned i, agg::int16u* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
}
void value_at(unsigned i, agg::int32* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
((agg::int8u*)v)[2] = at(i+2);
((agg::int8u*)v)[3] = at(i+3);
}
void value_at(unsigned i, agg::int32u* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
((agg::int8u*)v)[2] = at(i+2);
((agg::int8u*)v)[3] = at(i+3);
}
void value_at(unsigned i, float* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
((agg::int8u*)v)[2] = at(i+2);
((agg::int8u*)v)[3] = at(i+3);
}
void value_at(unsigned i, double* v) const
{
((agg::int8u*)v)[0] = at(i+0);
((agg::int8u*)v)[1] = at(i+1);
((agg::int8u*)v)[2] = at(i+2);
((agg::int8u*)v)[3] = at(i+3);
((agg::int8u*)v)[4] = at(i+4);
((agg::int8u*)v)[5] = at(i+5);
((agg::int8u*)v)[6] = at(i+6);
((agg::int8u*)v)[7] = at(i+7);
}
void value_at(unsigned i, agg::rgba8* v) const
{
v->r = at(i+0);
v->g = at(i+1);
v->b = at(i+2);
v->a = at(i+3);
}
template<class T> void read_value(T* v)
{
value_at(0, v);
m_pos += sizeof(T);
m_size -= sizeof(T);
}
agg::int8 int8_at(unsigned i) const { return (agg::int8)at(i); }
agg::int8u int8u_at(unsigned i) const { return (agg::int8u)at(i); }
agg::int16 int16_at(unsigned i) const { agg::int16 v; value_at(i, &v); return v; }
agg::int16u int16u_at(unsigned i) const { agg::int16u v; value_at(i, &v); return v; }
agg::int32 int32_at(unsigned i) const { agg::int32 v; value_at(i, &v); return v; }
agg::int32u int32u_at(unsigned i) const { agg::int32u v; value_at(i, &v); return v; }
coord_type coord_at(unsigned i) const { coord_type v; value_at(i, &v); return v; }
agg::rgba8 color_at(unsigned i) const { agg::rgba8 v; value_at(i, &v); return v; }
agg::int8 read_int8() { return (agg::int8)read_value(); }
agg::int8u read_int8u() { return (agg::int8u)read_value(); }
agg::int16 read_int16() { agg::int16 v; read_value(&v); return v; }
agg::int16u read_int16u() { agg::int16u v; read_value(&v); return v; }
agg::int32 read_int32() { agg::int32 v; read_value(&v); return v; }
agg::int32u read_int32u() { agg::int32u v; read_value(&v); return v; }
coord_type read_coord() { coord_type v; read_value(&v); return v; }
agg::rgba8 read_rgba8() { agg::rgba8 v; read_value(&v); return v; }
private:
const container_type* m_container;
unsigned m_pos;
unsigned m_size;
};
//-------------------------------------------------------------------------
template<class T1, class T2>
inline
bool operator<(data_accessor<T1> const & lhs, data_accessor<T2> const & rhs)
{
const agg::int32u count1 = lhs.size();
const agg::int32u count2 = rhs.size();
agg::int32u i = 0;
agg::int32u j = 0;
for (; i < count1 && j < count2; ++i, ++j)
if (lhs[i] < rhs[j])
return true;
else if (rhs[j] < lhs[i])
return false;
return (i == count1 && j != count2);
}
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_DATA_ACCESSOR_INCLUDED

View File

@ -0,0 +1,229 @@
#ifndef AGG_SVG_DEFINES_INCLUDED
#define AGG_SVG_DEFINES_INCLUDED
namespace agg
{
namespace svg
{
// Element types
//-------------------------------------------------------------------------
enum element_e
{
elem_circle,
elem_clipPath,
elem_defs,
elem_ellipse,
elem_g,
elem_line,
elem_linearGradient,
elem_path,
elem_polygon,
elem_polyline,
elem_radialGradient,
elem_rect,
elem_stop,
elem_svg,
elem_title,
elem_use,
end_of_elements
};
//-------------------------------------------------------------------------
enum attr_e
{
attr_color = 0,
attr_cx,
attr_cy,
attr_d,
attr_fill,
attr_fill_color,
attr_fill_gradient,
attr_fill_opacity,
attr_fill_rule,
attr_fx,
attr_fy,
attr_gradientTransform,
attr_gradientUnits,
attr_height,
attr_id,
attr_object_bbox,
attr_offset,
attr_opacity,
attr_points,
attr_preserveAspectRatio,
attr_r,
attr_rx,
attr_ry,
attr_spreadMethod,
attr_stop_color,
attr_stop_opacity,
attr_stroke,
attr_stroke_color,
attr_stroke_gradient,
attr_stroke_linecap,
attr_stroke_linejoin,
attr_stroke_miterlimit,
attr_stroke_opacity,
attr_stroke_width,
attr_style,
attr_transform,
attr_viewBox,
attr_width,
attr_x,
attr_x1,
attr_x2,
attr_xlink_href,
attr_y,
attr_y1,
attr_y2,
attr_bounds,
end_of_attr
};
//-----------------------------------------------------------uniform_scaling_e
enum uniform_scaling_e
{
usc_none,
usc_xMinYMin,
usc_xMidYMin,
usc_xMaxYMin,
usc_xMinYMid,
usc_xMidYMid,
usc_xMaxYMid,
usc_xMinYMax,
usc_xMidYMax,
usc_xMaxYMax
};
//---------------------------------------------------------window_fit_logic_e
enum window_fit_logic_e
{
window_meet,
window_slice
};
//---------------------------------------------------------------paint_type_e
enum paint_type_e
{
paint_none,
paint_color,
paint_currentColor,
paint_gradient,
paint_id
};
//---------------------------------------------------------------uri_type_e
enum uri_type_e
{
uri_none,
uri_id
};
//----------------------------------------------------------------gradient_e
enum gradient_e
{
gradient_linear,
gradient_radial
};
//-------------------------------------------------------------objectUnits_e
enum objectUnits_e
{
objectUnits_userSpaceOnUse,
objectUnits_objectBoundingBox,
objectUnits_strokeWidth
};
//------------------------------------------------------------spreadMethod_e
enum spreadMethod_e
{
spreadMethod_pad,
spreadMethod_reflect,
spreadMethod_repeat
};
//---------------------------------------------------------------transform_e
enum transform_e
{
transform_matrix,
transform_translate,
transform_rotate,
transform_scale,
transform_skew_x,
transform_skew_y
};
//----------------------------------------------------------stroke_linejoin_e
enum stroke_linejoin_e
{
stroke_linejoin_miter = 0,
stroke_linejoin_round = 1,
stroke_linejoin_bevel = 2
};
//-----------------------------------------------------------stroke_linecap_e
enum stroke_linecap_e
{
stroke_linecap_butt = 0,
stroke_linecap_round = 1,
stroke_linecap_square = 2
};
//----------------------------------------------------------------fill_rule_e
enum fill_rule_e
{
fill_rule_nonzero = 0,
fill_rule_evenodd = 1
};
//-----------------------------------------------------------------------------
enum units2_e
{
units_em, // The font size of the default font,
// usually equivalent to the height of a character
units_ex, // The height of the letter x
units_px, // Pixels
units_pt,
units_pt_x, // Points (1/72 of an inch)
units_pt_y,
units_pc,
units_pc_x, // Picas (1/6 of an inch)
units_pc_y,
units_cm,
units_cm_x, // Centimeters
units_cm_y,
units_mm,
units_mm_x, // Millimeters
units_mm_y,
units_in,
units_in_x, // Inches
units_in_y,
units_percent, // Percent
units_percent_x,
units_percent_y,
units_deg, // Angle units
units_grad,
units_rad,
};
} // namespace svg
} // namespace agg
#endif // ifndef AGG_SVG_DEFINES_INCLUDED

View File

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
#include "agg_svg_dom_read_protocol.h"
#include "agg_svg_dom_storage.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
read_protocol::read_protocol(dom_storage const& dom)
: m_storage(dom.storage())
, m_size(dom.storage().size())
, m_idx(0)
{
}
//-------------------------------------------------------------------------
tag_e read_protocol::read_tag()const
{
data_container::value_type val = m_storage[m_idx++];
tag_e tag = tag_e(val);
assert(tag < end_of_tags);
return tag;
}
//-------------------------------------------------------------------------
void read_protocol::element_bin(agg::int32u* el_idx, element_e* code) const
{
*el_idx = m_idx - 1;
*code = (element_e)m_storage[m_idx++];
}
//-------------------------------------------------------------------------
void read_protocol::attribute_bin(data_container const** cont,attr_e* type,
agg::int32u* data_idx, agg::int32u* size)const
{
*type = (attr_e)m_storage[m_idx++];
data_accessor_type accessor(m_storage);
accessor.value_at(m_idx, size);
m_idx += sizeof(agg::int32u);
*data_idx = m_idx;
m_idx += *size;
*cont = &m_storage;
}
//-------------------------------------------------------------------------
void read_protocol::attribute_bin_short(data_container const ** cont,
attr_e* type,
agg::int32u* data_idx, agg::int32u* size)const
{
*type = (attr_e)m_storage[m_idx++];
data_accessor_type accessor(m_storage);
*size = m_storage[m_idx++];
*data_idx = m_idx;
m_idx += *size;
*cont = &m_storage;
}
//-------------------------------------------------------------------------
void read_protocol::attribute_bin_byte(data_container const ** cont,
attr_e* type,
agg::int32u* data_idx)const
{
*type = (attr_e)m_storage[m_idx++];
*cont = &m_storage;
*data_idx = m_idx;
++m_idx;
}
//-------------------------------------------------------------------------
void read_protocol::end_element() const
{
}
//-------------------------------------------------------------------------
}
}

View File

@ -0,0 +1,80 @@
#ifndef AGG_SVG_DOM_STORAGE_READ_PROTOCOL_INCLUDE
#define AGG_SVG_DOM_STORAGE_READ_PROTOCOL_INCLUDE
//-----------------------------------------------------------------------------
#include "agg_svg_basics.h"
#include "agg_svg_defines.h"
#include "agg_svg_tags.h"
#include "agg_svg_iomemstream.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class dom_storage;
//-------------------------------------------------------------------------
class read_protocol
{
private:
read_protocol(read_protocol const&);
read_protocol operator=(read_protocol const&);
public:
//---------------------------------------------------------------------
explicit read_protocol(dom_storage const&);
//---------------------------------------------------------------------
void rewind(agg::int32u idx);
//---------------------------------------------------------------------
bool end()const;
//---------------------------------------------------------------------
void unread(unsigned offset = 1) const;
//---------------------------------------------------------------------
agg::int32u current_location() const;
//---------------------------------------------------------------------
tag_e read_tag()const;
//---------------------------------------------------------------------
void element_bin(agg::int32u* idx, element_e* code)const;
//---------------------------------------------------------------------
void attribute_bin(data_container const ** cont, attr_e* type,
agg::int32u* data_idx, agg::int32u* size) const;
//---------------------------------------------------------------------
void attribute_bin_short(data_container const ** cont, attr_e* type,
agg::int32u* data_idx,agg::int32u* size)const;
//---------------------------------------------------------------------
void attribute_bin_byte(data_container const ** cont, attr_e* type,
agg::int32u* data_idx)const;
//---------------------------------------------------------------------
void end_element() const;
//---------------------------------------------------------------------
private:
const data_container & m_storage;
agg::int32u m_size;
mutable agg::int32u m_idx;
};
//-------------------------------------------------------------------------
inline void read_protocol::rewind(agg::int32u idx)
{
m_idx = idx;
}
//-------------------------------------------------------------------------
inline bool read_protocol::end()const
{
return m_idx >= m_size;
}
//-------------------------------------------------------------------------
inline void read_protocol::unread(unsigned offset) const
{
m_idx -= offset;
}
//-------------------------------------------------------------------------
inline agg::int32u read_protocol::current_location() const
{
return m_idx;
}
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_DOM_STORAGE_READ_PROTOCOL_INCLUDE

View File

@ -0,0 +1,417 @@
#include "agg_svg_dom_storage.h"
#include "agg_svg_ptr_size_pair.h"
#include "agg_svg_basics.h"
#include "agg_svg_path_interpreter.h"
#include "agg_bounding_rect.h"
#include "agg_svg_rendering_interpreter.h"
#include "agg_svg_attribute_source.h"
#include "agg_svg_percent.h"
//-----------------------------------------------------------------------------
#include <cstring> // for std::strlen, std::memcpy
//-----------------------------------------------------------------------------
namespace
{
bool find_attribute(agg::svg::read_protocol const& rp, agg::svg::attr_data& attr)
{
using namespace agg::svg;
attr_e attr_type = end_of_attr;
agg::int32u data_size = 0u;
bool find = false;
const data_container* cont = 0;
agg::int32u data_idx = 0;
while (!rp.end())
{
tag_e tag = rp.read_tag();
switch (tag)
{
case tag_attribute_bin_byte:
rp.attribute_bin_byte(&cont, &attr_type, &data_idx);
if (attr.code == attr_type)
{
attr.data.init(*cont, data_idx, 1);
return true;
}
break;
case tag_attribute_bin:
rp.attribute_bin(&cont, &attr_type, &data_idx, &data_size);
if (attr.code == attr_type)
{
assert(!find);
attr.data.init(*cont, data_idx, data_size);
find = true;
}
break;
case tag_attribute_bin_short:
rp.attribute_bin_short(&cont, &attr_type, &data_idx, &data_size);
if (attr.code == attr_type)
{
assert(!find);
attr.data.init(*cont, data_idx, data_size);
find = true;
}
break;
default:
rp.unread(1);
return find;
}
}
assert(false);
return find;
}
}
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
namespace
{
void read_raw_data(data_container const & cont, agg::int8u* ptr,
unsigned size, unsigned idx)
{
for (unsigned i = 0u; i < size; ++i)
{
*ptr++ = cont[idx++];
}
}
}
//-------------------------------------------------------------------------
iomemstream& operator<<(iomemstream& s, tag_e tag)
{
return s << (agg::int8u)tag;
}
//-------------------------------------------------------------------------
iomemstream& operator<<(iomemstream& s, attr_e attr)
{
return s << (agg::int8u)attr;
}
//-------------------------------------------------------------------------
void dom_storage::start_element(element_e el)
{
m_storage << tag_element_bin << (agg::int8u)el;
}
//-------------------------------------------------------------------------
void dom_storage::end_element()
{
m_storage << tag_end_element;
}
//-------------------------------------------------------------------------
void dom_storage::attribute(attr_e attr, const void * data,
agg::int32u size)
{
assert(data && size);
if (size <= 255)
{
attribute_short(attr, data, size);
}
else
{
agg::svg::attribute_bin src(attr, data, size);
m_storage.add(src);
}
}
//-------------------------------------------------------------------------
void dom_storage::attribute_short(attr_e attr, const void* data,
agg::int8u size)
{
agg::svg::attribute_bin_short src(attr, data, size);
m_storage.add(src);
}
//-------------------------------------------------------------------------
void dom_storage::attribute(attr_e attr, agg::int8u type,
const void* data, agg::int32u size)
{
if (size <= 254)
{
attribute_short(attr, type, data, size);
}
else
{
agg::svg::attribute_bin src(attr, type, data, size);
m_storage.add(src);
}
}
//-------------------------------------------------------------------------
void dom_storage::attribute_short(attr_e attr, agg::int8u type,
const void* data, agg::int8u size)
{
agg::svg::attribute_bin_short src(attr, type, data, size);
m_storage.add(src);
}
//-------------------------------------------------------------------------
void dom_storage::attribute_byte(attr_e attr, agg::int8u val)
{
agg::svg::attribute_byte src(attr, val);
m_storage.add(src);
}
//-------------------------------------------------------------------------
void dom_storage::attribute_string(attr_e attr, const char* val)
{
using namespace std;
attribute(attr, val, static_cast<agg::int32u>(strlen(val)));
}
//-------------------------------------------------------------------------
void dom_storage::attribute(attr_e attr, const length & val)
{
m_storage << tag_attribute_bin_short
<< attr
<< agg::int8u(sizeof(coord_type) + 1);
m_storage.write(&val.value, sizeof(coord_type));
m_storage << (agg::int8u)val.unit;
if (attr==attr_width)
m_width = val.value;
if (attr==attr_height)
m_height = val.value;
}
//-------------------------------------------------------------------------
void dom_storage::attribute_numeric(attr_e attr, double val)
{
coord_type data = static_cast<coord_type>(val);
attribute_short(attr, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_unsigned(attr_e attr, unsigned val)
{
attribute_short(attr, &val, sizeof(unsigned));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_percent(attr_e attr, double val)
{
attribute_numeric(attr, percent::encrypt(val));
}
//-------------------------------------------------------------------------
void dom_storage::attribute(attr_e attr, const data_accessor_type & data)
{
if (data.size() <= 255u)
{
m_storage << tag_attribute_bin_short
<< attr
<< static_cast<agg::int8u>(data.size())
<< data;
}
else
{
m_storage << tag_attribute_bin << attr << data.size() << data;
}
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_matrix(double m0, double m1,
double m2, double m3,
double m4, double m5)
{
coord_type data[] = {coord_type(m0), coord_type(m1),
coord_type(m2), coord_type(m3),
coord_type(m4), coord_type(m5)};
attribute_short(attr_transform, transform_matrix, data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_translate(double dx, double dy)
{
coord_type data[] = {coord_type(dx), coord_type(dy)};
attribute_short(attr_transform, transform_translate, data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_rotate(double angle)
{
coord_type data = coord_type(angle);
attribute_short(attr_transform, transform_rotate, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_rotate(double angle,
double cx, double cy)
{
coord_type data[] = {coord_type(angle),
coord_type(cx),
coord_type(cy)};
attribute_short(attr_transform, transform_rotate, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_scale(double s)
{
coord_type data = coord_type(s);
attribute_short(attr_transform, transform_scale, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_scale(double sx, double sy)
{
coord_type data[] = {coord_type(sx), coord_type(sy)};
attribute_short(attr_transform, transform_scale, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_skew_x(double sx)
{
coord_type data = coord_type(sx);
attribute_short(attr_transform, transform_skew_x, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_transform_skew_y(double sy)
{
coord_type data = coord_type(sy);
attribute_short(attr_transform, transform_skew_y, &data, sizeof(data));
}
//-------------------------------------------------------------------------
void dom_storage::attribute_d_with_bounds(data_accessor_type data)
{
coord_type bounds[4];
path_interpreter<data_accessor_type> p(data);
agg::bounding_rect_single(p, 0,
&bounds[0], &bounds[1],
&bounds[2], &bounds[3]);
attribute(attr_bounds, bounds, sizeof(bounds));
attribute(attr_d, data);
}
//-------------------------------------------------------------------------
void dom_storage::attribute_points_with_bounds(data_accessor_type data)
{
coord_type bounds[4];
poly_interpreter<data_accessor_type> p(data, false);
agg::bounding_rect_single(p, 0,
&bounds[0], &bounds[1],
&bounds[2], &bounds[3]);
attribute(attr_bounds, bounds, sizeof(bounds));
attribute(attr_points, data);
}
//-------------------------------------------------------------------------
data_accessor_type dom_storage::get_attr_specified_value(unsigned offset, attr_e code)const
{
attr_data attr;
attr.code = code;
read_protocol rp(*this);
rp.rewind(offset);
if (rp.read_tag() == tag_element_bin)
{
element_data el;
el.clear();
rp.element_bin(&el.index, &el.code);
find_attribute(rp, attr);
}
return attr.data;
}
//-------------------------------------------------------------------------
void dom_storage::push_element(const element_data& el,
element_stack_type& element_stack) const
{
element_stack_data esd;
esd.index = el.index;
esd.code = el.code;
element_stack.add(esd);
}
//-------------------------------------------------------------------------
void dom_storage::pop_element(element_stack_type& element_stack) const
{
if (element_stack.size())
{
element_stack.remove_last();
}
}
//-------------------------------------------------------------------------
void dom_storage::proceed_attribute(attributes_type& attributes,
traverse_buffer_type& traverse_buffer,
element_data& el,
attr_data& attr,
data_container const& cont,
agg::int32u data_idx,
agg::int32u data_size) const
{
int i = -1;
switch (attr.code)
{
case attr_points:
case attr_d:
el.shape_data.init(cont, data_idx, data_size);
break;
case attr_bounds:
i = traverse_buffer.allocate_continuous_block(data_size);
if (i < -1)
{
el.bounds = 0;
}
else
{
read_raw_data(cont, &traverse_buffer[i], data_size, data_idx);
el.bounds = &traverse_buffer[i];
}
break;
default:
attr.processed = false;
attr.data.init(cont, data_idx, data_size);
if (attributes.size() >= attributes.capacity())
{
attributes.resize(attributes.size() + 256);
}
attributes.add(attr);
}
}
//-------------------------------------------------------------------------
void dom_storage::collect_attributes(read_protocol const& rp,
element_data& el, attributes_type& attributes,
traverse_buffer_type& traverse_buffer) const
{
attr_data attr;
unsigned data_idx;
unsigned data_size;
int i = -1;
const data_container* cont = 0;
attributes.remove_all();
traverse_buffer.remove_all();
while (!rp.end())
{
tag_e tag = rp.read_tag();
switch (tag)
{
default:
el.attr = &attributes[0];
el.num_attr = attributes.size();
rp.unread(1);
return;
case tag_attribute_bin:
rp.attribute_bin(&cont, &attr.code, &data_idx, &data_size);
proceed_attribute(attributes, traverse_buffer, el, attr, *cont, data_idx, data_size);
break;
case tag_attribute_bin_short:
rp.attribute_bin_short(&cont, &attr.code, &data_idx, &data_size);
proceed_attribute(attributes, traverse_buffer, el, attr, *cont, data_idx, data_size);
break;
case tag_attribute_bin_byte:
rp.attribute_bin_byte(&cont, &attr.code, &data_idx);
proceed_attribute(attributes, traverse_buffer, el, attr, *cont, data_idx, 1);
break;
}
}
}
}
}

View File

@ -0,0 +1,278 @@
#ifndef AGG_SVG_DOM_STORAGE_INCLUDE
#define AGG_SVG_DOM_STORAGE_INCLUDE
//-----------------------------------------------------------------------------
#include "agg_svg_defines.h"
#include "agg_svg_basics.h"
#include "agg_svg_tags.h"
#include "agg_svg_dom_read_protocol.h"
#include "agg_svg_assoc_pod_array.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//---------------------------------------------------------------------
// Attribute data. If the attribute is known, it has valid "code"
// (see enum attr_e). If it's unknown, its "code" has value
// "end_of_attributes".
// Fields "data" represent raw attribute data;
// its interpretation depends on the attribute.
//
//----------------------------------------------------------------------
struct attr_data
{
bool processed;
attr_e code;
data_accessor_type data;
};
//-------------------------------------------------------------------------
// Element data. Field "index" defines the starting index in the array
// where the element begins.
// If the attribute is known, it has valid "code"
// (see enum element_e). If it's unknown,
// its code has value "end_of_elements".
//
//-------------------------------------------------------------------------
struct element_data
{
agg::int32u index;
element_e code;
const agg::int8u* bounds;
attr_data* attr;
unsigned num_attr;
data_accessor_type shape_data;
void clear()
{
index = 0u;
code = end_of_elements;
bounds = 0;
attr = 0;
num_attr = 0u;
shape_data.reset();
}
};
//-------------------------------------------------------------------------
template <class DataAccessor>
struct data_accessor_compare
{
//---------------------------------------------------------------------
typedef data_accessor<agg::pod_array_adaptor<char const> > string_type;
//---------------------------------------------------------------------
bool operator()(const DataAccessor& lhs, const DataAccessor& rhs)const
{
return lhs < rhs;
}
//---------------------------------------------------------------------
bool operator()(const DataAccessor& lhs, const string_type& rhs)const
{
return lhs < rhs;
}
//---------------------------------------------------------------------
bool operator()(const string_type& lhs, const DataAccessor& rhs)const
{
return lhs < rhs;
}
};
//-------------------------------------------------------------------------
class dom_storage
{
public:
//---------------------------------------------------------------------
struct element_location
{
agg::int32u idx;
element_e code;
};
typedef assoc_pod_array
<
data_accessor_type,
element_location,
data_accessor_compare<data_accessor_type>
> map_type;
//---------------------------------------------------------------------
void clear()
{
m_storage.clear();
m_width = m_height = 0;
}
//---------------------------------------------------------------------
void start_element(element_e);
//---------------------------------------------------------------------
void attribute(attr_e, const void* data, agg::int32u size);
//---------------------------------------------------------------------
void attribute(attr_e, agg::int8u type, const void* data, agg::int32u);
//---------------------------------------------------------------------
template<class T>
void attribute_datatype(attr_e attr, const T& data)
{
attribute(attr, &data, sizeof(data));
}
//---------------------------------------------------------------------
template<class T>
void attribute_datatype(attr_e attr, agg::int8u type, const T& data)
{
attribute(attr, type, &data, sizeof(data));
}
//---------------------------------------------------------------------
void attribute(attr_e, const data_accessor_type &);
//---------------------------------------------------------------------
void attribute_byte(attr_e, agg::int8u val);
//---------------------------------------------------------------------
void attribute_string(attr_e attr, const char* val);
//---------------------------------------------------------------------
void attribute(attr_e attr, const length & val);
//---------------------------------------------------------------------
void attribute_numeric(attr_e, double val);
//---------------------------------------------------------------------
void attribute_unsigned(attr_e, unsigned val);
//---------------------------------------------------------------------
void attribute_percent(attr_e attr, double val);
//---------------------------------------------------------------------
void attribute_transform_matrix(double m0, double m1, double m2,
double m3, double m4, double m5);
//---------------------------------------------------------------------
void attribute_transform_translate(double dx, double dy);
//---------------------------------------------------------------------
void attribute_transform_rotate(double angle);
//---------------------------------------------------------------------
void attribute_transform_rotate(double angle, double cx, double cy);
//---------------------------------------------------------------------
void attribute_transform_scale(double s);
//---------------------------------------------------------------------
void attribute_transform_scale(double sx, double sy);
//---------------------------------------------------------------------
void attribute_transform_skew_x(double sx);
//---------------------------------------------------------------------
void attribute_transform_skew_y(double sy);
//---------------------------------------------------------------------
//---------------------------------------------------------------------
void attribute_d_with_bounds(data_accessor_type data);
//---------------------------------------------------------------------
void attribute_points_with_bounds(data_accessor_type data);
//---------------------------------------------------------------------
//---------------------------------------------------------------------
void end_element();
//---------------------------------------------------------------------
const data_container & storage()const { return m_storage.buffer(); }
data_container & storage() { return m_storage.buffer(); }
//---------------------------------------------------------------------
data_accessor_type get_attr_specified_value(unsigned offset, attr_e code)const;
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
void attribute_short(attr_e, const void* data, agg::int8u size);
//---------------------------------------------------------------------
void attribute_short(attr_e, agg::int8u type,
const void* data, agg::int8u size);
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
struct element_stack_data
{
unsigned index;
element_e code;
};
//---------------------------------------------------------------------
typedef agg::pod_bvector<element_stack_data, 5> element_stack_type;
//---------------------------------------------------------------------
void push_element(const element_data&, element_stack_type&) const;
//---------------------------------------------------------------------
void pop_element(element_stack_type&) const;
//---------------------------------------------------------------------
//---------------------------------------------------------------------
typedef agg::pod_vector<attr_data> attributes_type;
typedef agg::pod_bvector<agg::int8u, 10> traverse_buffer_type;
//---------------------------------------------------------------------
void collect_attributes(read_protocol const& rp,
element_data& el,
attributes_type& attributes,
traverse_buffer_type& traverse_buffer) const;
//---------------------------------------------------------------------
void proceed_attribute(attributes_type& attributes,
traverse_buffer_type& traverse_buffer,
element_data& el,
attr_data& attr,
data_container const& cont,
agg::int32u data_idx,
agg::int32u data_size) const;
//---------------------------------------------------------------------
public:
//---------------------------------------------------------------------
template <class Consumer>
agg::int32u traverse(Consumer& cons, agg::int32u idx = 0) const
{
traverse_buffer_type traverse_buffer(32);
element_stack_type element_stack(32);
attributes_type attributes(256);
element_data el;
const data_container* cont = 0;
agg::int32u data_idx = 0u;
agg::int32u data_size = 0u;
bool not_done = true;
read_protocol rp(*this);
rp.rewind(idx);
while (not_done && !rp.end())
{
tag_e tag = rp.read_tag();
switch (tag)
{
case tag_end_element:
el.clear();
rp.end_element();
if (element_stack.size())
{
const element_stack_data& esd = element_stack.last();
el.index = esd.index;
el.code = esd.code;
}
not_done = cons.end_element(*this, el);
pop_element(element_stack);
if (element_stack.size() == 0) not_done = false;
break;
case tag_element_bin:
el.clear();
rp.element_bin(&el.index, &el.code);
collect_attributes(rp, el, attributes, traverse_buffer);
push_element(el, element_stack);
not_done = cons.start_element(*this, el);
break;
default:
assert(false);
}
}
return rp.current_location();
}
private:
iomemstream m_storage;
/***************************************************************************/
private:
double m_width;
double m_height;
public:
double get_width() const {return m_width;};
double get_height() const {return m_height;};
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_DOM_STORAGE_INCLUDE

View File

@ -0,0 +1,50 @@
#ifndef AGG_SVG_EXCEPTION_INCLUDED
#define AGG_SVG_EXCEPTION_INCLUDED
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
namespace agg
{
namespace svg
{
class exception
{
public:
~exception()
{
delete [] m_msg;
}
exception() : m_msg(0) {}
exception(const char* fmt, ...) :
m_msg(0)
{
if(fmt)
{
m_msg = new char [4096];
va_list arg;
va_start(arg, fmt);
vsprintf(m_msg, fmt, arg);
va_end(arg);
}
}
exception(const exception& exc) :
m_msg(exc.m_msg ? new char[strlen(exc.m_msg) + 1] : 0)
{
if(m_msg) strcpy(m_msg, exc.m_msg);
}
const char* msg() const { return m_msg; }
private:
char* m_msg;
};
}
}
#endif

View File

@ -0,0 +1,107 @@
#ifndef AGG_SVG_FRAME_BUFFER_RGBA_INCLUDED
#define AGG_SVG_FRAME_BUFFER_RGBA_INCLUDED
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_renderer_base.h"
#include "agg_renderer_scanline.h"
namespace agg
{
namespace svg
{
//---------------------------------------------------------------------------
class frame_buffer_rgba
{
public:
typedef agg::blender_rgba<color_type, component_order> blender_type;
typedef agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer, pixel_type> pixfmt_type;
typedef agg::renderer_base<pixfmt_type> renderer_base_type;
typedef agg::renderer_scanline_aa_solid<renderer_base_type> renderer_solid_type;
enum { pix_size = sizeof(pixel_type) };
//-----------------------------------------------------------------------
~frame_buffer_rgba()
{
if (!m_buf_was_attach)
delete [] m_internal_buf;
}
//-----------------------------------------------------------------------
frame_buffer_rgba()
: m_internal_buf(0)
, m_is_valid(false)
, m_ren_buf()
, m_pixfmt()
, m_ren_base()
, m_ren_solid()
, m_buf_was_attach(false)
{}
//-----------------------------------------------------------------------
void create(unsigned width, unsigned height, bool flip, int& stride, void* buff=NULL)
{
if (!m_buf_was_attach)
delete [] m_internal_buf;
if (!buff)
{
stride = flip ? -int(width * pix_size) : int(width * pix_size);
m_internal_buf = new agg::int8u[width * height * pix_size];
m_buf_was_attach = false;
}
else
{
m_internal_buf = (agg::int8u*)buff;
m_buf_was_attach = true;
}
m_ren_buf.attach(m_internal_buf, width, height, stride);
m_pixfmt.attach(m_ren_buf);
m_ren_base.attach(m_pixfmt);
m_ren_solid.attach(m_ren_base);
m_is_valid = true;
}
//-----------------------------------------------------------------------
void clear() { m_ren_buf.clear(0); }
void clear(color_type c) { m_ren_base.clear(c); }
//-----------------------------------------------------------------------
const agg::rendering_buffer& ren_buf() const { return m_ren_buf; }
agg::rendering_buffer& ren_buf() { return m_ren_buf; }
bool is_valid() const { return m_is_valid; }
unsigned width() const { return m_ren_buf.width(); }
unsigned height() const { return m_ren_buf.height(); }
const pixfmt_type& pixfmt() const { return m_pixfmt; }
pixfmt_type& pixfmt() { return m_pixfmt; }
const renderer_base_type& ren_base() const { return m_ren_base; }
renderer_base_type& ren_base() { return m_ren_base; }
const renderer_solid_type& ren_solid()const { return m_ren_solid; }
renderer_solid_type& ren_solid() { return m_ren_solid; }
const agg::int8u* get_internal_buf() const {return m_internal_buf;}
private:
frame_buffer_rgba(const frame_buffer_rgba&);
const frame_buffer_rgba& operator = (const frame_buffer_rgba&);
agg::int8u* m_internal_buf;
bool m_is_valid;
agg::rendering_buffer m_ren_buf;
pixfmt_type m_pixfmt;
renderer_base_type m_ren_base;
renderer_solid_type m_ren_solid;
bool m_buf_was_attach;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_FRAME_BUFFER_RGBA_INCLUDED

View File

@ -0,0 +1,86 @@
//-----------------------------------------------------------------------------
#include "agg_svg_gradient.h"
#include "agg_svg_attributes.h"
#include "agg_dda_line.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class color_interpolator_rgba
{
public:
color_interpolator_rgba(const color_type& c1,
const color_type& c2,
unsigned len) :
r(c1.r, c2.r, len),
g(c1.g, c2.g, len),
b(c1.b, c2.b, len),
a(c1.a, c2.a, len)
{}
void operator ++ ()
{
++r; ++g; ++b; ++a;
}
color_type color() const
{
return color_type(r.y(), g.y(), b.y(), a.y());
}
private:
agg::dda_line_interpolator<14> r, g, b, a;
};
//-------------------------------------------------------------------------
void gradient::create_gradient_lut(attributes& attr, gradient_lut_cache& cache)
{
agg::quick_sort(m_colors, offset_less);
m_colors.cut_at(agg::remove_duplicates(m_colors, offset_equal));
m_lut = cache.get_lut(m_colors);
if (m_lut == 0)
{
if(m_colors.size() >= 2)
{
gradient_lut_type lut;
unsigned i;
unsigned start = unsigned(m_colors[0].offset * lut.size() + 0.5);
unsigned end;
color_type c1 = attr.gamma_color(m_colors[0].stop_color);
color_type c2;
c1.a = (color_type::value_type)(c1.a * m_colors[0].stop_opacity + 0.5);
for(i = 0; i < start; i++)
{
lut[i] = c1;
}
for(i = 1; i < m_colors.size(); i++)
{
end = unsigned(m_colors[i].offset * lut.size() + 0.5);
c1 = attr.gamma_color(m_colors[i-1].stop_color);
c1.a = (color_type::value_type)(c1.a * m_colors[i-1].stop_opacity + 0.5);
c2 = attr.gamma_color(m_colors[i].stop_color);
c2.a = (color_type::value_type)(c2.a * m_colors[i].stop_opacity + 0.5);
color_interpolator_rgba ci(c1, c2, end - start + 1);
while(start < end)
{
lut[start] = ci.color();
++ci;
++start;
}
}
c2 = attr.gamma_color(m_colors.last().stop_color);
c2.a = (color_type::value_type)(c2.a * m_colors.last().stop_opacity + 0.5);
for(; end < lut.size(); end++)
{
lut[end] = c2;
}
m_lut = cache.add(m_colors, lut);
}
}
}
}
}

View File

@ -0,0 +1,203 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_GRADIENT_INCLUDED
#define AGG_SVG_GRADIENT_INCLUDED
//-----------------------------------------------------------------------------
#include "agg_array.h"
#include "agg_trans_affine.h"
#include "agg_svg_basics.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
class attributes;
class gradient_lut_cache;
//-------------------------------------------------------------------------
class gradient
{
public:
//---------------------------------------------------------------------
struct stop
{
double offset;
color_type stop_color;
double stop_opacity;
stop() {}
stop(double off, const color_type& c, double op) :
offset(off), stop_color(c), stop_opacity(op)
{
if(offset < 0.0) offset = 0.0;
if(offset > 1.0) offset = 1.0;
if(stop_opacity < 0.0) stop_opacity = 0.0;
if(stop_opacity > 1.0) stop_opacity = 1.0;
}
};
typedef agg::pod_bvector<stop, 4> stop_array_type;
static bool offset_less(const stop& a, const stop& b)
{
return a.offset < b.offset;
}
static bool offset_equal(const stop& a, const stop& b)
{
return a.offset == b.offset;
}
//-----------------------------------------------------------------------
gradient() :
m_type(gradient_linear),
m_gradientUnits(objectUnits_objectBoundingBox),
m_spreadMethod(spreadMethod_pad),
m_gradientTransform(),
m_x1(0), m_y1(0), m_x2(1), m_y2(0),
m_cx(0.5), m_cy(0.5), m_r(0.5), m_fx(0.5), m_fy(0.5), m_lut(0)
{}
//-----------------------------------------------------------------------
void reset()
{
m_type = gradient_linear;
m_gradientUnits = objectUnits_objectBoundingBox;
m_spreadMethod = spreadMethod_pad;
m_gradientTransform.reset();
m_x1 = 0; m_y1 = 0; m_x2 = 1; m_y2 = 0;
m_cx = 0.5; m_cy = 0.5; m_r = 0.5; m_fx = 0.5; m_fy = 0.5;
m_colors.remove_all();
m_lut = 0;
}
//-----------------------------------------------------------------------
void type(gradient_e v) { m_type = v; }
void gradientUnits(objectUnits_e v) { m_gradientUnits = v; }
void spreadMethod(spreadMethod_e v) { m_spreadMethod = v; }
void linear(double x1, double y1, double x2, double y2)
{
m_type = gradient_linear;
m_x1 = x1; m_y1 = y1;
m_x2 = x2; m_y2 = y2;
}
void radial(double cx, double cy, double r)
{
m_type = gradient_radial;
m_cx = m_fx = cx;
m_cy = m_fy = cy;
m_r = r;
}
void focus(double fx, double fy)
{
m_fx = fx;
m_fy = fy;
}
void x1(double v) { m_x1 = v; }
void y1(double v) { m_y1 = v; }
void x2(double v) { m_x2 = v; }
void y2(double v) { m_y2 = v; }
void cx(double v) { m_cx = v; }
void cy(double v) { m_cy = v; }
void r(double v) { m_r = v; }
void fx(double v) { m_fx = v; }
void fy(double v) { m_fy = v; }
void remove_all_stops()
{
m_colors.remove_all();
}
void add_stop(double offset, const color_type& color, double opacity)
{
m_colors.add(stop(offset, color, opacity));
}
void create_gradient_lut(attributes& attr, gradient_lut_cache&);
//-----------------------------------------------------------------------
void transform(double a0, double a1, double a2,
double a3, double a4, double a5)
{
m_gradientTransform.premultiply(agg::trans_affine(a0, a1, a2, a3, a4, a5));
}
void translate(double dx, double dy)
{
m_gradientTransform.premultiply(agg::trans_affine_translation(dx, dy));
}
void rotate(double angle)
{
m_gradientTransform.premultiply(agg::trans_affine_rotation(angle));
}
void rotate(double angle, double cx, double cy)
{
agg::trans_affine_translation m(-cx, -cy);
m *= agg::trans_affine_rotation(angle);
m *= agg::trans_affine_translation(cx, cy);
m_gradientTransform.premultiply(m);
}
void scale(double s)
{
m_gradientTransform.premultiply(agg::trans_affine_scaling(s));
}
void scale(double sx, double sy)
{
m_gradientTransform.premultiply(agg::trans_affine_scaling(sx, sy));
}
void skew(double sx, double sy)
{
m_gradientTransform.premultiply(agg::trans_affine_skewing(sx, sy));
}
void skew_x(double s)
{
m_gradientTransform.premultiply(agg::trans_affine_skewing(s, 0.0));
}
void skew_y(double s)
{
m_gradientTransform.premultiply(agg::trans_affine_skewing(0.0, s));
}
// Accessors
//-----------------------------------------------------------------------
gradient_e type() const { return m_type; }
objectUnits_e gradientUnits() const { return m_gradientUnits; }
spreadMethod_e spreadMethod() const { return m_spreadMethod; }
agg::trans_affine& gradientTransform() { return m_gradientTransform; }
const agg::trans_affine& gradientTransform() const { return m_gradientTransform; }
double x1() const { return m_x1; }
double y1() const { return m_y1; }
double x2() const { return m_x2; }
double y2() const { return m_y2; }
double cx() const { return m_cx; }
double cy() const { return m_cy; }
double r() const { return m_r; }
double fx() const { return m_fx; }
double fy() const { return m_fy; }
const gradient_lut_type& lut() const { return *m_lut; }
private:
gradient(const gradient&);
const gradient& operator = (const gradient&);
//-----------------------------------------------------------------------
gradient_e m_type;
objectUnits_e m_gradientUnits;
spreadMethod_e m_spreadMethod;
agg::trans_affine m_gradientTransform;
double m_x1, m_y1, m_x2, m_y2;
double m_cx, m_cy, m_r, m_fx, m_fy;
stop_array_type m_colors;
gradient_lut_type* m_lut;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_GRADIENT_INCLUDED

View File

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_GRADIENT_LUT_CACHE_INCLUDED
#define AGG_SVG_GRADIENT_LUT_CACHE_INCLUDED
//-----------------------------------------------------------------------------
#include "agg_array.h"
#include "agg_svg_basics.h"
#include "agg_svg_gradient.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
class gradient_lut_cache
{
typedef gradient::stop_array_type stop_array_type;
typedef agg::pod_bvector<gradient_lut_type,8> cache_type;
typedef agg::pod_bvector<stop_array_type> stop_array_key_type;
cache_type m_cache;
stop_array_key_type m_colors_key;
static bool color_equal(const color_type& lhs,
const color_type& rhs)
{
return lhs.r == rhs.r &&
lhs.g == rhs.g &&
lhs.b == rhs.b &&
lhs.a == rhs.a;
}
static bool stop_equal(const gradient::stop& lhs,
const gradient::stop& rhs)
{
return lhs.offset == rhs.offset &&
lhs.stop_opacity == rhs.stop_opacity &&
color_equal(lhs.stop_color, rhs.stop_color);
}
static bool stop_array_equal(const stop_array_type& lhs,
const stop_array_type& rhs)
{
if (lhs.size() != rhs.size())
return false;
for (unsigned i = 0u, size = lhs.size(); i < size; ++i)
{
if (!stop_equal(lhs[i], rhs[i]))
return false;
}
return true;
}
unsigned find_lut_index(const stop_array_type& colors)
{
for (unsigned i = 0u, size = m_colors_key.size(); i < size; ++i)
if (stop_array_equal(m_colors_key[i], colors))
return i + 1;
return 0;
}
public:
gradient_lut_type* get_lut(const stop_array_type& colors)
{
unsigned idx = find_lut_index(colors);
return idx ? &m_cache[idx - 1] : 0;
}
gradient_lut_type* add(const stop_array_type& colors, const gradient_lut_type& lut)
{
m_cache.add(lut);
m_colors_key.add(colors);
return &m_cache.last();
}
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_GRADIENT_LUT_CACHE_INCLUDED

View File

@ -0,0 +1,53 @@
#ifndef AGG_SVG_INDEXATION_INTERPRETER
#define AGG_SVG_INDEXATION_INTERPRETER
//-----------------------------------------------------------------------------
#include "agg_svg_defines.h"
#include "agg_svg_dom_storage.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class indexation_interpreter
{
public:
//---------------------------------------------------------------------
explicit indexation_interpreter(dom_storage::map_type& map)
:
m_attr2element_map(map)
{
}
//---------------------------------------------------------------------
bool start_element(const dom_storage&, const element_data& el)
{
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (el.attr[i].code == attr_id)
{
dom_storage::element_location eloc;
eloc.code = el.code;
eloc.idx = el.index;
m_attr2element_map.insert(el.attr[i].data, eloc);
break;
}
}
return true;
}
//---------------------------------------------------------------------
bool end_element(const dom_storage&, const element_data&)
{
return true;
}
//---------------------------------------------------------------------
private:
dom_storage::map_type& m_attr2element_map;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_INDEXATION_INTERPRETER

View File

@ -0,0 +1,125 @@
#ifndef AGG_SVG_IOMEMSTREAM_INCLUDE
#define AGG_SVG_IOMEMSTREAM_INCLUDE
//-----------------------------------------------------------------------------
#include "agg_svg_basics.h"
#include "agg_svg_data_accessor.h"
#include "agg_svg_ptr_size_pair.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class iomemstream
{
public:
//---------------------------------------------------------------------
void clear();
//---------------------------------------------------------------------
agg::int32u size() const;
//---------------------------------------------------------------------
data_container const & buffer() const;
data_container & buffer() ;
//---------------------------------------------------------------------
iomemstream& operator<<(agg::int8u);
iomemstream& operator<<(agg::int32u);
iomemstream& operator<<(const ptr_size &);
iomemstream& operator<<(const ptr_size_short &);
iomemstream& operator<<(data_accessor_type);
//---------------------------------------------------------------------
iomemstream& write(const void* ptr, agg::int32u size);
//---------------------------------------------------------------------
template <class T>
void add(const T& attr)
{
m_buffer.add_array(attr.head(), attr.head_size());
m_buffer.add_array(attr.data(), attr.data_size());
}
//---------------------------------------------------------------------
private:
data_container m_buffer;
};
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
inline void iomemstream::clear()
{
m_buffer.free_all();
}
//-------------------------------------------------------------------------
inline agg::int32u iomemstream::size() const
{
return m_buffer.size();
}
//-------------------------------------------------------------------------
inline data_container const & iomemstream::buffer() const
{
return m_buffer;
}
//-------------------------------------------------------------------------
inline data_container & iomemstream::buffer()
{
return m_buffer;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::operator<<(agg::int8u v)
{
m_buffer.add(v);
return *this;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::operator<<(agg::int32u v)
{
m_buffer.add_array((const agg::int8u *)&v, sizeof(agg::int32u));
return *this;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::operator<<(const ptr_size & ps)
{
(*this) << ps.m_size;
m_buffer.add_array(ps.m_ptr, ps.m_size);
return *this;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::operator<<(const ptr_size_short& ps)
{
m_buffer.add(ps.m_size);
m_buffer.add_array(ps.m_ptr, ps.m_size);
return *this;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::operator<<(data_accessor_type data)
{
while (data.size())
{
m_buffer.add(*data);
++data;
}
return *this;
}
//-------------------------------------------------------------------------
inline iomemstream& iomemstream::write(const void * ptr, agg::int32u size)
{
assert(ptr);
const agg::int8u * p = (const agg::int8u *)ptr;
while (size--)
{
m_buffer.add(*p++);
}
return *this;
}
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_IOMEMSTREAM_INCLUDE

View File

@ -0,0 +1,56 @@
#include "agg_svg_parse_real.h"
namespace agg
{
namespace svg
{
namespace aux
{
//-----------------------------------------------------------------------------
struct contains_helper
{
contains_helper()
{
init_mask(m_set_mask, s_set);
}
bool operator()(unsigned c) const
{
return (m_set_mask[(c >> 3) & (256/8-1)] & (1 << (c & 7))) != 0;
}
private:
static void init_mask(unsigned char* mask, const unsigned char* char_set);
unsigned char m_set_mask[256/8];
static const unsigned char s_set[];
};
const unsigned char contains_helper::s_set[] = "0123456789";
//-----------------------------------------------------------------------------
void contains_helper::init_mask(unsigned char* mask, const unsigned
char* char_set)
{
memset(mask, 0, 256/8);
while(*char_set)
{
unsigned c = unsigned(*char_set++) & 0xFF;
mask[c >> 3] |= 1 << (c & 7);
}
}
}
namespace detail
{
bool isdigit(unsigned c)
{
static aux::contains_helper helper;
return helper(c);
}
}
}
}

View File

@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_PARSE_REAL_INCLUDED
#define AGG_SVG_PARSE_REAL_INCLUDED
//-----------------------------------------------------------------------------
#include <cstring>
#include <cmath>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
namespace detail
{
bool isdigit(unsigned c);
}
//-------------------------------------------------------------------------
template<int Radix>
struct radix_traits;
//-------------------------------------------------------------------------
////////////////////////////////// Decimal
template<>
struct radix_traits<10>
{
static bool is_valid(char ch)
{
return detail::isdigit(ch);
}
static int digit(char ch)
{
return ch - '0';
}
};
//-------------------------------------------------------------------------
template<int Radix>
struct positive_accumulate
{
// Use this accumulator if number is positive
template <typename T>
static bool check(T const& n, T const& prev)
{
return n < prev;
}
template <typename T, typename CharT>
static void add(T& n, CharT ch)
{
n += radix_traits<Radix>::digit(ch);
}
};
//-------------------------------------------------------------------------
template<int Radix>
struct negative_accumulate
{
// Use this accumulator if number is negative
template <typename T>
static bool check(T const& n, T const& prev)
{
return n > prev;
}
template <typename T, typename CharT>
static void add(T& n, CharT ch)
{
n -= radix_traits<Radix>::digit(ch);
}
};
//-------------------------------------------------------------------------
template <int Radix, typename Accumulate>
struct extract_int_base
{
// Common code for extract_int specializations
template <typename T>
static bool f(const char* scan, T& n)
{
T prev = n;
n *= Radix;
if (Accumulate::check(n, prev))
return false; // over/underflow!
prev = n;
Accumulate::add(n, *scan);
if (Accumulate::check(n, prev))
return false; // over/underflow!
return true;
}
};
//-------------------------------------------------------------------------
template <int Radix = 10, typename Accumulate = positive_accumulate<Radix> >
struct extract_int
{
template <typename T>
static bool f(const char* & scan, const char * const end, T& n, size_t& count)
{
typedef extract_int_base<Radix, Accumulate> base;
typedef radix_traits<Radix> check;
size_t i = 0;
for (; scan != end && check::is_valid(*scan);
++i, ++scan, ++count)
{
if (!base::f(scan, n))
return false; // over/underflow!
}
return i >= 1;
}
};
//-------------------------------------------------------------------------
class parse_real
{
private:
//-------------------------------------------------------------------------
const bool allow_leading_dot;
const bool allow_trailing_dot;
const bool expect_dot;
public:
//-------------------------------------------------------------------------
parse_real()
: allow_leading_dot(true),
allow_trailing_dot(true),
expect_dot(false)
{
}
private:
//---------------------------------------------------------------------
bool parse_sign(const char * & src)
{
bool neg = *src == '-';
if (neg || (*src == '+'))
{
++src;
return neg;
}
return false;
}
//---------------------------------------------------------------------
bool parse_dot(const char* & src)
{
if (*src == '.')
{
++src;
return true;
}
return false;
}
//---------------------------------------------------------------------
bool parse_exp(const char* & src)
{
if (*src == 'e' || *src == 'E')
{
++src;
return true;
}
return false;
}
//---------------------------------------------------------------------
template <class T>
bool parse_uint(const char * & beg, const char * const end, T& n, size_t& count)
{
count = 0;
bool result = extract_int<>::f(beg, end, n, count);
return result;
}
//---------------------------------------------------------------------
template <class T>
bool parse_int(const char * & beg, const char * const end, T& n, size_t& count)
{
typedef extract_int<10,negative_accumulate<10> > extract_int_neg_t;
typedef extract_int<> extract_int_pos_t;
if (*beg)
{
count = 0;
n = 0;
const char* save = beg;
bool hit = parse_sign(beg);
if (hit)
hit = extract_int_neg_t::f(beg, end, n, count);
else
hit = extract_int_pos_t::f(beg, end, n, count);
if (hit)
return true;
else
beg = save;
// return no-match if number overflows or underflows
}
return false;
}
public:
//-------------------------------------------------------------------------
bool parse(const char* beg, const char * const end,
double* d, const char** endptr)
{
const char * src = beg;
if (src == 0 || *src == 0)
return false;
double result = 0;
size_t count = 0;
bool neg = parse_sign(src);
bool got_a_number = parse_uint(src, end, result, count) && count;
if (!got_a_number && !allow_leading_dot)
return false;
bool exp_hit = false;
int exp = 0;
if (parse_dot(src))
{
// We got the decimal point. Now we will try to parse
// the fraction if it is there. If not, it defaults
// to zero (0) only if we already got a number.
if (parse_uint(src, end, result, count))
{
exp = (int)count;
exp = -exp;
}
else if (!got_a_number || !allow_trailing_dot)
return false;
exp_hit = parse_exp(src);
}
else
{
// We have reached a point where we
// still haven't seen a number at all.
// We return early with a no-match.
if (!got_a_number)
return false;
// If we must expect a dot and we didn't see
// an exponent, return early with a no-match.
exp_hit = parse_exp(src);
if (expect_dot && !exp_hit)
return false;
}
if (exp_hit)
{
// We got the exponent prefix. Now we will try to parse the
// actual exponent. It is an error if it is not there.
int temp;
if (parse_int(src, end, temp, count))
{
exp += temp;
}
else
{
return false;
}
}
*d = result;
if (neg)
*d = -(*d);
*d *= pow(10., exp);
*endptr = src;
return true;//src == end;
}
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_PARSE_REAL_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
//-----------------------------------------------------------------------------
//
// SVG parser.
//
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_PARSER_INCLUDED
#define AGG_SVG_PARSER_INCLUDED
//-----------------------------------------------------------------------------
#include "agg_svg_basics.h"
#include "agg_svg_path_serializer.h"
#include "agg_svg_path_interpreter.h"
#include "agg_svg_dom_storage.h"
#include <stack>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
class attributes_map;
//-------------------------------------------------------------------------
class parser
{
enum buf_size_e { buf_size = 8 * BUFSIZ };
public:
//---------------------------------------------------------------------
parser(dom_storage&, attributes_map& attr_map);
//---------------------------------------------------------------------
~parser();
//---------------------------------------------------------------------
void parse(const wchar_t* fname);
//---------------------------------------------------------------------
private:
// XML event handlers
static void on_start_element(void* data, const char* el, const char** attr);
static void on_end_element(void* data, const char* el);
static void on_content(void* data, const char* s, int len);
//---------------------------------------------------------------------
typedef path_tokenizer<char> path_tokenizer_type;
typedef path_serializer<data_container> path_serializer_type;
//---------------------------------------------------------------------
// utility
//
//---------------------------------------------------------------------
void prepare_attributes( const char**);
//---------------------------------------------------------------------
void start_element_cleanup();
//---------------------------------------------------------------------
const char* extract_attribute(attr_e attr);
//---------------------------------------------------------------------
attr_e find_known_attribute(const char* attr_name);
//---------------------------------------------------------------------
void parse_name_value(char* nv_start, char* nv_end);
//---------------------------------------------------------------------
void add_double_to_buffer(double val);
//---------------------------------------------------------------------
const char* get_attr_name( unsigned attr );
//---------------------------------------------------------------------
// Error processing
//
//---------------------------------------------------------------------
typedef void(parser::*error_checker_type)(double);
//---------------------------------------------------------------------
void not_negative(double);
//---------------------------------------------------------------------
// parse basic data types
//
//---------------------------------------------------------------------
enum axis_e {no_axis, axis_x, axis_y};
//---------------------------------------------------------------------
enum necessity_e {optional, required};
//---------------------------------------------------------------------
void parse_number(attr_e, necessity_e necessity);
//---------------------------------------------------------------------
void parse_color (attr_e, necessity_e necessity);
//---------------------------------------------------------------------
void parse_string(attr_e);
//---------------------------------------------------------------------
void parse_coordinate_attr(attr_e attr, axis_e axis,
necessity_e necessity, error_checker_type = 0);
//---------------------------------------------------------------------
bool length_parser(length& len, const char* begin, const char * end);
//---------------------------------------------------------------------
void parse_length_attr(attr_e attr, necessity_e necessity,
error_checker_type = 0);
//---------------------------------------------------------------------
// parse elements
//
//---------------------------------------------------------------------
void parse_polygon();
void parse_polyline();
void parse_svg();
void parse_path();
void parse_rect();
void parse_line();
void parse_circle();
void parse_ellipse();
void parse_linearGradient();
void parse_radialGradient();
void parse_stop();
void parse_defs();
void parse_title();
void parse_g();
void parse_use();
void parse_clipPath();
//---------------------------------------------------------------------
// parse attributes
//
void parse_attr_viewBox();
void parse_attr_preserveAspectRatio();
void parse_object_units_attr(attr_e);
void parse_paint_attr(attr_e);
void parse_uri_attr(attr_e);
unsigned parse_transform_args(const char* str, double* args,
unsigned max_na, unsigned* na);
unsigned parse_matrix (const char* str);
unsigned parse_translate(const char* str);
unsigned parse_rotate (const char* str);
unsigned parse_scale (const char* str);
unsigned parse_skew_x (const char* str);
unsigned parse_skew_y (const char* str);
//---------------------------------------------------------------------
// parse attribute sets
//
void parse_core_attributes ();
void parse_presentation_attributes ();
void parse_style_attributes ();
void parse_paint_attributes ();
void parse_color_attributes ();
void parse_opacity_attributes ();
void parse_xlink_attributes ();
void parse_common_gradient_attributes ();
void parse_basic_shapes_common_attributes();
void parse_transform_attributes (attr_e);
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
struct extra_attr
{
const char* name;
const char* value;
extra_attr() {}
extra_attr(const char* n, const char* v) : name(n), value(v) {}
};
//---------------------------------------------------------------------
struct unit_descriptor
{
units2_e unit;
const char * literal;
unsigned char length;
};
//---------------------------------------------------------------------
dom_storage& m_storage;
path_tokenizer_type m_path_tokenizer;
data_container m_buffer;
path_serializer_type m_path_serializer;
const char* m_curr_elem_name;
const char* m_known_attr[end_of_attr];
char* m_style_buffer;
unsigned m_style_buffer_len;
static unit_descriptor m_units[];
attributes_map& m_attr_map;
std::stack<bool> m_unknownElement;
char* m_buf;
};
} //namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_PARSER_INCLUDED

View File

@ -0,0 +1,630 @@
#ifndef AGG_SVG_PATH_INTERPRETER_INCLUDED
#define AGG_SVG_PATH_INTERPRETER_INCLUDED
#include "agg_bezier_arc.h"
#include "agg_math.h"
#include "agg_svg_basics.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// Use this class to interprete the serialized path.
//
//---------------------------------------------------------------------------
template<class DataAccessor> class path_interpreter
{
public:
typedef DataAccessor data_accessor_type;
typedef typename data_accessor_type::value_type value_type;
path_interpreter();
path_interpreter(const data_accessor_type& data);
void init(const data_accessor_type& data);
void rewind(unsigned);
unsigned vertex(double* x, double* y);
unsigned num_vertices() const { return m_num_vertices; }
private:
void rel_to_abs(double *x, double *y) const
{
if(m_num_vertices > 1)
{
*x += m_vertices[m_num_vertices - 2];
*y += m_vertices[m_num_vertices - 1];
}
}
unsigned last_command() const
{
if(m_last_command >= 'A' && m_last_command <= 'z')
{
return m_commands[m_last_command - 'A'];
}
return agg::path_cmd_stop;
}
void move_to(unsigned cmd);
void line_to(unsigned cmd);
void hline_to(unsigned cmd);
void vline_to(unsigned cmd);
void curve3_to(unsigned cmd);
void curve3_to_ref(unsigned cmd);
void curve4_to(unsigned cmd);
void curve4_to_ref(unsigned cmd);
void arc_to(unsigned cmd);
void close_subpath(unsigned cmd);
typedef void (path_interpreter<DataAccessor>::*command_handler)(unsigned cmd);
static const agg::int8u m_commands[58];
static const command_handler m_command_handlers[58];
data_accessor_type m_accessor;
data_accessor_type m_data;
double m_vertices[26];
unsigned m_num_vertices;
unsigned m_vertex;
double m_start_x;
double m_start_y;
unsigned m_last_command;
};
//------------------------------------------------------------------------
template<class DA>
const agg::int8u path_interpreter<DA>::m_commands[58] =
{
agg::path_cmd_curve4, //065 A
0, //066 B
agg::path_cmd_curve4, //067 C
0, //068 D
0, //069 E
0, //070 F
0, //071 G
agg::path_cmd_line_to, //072 H
0, //073 I
0, //074 J
0, //075 K
agg::path_cmd_line_to, //076 L
agg::path_cmd_move_to, //077 M
0, //078 N
0, //079 O
0, //080 P
agg::path_cmd_curve3, //081 Q
0, //082 R
agg::path_cmd_curve4, //083 S
agg::path_cmd_curve3, //084 T
0, //085 U
agg::path_cmd_line_to, //086 V
0, //087 W
0, //088 X
0, //089 Y
agg::path_cmd_end_poly | agg::path_flags_close, //090 Z
0, //091 [
0, //092 backslash
0, //093 ]
0, //094 ^
0, //095 _
0, //096 '
agg::path_cmd_curve4, //097 a
0, //098 b
agg::path_cmd_curve4, //099 c
0, //100 d
0, //101 e
0, //102 f
0, //103 g
agg::path_cmd_line_to, //104 h
0, //105 i
0, //106 j
0, //107 k
agg::path_cmd_line_to, //108 l
agg::path_cmd_move_to, //109 m
0, //110 n
0, //111 o
0, //112 p
agg::path_cmd_curve3, //113 q
0, //114 r
agg::path_cmd_curve4, //115 s
agg::path_cmd_curve3, //116 t
0, //117 u
agg::path_cmd_line_to, //118 v
0, //119 w
0, //120 x
0, //121 y
agg::path_cmd_end_poly | agg::path_flags_close //122 z
};
//------------------------------------------------------------------------
template<class DA>
path_interpreter<DA>::path_interpreter() :
m_accessor(),
m_data(),
m_num_vertices(0),
m_vertex(0),
m_start_x(0.0),
m_start_y(0.0),
m_last_command(0)
{
}
//------------------------------------------------------------------------
template<class DA>
path_interpreter<DA>::path_interpreter(const data_accessor_type& data) :
m_accessor(data),
m_data(data),
m_num_vertices(0),
m_vertex(0),
m_start_x(0.0),
m_start_y(0.0),
m_last_command(0)
{
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::init(const data_accessor_type& data)
{
m_accessor = data;
m_data = data;
m_num_vertices = 0;
m_vertex = 0;
m_start_x = 0.0;
m_start_y = 0.0;
m_last_command = 0;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::move_to(unsigned cmd)
{
double x = m_data.read_coord();
double y = m_data.read_coord();
if(cmd == 'm')
{
rel_to_abs(&x, &y);
}
m_start_x = x;
m_start_y = y;
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::line_to(unsigned cmd)
{
double x = m_data.read_coord();
double y = m_data.read_coord();
if(cmd == 'l')
{
rel_to_abs(&x, &y);
}
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::hline_to(unsigned cmd)
{
double x = m_data.read_coord();
double y = 0.0;
if(m_num_vertices > 1)
{
if(cmd == 'h')
{
x += m_vertices[m_num_vertices - 2];
}
y = m_vertices[m_num_vertices - 1];
}
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::vline_to(unsigned cmd)
{
double x = 0.0;
double y = m_data.read_coord();
if(m_num_vertices > 1)
{
x = m_vertices[m_num_vertices - 2];
if(cmd == 'v')
{
y += m_vertices[m_num_vertices - 1];
}
}
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::curve3_to(unsigned cmd)
{
double x1 = m_data.read_coord();
double y1 = m_data.read_coord();
double x = m_data.read_coord();
double y = m_data.read_coord();
if(cmd == 'q')
{
rel_to_abs(&x1, &y1);
rel_to_abs(&x, &y);
}
m_vertices[0] = x1;
m_vertices[1] = y1;
m_vertices[2] = x;
m_vertices[3] = y;
m_num_vertices = 4;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::curve3_to_ref(unsigned cmd)
{
double x1 = 0.0;
double y1 = 0.0;
double x = m_data.read_coord();
double y = m_data.read_coord();
rel_to_abs(&x1, &y1);
if(cmd == 't')
{
rel_to_abs(&x, &y);
}
if(agg::is_curve(last_command()) && m_num_vertices > 3)
{
x1 += x1 - m_vertices[m_num_vertices - 4];
y1 += y1 - m_vertices[m_num_vertices - 3];
}
m_vertices[0] = x1;
m_vertices[1] = y1;
m_vertices[2] = x;
m_vertices[3] = y;
m_num_vertices = 4;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::curve4_to(unsigned cmd)
{
double x1 = m_data.read_coord();
double y1 = m_data.read_coord();
double x2 = m_data.read_coord();
double y2 = m_data.read_coord();
double x = m_data.read_coord();
double y = m_data.read_coord();
if(cmd == 'c')
{
rel_to_abs(&x1, &y1);
rel_to_abs(&x2, &y2);
rel_to_abs(&x, &y);
}
m_vertices[0] = x1;
m_vertices[1] = y1;
m_vertices[2] = x2;
m_vertices[3] = y2;
m_vertices[4] = x;
m_vertices[5] = y;
m_num_vertices = 6;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::curve4_to_ref(unsigned cmd)
{
double x1 = 0.0;
double y1 = 0.0;
double x2 = m_data.read_coord();
double y2 = m_data.read_coord();
double x = m_data.read_coord();
double y = m_data.read_coord();
rel_to_abs(&x1, &y1);
if(cmd == 's')
{
rel_to_abs(&x, &y);
rel_to_abs(&x2, &y2);
}
if(agg::is_curve(last_command()) && m_num_vertices > 3)
{
x1 += x1 - m_vertices[m_num_vertices - 4];
y1 += y1 - m_vertices[m_num_vertices - 3];
}
m_vertices[0] = x1;
m_vertices[1] = y1;
m_vertices[2] = x2;
m_vertices[3] = y2;
m_vertices[4] = x;
m_vertices[5] = y;
m_num_vertices = 6;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::arc_to(unsigned cmd)
{
const double epsilon = 1e-30;
double x0 = 0.0;
double y0 = 0.0;
double rx = m_data.read_coord();
double ry = m_data.read_coord();
double x_axis_rotation = m_data.read_coord();
bool large_arc_flag = m_data.read_int8u() != '0';
bool sweep_flag = m_data.read_int8u() != '0';
double x = m_data.read_coord();
double y = m_data.read_coord();
if(m_num_vertices > 1)
{
x0 = m_vertices[m_num_vertices - 2];
y0 = m_vertices[m_num_vertices - 1];
}
if(cmd == 'a')
{
rel_to_abs(&x, &y);
}
rx = fabs(rx);
ry = fabs(ry);
if(rx < epsilon || ry < epsilon)
{
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = (cmd == 'a') ? 'l' : 'L';
return;
}
if(agg::calc_distance(x0, y0, x, y) < epsilon)
{
return;
}
agg::bezier_arc_svg a(x0, y0,
rx, ry,
x_axis_rotation,
large_arc_flag, sweep_flag,
x, y);
if(a.radii_ok())
{
for(unsigned i = 2; i < a.num_vertices(); i += 2)
{
m_vertices[i - 2] = a.vertices()[i];
m_vertices[i - 1] = a.vertices()[i + 1];
}
m_num_vertices = a.num_vertices() - 2;
m_last_command = cmd;
}
else
{
m_vertices[0] = x;
m_vertices[1] = y;
m_num_vertices = 2;
m_last_command = (cmd == 'a') ? 'l' : 'L';
}
}
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::close_subpath(unsigned cmd)
{
m_vertices[0] = m_start_x;
m_vertices[1] = m_start_y;
m_num_vertices = 2;
m_vertex = 0;
m_last_command = cmd;
}
//------------------------------------------------------------------------
template<class DA>
const typename path_interpreter<DA>::command_handler
path_interpreter<DA>::m_command_handlers[58] =
{
&path_interpreter<DA>::arc_to, //065 A
0, //066 B
&path_interpreter<DA>::curve4_to, //067 C
0, //068 D
0, //069 E
0, //070 F
0, //071 G
&path_interpreter<DA>::hline_to, //072 H
0, //073 I
0, //074 J
0, //075 K
&path_interpreter<DA>::line_to, //076 L
&path_interpreter<DA>::move_to, //077 M
0, //078 N
0, //079 O
0, //080 P
&path_interpreter<DA>::curve3_to, //081 Q
0, //082 R
&path_interpreter<DA>::curve4_to_ref, //083 S
&path_interpreter<DA>::curve3_to_ref, //084 T
0, //085 U
&path_interpreter<DA>::vline_to, //086 V
0, //087 W
0, //088 X
0, //089 Y
&path_interpreter<DA>::close_subpath, //090 Z
0, //091 [
0, //092 backslash
0, //093 ]
0, //094 ^
0, //095 _
0, //096 '
&path_interpreter<DA>::arc_to, //097 a
0, //098 b
&path_interpreter<DA>::curve4_to, //099 c
0, //100 d
0, //101 e
0, //102 f
0, //103 g
&path_interpreter<DA>::hline_to, //104 h
0, //105 i
0, //106 j
0, //107 k
&path_interpreter<DA>::line_to, //108 l
&path_interpreter<DA>::move_to, //109 m
0, //110 n
0, //111 o
0, //112 p
&path_interpreter<DA>::curve3_to, //113 q
0, //114 r
&path_interpreter<DA>::curve4_to_ref, //115 s
&path_interpreter<DA>::curve3_to_ref, //116 t
0, //117 u
&path_interpreter<DA>::vline_to, //118 v
0, //119 w
0, //120 x
0, //121 y
&path_interpreter<DA>::close_subpath //122 z
};
// AGG Vertex Source interface functions
//------------------------------------------------------------------------
template<class DA>
void path_interpreter<DA>::rewind(unsigned)
{
m_data = m_accessor;
m_num_vertices = 0;
m_vertex = 0;
m_start_x = 0.0;
m_start_y = 0.0;
m_last_command = 0;
}
//------------------------------------------------------------------------
template<class DA>
unsigned path_interpreter<DA>::vertex(double* x, double* y)
{
for(;;)
{
if(m_vertex < m_num_vertices)
{
*x = m_vertices[m_vertex++];
*y = m_vertices[m_vertex++];
break;
}
if(m_data.size() == 0)
{
*x = *y = 0.0;
return agg::path_cmd_stop;
}
unsigned cmd = m_data.read_int8u();
//----------------------------
command_handler ch;
if(cmd >= 'A' && cmd <= 'z' &&
(ch = m_command_handlers[cmd - 'A']) != 0)
{
(this->*ch)(cmd);
}
else
{
m_last_command = 0;
return agg::path_cmd_stop;
}
m_vertex = 0;
}
return last_command();
}
//-------------------------------------------------------------------------
// Similar to path_interpreter.
//
// Use flag "closed=false" for polylines and "closed=true" for polygons.
//
//-------------------------------------------------------------------------
template<class DataAccessor> class poly_interpreter
{
public:
typedef DataAccessor data_accessor_type;
typedef typename data_accessor_type::value_type value_type;
poly_interpreter() :
m_accessor(),
m_data(),
m_closed(false),
m_stop(false)
{}
poly_interpreter(const data_accessor_type& data, bool closed) :
m_accessor(data),
m_data(data),
m_closed(closed),
m_stop(false)
{}
void init(const data_accessor_type& data, bool closed)
{
m_accessor = data;
m_data = data;
m_closed = closed;
m_stop = false;
}
void rewind(unsigned)
{
m_data = m_accessor;
m_stop = false;
}
unsigned vertex(double* x, double* y)
{
if(m_data.size())
{
bool first = m_data.size() == m_accessor.size();
*x = m_data.read_coord();
*y = m_data.read_coord();
return first ? agg::path_cmd_move_to : agg::path_cmd_line_to;
}
*x = *y = 0.0;
if(m_closed && !m_stop)
{
m_stop = true;
return agg::path_cmd_end_poly | agg::path_flags_close;
}
return agg::path_cmd_stop;
}
private:
data_accessor_type m_accessor;
data_accessor_type m_data;
bool m_closed;
bool m_stop;
};
}
}
#endif

View File

@ -0,0 +1,453 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include "agg_svg_path_renderer.h"
namespace agg
{
namespace svg
{
//------------------------------------------------------------------------
path_renderer::path_renderer() :
m_curved(m_storage),
m_curved_count(m_curved),
m_curved_stroked(m_curved_count),
m_curved_stroked_trans(m_curved_stroked, m_transform),
m_curved_trans(m_curved_count, m_transform),
m_curved_trans_contour(m_curved_trans)
{
m_curved_trans_contour.auto_detect_orientation(false);
}
//------------------------------------------------------------------------
void path_renderer::remove_all()
{
m_storage.remove_all();
m_attr_storage.remove_all();
m_attr_stack.remove_all();
m_transform.reset();
m_all_gradients.remove_all();
}
void path_renderer::push_gradient(gradient_struct::GRADIENT_TYPE grTp)
{
m_all_gradients.add(gradient_struct());
gradient_struct& curGr = cur_gradient();
curGr.gradient_type = grTp;
}
void path_renderer::add_color_to_gradient(const rgba8& f, double offs)
{
if(m_all_gradients.size() == 0)
return;
gradient_struct& curGr = cur_gradient();
curGr.push_color(f,offs);
}
void path_renderer::set_id_to_gradient(const char* nid)
{
if(m_all_gradients.size() == 0 || !nid)
return;
gradient_struct& curGr = cur_gradient();
strcpy(curGr.id_string,nid);
}
void path_renderer::set_val_to_gradient(gradient_struct::vals_ids idV, double valNumb)
{
if(m_all_gradients.size() == 0)
return;
gradient_struct& curGr = cur_gradient();
curGr.rect_points[idV] = valNumb;
}
void path_renderer::set_colors_from_other(const char* other_id)
{
if(m_all_gradients.size() == 0)
return;
gradient_struct& curGr = cur_gradient();
unsigned cnt = m_all_gradients.size();
for (unsigned i=0;i<cnt-1;i++)
{
if (strcmp(m_all_gradients[i].id_string, other_id) == 0)
{
unsigned cnt_2 = m_all_gradients[i].all_colors.size();
for (unsigned j=0;j<cnt_2;j++)
curGr.all_colors.add(m_all_gradients[i].all_colors[j]);
break;
}
}
}
void path_renderer::set_gradient_brush_to_path(const char* gr_id)
{
if(m_all_gradients.size() == 0)
return;
path_attributes& attr = cur_attr();
unsigned cnt = m_all_gradients.size();
for (unsigned i=0;i<cnt;i++)
{
if (strcmp(m_all_gradients[i].id_string, gr_id) == 0)
{
attr.gradient_brush = &m_all_gradients[i];
break;
}
}
}
//------------------------------------------------------------------------
void path_renderer::begin_path()
{
push_attr();
unsigned idx = m_storage.start_new_path();
m_attr_storage.add(path_attributes(cur_attr(), idx));
}
//------------------------------------------------------------------------
void path_renderer::end_path()
{
if(m_attr_storage.size() == 0)
{
throw exception("end_path : The path was not begun");
}
path_attributes attr = cur_attr();
unsigned idx = m_attr_storage[m_attr_storage.size() - 1].index;
attr.index = idx;
m_attr_storage[m_attr_storage.size() - 1] = attr;
pop_attr();
}
//------------------------------------------------------------------------
void path_renderer::move_to(double x, double y, bool rel) // M, m
{
if(rel) m_storage.rel_to_abs(&x, &y);
m_storage.move_to(x, y);
}
//------------------------------------------------------------------------
void path_renderer::line_to(double x, double y, bool rel) // L, l
{
if(rel) m_storage.rel_to_abs(&x, &y);
m_storage.line_to(x, y);
}
//------------------------------------------------------------------------
void path_renderer::hline_to(double x, bool rel) // H, h
{
double x2 = 0.0;
double y2 = 0.0;
if(m_storage.total_vertices())
{
m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
if(rel) x += x2;
m_storage.line_to(x, y2);
}
}
//------------------------------------------------------------------------
void path_renderer::vline_to(double y, bool rel) // V, v
{
double x2 = 0.0;
double y2 = 0.0;
if(m_storage.total_vertices())
{
m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
if(rel) y += y2;
m_storage.line_to(x2, y);
}
}
//------------------------------------------------------------------------
void path_renderer::curve3(double x1, double y1, // Q, q
double x, double y, bool rel)
{
if(rel)
{
m_storage.rel_to_abs(&x1, &y1);
m_storage.rel_to_abs(&x, &y);
}
m_storage.curve3(x1, y1, x, y);
}
//------------------------------------------------------------------------
void path_renderer::curve3(double x, double y, bool rel) // T, t
{
// throw exception("curve3(x, y) : NOT IMPLEMENTED YET");
if(rel)
{
m_storage.curve3_rel(x, y);
} else
{
m_storage.curve3(x, y);
}
}
//------------------------------------------------------------------------
void path_renderer::curve4(double x1, double y1, // C, c
double x2, double y2,
double x, double y, bool rel)
{
if(rel)
{
m_storage.rel_to_abs(&x1, &y1);
m_storage.rel_to_abs(&x2, &y2);
m_storage.rel_to_abs(&x, &y);
}
m_storage.curve4(x1, y1, x2, y2, x, y);
}
//------------------------------------------------------------------------
void path_renderer::curve4(double x2, double y2, // S, s
double x, double y, bool rel)
{
//throw exception("curve4(x2, y2, x, y) : NOT IMPLEMENTED YET");
if(rel)
{
m_storage.curve4_rel(x2, y2, x, y);
} else
{
m_storage.curve4(x2, y2, x, y);
}
}
//------------------------------------------------------------------------
void path_renderer::arc(double rx, double ry, // A, a
double angle,
bool large_arc_flag,
bool sweep_flag,
double dx, double dy,
bool rel)
{
if(rel)
{
m_storage.rel_to_abs(&dx, &dy);
}
m_storage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
}
//------------------------------------------------------------------------
void path_renderer::close_subpath()
{
m_storage.end_poly(path_flags_close);
}
//------------------------------------------------------------------------
path_attributes& path_renderer::cur_attr()
{
if(m_attr_stack.size() == 0)
{
throw exception("cur_attr : Attribute stack is empty");
}
return m_attr_stack[m_attr_stack.size() - 1];
}
gradient_struct& path_renderer::cur_gradient()
{
if(m_all_gradients.size() == 0)
{
throw exception("cur_gradient : Gradients stack is empty");
}
return m_all_gradients[m_all_gradients.size() - 1];
}
//------------------------------------------------------------------------
void path_renderer::push_attr()
{
m_attr_stack.add(m_attr_stack.size() ?
m_attr_stack[m_attr_stack.size() - 1] :
path_attributes());
}
//------------------------------------------------------------------------
void path_renderer::pop_attr()
{
if(m_attr_stack.size() == 0)
{
throw exception("pop_attr : Attribute stack is empty");
}
m_attr_stack.remove_last();
}
//------------------------------------------------------------------------
void path_renderer::fill(const rgba8& f)
{
path_attributes& attr = cur_attr();
attr.fill_color = f;
attr.fill_flag = true;
}
//------------------------------------------------------------------------
void path_renderer::stroke(const rgba8& s)
{
path_attributes& attr = cur_attr();
attr.stroke_color = s;
attr.stroke_flag = true;
}
//------------------------------------------------------------------------
void path_renderer::even_odd(bool flag)
{
cur_attr().even_odd_flag = flag;
}
//------------------------------------------------------------------------
void path_renderer::stroke_width(double w)
{
cur_attr().stroke_width = w;
}
//------------------------------------------------------------------------
void path_renderer::fill_none()
{
cur_attr().fill_flag = false;
}
//------------------------------------------------------------------------
void path_renderer::stroke_none()
{
cur_attr().stroke_flag = false;
}
//------------------------------------------------------------------------
void path_renderer::fill_opacity(double op)
{
cur_attr().fill_color.opacity(op);
}
//------------------------------------------------------------------------
void path_renderer::stroke_opacity(double op)
{
cur_attr().stroke_color.opacity(op);
}
//------------------------------------------------------------------------
void path_renderer::line_join(line_join_e join)
{
cur_attr().line_join = join;
}
//------------------------------------------------------------------------
void path_renderer::line_cap(line_cap_e cap)
{
cur_attr().line_cap = cap;
}
//------------------------------------------------------------------------
void path_renderer::miter_limit(double ml)
{
cur_attr().miter_limit = ml;
}
//------------------------------------------------------------------------
trans_affine& path_renderer::transform()
{
return cur_attr().transform;
}
//------------------------------------------------------------------------
void path_renderer::parse_path(path_tokenizer& tok)
{
while(tok.next())
{
double arg[10];
char cmd = tok.last_command();
unsigned i;
bool b1,b2;
switch(cmd)
{
case 'M': case 'm':
arg[0] = tok.last_number();
arg[1] = tok.next(cmd);
move_to(arg[0], arg[1], cmd == 'm');
break;
case 'L': case 'l':
arg[0] = tok.last_number();
arg[1] = tok.next(cmd);
line_to(arg[0], arg[1], cmd == 'l');
break;
case 'V': case 'v':
vline_to(tok.last_number(), cmd == 'v');
break;
case 'H': case 'h':
hline_to(tok.last_number(), cmd == 'h');
break;
case 'Q': case 'q':
arg[0] = tok.last_number();
for(i = 1; i < 4; i++)
{
arg[i] = tok.next(cmd);
}
curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q');
break;
case 'T': case 't':
arg[0] = tok.last_number();
arg[1] = tok.next(cmd);
curve3(arg[0], arg[1], cmd == 't');
break;
case 'C': case 'c':
arg[0] = tok.last_number();
for(i = 1; i < 6; i++)
{
arg[i] = tok.next(cmd);
}
curve4(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c');
break;
case 'S': case 's':
arg[0] = tok.last_number();
for(i = 1; i < 4; i++)
{
arg[i] = tok.next(cmd);
}
curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's');
break;
case 'A': case 'a':
arg[0] = tok.last_number();
for(i = 1; i < 7; i++)
{
arg[i] = tok.next(cmd);
}
b1 = fabs(arg[3]-1)<0.00001;
b2 = fabs(arg[4]-1)<0.00001;
arc(arg[0], arg[1], arg[2], b1, b2, arg[5], arg[6], cmd == 'a');
break;
case 'Z': case 'z':
close_subpath();
break;
default:
{
char buf[100];
sprintf(buf, "parse_path: Invalid Command %c", cmd);
throw exception(buf);
}
}
}
}
}
}

View File

@ -0,0 +1,405 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PATH_RENDERER_INCLUDED
#define AGG_SVG_PATH_RENDERER_INCLUDED
#include "agg_path_storage.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_conv_contour.h"
#include "agg_conv_curve.h"
#include "agg_color_rgba.h"
#include "agg_renderer_scanline.h"
#include "agg_bounding_rect.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_svg_path_tokenizer.h"
namespace agg
{
namespace svg
{
struct stop_color
{
rgba8 color;
double offset;
};
struct gradient_struct
{
typedef pod_bvector<stop_color> colors_storage;
typedef enum
{
LINEAR_GR,
RADIAL_GR
} GRADIENT_TYPE;
GRADIENT_TYPE gradient_type;
typedef enum
{
X1 = 0,
Y1 = 1,
X2 = 2,
Y2 = 3,
CX = 0,
CY = 1,
R = 2,
FX = 3,
FY = 4
} vals_ids;
colors_storage all_colors;
char id_string[128];
double rect_points[5]; // x1, y1, x2, y2 - for LINEAR_GR
// cx, cy, r , fx, fy - for RADIAL_GR
gradient_struct():gradient_type(LINEAR_GR)
{
id_string[0]='\0';
memset(rect_points,0,sizeof(double)*5);
}
void push_color(const rgba8& col, double offs)
{
stop_color colr;
colr.color = col;
colr.offset = offs;
all_colors.add(colr);
}
};
template<class VertexSource> class conv_count
{
public:
conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {}
void count(unsigned n) { m_count = n; }
unsigned count() const { return m_count; }
void rewind(unsigned path_id) { m_source->rewind(path_id); }
unsigned vertex(double* x, double* y)
{
++m_count;
return m_source->vertex(x, y);
}
private:
VertexSource* m_source;
unsigned m_count;
};
//============================================================================
// Basic path attributes
struct path_attributes
{
unsigned index;
rgba8 fill_color;
rgba8 stroke_color;
bool fill_flag;
bool stroke_flag;
bool even_odd_flag;
line_join_e line_join;
line_cap_e line_cap;
double miter_limit;
double stroke_width;
trans_affine transform;
gradient_struct* gradient_brush;
// Empty constructor
path_attributes() :
index(0),
fill_color(rgba(0,0,0)),
stroke_color(rgba(0,0,0)),
fill_flag(true),
stroke_flag(false),
even_odd_flag(false),
line_join(miter_join),
line_cap(butt_cap),
miter_limit(4.0),
stroke_width(1.0),
transform(),
gradient_brush(NULL)
{
}
// Copy constructor
path_attributes(const path_attributes& attr) :
index(attr.index),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform),
gradient_brush(attr.gradient_brush)
{
}
// Copy constructor with new index value
path_attributes(const path_attributes& attr, unsigned idx) :
index(idx),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform),
gradient_brush(attr.gradient_brush)
{
}
};
//============================================================================
// Path container and renderer.
class path_renderer
{
public:
typedef pod_bvector<gradient_struct> gradients_storage;
void push_gradient(gradient_struct::GRADIENT_TYPE grTp);
void add_color_to_gradient(const rgba8& f, double offs);
void set_id_to_gradient(const char* nid);
void set_val_to_gradient(gradient_struct::vals_ids idV, double valNumb);
void set_colors_from_other(const char* other_id);
void set_gradient_brush_to_path(const char* gr_id);
public:
typedef pod_bvector<path_attributes> attr_storage;
typedef conv_curve<path_storage> curved;
typedef conv_count<curved> curved_count;
typedef conv_stroke<curved_count> curved_stroked;
typedef conv_transform<curved_stroked> curved_stroked_trans;
typedef conv_transform<curved_count> curved_trans;
typedef conv_contour<curved_trans> curved_trans_contour;
path_renderer();
void remove_all();
// Use these functions as follows:
// begin_path() when the XML tag <path> comes ("start_element" handler)
// parse_path() on "d=" tag attribute
// end_path() when parsing of the entire tag is done.
void begin_path();
void parse_path(path_tokenizer& tok);
void end_path();
// The following functions are essentially a "reflection" of
// the respective SVG path commands.
void move_to(double x, double y, bool rel=false); // M, m
void line_to(double x, double y, bool rel=false); // L, l
void hline_to(double x, bool rel=false); // H, h
void vline_to(double y, bool rel=false); // V, v
void curve3(double x1, double y1, // Q, q
double x, double y, bool rel=false);
void curve3(double x, double y, bool rel=false); // T, t
void curve4(double x1, double y1, // C, c
double x2, double y2,
double x, double y, bool rel=false);
void curve4(double x2, double y2, // S, s
double x, double y, bool rel=false);
void arc(double rx, double ry, // A, a
double angle,
bool large_arc_flag,
bool sweep_flag,
double dx, double dy,
bool rel);
void close_subpath(); // Z, z
// template<class VertexSource>
// void add_path(VertexSource& vs,
// unsigned path_id = 0,
// bool solid_path = true)
// {
// m_storage.add_path(vs, path_id, solid_path);
// }
unsigned vertex_count() const { return m_curved_count.count(); }
// Call these functions on <g> tag (start_element, end_element respectively)
void push_attr();
void pop_attr();
// Attribute setting functions.
void fill(const rgba8& f);
void stroke(const rgba8& s);
void even_odd(bool flag);
void stroke_width(double w);
void fill_none();
void stroke_none();
void fill_opacity(double op);
void stroke_opacity(double op);
void line_join(line_join_e join);
void line_cap(line_cap_e cap);
void miter_limit(double ml);
trans_affine& transform();
// Make all polygons CCW-oriented
void arrange_orientations()
{
m_storage.arrange_orientations_all_paths(path_flags_ccw);
}
// Expand all polygons
void expand(double value)
{
m_curved_trans_contour.width(value);
}
unsigned operator [](unsigned idx)
{
m_transform = m_attr_storage[idx].transform;
return m_attr_storage[idx].index;
}
void bounding_rect(double* x1, double* y1, double* x2, double* y2)
{
agg::conv_transform<agg::path_storage> trans(m_storage, m_transform);
agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2);
}
// Rendering. One can specify two additional parameters:
// trans_affine and opacity. They can be used to transform the whole
// image and/or to make it translucent.
template<class Rasterizer, class Scanline, class Renderer>
void render(Rasterizer& ras,
Scanline& sl,
Renderer& ren,
const trans_affine& mtx,
const rect_i& cb,
double opacity=1.0)
{
unsigned i;
ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2);
m_curved_count.count(0);
for(i = 0; i < m_attr_storage.size(); i++)
{
const path_attributes& attr = m_attr_storage[i];
m_transform = attr.transform;
m_transform *= mtx;
double scl = m_transform.scale();
//m_curved.approximation_method(curve_inc);
m_curved.approximation_scale(scl);
m_curved.angle_tolerance(0.0);
rgba8 color;
if (attr.gradient_brush)
{
ras.reset();
ras.filling_rule(fill_even_odd);
m_curved_trans_contour.miter_limit(attr.miter_limit);
ras.add_path(m_curved_trans_contour, attr.index);
ren.color(rgba8(0,255,0));
agg::render_scanlines(ras, sl, ren);
}
else
{
if(attr.fill_flag)
{
ras.reset();
ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
if(fabs(m_curved_trans_contour.width()) < 0.0001)
{
ras.add_path(m_curved_trans, attr.index);
}
else
{
m_curved_trans_contour.miter_limit(attr.miter_limit);
ras.add_path(m_curved_trans_contour, attr.index);
}
color = attr.fill_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
}
if(attr.stroke_flag)
{
m_curved_stroked.width(attr.stroke_width);
//m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
m_curved_stroked.line_join(attr.line_join);
m_curved_stroked.line_cap(attr.line_cap);
m_curved_stroked.miter_limit(attr.miter_limit);
m_curved_stroked.inner_join(inner_round);
m_curved_stroked.approximation_scale(scl);
// If the *visual* line width is considerable we
// turn on processing of curve cusps.
//---------------------
if(attr.stroke_width * scl > 1.0)
{
m_curved.angle_tolerance(0.2);
}
ras.reset();
ras.filling_rule(fill_non_zero);
ras.add_path(m_curved_stroked_trans, attr.index);
color = attr.stroke_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
}
}
private:
path_attributes& cur_attr();
gradient_struct& cur_gradient();
path_storage m_storage;
attr_storage m_attr_storage;
attr_storage m_attr_stack;
trans_affine m_transform;
gradients_storage m_all_gradients;
curved m_curved;
curved_count m_curved_count;
curved_stroked m_curved_stroked;
curved_stroked_trans m_curved_stroked_trans;
curved_trans m_curved_trans;
curved_trans_contour m_curved_trans_contour;
};
}
}
#endif

View File

@ -0,0 +1,614 @@
#ifndef AGG_SVG_PATH_SERIALIZER_INCLUDED
#define AGG_SVG_PATH_SERIALIZER_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include "agg_array.h"
#include "agg_svg_basics.h"
#include "agg_svg_parse_real.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// The tokenizer does all the routine job of parsing the SVG paths.
//----------------------------------------------------------------------------
template<class CharT=char> class path_tokenizer
{
public:
typedef CharT value_type;
path_tokenizer();
void path_str(const value_type* str);
bool rewind();
bool token();
double token(value_type cmd);
value_type last_command() const { return m_last_command; }
double last_number() const { return m_last_number; }
bool multiple_coordinate_pair() const
{
return (m_num_count > 2) && (m_num_count & 1) == 0;
}
private:
static void init_mask(agg::int8u* mask, const agg::int8u* char_set);
bool contains(const agg::int8u* mask, unsigned c) const
{
return (mask[(c >> 3) & (256/8-1)] & (1 << (c & 7))) != 0;
}
bool is_command(unsigned c) const
{
return contains(m_commands_mask, c);
}
bool is_numeric(unsigned c) const
{
return contains(m_numeric_mask, c);
}
bool is_separator(unsigned c) const
{
return contains(m_separators_mask, c);
}
bool parse_number();
agg::int8u m_separators_mask[256/8];
agg::int8u m_commands_mask[256/8];
agg::int8u m_numeric_mask[256/8];
const value_type* m_str;
const value_type* m_ptr;
double m_last_number;
unsigned m_num_count;
value_type m_last_command;
static const agg::int8u s_commands[];
static const agg::int8u s_numeric[];
static const agg::int8u s_separators[];
};
//------------------------------------------------------------------------
template<class CharT>
const agg::int8u path_tokenizer<CharT>::s_commands[] = "+-MmZzLlHhVvCcSsQqTtAa";
template<class CharT>
const agg::int8u path_tokenizer<CharT>::s_numeric[] = ".0123456789";
template<class CharT>
const agg::int8u path_tokenizer<CharT>::s_separators[] = " ,\t\n\r";
//------------------------------------------------------------------------
template<class CharT>
path_tokenizer<CharT>::path_tokenizer() :
m_str(0), m_ptr(0), m_last_number(0.0), m_num_count(0), m_last_command(0)
{
init_mask(m_commands_mask, s_commands);
init_mask(m_numeric_mask, s_numeric);
init_mask(m_separators_mask, s_separators);
}
//------------------------------------------------------------------------
template<class CharT>
void path_tokenizer<CharT>::path_str(const CharT* str)
{
m_ptr = m_str = str;
m_last_command = 0;
m_num_count = 0;
m_last_number = 0.0;
}
//------------------------------------------------------------------------
template<class CharT>
void path_tokenizer<CharT>::init_mask(agg::int8u* mask, const agg::int8u* char_set)
{
memset(mask, 0, 256/8);
while(*char_set)
{
unsigned c = unsigned(*char_set++) & 0xFF;
mask[c >> 3] |= 1 << (c & 7);
}
}
//------------------------------------------------------------------------
template<class CharT>
bool path_tokenizer<CharT>::rewind()
{
m_ptr = m_str;
m_last_command = 0;
m_num_count = 0;
m_last_number = 0.0;
return m_str != 0;
}
//------------------------------------------------------------------------
template<class CharT>
bool path_tokenizer<CharT>::token()
{
if(m_ptr == 0) return false;
// Skip all white spaces and other garbage
while(*m_ptr && !is_command(*m_ptr) && !is_numeric(*m_ptr))
{
if(!is_separator(*m_ptr))
{
throw exception("Parsing Path Structure: Invalid Character %c", *m_ptr);
}
m_ptr++;
}
if(*m_ptr == 0) return false;
if(is_command(*m_ptr))
{
// Check if the command is a numeric sign character
if(*m_ptr == '-' || *m_ptr == '+')
{
return parse_number();
}
m_last_command = *m_ptr++;
m_num_count = 0;
while(*m_ptr && is_separator(*m_ptr)) m_ptr++;
if(*m_ptr == 0) return true;
}
return parse_number();
}
//------------------------------------------------------------------------
template<class CharT>
double path_tokenizer<CharT>::token(CharT cmd)
{
if(!token())
{
throw exception("Parsing Path Structure: Unexpected end of Path");
}
if(last_command() != cmd)
{
throw exception("Parsing Path Structure: Command %c is bad or missing parameters", cmd);
}
return last_number();
}
//------------------------------------------------------------------------
template<class CharT>
bool path_tokenizer<CharT>::parse_number()
{
char buf[256]; // Should be enough for any number
char* buf_ptr = buf;
// Copy all sign characters
while(buf_ptr < buf+255 && *m_ptr == '-' || *m_ptr == '+')
{
*buf_ptr++ = char(*m_ptr++);
}
// Copy all numeric characters
while(buf_ptr < buf+255 && is_numeric(*m_ptr))
{
*buf_ptr++ = char(*m_ptr++);
}
// check for exponent
if (*m_ptr == 'e' || *m_ptr == 'E')
{
*buf_ptr++ = char(*m_ptr++);
// Copy all sign characters
while(buf_ptr < buf+255 && *m_ptr == '-' || *m_ptr == '+')
{
*buf_ptr++ = char(*m_ptr++);
}
// Copy all numeric characters
while(buf_ptr < buf+255 && is_numeric(*m_ptr))
{
*buf_ptr++ = char(*m_ptr++);
}
}
*buf_ptr = 0;
const char* endptr = 0;
parse_real pd;
pd.parse(buf, buf + strlen(buf), &m_last_number, &endptr);
++m_num_count;
return true;
}
//-------------------------------------------------------------------------
// Ths class is used to parse, validate, and serialize paths into binary format.
//
//----------------------------------------------------------------------------
template<class Container> class path_serializer
{
public:
typedef Container container_type;
path_serializer(container_type& buffer);
// Make path
//------------------------------------------------------------------------
void reset();
void move_to(double x, double y, bool rel=false);
void line_to(double x, double y, bool rel=false);
void hline_to(double x, bool rel=false);
void vline_to(double y, bool rel=false);
void curve3_to(double x1, double y1, double x, double y, bool rel=false);
void curve3_to(double x, double y, bool rel=false);
void curve4_to(double x1, double y1, double x2, double y2,
double x, double y, bool rel=false);
void curve4_to(double x2, double y2, double x, double y, bool rel=false);
void arc_to(double rx, double ry, double x_axis_rotation,
bool large_arc_flag, bool sweep_flag,
double x, double y, bool rel=false);
void close_subpath();
// Parse path string.
//------------------------------------------------------------------------
template<class Tokenizer> void parse(Tokenizer& tok)
{
reset();
if(!tok.rewind()) return;
while(tok.token())
{
double arg[10];
unsigned cmd = tok.last_command();
unsigned i;
switch(cmd)
{
case 'M': case 'm':
arg[0] = tok.last_number();
arg[1] = tok.token(cmd);
if(tok.multiple_coordinate_pair())
{
line_to(arg[0], arg[1], cmd == 'm');
}
else
{
move_to(arg[0], arg[1], cmd == 'm');
}
break;
case 'L': case 'l':
arg[0] = tok.last_number();
arg[1] = tok.token(cmd);
line_to(arg[0], arg[1], cmd == 'l');
break;
case 'V': case 'v':
vline_to(tok.last_number(), cmd == 'v');
break;
case 'H': case 'h':
hline_to(tok.last_number(), cmd == 'h');
break;
case 'Q': case 'q':
arg[0] = tok.last_number();
for(i = 1; i < 4; i++)
{
arg[i] = tok.token(cmd);
}
curve3_to(arg[0], arg[1], arg[2], arg[3], cmd == 'q');
break;
case 'T': case 't':
arg[0] = tok.last_number();
arg[1] = tok.token(cmd);
curve3_to(arg[0], arg[1], cmd == 't');
break;
case 'C': case 'c':
arg[0] = tok.last_number();
for(i = 1; i < 6; i++)
{
arg[i] = tok.token(cmd);
}
curve4_to(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c');
break;
case 'S': case 's':
arg[0] = tok.last_number();
for(i = 1; i < 4; i++)
{
arg[i] = tok.token(cmd);
}
curve4_to(arg[0], arg[1], arg[2], arg[3], cmd == 's');
break;
case 'A': case 'a':
arg[0] = tok.last_number();
for(i = 1; i < 7; i++)
{
arg[i] = tok.token(cmd);
}
arc_to(arg[0], arg[1], agg::deg2rad(arg[2]),
arg[3] > 0.1, arg[4] > 0.1,
arg[5], arg[6], cmd == 'a');
break;
case 'Z': case 'z':
close_subpath();
break;
default:
{
throw exception("Parsing Path Structure: Invalid Command %c", cmd);
}
}
}
}
private:
void check_last_vertex(unsigned cmd);
void check_curve_reflection(unsigned cmd);
//------------------------------------------------------------------------
void append_c(unsigned chr)
{
m_buffer->add((agg::int8u)chr);
}
void append_d(double val)
{
coord_type f = (coord_type)val;
const agg::int8u* p = (const agg::int8u*)&f;
unsigned i;
for(i = 0; i < sizeof(coord_type); i++)
{
m_buffer->add(*p++);
}
}
//------------------------------------------------------------------------
container_type* m_buffer;
unsigned m_last_command;
unsigned m_num_vertices;
};
//------------------------------------------------------------------------
template<class Container>
path_serializer<Container>::path_serializer(container_type& buffer) :
m_buffer(&buffer),
m_last_command(0),
m_num_vertices(0)
{}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::check_last_vertex(unsigned cmd)
{
if(m_num_vertices == 0)
{
throw exception("Parsing Path Structure: Invalid use of command '%c' - Path must begin with 'M' or 'm'", cmd);
}
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::check_curve_reflection(unsigned cmd)
{
if(m_last_command == 'C' || m_last_command == 'c' ||
m_last_command == 'S' || m_last_command == 's' ||
m_last_command == 'Q' || m_last_command == 'q' ||
m_last_command == 'T' || m_last_command == 't')
{
return;
}
throw exception("Parsing Path Structure: Invalid use of reflection in command '%c' - The command must be followed by a curve command", cmd);
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::reset()
{
m_last_command = 0;
m_num_vertices = 0;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::move_to(double x, double y, bool rel)
{
append_c(m_last_command = (rel ? 'm' : 'M'));
append_d(x);
append_d(y);
++m_num_vertices;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::line_to(double x, double y, bool rel)
{
check_last_vertex(rel ? 'l' : 'L');
append_c(m_last_command = (rel ? 'l' : 'L'));
append_d(x);
append_d(y);
++m_num_vertices;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::hline_to(double x, bool rel)
{
check_last_vertex(rel ? 'h' : 'H');
append_c(m_last_command = (rel ? 'h' : 'H'));
append_d(x);
++m_num_vertices;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::vline_to(double y, bool rel)
{
check_last_vertex(rel ? 'v' : 'V');
append_c(m_last_command = (rel ? 'v' : 'V'));
append_d(y);
++m_num_vertices;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::curve3_to(double x1, double y1,
double x, double y,
bool rel)
{
check_last_vertex(rel ? 'q' : 'Q');
append_c(m_last_command = (rel ? 'q' : 'Q'));
append_d(x1);
append_d(y1);
append_d(x);
append_d(y);
m_num_vertices += 2;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::curve3_to(double x, double y, bool rel)
{
check_last_vertex(rel ? 't' : 'T');
check_curve_reflection(rel ? 't' : 'T');
append_c(m_last_command = (rel ? 't' : 'T'));
append_d(x);
append_d(y);
++m_num_vertices;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::curve4_to(double x1, double y1,
double x2, double y2,
double x, double y, bool rel)
{
check_last_vertex(rel ? 'c' : 'C');
append_c(m_last_command = (rel ? 'c' : 'C'));
append_d(x1);
append_d(y1);
append_d(x2);
append_d(y2);
append_d(x);
append_d(y);
m_num_vertices += 3;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::curve4_to(double x2, double y2,
double x, double y, bool rel)
{
check_last_vertex(rel ? 's' : 'S');
check_curve_reflection(rel ? 's' : 'S');
append_c(m_last_command = (rel ? 's' : 'S'));
append_d(x2);
append_d(y2);
append_d(x);
append_d(y);
m_num_vertices += 2;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::arc_to(double rx, double ry,
double x_axis_rotation,
bool large_arc_flag,
bool sweep_flag,
double x, double y,
bool rel)
{
check_last_vertex(rel ? 'a' : 'A');
append_c(m_last_command = (rel ? 'a' : 'A'));
append_d(rx);
append_d(ry);
append_d(x_axis_rotation);
append_c(large_arc_flag ? '1' : '0');
append_c(sweep_flag ? '1' : '0');
append_d(x);
append_d(y);
m_num_vertices += 3;
}
//------------------------------------------------------------------------
template<class Container>
void path_serializer<Container>::close_subpath()
{
append_c('z');
}
//-------------------------------------------------------------------------
// Ths class is used to parse, validate, and serialize polygons and polylines
// into binary format.
//----------------------------------------------------------------------------
template<class Container> class poly_serializer
{
public:
typedef Container container_type;
poly_serializer(container_type& buffer) : m_buffer(&buffer) {}
//------------------------------------------------------------------------
template<class Tokenizer> void parse(Tokenizer& tok, bool closed)
{
unsigned np = 0;
while(tok.token())
{
double x = tok.last_number();
if(!tok.token())
{
throw exception("Parsing Polygon Structure: Odd number of coordinates");
}
double y = tok.last_number();
append_d(x);
append_d(y);
++np;
}
if(closed)
{
if(np < 3)
{
throw exception("Parsing Polygon Structure: Too few coordinates for polygon/polyline");
}
}
else
{
if(np < 2)
{
throw exception("Parsing Polygon Structure: Too few coordinates for polygon/polyline");
}
}
}
private:
void append_d(double val)
{
coord_type f = (coord_type)val;
const agg::int8u* p = (const agg::int8u*)&f;
unsigned i;
for(i = 0; i < sizeof(coord_type); i++)
{
m_buffer->add(*p++);
}
}
container_type* m_buffer;
};
}
}
#endif

View File

@ -0,0 +1,143 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path tokenizer.
//
//----------------------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "agg_svg_exception.h"
#include "agg_svg_path_tokenizer.h"
namespace agg
{
namespace svg
{
//------------------------------------------------------------------------
const char path_tokenizer::s_commands[] = "+-MmZzLlHhVvCcSsQqTtAaFfPp";
const char path_tokenizer::s_numeric[] = ".Ee0123456789";
const char path_tokenizer::s_separators[] = " ,\t\n\r";
//------------------------------------------------------------------------
path_tokenizer::path_tokenizer()
: m_path(0), m_last_command(0), m_last_number(0.0)
{
init_char_mask(m_commands_mask, s_commands);
init_char_mask(m_numeric_mask, s_numeric);
init_char_mask(m_separators_mask, s_separators);
}
//------------------------------------------------------------------------
void path_tokenizer::set_path_str(const char* str)
{
m_path = str;
m_last_command = 0;
m_last_number = 0.0;
}
//------------------------------------------------------------------------
void path_tokenizer::init_char_mask(char* mask, const char* char_set)
{
memset(mask, 0, 256/8);
while(*char_set)
{
unsigned c = unsigned(*char_set++) & 0xFF;
mask[c >> 3] |= 1 << (c & 7);
}
}
//------------------------------------------------------------------------
bool path_tokenizer::next()
{
if(m_path == 0) return false;
// Skip all white spaces and other garbage
while(*m_path && !is_command(*m_path) && !is_numeric(*m_path))
{
if(!is_separator(*m_path))
{
char buf[100];
sprintf(buf, "path_tokenizer::next : Invalid Character %c", *m_path);
throw exception(buf);
}
m_path++;
}
if(*m_path == 0) return false;
if(is_command(*m_path))
{
// Check if the command is a numeric sign character
if(*m_path == '-' || *m_path == '+')
{
return parse_number();
}
m_last_command = *m_path++;
while(*m_path && is_separator(*m_path)) m_path++;
if(*m_path == 0) return true;
}
return parse_number();
}
//------------------------------------------------------------------------
double path_tokenizer::next(char cmd)
{
if(!next()) throw exception("parse_path: Unexpected end of path");
if(last_command() != cmd)
{
char buf[100];
sprintf(buf, "parse_path: Command %c: bad or missing parameters", cmd);
throw exception(buf);
}
return last_number();
}
//------------------------------------------------------------------------
bool path_tokenizer::parse_number()
{
char buf[256]; // Should be enough for any number
char* buf_ptr = buf;
// Copy all sign characters
while(buf_ptr < buf+255 && *m_path == '-' || *m_path == '+')
{
*buf_ptr++ = *m_path++;
}
// Copy all numeric characters
while(buf_ptr < buf+255 && is_numeric(*m_path))
{
*buf_ptr++ = *m_path++;
}
*buf_ptr = 0;
m_last_number = atof(buf);
return true;
}
} //namespace svg
} //namespace agg

View File

@ -0,0 +1,114 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path tokenizer.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PATH_TOKENIZER_INCLUDED
#define AGG_SVG_PATH_TOKENIZER_INCLUDED
#include "agg_svg_exception.h"
namespace agg
{
namespace svg
{
// SVG path tokenizer.
// Example:
//
// agg::svg::path_tokenizer tok;
//
// tok.set_str("M-122.304 84.285L-122.304 84.285 122.203 86.179 ");
// while(tok.next())
// {
// printf("command='%c' number=%f\n",
// tok.last_command(),
// tok.last_number());
// }
//
// The tokenizer does all the routine job of parsing the SVG paths.
// It doesn't recognize any graphical primitives, it even doesn't know
// anything about pairs of coordinates (X,Y). The purpose of this class
// is to tokenize the numeric values and commands. SVG paths can
// have single numeric values for Horizontal or Vertical line_to commands
// as well as more than two coordinates (4 or 6) for Bezier curves
// depending on the semantics of the command.
// The behaviour is as follows:
//
// Each call to next() returns true if there's new command or new numeric
// value or false when the path ends. How to interpret the result
// depends on the sematics of the command. For example, command "C"
// (cubic Bezier curve) implies 6 floating point numbers preceded by this
// command. If the command assumes no arguments (like z or Z) the
// the last_number() values won't change, that is, last_number() always
// returns the last recognized numeric value, so does last_command().
//===============================================================
class path_tokenizer
{
public:
path_tokenizer();
void set_path_str(const char* str);
bool next();
double next(char cmd);
char last_command() const { return m_last_command; }
double last_number() const { return m_last_number; }
private:
static void init_char_mask(char* mask, const char* char_set);
bool contains(const char* mask, unsigned c) const
{
return (mask[(c >> 3) & (256/8-1)] & (1 << (c & 7))) != 0;
}
bool is_command(unsigned c) const
{
return contains(m_commands_mask, c);
}
bool is_numeric(unsigned c) const
{
return contains(m_numeric_mask, c);
}
bool is_separator(unsigned c) const
{
return contains(m_separators_mask, c);
}
bool parse_number();
char m_separators_mask[256/8];
char m_commands_mask[256/8];
char m_numeric_mask[256/8];
const char* m_path;
double m_last_number;
char m_last_command;
static const char s_commands[];
static const char s_numeric[];
static const char s_separators[];
};
} //namespace svg
} //namespace agg
#endif

View File

@ -0,0 +1,26 @@
#ifndef AGG_SVG_PERCENT_INCLUDE
#define AGG_SVG_PERCENT_INCLUDE
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
struct percent
{
static double decrypt(double val)
{
return (val > 1.)?
(val - (double)difference_helper) / 100.:val;
}
static double encrypt(double val)
{
return (double)difference_helper + val;
}
private:
enum {difference_helper = 2};
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_PERCENT_INCLUDE

View File

@ -0,0 +1,251 @@
#ifndef AGG_SVG_PIPELINE_INCLUDED
#define AGG_SVG_PIPELINE_INCLUDED
#include "agg_svg_attributes.h"
#include "agg_svg_transformer.h"
#include "agg_svg_renderer_rgba.h"
#include "agg_conv_curve.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_conv_contour.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class conv_polymorphic_base
{
public:
virtual ~conv_polymorphic_base() {}
virtual void rewind(unsigned path_id) = 0;
virtual unsigned vertex(double* x, double* y) = 0;
};
//-------------------------------------------------------------------------
template<class VertexSource>
class conv_polymorphic_wrapper : public conv_polymorphic_base
{
public:
conv_polymorphic_wrapper(VertexSource& source) : m_source(&source) {}
virtual void rewind(unsigned path_id)
{
m_source->rewind(path_id);
}
virtual unsigned vertex(double* x, double* y)
{
return m_source->vertex(x, y);
}
private:
VertexSource* m_source;
};
//-------------------------------------------------------------------------
struct fake_vertex_source : public conv_polymorphic_base
{
public:
virtual void rewind(unsigned) {}
virtual unsigned vertex(double*, double*)
{
return agg::path_cmd_stop;
}
};
//-------------------------------------------------------------------------
class pipeline
{
public:
//-----------------------------------------------------------------------
typedef agg::conv_curve<conv_polymorphic_base> conv_curve;
typedef agg::conv_transform<conv_curve, transformer> conv_curve_trans;
typedef agg::conv_stroke<conv_curve> conv_curve_stroke;
typedef agg::conv_transform<conv_curve_stroke, transformer> conv_curve_stroke_trans;
typedef agg::conv_contour<conv_curve_trans> conv_curve_trans_contour;
//-----------------------------------------------------------------------
pipeline()
: m_fake_source()
, m_identity_transformer()
, m_conv_curve(m_fake_source)
, m_conv_curve_trans(m_conv_curve, m_identity_transformer)
, m_conv_curve_stroke(m_conv_curve)
, m_conv_curve_stroke_trans(m_conv_curve_stroke, m_identity_transformer)
, m_conv_curve_trans_contour(m_conv_curve_trans)
, m_approximation_scale(4.0)
{
m_conv_curve_stroke.inner_join(agg::inner_round);
m_conv_curve_trans_contour.auto_detect_orientation(false);
m_conv_curve_trans_contour.width(0);
}
//-----------------------------------------------------------------------
void approximation_scale(double s) { m_approximation_scale = s; }
double approximation_scale() const { return m_approximation_scale; }
//-----------------------------------------------------------------------
#ifdef EXPAND_PATHS
// Expand all polygons
void expand(double value)
{
m_conv_curve_trans_contour.width(value);
}
#endif
//-----------------------------------------------------------------------
template<class Source>
void render(const attributes& attr, Source& src, renderer_rgba& ren)
{
if(!ren.is_valid()) return;
conv_polymorphic_wrapper<Source> psrc(src);
m_conv_curve.attach(psrc);
unsigned cmd;
double x, y;
double scale = attr.scale() * m_approximation_scale;
m_conv_curve.approximation_scale(scale);
m_conv_curve.angle_tolerance(0.0);
m_conv_curve_stroke.approximation_scale(scale);
ren.clip_box(attr.clip_x1(), attr.clip_y1(), attr.clip_x2(), attr.clip_y2());
if(attr.fill_type() != paint_none)
{
ren.reset();
m_conv_curve_trans.transformer(attr.transform());
if(fabs(m_conv_curve_trans_contour.width()) < 0.0001)
{
m_conv_curve_trans.rewind(0);
while(!agg::is_stop(cmd = m_conv_curve_trans.vertex(&x, &y)))
{
ren.add_vertex(x, y, cmd);
}
}
else
{
m_conv_curve_trans_contour.miter_limit(attr.stroke_miterlimit());
m_conv_curve_trans_contour.rewind(0);
while(!agg::is_stop(cmd = m_conv_curve_trans_contour.vertex(&x, &y)))
{
ren.add_vertex(x, y, cmd);
}
}
ren.fill(attr);
}
if(attr.stroke_type() != paint_none)
{
ren.reset();
m_conv_curve_stroke_trans.transformer(attr.transform());
m_conv_curve_stroke.width(attr.stroke_width());
m_conv_curve_stroke.line_join(g_stroke_linejoin_lut[attr.stroke_linejoin()]);
m_conv_curve_stroke.line_cap(g_stroke_linecap_lut[attr.stroke_linecap()]);
m_conv_curve_stroke.miter_limit(attr.stroke_miterlimit());
if(attr.stroke_width() * scale > 1.0)
{
m_conv_curve.angle_tolerance(agg::deg2rad(10.0));
}
m_conv_curve_stroke_trans.rewind(0);
while(!agg::is_stop(cmd = m_conv_curve_stroke_trans.vertex(&x, &y)))
{
ren.add_vertex(x, y, cmd);
}
ren.stroke(attr);
}
}
private:
//-----------------------------------------------------------------------
transformer m_identity_transformer;
fake_vertex_source m_fake_source;
conv_curve m_conv_curve;
conv_curve_trans m_conv_curve_trans;
conv_curve_stroke m_conv_curve_stroke;
conv_curve_stroke_trans m_conv_curve_stroke_trans;
conv_curve_trans_contour m_conv_curve_trans_contour;
double m_approximation_scale;
};
//---------------------------------------------------------------------------
class object_bbox
{
public:
//-----------------------------------------------------------------------
typedef agg::conv_curve<conv_polymorphic_base> conv_curve;
//-----------------------------------------------------------------------
object_bbox() :
m_fake_source(),
m_conv_curve(m_fake_source),
m_minx(1e100),
m_miny(1e100),
m_maxx(-1e100),
m_maxy(-1e100)
{}
//-----------------------------------------------------------------------
void reset()
{
m_minx = 1e100;
m_miny = 1e100;
m_maxx = -1e100;
m_maxy = -1e100;
}
//-----------------------------------------------------------------------
template<class Source> void calculate(const attributes& attr,
Source& src,
bool reset_flag=true)
{
if(reset_flag) reset();
conv_polymorphic_wrapper<Source> psrc(src);
m_conv_curve.attach(psrc);
unsigned cmd;
double x, y;
m_conv_curve.approximation_scale(attr.scale());
m_conv_curve.rewind(0);
while(!agg::is_stop(cmd = m_conv_curve.vertex(&x, &y)))
{
if(agg::is_vertex(cmd))
{
if(x < m_minx) m_minx = x;
if(y < m_miny) m_miny = y;
if(x > m_maxx) m_maxx = x;
if(y > m_maxy) m_maxy = y;
}
}
m_conv_curve.attach(m_fake_source);
}
double minx() const { return m_minx; }
double miny() const { return m_miny; }
double maxx() const { return m_maxx; }
double maxy() const { return m_maxy; }
rectangle bbox() const { return rectangle(m_minx, m_miny, m_maxx, m_maxy); }
private:
fake_vertex_source m_fake_source;
conv_curve m_conv_curve;
double m_minx;
double m_miny;
double m_maxx;
double m_maxy;
};
}
}
#endif

View File

@ -0,0 +1,42 @@
#ifndef AGG_SVG_PTR_SIZE_PAIR_INCLUDE
#define AGG_SVG_PTR_SIZE_PAIR_INCLUDE
//-----------------------------------------------------------------------------
#include "agg_basics.h"
#include <cassert>
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
struct ptr_size
{
ptr_size(const void * ptr, agg::int32u size)
: m_ptr(static_cast<const agg::int8u *>(ptr)),
m_size(size)
{
}
const agg::int8u * m_ptr;
agg::int32u m_size;
};
//-------------------------------------------------------------------------
struct ptr_size_short
{
ptr_size_short(const void * ptr, agg::int32u size)
: m_ptr(static_cast<const agg::int8u *>(ptr)),
m_size(static_cast<agg::int8u>(size))
{
assert(m_size == size);
}
const agg::int8u * m_ptr;
agg::int8u m_size;
};
//-------------------------------------------------------------------------
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_PTR_SIZE_PAIR_INCLUDE

View File

@ -0,0 +1,87 @@
#ifndef AGG_SVG_RASTERIZER_INCLUDED
#define AGG_SVG_RASTERIZER_INCLUDED
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_span_allocator.h"
#include "agg_svg_attributes.h" // for g_fill_rule_lut
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
//
// This class incapsulates AGG scanline rasterizer, AGG scanline container
// and RGBA span allocators.
//
//---------------------------------------------------------------------------
class rasterizer
{
public:
typedef agg::span_allocator<color_type> span_allocator_rgba_type;
typedef agg::rasterizer_scanline_aa<> rasterizer_type;
rasterizer()
: m_scanline()
, m_rasterizer()
, m_allocator_rgba()
{}
//-----------------------------------------------------------------------
void fill_rule(fill_rule_e fr)
{
m_rasterizer.filling_rule(g_fill_rule_lut[fr]);
}
void gamma(double g)
{
m_rasterizer.gamma(agg::gamma_power(g));
}
void gamma_multi(double g)
{
m_rasterizer.gamma(agg::gamma_multiply(g));
}
void clip_box(double x1, double y1, double x2, double y2)
{
m_rasterizer.clip_box(x1, y1, x2, y2);
}
void reset_clipping()
{
m_rasterizer.reset_clipping();
}
//-----------------------------------------------------------------------
// Rasterizer Interface
void reset()
{
m_rasterizer.reset();
}
void add_vertex(double x, double y, unsigned cmd)
{
m_rasterizer.add_vertex(x, y, cmd);
}
template<class Renderer> void render(Renderer& ren)
{
agg::render_scanlines(m_rasterizer, m_scanline, ren);
}
span_allocator_rgba_type& allocator_rgba() { return m_allocator_rgba; }
rasterizer_type& get_rasterizer() { return m_rasterizer; }
agg::scanline_u8& get_scanline() { return m_scanline; }
private:
agg::scanline_u8 m_scanline;
rasterizer_type m_rasterizer;
span_allocator_rgba_type m_allocator_rgba;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_RASTERIZER_INCLUDED

View File

@ -0,0 +1,265 @@
#include "agg_svg_renderer_rgba.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class gradient_opacity_adaptor
{
public:
//---------------------------------------------------------------------
gradient_opacity_adaptor(const gradient_lut_type& lut, double opacity)
: m_lut(lut)
, m_opacity(unsigned(opacity * color_type::base_scale + 0.5))
{}
//---------------------------------------------------------------------
static unsigned size()
{
return gradient_lut_type::size();
}
//---------------------------------------------------------------------
color_type operator[] (unsigned i) const
{
color_type c = m_lut[i];
c.a = (color_type::value_type)((c.a * m_opacity) >> color_type::base_shift);
return c;
}
//---------------------------------------------------------------------
private:
const gradient_lut_type& m_lut;
unsigned m_opacity;
};
//-------------------------------------------------------------------------
renderer_rgba::renderer_rgba(rasterizer& ras, frame_buffer_type& fb)
: m_rasterizer(ras)
, m_frame_buffer(&fb)
, m_fill_gradient(0)
, m_stroke_gradient(0)
{}
//-------------------------------------------------------------------------
template<class GradientFunc, class InterpolatorType>
void renderer_rgba::render_gradient_func(const GradientFunc& gradient_func,
InterpolatorType& span_interpolator,
const gradient_opacity_adaptor& gradient_colors)
{
typedef agg::span_gradient
<
color_type,
InterpolatorType,
GradientFunc,
gradient_opacity_adaptor
>
span_gradient_type;
span_gradient_type span_gradient(span_interpolator, gradient_func, gradient_colors, 0, 100);
agg::renderer_scanline_aa
<
renderer_base_type,
rasterizer::span_allocator_rgba_type,
span_gradient_type
>
ren_gradient(m_frame_buffer->ren_base(), m_rasterizer.allocator_rgba(), span_gradient);
m_rasterizer.render(ren_gradient);
}
//-------------------------------------------------------------------------
void renderer_rgba::fill(const attributes& attr)
{
if (!m_frame_buffer->is_valid()) return;
m_rasterizer.fill_rule(attr.fill_rule());
switch (attr.fill_type())
{
case paint_none:
break;
case paint_color:
case paint_currentColor:
m_frame_buffer->ren_solid().color(attr.fill_color());
m_rasterizer.render(m_frame_buffer->ren_solid());
break;
case paint_gradient:
render_gradient(attr,
*m_fill_gradient,
m_fill_gradient->lut(),
attr.fill_opacity());
break;
}
}
//-------------------------------------------------------------------------
void renderer_rgba::stroke(const attributes& attr)
{
if(!m_frame_buffer->is_valid()) return;
m_rasterizer.fill_rule(fill_rule_nonzero);
switch (attr.stroke_type())
{
case paint_none:
break;
case paint_color:
case paint_currentColor:
m_frame_buffer->ren_solid().color(attr.stroke_color());
m_rasterizer.render(m_frame_buffer->ren_solid());
break;
case paint_gradient:
render_gradient(attr,
*m_stroke_gradient,
m_stroke_gradient->lut(),
attr.stroke_opacity());
break;
}
}
//-------------------------------------------------------------------------
void renderer_rgba::render_gradient(const attributes& attr,
const gradient& g,
const gradient_lut_type& lut,
double opacity)
{
enum gradient_type
{
linear_pad = 0 | 0,
linear_reflect = 4 | 0,
linear_repeat = 8 | 0,
radial_pad = 0 | 1,
radial_reflect = 4 | 1,
radial_repeat = 8 | 1,
radial_focus_pad = 0 | 2,
radial_focus_reflect = 4 | 2,
radial_focus_repeat = 8 | 2
};
// Deduce gradient type and calculate the transformation matrix
//------------------
agg::trans_affine mtx;
int gradient_type = 0;
double fx = 0;
double fy = 0;
if (g.type() == gradient_linear)
{
mtx = agg::trans_affine_line_segment(g.x1(), g.y1(), g.x2(), g.y2(), 100.0);
}
else
{
gradient_type = (g.fx() == g.cx() && g.fy() == g.cy()) ? 1 : 2;
mtx = agg::trans_affine_scaling(g.r() / 100.0);
mtx *= agg::trans_affine_translation(g.cx(), g.cy());
fx = g.fx();
fy = g.fy();
mtx.inverse_transform(&fx, &fy);
}
switch (g.spreadMethod())
{
default: break;
case spreadMethod_reflect: gradient_type |= 4; break;
case spreadMethod_repeat: gradient_type |= 8; break;
}
if (g.gradientUnits() == objectUnits_objectBoundingBox)
{
double parl[6] = { 0,0, 1,0, 1,1 };
double x1 = attr.object_x1();
double y1 = attr.object_y1();
double x2 = attr.object_x2();
double y2 = attr.object_y2();
if (y1 == y2)
y2 += .1;
if (x1 == x2)
x2 += .1;
mtx *= agg::trans_affine(parl, x1, y1, x2, y2);
}
mtx *= g.gradientTransform();
mtx *= attr.transform().transform();
mtx.invert();
gradient_opacity_adaptor gradient_colors(lut, opacity);
agg::span_interpolator_linear<> span_interpolator(mtx);
switch (gradient_type)
{
default: break;
case linear_pad:
{
agg::gradient_x gradient_func;
render_gradient_func(gradient_func, span_interpolator, gradient_colors);
}
break;
case linear_reflect:
{
agg::gradient_x gradient_func;
agg::gradient_reflect_adaptor<agg::gradient_x> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
case linear_repeat:
{
agg::gradient_x gradient_func;
agg::gradient_repeat_adaptor<agg::gradient_x> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
case radial_pad:
{
agg::gradient_radial gradient_func;
render_gradient_func(gradient_func, span_interpolator, gradient_colors);
}
break;
case radial_reflect:
{
agg::gradient_radial gradient_func;
agg::gradient_reflect_adaptor<agg::gradient_radial> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
case radial_repeat:
{
agg::gradient_radial gradient_func;
agg::gradient_repeat_adaptor<agg::gradient_radial> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
case radial_focus_pad:
{
agg::gradient_radial_focus gradient_func(100.0, fx, fy);
render_gradient_func(gradient_func, span_interpolator, gradient_colors);
}
break;
case radial_focus_reflect:
{
agg::gradient_radial_focus gradient_func(100.0, fx, fy);
agg::gradient_reflect_adaptor<agg::gradient_radial_focus> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
case radial_focus_repeat:
{
agg::gradient_radial_focus gradient_func(100.0, fx, fy);
agg::gradient_repeat_adaptor<agg::gradient_radial_focus> gradient_adaptor(gradient_func);
render_gradient_func(gradient_adaptor, span_interpolator, gradient_colors);
}
break;
}
}
} // namespace svg
} // namespace agg

View File

@ -0,0 +1,114 @@
#ifndef AGG_SVG_RENDERER_RGBA_INCLUDED
#define AGG_SVG_RENDERER_RGBA_INCLUDED
//-----------------------------------------------------------------------------
#include "agg_svg_attributes.h"
#include "agg_svg_rasterizer.h"
#include "agg_svg_frame_buffer_rgba.h"
#include "agg_span_interpolator_linear.h"
#include "agg_span_gradient.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
class gradient_opacity_adaptor;
//-------------------------------------------------------------------------
// Main rgba renderer
//
// Used to incapsulate AGG rendering functionality
//
//-------------------------------------------------------------------------
class renderer_rgba
{
public:
//---------------------------------------------------------------------
typedef frame_buffer_rgba frame_buffer_type;
typedef frame_buffer_type::pixfmt_type pixfmt_type;
typedef frame_buffer_type::renderer_base_type renderer_base_type;
typedef frame_buffer_type::renderer_solid_type renderer_solid_type;
//---------------------------------------------------------------------
enum { pixel_size = sizeof(pixel_type) };
//---------------------------------------------------------------------
renderer_rgba(rasterizer&, frame_buffer_type&);
//---------------------------------------------------------------------
void attach(frame_buffer_type&);
//---------------------------------------------------------------------
void fill_gradient(const gradient&);
void stroke_gradient(const gradient&);
//---------------------------------------------------------------------
void reset();
void clip_box(double x1, double y1, double x2, double y2);
void add_vertex(double x, double y, unsigned cmd);
//---------------------------------------------------------------------
void fill(const attributes& attr);
void stroke(const attributes& attr);
//---------------------------------------------------------------------
bool is_valid()const;
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
renderer_rgba(const renderer_rgba&);
const renderer_rgba& operator = (const renderer_rgba&);
//---------------------------------------------------------------------
void render_gradient(const attributes&,
const gradient&,
const gradient_lut_type&,
double opacity);
//---------------------------------------------------------------------
template <class GradientFunc, class InterpolatorType>
void render_gradient_func(const GradientFunc& gradient_func,
InterpolatorType& span_interpolator,
const gradient_opacity_adaptor& gradient_colors);
//---------------------------------------------------------------------
rasterizer& m_rasterizer;
frame_buffer_type* m_frame_buffer;
const gradient* m_fill_gradient;
const gradient* m_stroke_gradient;
};
//-------------------------------------------------------------------------
inline void renderer_rgba::attach(frame_buffer_type& fb)
{
m_frame_buffer = &fb;
}
//-------------------------------------------------------------------------
inline void renderer_rgba::fill_gradient(const gradient& g)
{
m_fill_gradient = &g;
}
//-------------------------------------------------------------------------
inline void renderer_rgba::stroke_gradient(const gradient& g)
{
m_stroke_gradient = &g;
}
//-------------------------------------------------------------------------
inline void renderer_rgba::reset()
{
m_rasterizer.reset();
}
//---------------------------------------------------------------------
inline void renderer_rgba::clip_box(double x1, double y1, double x2, double y2)
{
m_rasterizer.clip_box(x1, y1, x2, y2);
}
//---------------------------------------------------------------------
inline void renderer_rgba::add_vertex(double x, double y, unsigned cmd)
{
m_rasterizer.add_vertex(x, y, cmd);
}
//---------------------------------------------------------------------
inline bool renderer_rgba::is_valid()const
{
return m_frame_buffer->is_valid();
}
//---------------------------------------------------------------------
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_RENDERER_RGBA_INCLUDED

View File

@ -0,0 +1,862 @@
//-----------------------------------------------------------------------------
#include "agg_svg_rendering_interpreter.h"
#include "agg_svg_pipeline.h"
#include "agg_svg_frame_buffer_rgba.h"
#include "agg_svg_renderer_rgba.h"
#include "agg_svg_shape_adaptors.h"
#include "agg_svg_gradient_lut_cache.h"
#include "agg_bounding_rect.h"
#include "agg_svg_percent.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
rendering_interpreter::el_interpreter const
rendering_interpreter::element_interpreters[end_of_elements] = {
&render_circle,
&render_clipPath,
&render_defs,
&render_ellipse,
&render_g,
&render_line,
&render_linearGradient,
&render_path,
&render_polygon,
&render_polyline,
&render_radialGradient,
&render_rect,
&render_stop,
&render_svg,
&set_title_element,
&render_use,
};
//-------------------------------------------------------------------------
rendering_interpreter::rendering_interpreter(pipeline& p,
attributes& attr,
renderer_rgba_type& ren,
dom_storage::map_type& map,
gradient_lut_cache& g_lut_cache,
bool render_paint_servers)
: m_storage(0)
, m_pipeline(p)
, m_attributes(attr)
, m_renderer(ren)
, m_it2element_map(map)
, m_gradient_lut_cache(g_lut_cache)
, m_current_element(end_of_elements)
, m_vertex_source(0)
, m_defs_counter(0)
, m_paint_server_counter(0)
, m_attr_setter(m_attributes)
, m_render_paint_servers(render_paint_servers)
, m_clipPath(false)
, m_gradient(0)
, m_ignore_view_box(false)
{
m_attr_setter.set_interpreter(this);
}
//-------------------------------------------------------------------------
rendering_interpreter::rendering_interpreter(rendering_interpreter const& r,
attributes& attr,
renderer_rgba_type& ren,
bool render_paint_servers)
: m_storage(r.m_storage)
, m_pipeline(r.m_pipeline)
, m_attributes(attr)
, m_renderer(ren)
, m_it2element_map(r.m_it2element_map)
, m_current_element(end_of_elements)
, m_vertex_source(r.m_vertex_source)
, m_defs_counter(0)
, m_paint_server_counter(render_paint_servers ? -1 : 0)
, m_attr_setter(attr)
, m_render_paint_servers(render_paint_servers)
, m_gradient(0)
, m_gradient_lut_cache(r.m_gradient_lut_cache)
, m_clipPath(false)
, m_ignore_view_box(false)
{
m_attr_setter.set_interpreter(this);
}
//-------------------------------------------------------------------------
bool rendering_interpreter::element_is_paint_server(element_e code) const
{
return (code == elem_linearGradient || code == elem_radialGradient);
}
//-------------------------------------------------------------------------
bool rendering_interpreter::start_element(const dom_storage& st,
const element_data& el)
{
m_storage = &st;
m_current_element = el.code;
if (m_defs_counter)
{
if (el.code == elem_defs)
{
++m_defs_counter;
m_attributes.begin_session();
render_defs(el);
}
return true;
}
else if (el.code == elem_defs)
++m_defs_counter;
if (element_is_paint_server(el.code))
{
++m_paint_server_counter;
}
if (m_paint_server_counter > 0)
return true;
if (m_clipPath)
return true;
m_attributes.begin_session();
if (el.code != end_of_elements)
{
(this->*element_interpreters[el.code])(el);
}
return true;
}
//-------------------------------------------------------------------------
bool rendering_interpreter::end_element(const dom_storage& st,
const element_data& el)
{
m_current_element = el.code;
if (el.code == elem_defs)
{
--m_defs_counter;
m_attributes.end_session();
return true;
}
if (m_defs_counter)
{
return true;
}
if (element_is_paint_server(el.code))
{
if (m_paint_server_counter)
{
--m_paint_server_counter;
return true;
}
}
if (m_clipPath)
m_clipPath = false;
else if (m_paint_server_counter == 0)
m_attributes.end_session();
return true;
}
//-------------------------------------------------------------------------
void rendering_interpreter::prepare_gradient_fill(gradient& g)
{
if (m_attributes.fill_type() == paint_gradient)
{
create_gradient(g, locate(m_attributes.fill_gradient_id()));
m_renderer.fill_gradient(g);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::prepare_gradient_stroke(gradient& g)
{
if (m_attributes.stroke_type() == paint_gradient)
{
create_gradient(g, locate(m_attributes.stroke_gradient_id()));
m_renderer.stroke_gradient(g);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::calculate_and_set_object_bbox(object_bbox& bbox)
{
assert(m_vertex_source);
bbox.calculate(m_attributes, *m_vertex_source);
m_attributes.object_bbox(bbox.bbox());
}
//-------------------------------------------------------------------------
bool rendering_interpreter::is_visible(coord_type(&bounds)[4]) const
{
coord_type stroke_width = (coord_type)m_attributes.stroke_width();
bounds[0] -= stroke_width;
bounds[1] -= stroke_width;
bounds[2] += stroke_width;
bounds[3] += stroke_width;
double x1 = bounds[0];
double y1 = bounds[1];
double x2 = bounds[2];
double y2 = bounds[1];
double x3 = bounds[2];
double y3 = bounds[3];
double x4 = bounds[0];
double y4 = bounds[3];
m_attributes.transform().transform(&x1, &y1);
m_attributes.transform().transform(&x2, &y2);
m_attributes.transform().transform(&x3, &y3);
m_attributes.transform().transform(&x4, &y4);
double cx1 = x1;
double cy1 = y1;
double cx2 = x1;
double cy2 = y1;
if(x2 < cx1) cx1 = x2;
if(y2 < cy1) cy1 = y2;
if(x3 < cx1) cx1 = x3;
if(y3 < cy1) cy1 = y3;
if(x4 < cx1) cx1 = x4;
if(y4 < cy1) cy1 = y4;
if(x2 > cx2) cx2 = x2;
if(y2 > cy2) cy2 = y2;
if(x3 > cx2) cx2 = x3;
if(y3 > cy2) cy2 = y3;
if(x4 > cx2) cx2 = x4;
if(y4 > cy2) cy2 = y4;
// Check for clipping
//----------------------
if(!m_attributes.is_visible(cx1, cy1, cx2, cy2))
{
return false;
}
// If not clipped check if the bounding box area
// is more than 0.01 of a pixel.
//----------------------
return (cx2 - cx1) * (cy2 - cy1) > 0.01;
}
//-------------------------------------------------------------------------
void rendering_interpreter::set_common_gradient_attributes(attr_data* attr,
unsigned num_attr)
{
spreadMethod_e spreadMethod;
for (unsigned i = 0; i < num_attr; ++i)
{
if (!attr[i].processed) switch (attr[i].code)
{
case attr_spreadMethod:
assert(attr[i].data.size() == 1);
spreadMethod = (spreadMethod_e)attr[i].data.int8u_at(0);
assert(spreadMethod == spreadMethod_pad ||
spreadMethod == spreadMethod_reflect ||
spreadMethod == spreadMethod_repeat);
m_gradient->spreadMethod(spreadMethod);
attr[i].processed = true;
break;
case attr_gradientUnits:
m_gradient->gradientUnits(read_objectUnits(attr[i].data));
attr[i].processed = true;
break;
case attr_transform:
m_attr_setter.set_transform(*m_gradient, attr[i].data);
attr[i].processed = true;
break;
}
}
}
//-------------------------------------------------------------------------
double rendering_interpreter::read_length(
const data_accessor_type& data) const
{
assert(data.size() == sizeof(coord_type) + 1);
double value = data.units_value(m_attributes);
return value;
}
//-------------------------------------------------------------------------
objectUnits_e rendering_interpreter::read_objectUnits(
const data_accessor_type& data) const
{
assert(data.size() == 1);
objectUnits_e objectUnits = (objectUnits_e)data.int8u_at(0);
assert(objectUnits == objectUnits_userSpaceOnUse ||
objectUnits == objectUnits_objectBoundingBox ||
objectUnits == objectUnits_strokeWidth);
return objectUnits;
}
//-------------------------------------------------------------------------
void rendering_interpreter::read_viewBox(const data_accessor_type& data,
double* x, double* y,
double* w, double* h) const
{
assert(data.size() == 4 * sizeof(coord_type));
*x = data.coord_at(sizeof(coord_type) * 0);
*y = data.coord_at(sizeof(coord_type) * 1);
*w = data.coord_at(sizeof(coord_type) * 2);
*h = data.coord_at(sizeof(coord_type) * 3);
}
//-------------------------------------------------------------------------
void rendering_interpreter::read_preserveAspectRatio(
const data_accessor_type& data,
uniform_scaling_e* usc,
window_fit_logic_e* wfl) const
{
assert(data.size() == 2);
*usc = uniform_scaling_e (data.int8u_at(0));
*wfl = window_fit_logic_e(data.int8u_at(sizeof(agg::int8u)));
}
//-------------------------------------------------------------------------
// render basic shapes
//-------------------------------------------------------------------------
void rendering_interpreter::render_rect(const element_data& el)
{
double x = 0.;
double y = 0.;
double w = 0.;
double h = 0.;
double rx = -1.;
double ry = -1.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_x: x = read_length(el.attr[i].data); break;
case attr_y: y = read_length(el.attr[i].data); break;
case attr_width: w = read_length(el.attr[i].data); break;
case attr_height: h = read_length(el.attr[i].data); break;
case attr_rx: rx = read_length(el.attr[i].data); break;
case attr_ry: rx = read_length(el.attr[i].data); break;
}
}
if (rx < 0. && ry < 0.)
{
rx = 0.;
rx = 0.;
}
if (rx < 0.) rx = ry;
if (ry < 0.) ry = rx;
if (rx > w / 2.) rx = w / 2.;
if (ry > h / 2.) ry = h / 2.;
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
coord_type bounds[4] = {x, y, x + w, y + h};
if (is_visible(bounds))
{
rectangle_adaptor source(x, y, w, h, rx, ry);
general_work_for_basic_shapes(el, source);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_circle(const element_data& el)
{
double cx = 0.;
double cy = 0.;
double r = 0.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_cx: cx = read_length(el.attr[i].data); break;
case attr_cy: cy = read_length(el.attr[i].data); break;
case attr_r: r = read_length(el.attr[i].data); break;
}
}
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
coord_type bounds[4] = {cx - r, cy - r, cx + r, cy + r};
if (is_visible(bounds))
{
circle_adaptor source(cx, cy, r);
general_work_for_basic_shapes(el, source);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_clipPath(const element_data&)
{
m_clipPath = true;
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_ellipse(const element_data& el)
{
double cx = 0.;
double cy = 0.;
double rx = 0.;
double ry = 0.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_cx: cx = read_length(el.attr[i].data); break;
case attr_cy: cy = read_length(el.attr[i].data); break;
case attr_rx: rx = read_length(el.attr[i].data); break;
case attr_ry: ry = read_length(el.attr[i].data); break;
}
}
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
coord_type bounds[4] = {cx - rx, cy - ry, cx + rx, cy + ry};
if (is_visible(bounds))
{
ellipse_adaptor source(cx, cy, rx, ry);
general_work_for_basic_shapes(el, source);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_line(const element_data& el)
{
double x1 = 0.;
double y1 = 0.;
double x2 = 0.;
double y2 = 0.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_x1: x1 = read_length(el.attr[i].data); break;
case attr_y1: y1 = read_length(el.attr[i].data); break;
case attr_x2: x2 = read_length(el.attr[i].data); break;
case attr_y2: y2 = read_length(el.attr[i].data); break;
}
}
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
coord_type bounds[4] = {x1, y1, x2, y2};
if (is_visible(bounds))
{
line_adaptor source(x1, y1, x2, y2);
general_work_for_basic_shapes(el, source);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_polygon(const element_data& el)
{
assert(el.shape_data.size() > 0);
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
if (el.bounds)
{
coord_type bounds[4];
memcpy(bounds, el.bounds, sizeof(bounds));
if (is_visible(bounds))
{
poly_interpreter<data_accessor_type> source(el.shape_data, true);
general_work_for_basic_shapes(el, source);
}
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_polyline(const element_data& el)
{
assert(el.shape_data.size() > 0);
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
if (el.bounds)
{
coord_type bounds[4];
memcpy(bounds, el.bounds, sizeof(bounds));
if (is_visible(bounds))
{
poly_interpreter<data_accessor_type> source(el.shape_data, false);
general_work_for_basic_shapes(el, source);
}
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_path(const element_data& el)
{
assert(el.shape_data.size() > 0);
m_attr_setter.set_transform_attributes(el.attr, el.num_attr);
if (el.bounds)
{
coord_type bounds[4];
memcpy(bounds, el.bounds, sizeof(bounds));
if (is_visible(bounds))
{
path_interpreter<data_accessor_type> source(el.shape_data);
general_work_for_basic_shapes(el, source);
}
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_radialGradient(const element_data& el)
{
m_attr_setter.set_color_attributes (el.attr, el.num_attr);
m_attr_setter.set_xlink_attributes (el.attr, el.num_attr);
set_common_gradient_attributes (el.attr, el.num_attr);
// set default values
double cx = m_attributes.conv_units(50., units_percent);
double cy = m_attributes.conv_units(50., units_percent);
double r = m_attributes.conv_units(50., units_percent );
// read attributes from DOM storage
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_cx:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
cx = el.attr[i].data.units_value(m_attributes);
break;
case attr_cy:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
cy = el.attr[i].data.units_value(m_attributes);
break;
case attr_r:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
r = el.attr[i].data.units_value(m_attributes);
break;
case attr_fx:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
m_gradient->fx(el.attr[i].data.units_value(m_attributes));
break;
case attr_fy:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
m_gradient->fy(el.attr[i].data.units_value(m_attributes));
break;
}
}
m_gradient->radial(cx, cy, r);
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_linearGradient(const element_data& el)
{
m_attr_setter.set_color_attributes (el.attr, el.num_attr);
m_attr_setter.set_xlink_attributes (el.attr, el.num_attr);
set_common_gradient_attributes (el.attr, el.num_attr);
double x1 = 0.;
double y1 = 0.;
double x2 = 1.;
double y2 = 0.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_x1:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
x1 = el.attr[i].data.units_value(m_attributes);
break;
case attr_y1:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
y1 = el.attr[i].data.units_value(m_attributes);
break;
case attr_x2:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
x2 = el.attr[i].data.units_value(m_attributes);
break;
case attr_y2:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
y2 = el.attr[i].data.units_value(m_attributes);
break;
}
}
m_gradient->linear(x1, y1, x2, y2);
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_defs(const element_data& el)
{
m_vertex_source = 0;
m_attr_setter.set_presentation_attributes (el.attr, el.num_attr);
m_attr_setter.set_transform_attributes (el.attr, el.num_attr);
}
//-------------------------------------------------------------------------
void rendering_interpreter::create_gradient(gradient& g, unsigned idx)
{
object_bbox bbox;
bool is_necessary_set_bbox =
units_is_objectBoundingBox(idx, attr_gradientUnits);
if (is_necessary_set_bbox)
{
calculate_and_set_object_bbox(bbox);
}
attributes attr(m_attributes.settings());
attr.begin_session();
if (is_necessary_set_bbox)
{
attr.object_bbox(bbox.bbox());
}
rendering_interpreter rin(*this, attr, m_renderer,true);
rin.set_gradient(&g);
m_storage->traverse(rin, idx);
g.create_gradient_lut(attr, m_gradient_lut_cache);
attr.end_session();
}
//-------------------------------------------------------------------------
bool rendering_interpreter::units_is_objectBoundingBox(unsigned idx,
attr_e code) const
{
data_accessor_type data = m_storage->get_attr_specified_value(idx, code);
if (data.size() == 1)
{
objectUnits_e units = read_objectUnits(data);
return units == objectUnits_objectBoundingBox;
}
else if (data.size() == 0)
{
return true;
}
return false;
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_g(const element_data& el)
{
m_vertex_source = 0;
m_attr_setter.set_presentation_attributes (el.attr, el.num_attr);
m_attr_setter.set_transform_attributes (el.attr, el.num_attr);
}
//-------------------------------------------------------------------------
void rendering_interpreter::process_xlink_href(data_accessor_type data)
{
unsigned index = locate(data);
if (index == 0) return;
if (m_current_element == elem_linearGradient ||
m_current_element == elem_radialGradient)
{
rendering_interpreter rin(*this, m_attributes, m_renderer, true);
rin.set_gradient(m_gradient);
m_storage->traverse(rin, index);
}
else
{
assert(false);
}
}
//-------------------------------------------------------------------------
unsigned rendering_interpreter::locate(const char* id)
{
using namespace std;
typedef agg::pod_array_adaptor<char const> adaptor_type;
adaptor_type id_adaptor(id, (unsigned)strlen(id));
data_accessor<adaptor_type> data(id_adaptor);
return locate(data);
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_stop(const element_data& el)
{
m_vertex_source = 0;
m_attr_setter.set_color_attributes(el.attr, el.num_attr);
double stop_offset = 0.;
color_type stop_color = color_type(0, 0, 0);
double stop_opacity = 1.;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_offset:
assert(el.attr[i].data.size() == sizeof(coord_type));
stop_offset = percent::decrypt(el.attr[i].data.coord_at(0));
break;
case attr_stop_color:
assert(el.attr[i].data.size() == sizeof(color_type));
stop_color = el.attr[i].data.color_at(0);
break;
case attr_stop_opacity:
assert(el.attr[i].data.size() == sizeof(coord_type));
stop_opacity = el.attr[i].data.coord_at(0);
break;
}
}
m_gradient->add_stop(stop_offset, stop_color, stop_opacity);
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_svg(const element_data& el)
{
m_vertex_source = 0;
m_attr_setter.set_presentation_attributes(el.attr, el.num_attr);
// set default values
coordinate x = { 0, units_px};
coordinate y = { 0, units_px};
length w = {100, units_percent_x};
length h = {100, units_percent_y};
double vb_x = 0.;
double vb_y = 0.;
double vb_w = 0.;
double vb_h = 0.;
uniform_scaling_e usc = usc_xMidYMid;
if (m_ignore_view_box)
usc = usc_none;
window_fit_logic_e wfl = window_meet;
bool is_viewBox_present = false;
// read attributes
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_x:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
x.value = el.attr[i].data.coord_at(0);
x.unit = units2_e(el.attr[i].data.int8u_at(sizeof(coord_type)));
break;
case attr_y:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
y.value = el.attr[i].data.coord_at(0);
y.unit = units2_e(el.attr[i].data.int8u_at(sizeof(coord_type)));
break;
case attr_width:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
w.value = el.attr[i].data.coord_at(0);
w.unit = units2_e(el.attr[i].data.int8u_at(sizeof(coord_type)));
break;
case attr_height:
assert(el.attr[i].data.size() == sizeof(coord_type) + 1);
h.value = el.attr[i].data.coord_at(0);
h.unit = units2_e(el.attr[i].data.int8u_at(sizeof(coord_type)));
break;
case attr_viewBox:
read_viewBox(el.attr[i].data, &vb_x, &vb_y, &vb_w, &vb_h);
is_viewBox_present = true;
break;
case attr_preserveAspectRatio:
read_preserveAspectRatio(el.attr[i].data, &usc, &wfl);
break;
}
}
// Normalize values
x.value = m_attributes.conv_units(x.value, x.unit);
y.value = m_attributes.conv_units(y.value, y.unit);
w.value = m_attributes.conv_units(w.value, w.unit);
h.value = m_attributes.conv_units(h.value, h.unit);
if (!is_viewBox_present)
{
vb_w = w.value;
vb_h = h.value;
}
if (m_ignore_view_box)
{
double scrW = (m_attributes.window_x2()<0)?w.value:(m_attributes.window_x2()/2-m_attributes.window_x1());
double scrH = (m_attributes.window_y2()<0)?h.value:(m_attributes.window_y2()/2-m_attributes.window_y1());
m_attributes.viewBox(m_attributes.window_x1(), m_attributes.window_y1(),
scrW,
scrH,
vb_x, vb_y, vb_w, vb_h, usc, wfl, false);
}
else
{
m_attributes.viewBox(x.value, y.value, w.value, h.value,
vb_x, vb_y, vb_w, vb_h, usc, wfl, false);
}
}
//-------------------------------------------------------------------------
void rendering_interpreter::set_title_element(const element_data& el)
{
m_vertex_source = 0;
}
//-------------------------------------------------------------------------
void rendering_interpreter::render_use(const element_data& el)
{
m_attr_setter.set_paint_attributes (el.attr, el.num_attr);
m_attr_setter.set_color_attributes (el.attr, el.num_attr);
m_attr_setter.set_opacity_attributes (el.attr, el.num_attr);
m_attr_setter.set_transform_attributes (el.attr, el.num_attr);
double x = 0.;
double y = 0.;
data_accessor_type href;
for (unsigned i = 0; i < el.num_attr; ++i)
{
if (!el.attr[i].processed) switch (el.attr[i].code)
{
case attr_x: x = read_length(el.attr[i].data); break;
case attr_y: y = read_length(el.attr[i].data); break;
case attr_xlink_href: href = el.attr[i].data; break;
}
}
if (href.size() > 0)
{
m_attributes.translate(x, y);
unsigned index = locate(href, 0);
if (index != 0)
{
rendering_interpreter rin(*this, m_attributes, m_renderer);
m_storage->traverse(rin, index);
}
}
}
}
}

View File

@ -0,0 +1,187 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_RENDERING_INTERPRETER_INCLUDED
#define AGG_SVG_RENDERING_INTERPRETER_INCLUDED
//-----------------------------------------------------------------------------
#include "agg_array.h"
#include "agg_svg_basics.h"
#include "agg_svg_attributes_setter.h"
#include "agg_svg_attributes.h"
#include "agg_svg_dom_storage.h"
#include "agg_svg_assoc_pod_array.h"
#include "agg_svg_pipeline.h"
#include "agg_svg_exception.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// forward declarations
//
class pipeline;
class gradient_lut_cache;
class frame_buffer_rgba;
class renderer_rgba;
//-------------------------------------------------------------------------
class rendering_interpreter
{
public:
//---------------------------------------------------------------------
typedef renderer_rgba renderer_rgba_type;
//---------------------------------------------------------------------
rendering_interpreter(rendering_interpreter const&,
attributes&,
renderer_rgba_type&,
bool render_paint_servers = false);
//---------------------------------------------------------------------
rendering_interpreter(pipeline&,
attributes&,
renderer_rgba_type&,
dom_storage::map_type&,
gradient_lut_cache&,
bool render_paint_servers = false);
//---------------------------------------------------------------------
void ignore_viewBox(bool ignVB)
{
m_ignore_view_box = ignVB;
}
//---------------------------------------------------------------------
bool start_element(const dom_storage& st,
const element_data& el);
//---------------------------------------------------------------------
bool end_element(const dom_storage& st, const element_data& el);
//---------------------------------------------------------------------
#ifdef EXPAND_PATHS
void expand(double value)
{
m_pipeline.expand(value);
}
#endif
//---------------------------------------------------------------------
element_e current_element() {return m_current_element;}
//---------------------------------------------------------------------
template <class DataAccessor>
element_e interpret_element(const DataAccessor& data)
{
dom_storage::map_type::iterator it = m_it2element_map.find(data);
if (it == m_it2element_map.end())
{
return end_of_elements;
}
m_current_element = end_of_elements;
return (*it).second.code;
}
//---------------------------------------------------------------------
void process_xlink_href(data_accessor_type data);
//---------------------------------------------------------------------
private:
//---------------------------------------------------------------------
typedef rendering_interpreter this_type;
typedef void (this_type::*el_interpreter)(const element_data&);
static el_interpreter const element_interpreters[];
//---------------------------------------------------------------------
void render_circle (const element_data&);
void render_clipPath (const element_data&);
void render_defs (const element_data&);
void render_ellipse (const element_data&);
void render_g (const element_data&);
void render_line (const element_data&);
void render_linearGradient (const element_data&);
void render_path (const element_data&);
void render_polygon (const element_data&);
void render_polyline (const element_data&);
void render_radialGradient (const element_data&);
void render_rect (const element_data&);
void render_stop (const element_data&);
void render_svg (const element_data&);
void set_title_element (const element_data&);
void render_use (const element_data&);
//---------------------------------------------------------------------
double read_length(const data_accessor_type& data) const;
//---------------------------------------------------------------------
objectUnits_e read_objectUnits(const data_accessor_type& data) const;
//---------------------------------------------------------------------
void read_viewBox(const data_accessor_type& data,
double* x, double* y, double* w, double* h) const;
//---------------------------------------------------------------------
void read_preserveAspectRatio(const data_accessor_type& data,
uniform_scaling_e* usc,
window_fit_logic_e* wfl) const;
//---------------------------------------------------------------------
template <class VertexSource>
void general_work_for_basic_shapes(const element_data& el,
VertexSource& src)
{
conv_polymorphic_wrapper<VertexSource> source(src);
m_vertex_source = &source;
m_attr_setter.set_basic_shapes_common_attributes(el.attr, el.num_attr);
gradient fill_gradient;
gradient stroke_gradient;
prepare_gradient_fill (fill_gradient);
prepare_gradient_stroke (stroke_gradient);
m_pipeline.render(m_attributes, src, m_renderer);
}
//---------------------------------------------------------------------
bool element_is_paint_server(element_e code) const;
//---------------------------------------------------------------------
void calculate_and_set_object_bbox(object_bbox& bbox);
//---------------------------------------------------------------------
bool units_is_objectBoundingBox(unsigned idx, attr_e code) const;
//---------------------------------------------------------------------
void create_gradient(gradient&, unsigned);
//---------------------------------------------------------------------
void prepare_gradient_fill (gradient&);
//---------------------------------------------------------------------
void prepare_gradient_stroke(gradient&);
//---------------------------------------------------------------------
bool is_visible(coord_type(&)[4]) const;
//---------------------------------------------------------------------
void set_common_gradient_attributes(attr_data*, unsigned);
//---------------------------------------------------------------------
void set_gradient (gradient* g) {m_gradient = g; }
//---------------------------------------------------------------------
unsigned locate(const char* str);
//---------------------------------------------------------------------
template <class DataAccessor>
unsigned locate(DataAccessor id, int* = 0)
{
dom_storage::map_type::iterator it;
it = m_it2element_map.find(id);
if (it == m_it2element_map.end())
{
return 0;
}
return it->second.idx;
}
//---------------------------------------------------------------------
pipeline& m_pipeline;
attributes& m_attributes;
gradient_lut_cache& m_gradient_lut_cache;
renderer_rgba_type& m_renderer;
dom_storage const * m_storage;
dom_storage::map_type& m_it2element_map;
element_e m_current_element;
gradient* m_gradient;
attributes_setter m_attr_setter;
int m_defs_counter;
int m_paint_server_counter;
conv_polymorphic_base* m_vertex_source;
bool m_render_paint_servers;
bool m_clipPath;
bool m_ignore_view_box;
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_RENDERING_INTERPRETER_INCLUDED

View File

@ -0,0 +1,305 @@
#ifndef AGG_SVG_SHAPE_ADAPTORS_INCLUDED
#define AGG_SVG_SHAPE_ADAPTORS_INCLUDED
#include "agg_bezier_arc.h"
#include "agg_svg_basics.h"
#include "agg_svg_path_serializer.h"
#include "agg_svg_path_interpreter.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
template<class CoordT, unsigned MaxVertices=32> class simple_path_container
{
public:
typedef CoordT coord_type;
enum { max_vertices = MaxVertices };
//-----------------------------------------------------------------------
simple_path_container() :
m_end_of_buffer(m_buffer + max_vertices * (sizeof(agg::int8u) + sizeof(CoordT) * 2)),
m_end_of_data(m_buffer),
m_vertex(m_buffer)
{}
//-----------------------------------------------------------------------
void remove_all()
{
m_end_of_data = m_buffer;
m_vertex = m_buffer;
}
//-----------------------------------------------------------------------
bool add_vertex(double x, double y, unsigned cmd)
{
if((m_end_of_data + sizeof(agg::int8u) + sizeof(CoordT) * 2) <= m_end_of_buffer)
{
CoordT tx = (CoordT)x;
CoordT ty = (CoordT)y;
*m_end_of_data++ = (agg::int8u)cmd;
memcpy(m_end_of_data, &tx, sizeof(CoordT));
m_end_of_data += sizeof(CoordT);
memcpy(m_end_of_data, &ty, sizeof(CoordT));
m_end_of_data += sizeof(CoordT);
return true;
}
return false;
}
//-----------------------------------------------------------------------
void move_to(double x, double y)
{
add_vertex(x, y, agg::path_cmd_move_to);
}
//-----------------------------------------------------------------------
void line_to(double x, double y)
{
add_vertex(x, y, agg::path_cmd_line_to);
}
//-----------------------------------------------------------------------
void curve3_to(double x1, double y1, double x, double y)
{
add_vertex(x1, y1, agg::path_cmd_curve3);
add_vertex(x , y, agg::path_cmd_curve3);
}
//-----------------------------------------------------------------------
void curve4_to(double x1, double y1,
double x2, double y2,
double x, double y)
{
add_vertex(x1, y1, agg::path_cmd_curve4);
add_vertex(x2, y2, agg::path_cmd_curve4);
add_vertex(x , y, agg::path_cmd_curve4);
}
//-----------------------------------------------------------------------
void close_subpath()
{
add_vertex(0.0, 0.0, agg::path_cmd_end_poly | agg::path_flags_close);
}
//-----------------------------------------------------------------------
template<class VertexSource> void add_path(VertexSource& vs, unsigned path_id=0)
{
double x;
double y;
unsigned cmd;
vs.rewind(path_id);
while(!agg::is_stop(cmd = vs.vertex(&x, &y)))
{
if(!add_vertex(x, y, cmd)) break;
}
}
//-----------------------------------------------------------------------
template<class VertexSource> void add_path_solid(VertexSource& vs, unsigned path_id=0)
{
double x;
double y;
unsigned cmd;
vs.rewind(path_id);
while(agg::is_move_to(cmd = vs.vertex(&x, &y)));
if(!agg::is_stop(cmd))
{
if(add_vertex(x, y, cmd))
{
while(!agg::is_stop(cmd = vs.vertex(&x, &y)))
{
if(!add_vertex(x, y, cmd)) break;
}
}
}
}
//-----------------------------------------------------------------------
void rewind(unsigned)
{
m_vertex = m_buffer;
}
//-----------------------------------------------------------------------
unsigned vertex(double* x, double* y)
{
if(m_vertex >= m_end_of_data) return agg::path_cmd_stop;
CoordT tx;
CoordT ty;
unsigned cmd = *m_vertex++;
memcpy(&tx, m_vertex, sizeof(CoordT));
m_vertex += sizeof(CoordT);
memcpy(&ty, m_vertex, sizeof(CoordT));
m_vertex += sizeof(CoordT);
*x = (double)tx;
*y = (double)ty;
return cmd;
}
private:
agg::int8u m_buffer[max_vertices * (sizeof(agg::int8u) + sizeof(CoordT) * 2)];
agg::int8u* m_end_of_buffer;
agg::int8u* m_end_of_data;
const agg::int8u* m_vertex;
};
//-------------------------------------------------------------------------
class line_adaptor
{
public:
line_adaptor() {}
line_adaptor(double x1, double y1, double x2, double y2)
{
init(x1, y1, x2, y2);
}
void init(double x1, double y1, double x2, double y2)
{
m_path.remove_all();
m_path.move_to(x1, y1);
m_path.line_to(x2, y2);
}
//-----------------------------------------------------------------------
void rewind(unsigned) { m_path.rewind(0); }
unsigned vertex(double* x, double* y) { return m_path.vertex(x, y); }
private:
simple_path_container<coord_type, 2> m_path;
};
//-------------------------------------------------------------------------
class rectangle_adaptor
{
public:
rectangle_adaptor() {}
rectangle_adaptor(double x, double y, double w, double h, double rx=0, double ry=0)
{
init(x, y, w, h, rx, ry);
}
void init(double x, double y, double w, double h, double rx=0, double ry=0)
{
m_path.remove_all();
if(w < 0.0) return;
if(h < 0.0) return;
double x1 = x;
double y1 = y;
double x2 = x + w;
double y2 = y + h;
if(rx == 0.0) rx = ry;
if(ry == 0.0) ry = rx;
if(rx == 0.0 || ry == 0.0)
{
m_path.move_to(x1, y1);
m_path.line_to(x2, y1);
m_path.line_to(x2, y2);
m_path.line_to(x1, y2);
m_path.close_subpath();
}
else
{
double dx = fabs(y2 - y1);
double dy = fabs(x2 - x1);
double k = 1.0;
double t;
t = dx / (rx * 2.0); if(t < k) k = t;
t = dy / (ry * 2.0); if(t < k) k = t;
if(k < 1.0)
{
rx *= k;
ry *= k;
}
agg::bezier_arc a;
m_path.move_to(x1 + rx, y1);
m_path.line_to(x2 - rx, y1);
a.init(x2 - rx, y1 + ry, rx, ry, -agg::pi/2.0, agg::pi/2.0);
m_path.add_path_solid(a);
m_path.line_to(x2, y2 - ry);
a.init(x2 - rx, y2 - ry, rx, ry, 0.0, agg::pi/2.0);
m_path.add_path_solid(a);
m_path.line_to(x1 + rx, y2);
a.init(x1 + rx, y2 - ry, rx, ry, agg::pi/2.0, agg::pi/2.0);
m_path.add_path_solid(a);
m_path.line_to(x1, y1 + ry);
a.init(x1 + rx, y1 + ry, rx, ry, agg::pi, agg::pi/2.0);
m_path.add_path_solid(a);
m_path.close_subpath();
}
}
//------------------------------------------------------------------------
void rewind(unsigned) { m_path.rewind(0); }
unsigned vertex(double* x, double* y) { return m_path.vertex(x, y); }
private:
simple_path_container<coord_type, 30> m_path;
};
//-------------------------------------------------------------------------
class circle_adaptor
{
public:
circle_adaptor() {}
circle_adaptor(double cx, double cy, double r)
{
init(cx, cy, r);
}
void init(double cx, double cy, double r)
{
m_path.remove_all();
if(r > 0.0)
{
agg::bezier_arc a(cx, cy, r, r, 0, 2.0*agg::pi);
m_path.add_path(a);
m_path.close_subpath();
}
}
//------------------------------------------------------------------------
void rewind(unsigned) { m_path.rewind(0); }
unsigned vertex(double* x, double* y) { return m_path.vertex(x, y); }
private:
simple_path_container<coord_type, 20> m_path;
};
//-------------------------------------------------------------------------
class ellipse_adaptor
{
public:
ellipse_adaptor() {}
ellipse_adaptor(double cx, double cy, double rx, double ry)
{
init(cx, cy, rx, ry);
}
void init(double cx, double cy, double rx, double ry)
{
m_path.remove_all();
if(rx > 0.0 && ry > 0.0)
{
agg::bezier_arc a(cx, cy, rx, ry, 0, 2.0*agg::pi);
m_path.add_path(a);
m_path.close_subpath();
}
}
//------------------------------------------------------------------------
void rewind(unsigned) { m_path.rewind(0); }
unsigned vertex(double* x, double* y) { return m_path.vertex(x, y); }
private:
simple_path_container<coord_type, 20> m_path;
};
}
}
#endif

View File

@ -0,0 +1,26 @@
#ifndef AGG_SVG_TAGS_INCLUDE
#define AGG_SVG_TAGS_INCLUDE
namespace agg
{
namespace svg
{
enum tag_e
{
tag_end_element = 0,
tag_element_bin,
tag_attribute_bin,
tag_attribute_bin_short,
tag_attribute_bin_byte,
end_of_tags,
};
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_TAGS_INCLUDE

View File

@ -0,0 +1,276 @@
#include "agg_svg_transformer.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
void viewbox_to_viewport(agg::trans_viewport& tr,
double x, double y, double w, double h,
uniform_scaling_e align_type,
window_fit_logic_e meet_or_slice)
{
if(w > 0.0 && h > 0.0)
{
tr.world_viewport(x, y, x + w, y + h);
}
agg::aspect_ratio_e ar =
(meet_or_slice == window_meet) ? agg::aspect_ratio_meet :
agg::aspect_ratio_slice;
switch(align_type)
{
case usc_none: tr.preserve_aspect_ratio(0.0, 0.0, agg::aspect_ratio_stretch); break;
case usc_xMinYMin: tr.preserve_aspect_ratio(0.0, 0.0, ar); break;
case usc_xMidYMin: tr.preserve_aspect_ratio(0.5, 0.0, ar); break;
case usc_xMaxYMin: tr.preserve_aspect_ratio(1.0, 0.0, ar); break;
case usc_xMinYMid: tr.preserve_aspect_ratio(0.0, 0.5, ar); break;
case usc_xMidYMid: tr.preserve_aspect_ratio(0.5, 0.5, ar); break;
case usc_xMaxYMid: tr.preserve_aspect_ratio(1.0, 0.5, ar); break;
case usc_xMinYMax: tr.preserve_aspect_ratio(0.0, 1.0, ar); break;
case usc_xMidYMax: tr.preserve_aspect_ratio(0.5, 1.0, ar); break;
case usc_xMaxYMax: tr.preserve_aspect_ratio(1.0, 1.0, ar); break;
}
}
//-------------------------------------------------------------
void transformer::update()
{
if(is_valid())
{
m_transformer = m_affine;
m_transformer *= m_viewport.to_affine();
m_transformer *= m_zoom.to_affine();
m_transformer *= agg::trans_affine_translation(-m_dx, -m_dy);
m_scale = m_transformer.scale();
m_viewport.device_viewport(&m_device_x1, &m_device_y1,
&m_device_x2, &m_device_y2);
m_clip_x1 = m_viewbox_x1;
m_clip_y1 = m_viewbox_y1;
m_clip_x2 = m_viewbox_x2;
m_clip_y2 = m_viewbox_y2;
double w = m_buffer_x2 - m_buffer_x1;
double h = m_buffer_y2 - m_buffer_y1;
if(m_clip_x1 < 0) m_clip_x1 = 0;
if(m_clip_x2 > w) m_clip_x2 = w;
if(m_clip_y1 < 0) m_clip_y1 = 0;
if(m_clip_y2 > h) m_clip_y2 = h;
}
else
{
invalidate();
}
}
//-------------------------------------------------------------
void transformer::invalidate()
{
m_transformer = m_affine;
m_scale = m_affine.scale();
m_dx = 0;
m_dy = 0;
m_device_x1 = 0;
m_device_y1 = 0;
m_device_x2 = 1;
m_device_y2 = 1;
m_window_x1 = 0;
m_window_y1 = 0;
m_window_x2 = -1;
m_window_y2 = -1;
m_viewbox_x1 = 0;
m_viewbox_y1 = 0;
m_viewbox_x2 = -1;
m_viewbox_y2 = -1;
m_viewbox_dx = 0;
m_viewbox_dy = 0;
m_buffer_x1 = 0;
m_buffer_y1 = 0;
m_buffer_x2 = -1;
m_buffer_y2 = -1;
m_clip_x1 = 0;
m_clip_y1 = 0;
m_clip_x2 = -1;
m_clip_y2 = -1;
}
//-------------------------------------------------------------
void transformer::viewBox(const agg::trans_viewport& vp)
{
m_viewport = vp;
m_viewport.device_viewport(&m_device_x1, &m_device_y1,
&m_device_x2, &m_device_y2);
m_buffer_x1 = int(floor(m_device_x1));
m_buffer_y1 = int(floor(m_device_y1));
m_buffer_x2 = int( ceil(m_device_x2));
m_buffer_y2 = int( ceil(m_device_y2));
m_window_x1 = int(floor(m_device_x1));
m_window_y1 = int(floor(m_device_y1));
m_window_x2 = int( ceil(m_device_x2));
m_window_y2 = int( ceil(m_device_y2));
m_dx = 0;
m_dy = 0;
m_viewbox_x1 = m_device_x1;
m_viewbox_y1 = m_device_y1;
m_viewbox_x2 = m_device_x2;
m_viewbox_y2 = m_device_y2;
m_viewbox_dx = 0;
m_viewbox_dy = 0;
m_clip_x1 = m_device_x1;
m_clip_y1 = m_device_y1;
m_clip_x2 = m_device_x2;
m_clip_y2 = m_device_y2;
m_viewBox_level = 1;
update();
}
//-------------------------------------------------------------
void transformer::viewBox(double scx, double scy, double scw, double sch,
double vbx, double vby, double vbw, double vbh,
uniform_scaling_e align_type,
window_fit_logic_e meet_or_slice,
bool separate_buffer)
{
if(!is_valid())
{
invalidate();
return;
}
double x0, y0, x1, y1, x2, y2;
x2 = scx + scw;
y2 = scy + sch;
m_viewport.transform(&scx, &scy);
m_viewport.transform(&x2, &y2);
if(separate_buffer)
{
x0 = 0;
y0 = 0;
m_viewport.transform(&x0, &y0);
if(m_viewBox_level > 0)
{
x1 = m_zoom.device_dx() - m_viewbox_dx;
y1 = m_zoom.device_dy() - m_viewbox_dy;
m_zoom.inverse_transform_scale_only(&x1, &y1);
x0 += x1;
y0 += y1;
}
x1 = m_viewbox_x1;
y1 = m_viewbox_y1;
m_zoom.inverse_transform_scale_only(&x1, &y1);
x0 -= x1;
y0 -= y1;
scx -= x0;
scy -= y0;
x2 -= x0;
y2 -= y0;
}
else
{
x0 = m_dx;
y0 = m_dy;
m_zoom.inverse_transform_scale_only(&x0, &y0);
scx -= x0;
scy -= y0;
x2 -= x0;
y2 -= y0;
}
m_viewport.device_viewport(scx, scy, x2, y2);
viewbox_to_viewport(m_viewport, vbx, vby, vbw, vbh, align_type, meet_or_slice);
if(!m_viewport.is_valid())
{
invalidate();
return;
}
m_dx = 0;
m_dy = 0;
if(separate_buffer)
{
bool wflag = m_window_x1 < m_window_x2 && m_window_y1 < m_window_y2;
if(wflag)
{
m_viewport.world_viewport(&x1, &y1, &x2, &y2);
m_viewport.transform(&x1, &y1);
m_viewport.transform(&x2, &y2);
x0 = x1;
y0 = y1;
m_zoom.transform(&x1, &y1);
m_zoom.transform(&x2, &y2);
m_viewbox_x1 = x1;
m_viewbox_y1 = y1;
m_viewbox_x2 = x2;
m_viewbox_y2 = y2;
m_viewbox_dx = 0;
m_viewbox_dy = 0;
if(m_viewbox_x1 < m_window_x1)
{
m_viewbox_dx = m_viewbox_x1 - m_window_x1;
m_viewbox_x1 = m_window_x1;
}
if(m_viewbox_y1 < m_window_y1)
{
m_viewbox_dy = m_viewbox_y1 - m_window_y1;
m_viewbox_y1 = m_window_y1;
}
if(m_viewbox_x2 > m_window_x2) m_viewbox_x2 = m_window_x2;
if(m_viewbox_y2 > m_window_y2) m_viewbox_y2 = m_window_y2;
m_buffer_x1 = int(floor(m_viewbox_x1));
m_buffer_y1 = int(floor(m_viewbox_y1));
m_buffer_x2 = int( ceil(m_viewbox_x2));
m_buffer_y2 = int( ceil(m_viewbox_y2));
m_viewbox_x1 -= m_buffer_x1;
m_viewbox_y1 -= m_buffer_y1;
m_viewbox_x2 -= m_buffer_x1;
m_viewbox_y2 -= m_buffer_y1;
m_viewport.transform(&m_dx, &m_dy);
m_zoom.transform(&m_dx, &m_dy);
m_dx -= m_viewbox_x1 + m_viewbox_dx;
m_dy -= m_viewbox_y1 + m_viewbox_dy;
}
update();
if(!wflag)
{
m_buffer_x1 = int(floor(m_device_x1));
m_buffer_y1 = int(floor(m_device_y1));
m_buffer_x2 = int(ceil(m_device_x2));
m_buffer_y2 = int(ceil(m_device_y2));
}
}
else
{
update();
m_viewbox_x1 = vbx;
m_viewbox_y1 = vby;
m_viewbox_x2 = vbx + vbw;
m_viewbox_y2 = vby + vbh;
m_viewport.transform(&m_viewbox_x1, &m_viewbox_y1);
m_viewport.transform(&m_viewbox_x2, &m_viewbox_y2);
m_zoom.transform(&m_viewbox_x1, &m_viewbox_y1);
m_zoom.transform(&m_viewbox_x2, &m_viewbox_y2);
m_clip_x1 = m_viewbox_x1;
m_clip_y1 = m_viewbox_y1;
m_clip_x2 = m_viewbox_x2;
m_clip_y2 = m_viewbox_y2;
double w = m_buffer_x2 - m_buffer_x1;
double h = m_buffer_y2 - m_buffer_y1;
if(m_clip_x1 < 0) m_clip_x1 = 0;
if(m_clip_x2 > w) m_clip_x2 = w;
if(m_clip_y1 < 0) m_clip_y1 = 0;
if(m_clip_y2 > h) m_clip_y2 = h;
}
++m_viewBox_level;
}
}
}

View File

@ -0,0 +1,364 @@
#ifndef AGG_SVG_TRANSFORMER_INCLUDED
#define AGG_SVG_TRANSFORMER_INCLUDED
#include "agg_trans_affine.h"
#include "agg_trans_viewport.h"
#include "agg_svg_basics.h"
#include "agg_svg_defines.h"
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
// The transformer class integrates the viewport, additional zoom, and
// arbitary affine transformations.
//
// USAGE:
// transformer tr;
// tr.viewBox(. . .);
// . . .
// tr.transform(&x, &y);
//
//----------------------------------------------------------------------------
class transformer
{
public:
//-------------------------------------------------------------
transformer() :
m_affine(),
m_viewport(),
m_zoom(),
m_transformer(),
m_viewBox_level(0),
m_scale(1.0),
m_dx(0),
m_dy(0),
m_device_x1(0),
m_device_y1(0),
m_device_x2(1),
m_device_y2(1),
m_window_x1(0),
m_window_y1(0),
m_window_x2(-1),
m_window_y2(-1),
m_viewbox_x1(0),
m_viewbox_y1(0),
m_viewbox_x2(-1),
m_viewbox_y2(-1),
m_viewbox_dx(0),
m_viewbox_dy(0),
m_buffer_x1(0),
m_buffer_y1(0),
m_buffer_x2(-1),
m_buffer_y2(-1),
m_clip_x1(0),
m_clip_y1(0),
m_clip_x2(-1),
m_clip_y2(-1)
{
m_viewport.preserve_aspect_ratio(0.5, 0.5, agg::aspect_ratio_meet);
m_zoom.preserve_aspect_ratio(0.5, 0.5, agg::aspect_ratio_meet);
}
//-------------------------------------------------------------
void reset()
{
*this = transformer();
}
//-------------------------------------------------------------
void window(int x1, int y1, int x2, int y2)
{
m_viewBox_level = 0;
m_dx = 0;
m_dy = 0;
m_window_x1 = x1;
m_window_y1 = y1;
m_window_x2 = x2;
m_window_y2 = y2;
m_viewbox_x1 = x1;
m_viewbox_y1 = y1;
m_viewbox_x2 = x2;
m_viewbox_y2 = y2;
m_viewbox_dx = 0;
m_viewbox_dy = 0;
m_buffer_x1 = x1;
m_buffer_y1 = y1;
m_buffer_x2 = x2;
m_buffer_y2 = y2;
m_clip_x1 = x1;
m_clip_y1 = y1;
m_clip_x2 = x2;
m_clip_y2 = y2;
m_viewport.device_viewport(x1, y1, x2, y2);
m_viewport.world_viewport(x1, y1, x2, y2);
m_zoom.device_viewport(x1, y1, x2, y2);
m_zoom.world_viewport(x1, y1, x2, y2);
update();
}
//-------------------------------------------------------------
void viewBox(const agg::trans_viewport& vp);
void viewBox(double scx, double scy, double scw, double sch,
double vbx, double vby, double vbw, double vbh,
uniform_scaling_e align_type,
window_fit_logic_e meet_or_slice,
bool separate_window);
//-------------------------------------------------------------
unsigned viewBox_level() const { return m_viewBox_level; }
//-------------------------------------------------------------
bool is_visible(double x1, double y1, double x2, double y2) const
{
agg::rect_d cb(m_clip_x1, m_clip_y1, m_clip_x2, m_clip_y2);
return cb.clip(agg::rect_d(x1, y1, x2, y2));
}
//-------------------------------------------------------------
void zoom(double wx1, double wy1, double wx2, double wy2,
double sx1, double sy1, double sx2, double sy2)
{
m_zoom.device_viewport(sx1, sy1, sx2, sy2);
m_zoom.world_viewport(wx1, wy1, wx2, wy2);
update();
}
//-------------------------------------------------------------
void zoom(double wx1, double wy1, double wx2, double wy2)
{
m_zoom.world_viewport(wx1, wy1, wx2, wy2);
update();
}
//-------------------------------------------------------------
void zoom(double* x1, double* y1, double* x2, double* y2) const
{
m_zoom.transform(x1, y1);
m_zoom.transform(x2, y2);
}
//-------------------------------------------------------------
void inverse_zoom(double* x1, double* y1, double* x2, double* y2) const
{
m_zoom.inverse_transform(x1, y1);
m_zoom.inverse_transform(x2, y2);
}
//-------------------------------------------------------------
void device_viewport(double* x1, double* y1, double* x2, double* y2) const
{
m_viewport.device_viewport(x1, y1, x2, y2);
}
//-------------------------------------------------------------
void world_viewport(double* x1, double* y1, double* x2, double* y2) const
{
m_viewport.world_viewport(x1, y1, x2, y2);
}
//-------------------------------------------------------------
const agg::trans_viewport& viewport() const { return m_viewport; }
agg::trans_viewport& viewport() { return m_viewport; }
//-------------------------------------------------------------
const agg::trans_viewport& zoom() const { return m_zoom; }
agg::trans_viewport& zoom() { return m_zoom; }
//-------------------------------------------------------------
void transform(const agg::trans_affine& mtx)
{
m_affine.premultiply(mtx);
update();
}
//-------------------------------------------------------------
void transform(double a0, double a1, double a2,
double a3, double a4, double a5)
{
m_affine.premultiply(agg::trans_affine(a0, a1, a2, a3, a4, a5));
update();
}
//-------------------------------------------------------------
void translate(double dx, double dy)
{
m_affine.premultiply(agg::trans_affine_translation(dx, dy));
update();
}
//-------------------------------------------------------------
void rotate(double angle)
{
m_affine.premultiply(agg::trans_affine_rotation(angle));
update();
}
//-------------------------------------------------------------
void rotate(double angle, double cx, double cy)
{
agg::trans_affine_translation m(-cx, -cy);
m *= agg::trans_affine_rotation(angle);
m *= agg::trans_affine_translation(cx, cy);
m_affine.premultiply(m);
update();
}
//-------------------------------------------------------------
void scale(double s)
{
m_affine.premultiply(agg::trans_affine_scaling(s));
update();
}
//-------------------------------------------------------------
void scale(double sx, double sy)
{
m_affine.premultiply(agg::trans_affine_scaling(sx, sy));
update();
}
//-------------------------------------------------------------
void skew(double sx, double sy)
{
m_affine.premultiply(agg::trans_affine_skewing(sx, sy));
update();
}
//-------------------------------------------------------------
void skew_x(double s)
{
m_affine.premultiply(agg::trans_affine_skewing(s, 0.0));
update();
}
//-------------------------------------------------------------
void skew_y(double s)
{
m_affine.premultiply(agg::trans_affine_skewing(0.0, s));
update();
}
//-------------------------------------------------------------
unsigned byte_size_affine() const
{
return 6 * sizeof(double);
}
//-------------------------------------------------------------
void serialize_affine(agg::int8u* ptr) const
{
double mtx[6];
m_affine.store_to(mtx);
memcpy(ptr, mtx, sizeof(mtx));
}
//-------------------------------------------------------------
void deserialize_affine(const agg::int8u* ptr)
{
double mtx[6];
memcpy(mtx, ptr, sizeof(mtx));
m_affine.load_from(mtx);
update();
}
//-------------------------------------------------------------
void transform(double* x, double* y) const
{
m_transformer.transform(x, y);
}
//-------------------------------------------------------------
void inverse_transform(double* x, double* y) const
{
m_transformer.inverse_transform(x, y);
}
//-------------------------------------------------------------
bool is_valid() const
{
return m_viewport.is_valid() &&
m_zoom.is_valid() &&
m_buffer_x2 > m_buffer_x1 &&
m_buffer_y2 > m_buffer_y1;
}
//-------------------------------------------------------------
double scale() const
{
return m_scale;
}
//-------------------------------------------------------------
const agg::trans_affine& transform() const
{
return m_transformer;
}
//-------------------------------------------------------------------
double device_x1() const { return m_device_x1; }
double device_y1() const { return m_device_y1; }
double device_x2() const { return m_device_x2; }
double device_y2() const { return m_device_y2; }
int window_x1() const { return m_window_x1; }
int window_y1() const { return m_window_y1; }
int window_x2() const { return m_window_x2; }
int window_y2() const { return m_window_y2; }
double clip_x1() const { return m_clip_x1; }
double clip_y1() const { return m_clip_y1; }
double clip_x2() const { return m_clip_x2; }
double clip_y2() const { return m_clip_y2; }
int buffer_x1() const { return m_buffer_x1; }
int buffer_y1() const { return m_buffer_y1; }
int buffer_x2() const { return m_buffer_x2; }
int buffer_y2() const { return m_buffer_y2; }
private:
void update();
void invalidate();
agg::trans_affine m_affine;
agg::trans_viewport m_viewport;
agg::trans_viewport m_zoom;
agg::trans_affine m_transformer;
unsigned m_viewBox_level;
double m_scale;
double m_dx;
double m_dy;
double m_device_x1;
double m_device_y1;
double m_device_x2;
double m_device_y2;
int m_window_x1;
int m_window_y1;
int m_window_x2;
int m_window_y2;
double m_viewbox_x1;
double m_viewbox_y1;
double m_viewbox_x2;
double m_viewbox_y2;
double m_viewbox_dx;
double m_viewbox_dy;
double m_clip_x1;
double m_clip_y1;
double m_clip_x2;
double m_clip_y2;
int m_buffer_x1;
int m_buffer_y1;
int m_buffer_x2;
int m_buffer_y2;
};
}
}
#endif

View File

@ -0,0 +1,70 @@
#include "agg_svg_utils.h"
#include <cstdlib> // for wcstombs
namespace agg
{
namespace svg
{
namespace aux
{
//-------------------------------------------------------------------------
const unsigned char is_numeric_helper::s_set[] = "0123456789+-.eE";
//-------------------------------------------------------------------------
const unsigned char is_wsp_helper::s_set[] = " \t\n\r";
//-------------------------------------------------------------------------
}
std::string to_str(const wchar_t* chars, int len )
{
using namespace std;
if( len==0 ) len = (int)wcslen( chars );
std::string result_str;
if (len <= 512)
{
char buf[512];
wcstombs(buf, chars, len);
return std::string( buf, len );
}else
{
std::vector<char> vecch;
vecch.reserve(len);
wcstombs( &vecch[0], chars, len );
return std::string( &vecch[0], len );
}
}
std::wstring to_wstr(const char* chars, int len )
{
using namespace std;
if( len == 0 ) len = (int)strlen(chars);
std::wstring result_str;
if (len <= 512)
{
wchar_t buf[512];
mbstowcs(buf, chars, len);
return std::wstring( buf, len );
}else
{
std::vector<wchar_t> vecwch;
vecwch.reserve(len);
mbstowcs( &vecwch[0], chars, len );
return std::wstring( &vecwch[0], len );
}
}
}
}

View File

@ -0,0 +1,194 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_UTILS_INCLUDED
#define AGG_SVG_UTILS_INCLUDED
//-----------------------------------------------------------------------------
#include <vector>
#include <string>
#include <algorithm>
#include <cctype>
#include <cstdlib> // for atof
#include <cstring>
#include "agg_svg_parse_real.h"
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
namespace aux
{
//---------------------------------------------------------------------
struct is_numeric_helper
{
is_numeric_helper() { init_mask(m_set_mask, s_set); }
bool operator()(unsigned c) const
{
return (m_set_mask[(c >> 3) & (256/8-1)] & (1 << (c & 7)))!= 0;
}
private:
static void init_mask(unsigned char* mask,
const unsigned char* char_set);
unsigned char m_set_mask[256/8];
static const unsigned char s_set[];
};
//---------------------------------------------------------------------
inline void is_numeric_helper::init_mask(unsigned char* mask,
const unsigned char* char_set)
{
using namespace std;
memset(mask, 0, 256/8);
while(*char_set)
{
unsigned c = unsigned(*char_set++) & 0xFF;
mask[c >> 3] |= 1 << (c & 7);
}
}
//---------------------------------------------------------------------
struct is_wsp_helper
{
is_wsp_helper() { init_mask(m_set_mask, s_set); }
bool operator()(unsigned c) const
{
return (m_set_mask[(c >> 3) & (256/8-1)] & (1 << (c & 7)))!= 0;
}
private:
static void init_mask(unsigned char* mask,
const unsigned char* char_set);
unsigned char m_set_mask[256/8];
static const unsigned char s_set[];
};
//---------------------------------------------------------------------
inline void is_wsp_helper::init_mask(unsigned char* mask,
const unsigned char* char_set)
{
using namespace std;
memset(mask, 0, 256/8);
while(*char_set)
{
unsigned c = unsigned(*char_set++) & 0xFF;
mask[c >> 3] |= 1 << (c & 7);
}
}
//---------------------------------------------------------------------
} // namespace aux
//-------------------------------------------------------------------------
std::string to_str (const wchar_t* chars, int len = 0);
std::wstring to_wstr(const char* chars, int len = 0);
//-------------------------------------------------------------------------
inline bool is_wsp_or_eol(char c)
{
static aux::is_wsp_helper helper;
return helper(c);
}
//-------------------------------------------------------------------------
inline bool is_wsp( char c)
{
return c == ' ' || c == '\t';
}
//-------------------------------------------------------------------------
inline bool is_numeric(char c)
{
static aux::is_numeric_helper helper;
return helper(c);
}
//-------------------------------------------------------------------------
inline double to_double(const char* str)
{
using namespace std;
while(*str == ' ') ++str;
double val;
const char* endptr;
parse_real pd;
if (!pd.parse(str, str + strlen(str), &val, &endptr))
return 0.;
return val;
}
//-------------------------------------------------------------------------
inline const char* next_number(const char* str)
{
while(*str && (*str == ' ' || *str == ',' || *str == ';')) ++str;
while(*str && !(*str == ' ' || *str == ',' || *str == ';')) ++str;
return str;
}
//-------------------------------------------------------------------------
inline const char* get_token(const char* str, char* buf, unsigned max_len)
{
while(*str && (*str == ' ' || *str == ',' || *str == ';')) ++str;
while(*str && !(*str == ' ' || *str == ',' || *str == ';'))
{
if(max_len == 0) break;
*buf++ = *str++;
--max_len;
}
*buf = 0;
return str;
}
//-------------------------------------------------------------------------
inline void left_trim(const char*& str)
{
while( is_wsp(*str) ) ++str;
}
//-------------------------------------------------------------------------
inline void left_trim(char*& str_begin, char* str_end )
{
using namespace std;
while(str_begin < str_end && isspace(*str_begin)) ++str_begin;
}
//-------------------------------------------------------------------------
inline void right_trim(char* str_begin, char*& str_end,
char additionalTokenToSkip = ' ')
{
using namespace std;
char* ts = str_end;
while(str_end > str_begin &&
(*str_end == additionalTokenToSkip || isspace(*str_end))) --str_end;
if(str_end < ts) ++str_end;
}
//-------------------------------------------------------------------------
inline void right_trim( const char* str )
{
using namespace std;
char* p = const_cast<char*>(str) + strlen(str)-1;
while( p >= str && isspace(*p) ) { *p=0x0; --p; }
}
//-------------------------------------------------------------------------
inline bool str_starts( const char* str1, char ch )
{
return ( str1[0] == ch );
}
//-------------------------------------------------------------------------
inline bool str_starts( const char* str1, const char* str2 )
{
return ( strncmp( str1, str2, strlen(str2) )==0 );
}
//-------------------------------------------------------------------------
inline bool str_ends( const char* str1, char ch )
{
return ( str1[ strlen(str1)-1 ] == ch );
}
//-------------------------------------------------------------------------
inline bool str_ends( const char* str1, const char* str2 )
{
size_t len1 = strlen( str1 );
size_t len2 = strlen( str2 );
if( len1 < len2 )
return false;
return ( strncmp( str1+len1-len2, str2, len2)==0 );
}
//-------------------------------------------------------------------------
}
}
#endif

View File

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
#ifndef AGG_SVG_MEMBER_COMPARER_INCLUDED
#define AGG_SVG_MEMBER_COMPARER_INCLUDED
//-----------------------------------------------------------------------------
#include <functional> // for std::less
//-----------------------------------------------------------------------------
namespace agg
{
namespace svg
{
//-------------------------------------------------------------------------
template <class T, class Type, class comparer>
struct member_comparer
{
//---------------------------------------------------------------------
typedef Type result_type;
typedef T class_type;
//---------------------------------------------------------------------
member_comparer(Type T::*PtrToMember, comparer comp = comparer())
: m_PtrToMember(PtrToMember),
m_comparer(comp)
{}
//---------------------------------------------------------------------
bool operator()(class_type const& lhs, class_type const& rhs) const
{
return m_comparer(lhs.*m_PtrToMember, rhs.*m_PtrToMember);
}
//---------------------------------------------------------------------
bool operator()(Type const& lhs, class_type const& rhs, int = 0) const
{
return m_comparer(lhs, rhs.*m_PtrToMember);
}
//---------------------------------------------------------------------
bool operator()(class_type const& lhs, Type const& rhs) const
{
return m_comparer(lhs.*m_PtrToMember, rhs);
}
//---------------------------------------------------------------------
private:
Type T::*m_PtrToMember;
comparer m_comparer;
};
//-------------------------------------------------------------------------
template <class T, class Type, class comparer>
inline
member_comparer<T, Type, comparer>
make_comparer(Type T::*PtrToMember, comparer comp)
{
return member_comparer<T, Type, comparer>(PtrToMember, comp);
}
//-------------------------------------------------------------------------
template <class T, class Type>
inline
member_comparer<T, Type, std::less<Type> >
make_comparer(Type T::*PtrToMember)
{
return member_comparer<T, Type, std::less<Type> >
(PtrToMember, std::less<Type>());
}
} // namespace svg
} // namespace agg
#endif // #ifndef AGG_SVG_MEMBER_COMPARER_INCLUDED

View File

@ -0,0 +1,409 @@
#include <stdio.h>
#include <stdlib.h>
#include "agg_scanline_p.h"
#include "platform/agg_platform_support.h"
#include "ctrl/agg_slider_ctrl.h"
#include "agg_svg_exception.h"
#include "agg_svg_parser.h"
#include "agg_svg_indexation_interpreter.h"
#include "agg_svg_rendering_interpreter.h"
#include "agg_svg_attributes_map.h"
#include "agg_svg_rasterizer.h"
enum { flip_y_e = false };
class the_application : public agg::platform_support
{
agg::svg::dom_storage m_storage;
agg::svg::dom_storage::map_type m_id2elem_map;
agg::svg::attributes_map m_attr_map;
agg::svg::global_settings m_settings;
agg::svg::attributes m_attributes;
agg::svg::frame_buffer_rgba m_frame_buffer;
agg::svg::rasterizer m_rasterizer;
agg::svg::renderer_rgba m_renderer;
agg::svg::pipeline m_pipeline;
agg::svg::gradient_lut_cache m_gradient_lut_cache;
//agg::slider_ctrl<agg::rgba8> m_expand;
agg::slider_ctrl<agg::rgba8> m_gamma;
//agg::slider_ctrl<agg::rgba8> m_scale;
//agg::slider_ctrl<agg::rgba8> m_rotate;
enum tool_type_e {tool_none, tool_zoom, tool_pan};
tool_type_e m_current_tool;
int m_x1;
int m_y1;
int m_x2;
int m_y2;
bool m_drag_flag;
public:
the_application(agg::pix_format_e format, bool flip_y) :
agg::platform_support(format, flip_y),
//m_expand(5, 5, 256-5, 11, !flip_y),
m_gamma (5, 5, 256-5, 20, !flip_y),
//m_scale (256+5, 5, 512-5, 11, !flip_y),
//m_rotate(256+5, 5+15, 512-5, 11+15, !flip_y),
m_x1(0),
m_y1(0),
m_x2(0),
m_y2(0),
m_drag_flag(false),
m_attributes(m_settings),
m_renderer(m_rasterizer, m_frame_buffer),
m_current_tool(tool_none)
{
//add_ctrl(m_expand);
add_ctrl(m_gamma);
//add_ctrl(m_scale);
//add_ctrl(m_rotate);
//m_expand.label("Expand=%3.2f");
//m_expand.range(-1, 1.2);
//m_expand.value(0.0);
m_gamma.label("Gamma=%3.2f");
m_gamma.range(0.0, 3.0);
m_gamma.value(1.0);
//m_scale.label("Scale=%3.2f");
//m_scale.range(0.2, 10.0);
//m_scale.value(1.0);
//m_rotate.label("Rotate=%3.2f");
//m_rotate.range(-180.0, 180.0);
//m_rotate.value(0.0);
}
void swap_int(int* n1, int* n2)
{
int temp;
temp = *n1;
*n1 = *n2;
*n2 = temp;
}
void normalize_rect(int* x1, int* y1, int* x2, int* y2)
{
if (*x1 > *x2)
{
swap_int(x1, x2);
}
if (*y1 > *y2)
{
swap_int(y1, y2);
}
}
void update_zoom()
{
if (m_current_tool == tool_zoom)
{
int x1 = m_x1;
int y1 = m_y1;
int x2 = m_x2;
int y2 = m_y2;
normalize_rect(&x1, &y1, &x2, &y2);
m_attributes.set_zoom(x1, y1, x2, y2);
}
else if (m_current_tool == tool_pan)
{
int offset_x = m_x2 - m_x1;
int offset_y = m_y2 - m_y1;
int x1 = -offset_x;
int y1 = -offset_y;
int x2 = rbuf_window().width() - offset_x;
int y2 = rbuf_window().height() - offset_y;
m_attributes.set_zoom(x1, y1, x2, y2);
}
}
void indexation()
{
agg::svg::indexation_interpreter consumer(m_id2elem_map);
m_storage.traverse(consumer);
m_id2elem_map.sort_state(agg::svg::on);
}
void reset()
{
m_id2elem_map.clear();
m_attributes.clear();
m_renderer.reset();
}
void parse_svg(const char* fname)
{
if(!fname)
return;
m_attributes.initial_zoom();
m_storage.clear();
reset();
agg::svg::parser p(m_storage, m_attr_map);
p.parse(fname);
indexation();
}
void on_resize(int sx, int sy)
{
m_frame_buffer.create(sx, sy, flip_y_e);
}
void draw(agg::rendering_buffer& rbuf, double expand, double gamma)
{
agg::svg::renderer_rgba::pixfmt_type pixfmt(rbuf);
agg::svg::renderer_rgba::renderer_base_type rbase(pixfmt);
m_rasterizer.gamma(gamma);
m_settings.gamma(gamma);
m_attributes.window(0, 0, rbuf.width(), rbuf.height());
m_frame_buffer.clear(agg::svg::color_type(255, 255, 255));
m_renderer.attach(m_frame_buffer);
agg::svg::rendering_interpreter rin( m_pipeline,
m_attributes,
m_renderer,
m_id2elem_map,
m_gradient_lut_cache
);
#ifdef EXPAND_PATHS
rin.expand(expand);
#endif
m_storage.traverse(rin);
assert(0 == m_attributes.num_sessions());
if (m_settings.gamma() != 1.0)
{
m_frame_buffer.pixfmt().apply_gamma_inv(m_settings.gamma_lut());
}
if(m_frame_buffer.is_valid())
{
rbase.copy_from(m_frame_buffer.ren_buf());
if (m_current_tool == tool_zoom)
{
agg::rgba8 color(0, 0, 0, 255);
rbase.blend_hline(m_x1, m_y1, m_x2, color, agg::cover_full);
rbase.blend_hline(m_x1, m_y2, m_x2, color, agg::cover_full);
rbase.blend_vline(m_x1, m_y1, m_y2, color, agg::cover_full);
rbase.blend_vline(m_x2, m_y1, m_y2, color, agg::cover_full);
}
}
else
{
rbase.clear(agg::svg::color_type(255, 255, 255));
}
}
virtual void on_draw()
{
try
{
typedef agg::pixfmt_bgra32 pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
pixfmt pixf(rbuf_window());
renderer_base rb(pixf);
renderer_solid ren(rb);
rb.clear(agg::rgba(1,1,1));
agg::rasterizer_scanline_aa<> ras;
agg::scanline_p8 sl;
//ras.gamma(agg::gamma_power(m_gamma.value()));
start_timer();
draw(rbuf_window(), 0.0/*m_expand.value()*/, m_gamma.value());
double tm = elapsed_time();
ras.gamma(agg::gamma_none());
//agg::render_ctrl(ras, sl, rb, m_expand);
agg::render_ctrl(ras, sl, rb, m_gamma);
//agg::render_ctrl(ras, sl, rb, m_scale);
//agg::render_ctrl(ras, sl, rb, m_rotate);
char buf[128];
agg::gsv_text t;
t.size(10.0);
t.flip(true);
agg::conv_stroke<agg::gsv_text> pt(t);
pt.width(1.5);
//sprintf(buf, "Vertices=%d Time=%.3f ms", vertex_count, tm);
sprintf(buf, "Time=%.3f ms", tm);
t.start_point(4.0, 40.0);
t.text(buf);
ras.add_path(pt);
ren.color(agg::rgba(0,0,0));
agg::render_scanlines(ras, sl, ren);
}
catch (agg::svg::exception&)
{
}
}
virtual void on_mouse_button_down(int x, int y, unsigned flags)
{
if (flags & agg::mouse_left)
m_current_tool = tool_zoom;
if (flags & agg::mouse_right)
m_current_tool = tool_pan;
m_x1 = x;
m_y1 = y;
m_x2 = x;
m_y2 = y;
m_drag_flag = true;
}
virtual void on_mouse_move(int x, int y, unsigned flags)
{
if(flags == 0)
{
m_drag_flag = false;
}
if (m_drag_flag)
{
m_x2 = x;
m_y2 = y;
if (m_current_tool == tool_zoom)
{
force_redraw();
}
else if (m_current_tool == tool_pan)
{
update_zoom();
m_x1 = x;
m_y1 = y;
force_redraw();
}
}
}
void zoom_out(int x, int y)
{
int d = 100;
int x1 = -d;
int y1 = -d;
int x2 = rbuf_window().width() + d;
int y2 = rbuf_window().height() + d;
int w = x2 - x1;
int h = y2 - y1;
int cx = x1 + w/2;
int cy = y1 + h/2;
int dx = x - cx;
int dy = y - cy;
m_attributes.set_zoom(x1 + dx, y1 + dy, x2 + dx, y2 + dy);
force_redraw();
}
virtual void on_mouse_button_up(int x, int y, unsigned flags)
{
if ((flags & agg::kbd_shift) && m_x1 == x && m_y1 == y)
{
zoom_out(x,y);
m_drag_flag = false;
m_current_tool = tool_none;
}
if (m_drag_flag)
{
if (m_current_tool == tool_zoom)
{
if(x != m_x1 && y != m_y1)
{
m_x2 = x;
m_y2 = y;
update_zoom();
}
force_redraw();
}
m_drag_flag = false;
}
m_current_tool = tool_none;
}
virtual void on_key(int x, int y, unsigned key, unsigned flags)
{
if(key == agg::key_home)
{
m_attributes.initial_zoom();
force_redraw();
}
}
};
int agg_main(int argc, char* argv[])
{
the_application app(agg::svg::pix_format, flip_y_e);
const char* fname = "tiger.svg";
if(argc <= 1)
{
FILE* fd = fopen(app.full_file_name(fname), "r");
if(fd == 0)
{
app.message("Usage: svg_test <svg_file>\n"
"Download http://antigrain.com/svg/tiger.svg");
return 1;
}
fclose(fd);
}
else
{
fname = argv[1];
}
try
{
app.parse_svg(app.full_file_name(fname));
}
catch (agg::svg::exception& e)
{
app.message(e.msg());
return 1;
}
if(app.init(512, 600, agg::window_resize))
{
return app.run();
}
return 1;
}