Skip to content

Instantly share code, notes, and snippets.

@springmeyer
Created November 22, 2012 03:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save springmeyer/4129366 to your computer and use it in GitHub Desktop.
Save springmeyer/4129366 to your computer and use it in GitHub Desktop.
svg patch against agg from http://pastebin.com/CtysNL14
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt (revision 50)
+++ CMakeLists.txt (working copy)
@@ -302,6 +302,8 @@
./svg_viewer/agg_svg_path_renderer.h
./svg_viewer/agg_svg_path_tokenizer.cpp
./svg_viewer/agg_svg_path_tokenizer.h
+ ./svg_viewer/agg_svg_gradient.cpp
+ ./svg_viewer/agg_svg_gradient.h
)
ENDIF ( agg_USE_EXPAT )
Index: svg_viewer/agg_svg_gradient.cpp
===================================================================
--- svg_viewer/agg_svg_gradient.cpp (revision 0)
+++ svg_viewer/agg_svg_gradient.cpp (working copy)
@@ -0,0 +1,197 @@
+//----------------------------------------------------------------------------
+// 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
+//----------------------------------------------------------------------------
+//
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+#include "agg_svg_gradient.h"
+#include <vector>
+#include "agg_trans_affine.h"
+#include "agg_gradient_lut.h"
+
+
+
+
+
+
+namespace agg {
+ namespace svg {
+
+
+
+ // constructor
+ gradient::gradient()
+ :
+ m_type(GRADIENT_LINEAR),
+ m_id(""),
+ m_colcnt(0),
+ m_opaque(1.0)
+ {
+ }
+
+ // destructor
+ gradient::~gradient()
+ {
+
+ }
+
+ // SetID
+ void
+ gradient::set_id(const char* id)
+ {
+ m_id = id;
+ }
+
+ // ID
+ const char*
+ gradient::id() const
+ {
+ return m_id.c_str();
+ }
+
+ // AddStop
+ void
+ gradient::add_stop(double offset, rgba8 color)
+ {
+ m_colcnt++;
+ m_gradient_lut.add_color(offset,color);
+ }
+
+ // SetTransformation
+ void
+ gradient::set_transformation(const trans_affine& transform)
+ {
+ m_transform.multiply(transform);
+ }
+ // constructor
+ linear_gradient::linear_gradient()
+ : gradient()
+ {
+ }
+
+ // destructor
+ linear_gradient::~linear_gradient()
+ {
+ }
+
+ // MakeGradient
+
+ void linear_gradient::realize()
+ {
+
+ set_type(GRADIENT_LINEAR);
+ // setup the gradient transform
+ point_d start(-lut_range, -lut_range);
+ point_d end(lut_range, -lut_range);
+ std::string coordinate;
+ if (find_string("x1", &coordinate) )
+ start.x = atof(coordinate.c_str());
+ if (find_string("y1", &coordinate) )
+ start.y = atof(coordinate.c_str());
+ if (find_string("x2", &coordinate) )
+ end.x = atof(coordinate.c_str());
+ if (find_string("y2", &coordinate) )
+ end.y = atof(coordinate.c_str());
+
+
+ // the transformed parallelogram
+ double parl[6];
+ parl[0] = start.x;
+ parl[1] = start.y;
+ parl[2] = end.x;
+ parl[3] = end.y;
+ parl[4] = end.x - (end.y - start.y);
+ parl[5] = end.y + (end.x - start.x);
+ trans_affine transform(-lut_range, -lut_range, lut_range, lut_range, parl);
+ m_transform.premultiply(transform);
+ m_gradient_lut.build_lut(1.0);
+ }
+
+ // constructor
+ radial_gradient::radial_gradient()
+ : gradient()
+ {
+ }
+
+ // destructor
+ radial_gradient::~radial_gradient()
+ {
+ }
+
+ // MakeGradient
+
+ void radial_gradient::realize()
+ {
+ //printf("SVGRadialGradient::MakeGradient()\n");
+ // TODO: handle userSpaceOnUse/objectBoundingBox
+
+ set_type(GRADIENT_CIRCULAR);
+
+ double cx = 0.0;
+ double cy = 0.0;
+ double r = 100.0;
+ double fx = 0.0;
+ double fy = 0.0;
+
+ std::string value;
+ if (find_string("cx", &value) )
+ cx = atof(value.c_str());
+ if (find_string("cy", &value) )
+ cy = atof(value.c_str());
+ if (find_string("r", &value) )
+ r = atof(value.c_str());
+/*
+ if (FindString("fx", &value) )
+ {
+ fx = atof(value.c_str());
+ if (FindString("fy", &value) )
+ fy = atof(value.c_str());
+ SetType(GRADIENT_CIRCULAR_FOCAL);
+ }
+*/
+
+
+ // the transformed parallelogram
+ double parl[6];
+ parl[0] = cx - r;
+ parl[1] = cy - r;
+ parl[2] = cx + r;
+ parl[3] = cy - r;
+ parl[4] = cx + r;
+ parl[5] = cy + r;
+
+ trans_affine transform(-lut_range, -lut_range, lut_range, lut_range, parl);
+ m_transform.premultiply(transform);
+ m_gradient_lut.build_lut(1.0);
+ }
+
+ } // namespace svg
+} // namespace agg
\ No newline at end of file
Index: svg_viewer/agg_svg_gradient.h
===================================================================
--- svg_viewer/agg_svg_gradient.h (revision 0)
+++ svg_viewer/agg_svg_gradient.h (working copy)
@@ -0,0 +1,274 @@
+//----------------------------------------------------------------------------
+// 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
+//----------------------------------------------------------------------------
+//
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
+//
+
+#ifndef SVG_GRADIENTS_H
+#define SVG_GRADIENTS_H
+
+
+#include <agg_color_rgba.h>
+#include <agg_trans_affine.h>
+
+
+#include <String.h>
+#include <string>
+#include <map>
+#include "agg_gradient_lut.h"
+
+
+namespace agg {
+ namespace svg {
+
+ template<class ColorInterpolator,
+ unsigned ColorLutSize=256> class gradient_lut_opaque
+ {
+ public:
+ typedef ColorInterpolator interpolator_type;
+ typedef typename interpolator_type::color_type color_type;
+ enum { color_lut_size = ColorLutSize };
+
+ //--------------------------------------------------------------------
+ gradient_lut_opaque() : m_color_lut(color_lut_size) {}
+
+ // Build Gradient Lut
+ // First, call remove_all(), then add_color() at least twice,
+ // then build_lut(). Argument "offset" in add_color must be
+ // in range [0...1] and defines a color stop as it is described
+ // in SVG specification, section Gradients and Patterns.
+ // The simplest linear gradient is:
+ // gradient_lut.add_color(0.0, start_color);
+ // gradient_lut.add_color(1.0, end_color);
+ //--------------------------------------------------------------------
+ void remove_all();
+ void add_color(double offset, const color_type& color);
+ void build_lut(double opaque );
+
+ // Size-index Interface. This class can be used directly as the
+ // ColorF in span_gradient. All it needs is two access methods
+ // size() and operator [].
+ //--------------------------------------------------------------------
+ static unsigned size()
+ {
+ return color_lut_size;
+ }
+ const color_type& operator [] (unsigned i) const
+ {
+ return m_color_lut[i];
+ }
+
+ private:
+ //--------------------------------------------------------------------
+ struct color_point
+ {
+ double offset;
+ color_type color;
+
+ color_point() {}
+ color_point(double off, const color_type& c) :
+ offset(off), color(c)
+ {
+ if(offset < 0.0) offset = 0.0;
+ if(offset > 1.0) offset = 1.0;
+ }
+ };
+ typedef agg::pod_bvector<color_point, 4> color_profile_type;
+ typedef agg::pod_array<color_type> color_lut_type;
+
+ static bool offset_less(const color_point& a, const color_point& b)
+ {
+ return a.offset < b.offset;
+ }
+ static bool offset_equal(const color_point& a, const color_point& b)
+ {
+ return a.offset == b.offset;
+ }
+
+ //--------------------------------------------------------------------
+ color_profile_type m_color_profile;
+ color_lut_type m_color_lut;
+ };
+
+
+
+ //------------------------------------------------------------------------
+ template<class T, unsigned S>
+ void gradient_lut_opaque<T,S>::remove_all()
+ {
+ m_color_profile.remove_all();
+ }
+
+ //------------------------------------------------------------------------
+ template<class T, unsigned S>
+ void gradient_lut_opaque<T,S>::add_color(double offset, const color_type& color)
+ {
+ m_color_profile.add(color_point(offset, color));
+ }
+
+ //------------------------------------------------------------------------
+ template<class T, unsigned S>
+ void gradient_lut_opaque<T,S>::build_lut(double opaque)
+ {
+ quick_sort(m_color_profile, offset_less);
+ m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal));
+ if(m_color_profile.size() >= 2)
+ {
+ unsigned i;
+ unsigned start = uround(m_color_profile[0].offset * color_lut_size);
+ unsigned end;
+ color_type c = m_color_profile[0].color;
+ c.opacity(c.opacity() * opaque);
+ for(i = 0; i < start; i++)
+ {
+ m_color_lut[i] = c;
+ }
+ for(i = 1; i < m_color_profile.size(); i++)
+ {
+ end = uround(m_color_profile[i].offset * color_lut_size);
+ color_type c1 = m_color_profile[i-1].color;
+ c1.opacity(c1.opacity() * opaque);
+ color_type c2 = m_color_profile[i].color;
+ c2.opacity(c2.opacity() * opaque);
+ interpolator_type ci(c1,
+ c2 ,
+ end - start + 1);
+ while(start < end)
+ {
+ m_color_lut[start] = ci.color();
+ ++ci;
+ ++start;
+ }
+ }
+ c = m_color_profile.last().color;
+ c.opacity(c.opacity() * opaque);
+ for(; end < m_color_lut.size(); end++)
+ {
+ m_color_lut[end] = c;
+ }
+ }
+ }
+ class gradient {
+ public:
+ static const int lut_range = 128;
+ typedef gradient_lut_opaque<agg::color_interpolator<agg::rgba8>, lut_range * 2> color_func_type;
+ enum gradients_type {
+ GRADIENT_LINEAR = 0,
+ GRADIENT_CIRCULAR,
+ GRADIENT_CIRCULAR_FOCAL,
+ GRADIENT_DIAMOND,
+ GRADIENT_CONIC,
+ GRADIENT_XY,
+ GRADIENT_SQRT_XY
+ };
+ gradient();
+ virtual ~gradient();
+
+ void set_id(const char* id);
+ const char* id() const;
+ void set_opaque(double opaque)
+ {
+ if(opaque != m_opaque)
+ {
+ m_opaque = opaque;
+ m_gradient_lut.build_lut(m_opaque);
+ }
+ }
+ virtual void add_stop(double offset, rgba8 color);
+ void set_transformation(const trans_affine& transform);
+ virtual void realize() = 0;
+
+
+ void add_string(const char *name, const char *string)
+ {
+ m_mapStrings[name] = string;
+ }
+
+ color_func_type &lut()
+ {
+ return m_gradient_lut;
+ }
+
+ void set_type(gradients_type type)
+ {
+ m_type = type;
+ }
+ gradients_type type() const
+ { return m_type; }
+
+ const trans_affine & transform()
+ {
+ return m_transform;
+ }
+ unsigned count_colors()
+ {
+ return m_colcnt;
+ }
+ std::string xlink()
+ {
+ std::string xlink;
+ find_string("xlink:href",&xlink);
+ return xlink;
+ }
+
+ protected:
+ bool find_string(const char * key,std::string * pVal ) const
+ {
+ std::map<std::string,std::string>::const_iterator it = m_mapStrings.find(key);
+ if(it == m_mapStrings.end())
+ return false;
+ *pVal=it->second;
+ return true;
+ }
+ trans_affine m_transform;
+ color_func_type m_gradient_lut;
+ unsigned m_colcnt;
+ private:
+ std::map<std::string,std::string> m_mapStrings;
+ gradients_type m_type;
+ double m_opaque;
+ std::string m_id;
+ };
+
+ class linear_gradient : public gradient {
+ public:
+ linear_gradient();
+ virtual ~linear_gradient();
+
+ virtual void realize();
+ };
+
+ class radial_gradient : public gradient {
+ public:
+ radial_gradient();
+ virtual ~radial_gradient();
+ virtual void realize();
+ };
+
+ } // namespace svg
+} // namespace agg
+
+#endif // SVG_GRADIENTS_H
\ No newline at end of file
Index: svg_viewer/agg_svg_parser.cpp
===================================================================
--- svg_viewer/agg_svg_parser.cpp (revision 50)
+++ svg_viewer/agg_svg_parser.cpp (working copy)
@@ -13,6 +13,19 @@
// http://www.antigrain.com
//----------------------------------------------------------------------------
//
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
+//
// SVG parser.
//
//----------------------------------------------------------------------------
@@ -22,7 +35,7 @@
#include <ctype.h>
#include "agg_svg_parser.h"
#include "expat.h"
-
+#include "agg_svg_gradient.h"
namespace agg
{
namespace svg
@@ -185,7 +198,99 @@
{ "zzzzzzzzzzz",0,0,0, 0 }
};
+ //-------------------------------------------------------------
+ int cmp_color(const void* p1, const void* p2)
+ {
+ return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name);
+ }
+ //-------------------------------------------------------------
+ rgba8 parse_color(const char* str)
+ {
+ while(*str == ' ') ++str;
+ if (*str == '#') {
+ str++;
+ int32 length = strlen(str);
+ unsigned c = 0;
+ if (length == 3) {
+ // if there are only 3 byte, than it means that we
+ // need to expand the color (#f60 -> #ff6600)
+ // TODO: There must be an easier way...
+ char expanded[7];
+ expanded[0] = *str;
+ expanded[1] = *str++;
+ expanded[2] = *str;
+ expanded[3] = *str++;
+ expanded[4] = *str;
+ expanded[5] = *str++;
+ expanded[6] = 0;
+ sscanf(expanded, "%x", &c);
+ } else {
+ sscanf(str, "%x", &c);
+ }
+ return rgb8_packed(c);
+ }
+ else if(*str == 'r')
+ {
+ int r,g,b;
+ sscanf(str,"rgb(%d,%d,%d)",&r,&g,&b);
+ return rgba8(r,g,b);
+ }
+ else
+ {
+ named_color c;
+ unsigned len = strlen(str);
+ if(len > sizeof(c.name) - 1)
+ {
+ throw exception("parse_color: Invalid color name '%s'", str);
+ }
+ strcpy(c.name, str);
+ const void* p = bsearch(&c,
+ colors,
+ sizeof(colors) / sizeof(colors[0]),
+ sizeof(colors[0]),
+ cmp_color);
+ if(p == 0)
+ {
+ throw exception("parse_color: Invalid color name '%s'", str);
+ }
+ const named_color* pc = (const named_color*)p;
+ return rgba8(pc->r, pc->g, pc->b, pc->a);
+ }
+ }
+ double parse_double(const char* str)
+ {
+ while(*str == ' ') ++str;
+ double value = atof(str);
+ // handle percent
+ int32 length = strlen(str);
+ if (str[length - 1] == '%')
+ value /= 100.0;
+ return value;
+ }
+// parse_url
+ char*
+ parse_url(const char* str)
+ {
+ const char* begin = str;
+ while (*begin != '#')
+ begin++;
+
+ begin++;
+ const char* end = begin;
+ while (*end != ')')
+ end++;
+
+ end--;
+
+ int32 length = end - begin + 2;
+ char* result = new char[length];
+ memcpy(result, begin, length - 1);
+ result[length - 1] = 0;
+
+ return result;
+}
+
//------------------------------------------------------------------------
parser::~parser()
{
@@ -207,7 +312,8 @@
m_attr_name(new char[128]),
m_attr_value(new char[1024]),
m_attr_name_len(127),
- m_attr_value_len(1023)
+ m_attr_value_len(1023),
+ m_tags_ignored(false)
{
m_title[0] = 0;
}
@@ -264,7 +370,11 @@
void parser::start_element(void* data, const char* el, const char** attr)
{
parser& self = *(parser*)data;
-
+ if (strcmp(el, "svg") == 0)
+ {
+ self.parse_svg(attr);
+ }
+ else
if(strcmp(el, "title") == 0)
{
self.m_title_flag = true;
@@ -288,6 +398,16 @@
self.m_path_flag = true;
}
else
+ if (strcmp(el, "circle") == 0)
+ {
+ self.parse_circle(attr);
+ }
+ else
+ if (strcmp(el, "ellipse") == 0)
+ {
+ self.parse_ellipse(attr);
+ }
+ else
if(strcmp(el, "rect") == 0)
{
self.parse_rect(attr);
@@ -307,11 +427,26 @@
{
self.parse_poly(attr, true);
}
+ else
+ if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") == 0)
+ {
+ self.parse_gradient(attr, strcmp(el, "radialGradient") == 0);
+ }
+ else
+ if (strcmp(el, "stop") == 0)
+ {
+ self.parse_gradient_stop(attr);
+ }
//else
//if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
//{
//}
// . . .
+ else
+ {
+ fprintf(stderr, "SVGParser igoring tag: \"%s\"\n", el);
+ self.m_tags_ignored = true;
+ }
}
@@ -334,6 +469,12 @@
{
self.m_path_flag = false;
}
+ else
+ if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") == 0)
+ {
+ self.m_path.end_gradient();
+ }
+
//else
//if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
//{
@@ -361,6 +502,55 @@
}
}
+// parse_svg
+ void parser::parse_svg(const char** attr)
+ {
+ double width = 0.0;
+ double height = 0.0;
+ rect_d viewBox(0.0, 0.0, -1.0, -1.0);
+
+ for (int i = 0; attr[i]; i += 2) {
+ if (strcmp(attr[i], "width") == 0)
+ {
+ width = parse_double(attr[i + 1]);
+ }
+ else
+ if (strcmp(attr[i], "height") == 0)
+ {
+ height = parse_double(attr[i + 1]);
+ }
+ else
+ if (strcmp(attr[i], "viewBox") == 0)
+ {
+ m_tokenizer.set_path_str(attr[i + 1]);
+ if(!m_tokenizer.next())
+ {
+ throw exception("parse_svg (viewBox): Too few coordinates");
+ }
+ viewBox.x1 = m_tokenizer.last_number();
+ if(!m_tokenizer.next())
+ {
+ throw exception("parse_svg (viewBox): Too few coordinates");
+ }
+ viewBox.y1 = m_tokenizer.last_number();
+ if(!m_tokenizer.next())
+ {
+ throw exception("parse_svg (viewBox): Too few coordinates");
+ }
+ viewBox.x2 = m_tokenizer.last_number();
+ if(!m_tokenizer.next())
+ {
+ throw exception("parse_svg (viewBox): Too few coordinates");
+ }
+ viewBox.y2 = m_tokenizer.last_number();
+ }
+ }
+ if (width >= 0.0 && height >= 0.0) {
+ //set viewBox
+ } else {
+ throw exception("parse_svg: Invalid width or height\n");
+ }
+ }
//------------------------------------------------------------------------
void parser::parse_attr(const char** attr)
@@ -410,53 +600,10 @@
}
- //-------------------------------------------------------------
- int cmp_color(const void* p1, const void* p2)
- {
- return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name);
- }
- //-------------------------------------------------------------
- rgba8 parse_color(const char* str)
- {
- while(*str == ' ') ++str;
- unsigned c = 0;
- if(*str == '#')
- {
- sscanf(str + 1, "%x", &c);
- return rgb8_packed(c);
- }
- else
- {
- named_color c;
- unsigned len = strlen(str);
- if(len > sizeof(c.name) - 1)
- {
- throw exception("parse_color: Invalid color name '%s'", str);
- }
- strcpy(c.name, str);
- const void* p = bsearch(&c,
- colors,
- sizeof(colors) / sizeof(colors[0]),
- sizeof(colors[0]),
- cmp_color);
- if(p == 0)
- {
- throw exception("parse_color: Invalid color name '%s'", str);
- }
- const named_color* pc = (const named_color*)p;
- return rgba8(pc->r, pc->g, pc->b, pc->a);
- }
- }
- double parse_double(const char* str)
- {
- while(*str == ' ') ++str;
- return atof(str);
- }
-
//-------------------------------------------------------------
bool parser::parse_attr(const char* name, const char* value)
{
@@ -465,12 +612,21 @@
parse_style(value);
}
else
+ if(strcmp(name, "opacity") == 0) {
+ m_path.opacity(parse_double(value));
+ } else
if(strcmp(name, "fill") == 0)
{
if(strcmp(value, "none") == 0)
{
m_path.fill_none();
}
+ else if (strncmp(value, "url", 3) == 0)
+ {
+ char* url = parse_url(value);
+ m_path.fill_url(url);
+ delete[] url;
+ }
else
{
m_path.fill(parse_color(value));
@@ -482,12 +638,22 @@
m_path.fill_opacity(parse_double(value));
}
else
+ if(strcmp(name, "fill-rule") == 0)
+ {
+ m_path.even_odd(strcmp(value, "evenodd") == 0);
+ }
+ else
if(strcmp(name, "stroke") == 0)
{
if(strcmp(value, "none") == 0)
{
m_path.stroke_none();
}
+ else if (strncmp(value, "url", 3) == 0) {
+ char* url = parse_url(value);
+ m_path.stroke_url(url);
+ delete[] url;
+ }
else
{
m_path.stroke(parse_color(value));
@@ -525,8 +691,17 @@
else
if(strcmp(name, "transform") == 0)
{
- parse_transform(value);
+ m_path.transform().premultiply(parse_transform(value));
}
+ else
+ if (strcmp(name, "stop-color") == 0)
+ {
+ m_gradient_stop_color = parse_color(value);
+ }
+ else
+ if (strcmp(name, "stop-opacity") == 0) {
+ m_gradient_stop_color.opacity(parse_double(value));
+ }
//else
//if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0)
//{
@@ -617,7 +792,89 @@
}
+ // parse_circle
+ void
+ parser::parse_circle(const char** attr)
+ {
+ int i;
+ double cx = 0.0;
+ double cy = 0.0;
+ double r = 0.0;
+ m_path.begin_path();
+ for(i = 0; attr[i]; i += 2) {
+ if (!parse_attr(attr[i], attr[i + 1])) {
+ if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "r") == 0) r = parse_double(attr[i + 1]);
+ }
+ }
+
+
+ if (r != 0.0) {
+ if (r < 0.0) throw exception("parse_circle: Invalid radius: %f", r);
+
+ m_path.move_to(cx, cy - r);
+ m_path.curve4(cx + r * 0.56, cy - r,
+ cx + r, cy - r * 0.56,
+ cx + r, cy);
+ m_path.curve4(cx + r, cy + r * 0.56,
+ cx + r * 0.56, cy + r,
+ cx, cy + r);
+ m_path.curve4(cx - r * 0.56, cy + r,
+ cx - r, cy + r * 0.56,
+ cx - r, cy);
+ m_path.curve4(cx - r, cy - r * 0.56,
+ cx - r * 0.56, cy - r,
+ cx, cy - r);
+ m_path.close_subpath();
+ }
+ m_path.end_path();
+ }
+
+ // parse_ellipse
+ void
+ parser::parse_ellipse(const char** attr)
+ {
+ int i;
+ double cx = 0.0;
+ double cy = 0.0;
+ double rx = 0.0;
+ double ry = 0.0;
+
+ m_path.begin_path();
+ for(i = 0; attr[i]; i += 2) {
+ if (!parse_attr(attr[i], attr[i + 1])) {
+ if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]);
+ }
+ }
+
+
+ if (rx != 0.0 && ry != 0.0) {
+ if (rx < 0.0) throw exception("parse_ellipse: Invalid x-radius: %f", rx);
+ if (ry < 0.0) throw exception("parse_ellipse: Invalid y-radius: %f", ry);
+
+ m_path.move_to(cx, cy - ry);
+ m_path.curve4(cx + rx * 0.56, cy - ry,
+ cx + rx, cy - ry * 0.56,
+ cx + rx, cy);
+ m_path.curve4(cx + rx, cy + ry * 0.56,
+ cx + rx * 0.56, cy + ry,
+ cx, cy + ry);
+ m_path.curve4(cx - rx * 0.56, cy + ry,
+ cx - rx, cy + ry * 0.56,
+ cx - rx, cy);
+ m_path.curve4(cx - rx, cy - ry * 0.56,
+ cx - rx * 0.56, cy - ry,
+ cx, cy - ry);
+ m_path.close_subpath();
+ }
+ m_path.end_path();
+ }
+
//-------------------------------------------------------------
void parser::parse_rect(const char** attr)
{
@@ -626,7 +883,8 @@
double y = 0.0;
double w = 0.0;
double h = 0.0;
-
+ double rx = 0.0;
+ double ry = 0.0;
m_path.begin_path();
for(i = 0; attr[i]; i += 2)
{
@@ -636,9 +894,9 @@
if(strcmp(attr[i], "y") == 0) y = parse_double(attr[i + 1]);
if(strcmp(attr[i], "width") == 0) w = parse_double(attr[i + 1]);
if(strcmp(attr[i], "height") == 0) h = parse_double(attr[i + 1]);
- // rx - to be implemented
- // ry - to be implemented
- }
+ if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]);
+ if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]);
+ }
}
@@ -646,12 +904,18 @@
{
if(w < 0.0) throw exception("parse_rect: Invalid width: %f", w);
if(h < 0.0) throw exception("parse_rect: Invalid height: %f", h);
-
- m_path.move_to(x, y);
- m_path.line_to(x + w, y);
- m_path.line_to(x + w, y + h);
- m_path.line_to(x, y + h);
- m_path.close_subpath();
+ if(rx >0 || ry > 0)
+ {
+ m_path.roundrect(x,y,x+w,y+h,rx,ry);
+ }
+ else
+ {
+ m_path.move_to(x, y);
+ m_path.line_to(x + w, y);
+ m_path.line_to(x + w, y + h);
+ m_path.line_to(x, y + h);
+ m_path.close_subpath();
+ }
}
m_path.end_path();
}
@@ -731,18 +995,19 @@
}
//-------------------------------------------------------------
- void parser::parse_transform(const char* str)
+ trans_affine parser::parse_transform(const char* str)
{
+ trans_affine transform;
while(*str)
{
if(islower(*str))
{
- if(strncmp(str, "matrix", 6) == 0) str += parse_matrix(str); else
- if(strncmp(str, "translate", 9) == 0) str += parse_translate(str); else
- if(strncmp(str, "rotate", 6) == 0) str += parse_rotate(str); else
- if(strncmp(str, "scale", 5) == 0) str += parse_scale(str); else
- if(strncmp(str, "skewX", 5) == 0) str += parse_skew_x(str); else
- if(strncmp(str, "skewY", 5) == 0) str += parse_skew_y(str); else
+ if(strncmp(str, "matrix", 6) == 0) str += parse_matrix(str,transform); else
+ if(strncmp(str, "translate", 9) == 0) str += parse_translate(str,transform); else
+ if(strncmp(str, "rotate", 6) == 0) str += parse_rotate(str,transform); else
+ if(strncmp(str, "scale", 5) == 0) str += parse_scale(str,transform); else
+ if(strncmp(str, "skewX", 5) == 0) str += parse_skew_x(str,transform); else
+ if(strncmp(str, "skewY", 5) == 0) str += parse_skew_y(str,transform); else
{
++str;
}
@@ -752,9 +1017,70 @@
++str;
}
}
+ return transform;
}
+ // parse_gradient
+ void
+ parser::parse_gradient(const char** attr, bool radial)
+ {
+ // printf("parser::parse_gradient(%s)\n", attr[0]);
+ m_path.start_gradient(radial);
+
+ for (int32 i = 0; attr[i]; i += 2)
+ {
+ /* if(!parse_attr(attr[i], attr[i + 1]))
+ {*/
+ if (strcmp(attr[i], "id") == 0)
+ m_path.current_gradient()->set_id(attr[i + 1]);
+ else if(strcmp(attr[i], "gradientTransform") == 0) {
+ m_path.current_gradient()->set_transformation(parse_transform(attr[i + 1]));
+ } else
+ m_path.current_gradient()->add_string(attr[i], attr[i + 1]);
+ /*}*/
+ }
+ }
+
+ // parse_gradient_stop
+ void
+ parser::parse_gradient_stop(const char** attr)
+ {
+ // printf("parser::parse_gradient_stop(%s)\n", attr[0]);
+
+ double offset = 0.0;
+ rgba8 color;
+ for (int32 i = 0; attr[i]; i += 2) {
+ if (strcmp(attr[i], "offset") == 0) {
+ offset = parse_double(attr[i + 1]);
+ } else
+ if (strcmp(attr[i], "style") == 0) {
+ parse_style(attr[i + 1]);
+ // here we get a bit hacky, in order not to change too much code at once...
+ // historically, parse_style() was for parsing path attributes only, but
+ // it comes in handy here as well, and I added "stop-color" and "stop-opacity"
+ // to parse_name_value(). It remembers the color in "fGradientStopColor".
+ // The color will of course be broken if the "style" attribute did not contain
+ // any valid stuff.
+ color = m_gradient_stop_color;
+ } else
+ if (strcmp(attr[i], "stop-color") == 0) {
+ color = parse_color(attr[i + 1]);
+ } else
+ if (strcmp(attr[i], "stop-opacity") == 0) {
+ color.opacity(parse_double(attr[i + 1]));
+ }
+ }
+
+ // printf(" offset: %f, color: %d, %d, %d, %d\n", offset, color.r, color.g, color.b, color.a);
+
+ if (gradient* gradient = m_path.current_gradient()) {
+ gradient->add_stop(offset, color);
+ } else {
+ throw exception("parse_gradient_stop() outside of gradient tag!\n");
+ }
+ }
+
//-------------------------------------------------------------
static bool is_numeric(char c)
{
@@ -801,7 +1127,7 @@
}
//-------------------------------------------------------------
- unsigned parser::parse_matrix(const char* str)
+ unsigned parser::parse_matrix(const char* str, trans_affine& transform)
{
double args[6];
unsigned na = 0;
@@ -810,37 +1136,37 @@
{
throw exception("parse_matrix: Invalid number of arguments");
}
- m_path.transform().premultiply(trans_affine(args[0], args[1], args[2], args[3], args[4], args[5]));
+ transform.premultiply(trans_affine(args[0], args[1], args[2], args[3], args[4], args[5]));
return len;
}
//-------------------------------------------------------------
- unsigned parser::parse_translate(const char* str)
+ unsigned parser::parse_translate(const char* str, trans_affine& transform)
{
double args[2];
unsigned na = 0;
unsigned len = parse_transform_args(str, args, 2, &na);
if(na == 1) args[1] = 0.0;
- m_path.transform().premultiply(trans_affine_translation(args[0], args[1]));
+ transform.premultiply(trans_affine_translation(args[0], args[1]));
return len;
}
//-------------------------------------------------------------
- unsigned parser::parse_rotate(const char* str)
+ unsigned parser::parse_rotate(const char* str, trans_affine& transform)
{
double args[3];
unsigned na = 0;
unsigned len = parse_transform_args(str, args, 3, &na);
if(na == 1)
{
- m_path.transform().premultiply(trans_affine_rotation(deg2rad(args[0])));
+ transform.premultiply(trans_affine_rotation(deg2rad(args[0])));
}
else if(na == 3)
{
trans_affine t = trans_affine_translation(-args[1], -args[2]);
t *= trans_affine_rotation(deg2rad(args[0]));
t *= trans_affine_translation(args[1], args[2]);
- m_path.transform().premultiply(t);
+ transform.premultiply(t);
}
else
{
@@ -850,33 +1176,33 @@
}
//-------------------------------------------------------------
- unsigned parser::parse_scale(const char* str)
+ unsigned parser::parse_scale(const char* str, trans_affine& transform)
{
double args[2];
unsigned na = 0;
unsigned len = parse_transform_args(str, args, 2, &na);
if(na == 1) args[1] = args[0];
- m_path.transform().premultiply(trans_affine_scaling(args[0], args[1]));
+ transform.premultiply(trans_affine_scaling(args[0], args[1]));
return len;
}
//-------------------------------------------------------------
- unsigned parser::parse_skew_x(const char* str)
+ unsigned parser::parse_skew_x(const char* str, trans_affine& transform)
{
double arg;
unsigned na = 0;
unsigned len = parse_transform_args(str, &arg, 1, &na);
- m_path.transform().premultiply(trans_affine_skewing(deg2rad(arg), 0.0));
+ transform.premultiply(trans_affine_skewing(deg2rad(arg), 0.0));
return len;
}
//-------------------------------------------------------------
- unsigned parser::parse_skew_y(const char* str)
+ unsigned parser::parse_skew_y(const char* str, trans_affine& transform)
{
double arg;
unsigned na = 0;
unsigned len = parse_transform_args(str, &arg, 1, &na);
- m_path.transform().premultiply(trans_affine_skewing(0.0, deg2rad(arg)));
+ transform.premultiply(trans_affine_skewing(0.0, deg2rad(arg)));
return len;
}
Index: svg_viewer/agg_svg_parser.h
===================================================================
--- svg_viewer/agg_svg_parser.h (revision 50)
+++ svg_viewer/agg_svg_parser.h (working copy)
@@ -12,6 +12,18 @@
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
//
// SVG parser.
//
@@ -38,27 +50,35 @@
void parse(const char* fname);
const char* title() const { return m_title; }
+ bool tags_ignored() const
+ { return m_tags_ignored; }
+
private:
// XML event handlers
static void start_element(void* data, const char* el, const char** attr);
static void end_element(void* data, const char* el);
static void content(void* data, const char* s, int len);
+ void parse_svg(const char** attr);
void parse_attr(const char** attr);
void parse_path(const char** attr);
void parse_poly(const char** attr, bool close_flag);
+ void parse_circle(const char** attr);
+ void parse_ellipse(const char** attr);
void parse_rect(const char** attr);
void parse_line(const char** attr);
void parse_style(const char* str);
- void parse_transform(const char* str);
+ trans_affine parse_transform(const char* str);
+ void parse_gradient(const char** attr, bool radial);
+ void parse_gradient_stop(const char** attr);
- 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);
+ unsigned parse_matrix(const char* str, trans_affine& transform);
+ unsigned parse_translate(const char* str, trans_affine& transform);
+ unsigned parse_rotate(const char* str, trans_affine& transform);
+ unsigned parse_scale(const char* str, trans_affine& transform);
+ unsigned parse_skew_x(const char* str, trans_affine& transform);
+ unsigned parse_skew_y(const char* str, trans_affine& transform);
bool parse_attr(const char* name, const char* value);
bool parse_name_value(const char* nv_start, const char* nv_end);
@@ -77,6 +97,10 @@
char* m_attr_value;
unsigned m_attr_name_len;
unsigned m_attr_value_len;
+ rgba8 m_gradient_stop_color;
+
+bool m_tags_ignored;
+
};
}
Index: svg_viewer/agg_svg_path_renderer.cpp
===================================================================
--- svg_viewer/agg_svg_path_renderer.cpp (revision 50)
+++ svg_viewer/agg_svg_path_renderer.cpp (working copy)
@@ -13,6 +13,19 @@
// http://www.antigrain.com
//----------------------------------------------------------------------------
//
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
+//
// SVG path renderer.
//
//----------------------------------------------------------------------------
@@ -26,7 +39,9 @@
{
//------------------------------------------------------------------------
- path_renderer::path_renderer() :
+ path_renderer::path_renderer()
+ :
+ m_cur_gradient(NULL),
m_curved(m_storage),
m_curved_count(m_curved),
@@ -163,7 +178,19 @@
m_storage.curve4(x2, y2, x, y);
}
}
-
+// elliptical_arc
+void
+path_renderer::elliptical_arc(double rx, double ry, double angle,
+ bool large_arc_flag, bool sweep_flag,
+ double x, double y, bool rel)
+ {
+ angle = angle / 180.0 * pi;
+ if (rel) {
+ m_storage.arc_rel(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
+ } else {
+ m_storage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
+ }
+ }
//------------------------------------------------------------------------
void path_renderer::close_subpath()
{
@@ -223,7 +250,8 @@
//------------------------------------------------------------------------
void path_renderer::stroke_width(double w)
{
- cur_attr().stroke_width = w;
+ path_attributes& attr = cur_attr();
+ attr.stroke_width = w;
}
//------------------------------------------------------------------------
@@ -231,13 +259,31 @@
{
cur_attr().fill_flag = false;
}
+// fill_url
+ void path_renderer::fill_url(const char* url)
+ {
+ sprintf(cur_attr().fill_url, "%s", url);
+ }
+
//------------------------------------------------------------------------
void path_renderer::stroke_none()
{
cur_attr().stroke_flag = false;
}
-
+// stroke_url
+ void
+ path_renderer::stroke_url(const char* url)
+ {
+ sprintf(cur_attr().stroke_url, "%s", url);
+ }
+
+ // opacity
+ void
+ path_renderer::opacity(double op)
+ {
+ cur_attr().opacity *= op;
+ }
//------------------------------------------------------------------------
void path_renderer::fill_opacity(double op)
{
@@ -277,6 +323,7 @@
//------------------------------------------------------------------------
void path_renderer::parse_path(path_tokenizer& tok)
{
+ char lastCmd = 0;
while(tok.next())
{
double arg[10];
@@ -287,7 +334,10 @@
case 'M': case 'm':
arg[0] = tok.last_number();
arg[1] = tok.next(cmd);
- move_to(arg[0], arg[1], cmd == 'm');
+ if (lastCmd != cmd)
+ move_to(arg[0], arg[1], cmd == 'm');
+ else
+ line_to(arg[0], arg[1], lastCmd == 'm');
break;
case 'L': case 'l':
@@ -337,11 +387,30 @@
curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's');
break;
- case 'A': case 'a':
- throw exception("parse_path: Command A: NOT IMPLEMENTED YET");
+ case 'A': case 'a': {
+ arg[0] = tok.last_number();
+ for(i = 1; i < 3; i++) {
+ arg[i] = tok.next(cmd);
+ }
+ bool large_arc_flag = tok.next(cmd) ? true : false;
+ bool sweep_flag = tok.next(cmd) ? true : false;
+ for(i = 3; i < 5; i++) {
+ arg[i] = tok.next(cmd);
+ }
+ elliptical_arc(arg[0], arg[1], arg[2],
+ large_arc_flag, sweep_flag,
+ arg[3], arg[4], cmd == 'a');
+ break;
+ }
case 'Z': case 'z':
- close_subpath();
+ {
+ double x = m_storage.last_x();
+ double y = m_storage.last_y();
+ close_subpath();
+ move_to(x,y,false);
+ }
+
break;
default:
@@ -351,9 +420,68 @@
throw exception(buf);
}
}
+ lastCmd = cmd;
}
}
+
+ void path_renderer::start_gradient(bool radial)
+ {
+ if (m_cur_gradient) {
+ fprintf(stderr, "path_renderer::StartGradient() - ERROR: "
+ "previous gradient (%s) not finished!\n",
+ m_cur_gradient->id());
+ }
+
+ if (radial)
+ m_cur_gradient = new radial_gradient();
+ else
+ m_cur_gradient = new linear_gradient();
+
+ add_gradient(m_cur_gradient);
+ }
+
+
+ void path_renderer::end_gradient()
+ {
+ if (m_cur_gradient) {
+ m_cur_gradient->realize();
+ } else {
+ fprintf(stderr, "path_renderer::EndGradient() - "
+ "ERROR: no gradient started!\n");
+ }
+ m_cur_gradient = NULL;
+ }
+
+ // #pragma mark -
+
+ // _AddGradient
+ void
+ path_renderer::add_gradient(gradient* gradient)
+ {
+ if (gradient) {
+ m_gradients.push_back(gradient);
+ }
+ }
+
+ // _GradientAt
+ gradient*
+ path_renderer::gradient_at(int32 index) const
+ {
+ return m_gradients.at(index);
+ }
+
+ // _FindGradient
+ gradient*
+ path_renderer::find_gradient(const char* name) const
+ {
+ for (int32 i = 0; gradient* g = gradient_at(i); i++) {
+ if (strcmp(g->id(), name) == 0)
+ return g;
+ }
+ return NULL;
+ }
+
}
}
Index: svg_viewer/agg_svg_path_renderer.h
===================================================================
--- svg_viewer/agg_svg_path_renderer.h (revision 50)
+++ svg_viewer/agg_svg_path_renderer.h (working copy)
@@ -12,7 +12,20 @@
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
+// Gunnar Roth: add support for linear and radial gradients(support xlink attr),
+// shape gradient opaqueness, rounded rects, circles,ellipses. support a command (arc) in pathes.
+// set new origin correctly to last postion on z command in a path( was set to 0,0 before).
+// enable parsing of colors written as rgb()
+// some code was inspired by code from Haiku OS
+/*
+* Copyright 2006-2007, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+* Stephan Aßmus <superstippi@gmx.de>
+*/
//
+//
// SVG path renderer.
//
//----------------------------------------------------------------------------
@@ -29,7 +42,12 @@
#include "agg_bounding_rect.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_svg_path_tokenizer.h"
-
+#include <vector>
+#include "agg_svg_gradient.h"
+#include "agg_span_gradient.h"
+#include "agg_span_allocator.h"
+#include "agg_span_interpolator_linear.h"
+#include "agg_rounded_rect.h"
namespace agg
{
namespace svg
@@ -56,6 +74,7 @@
+class gradient;
//============================================================================
// Basic path attributes
@@ -64,6 +83,7 @@
unsigned index;
rgba8 fill_color;
rgba8 stroke_color;
+ double opacity;
bool fill_flag;
bool stroke_flag;
bool even_odd_flag;
@@ -73,20 +93,26 @@
double stroke_width;
trans_affine transform;
+ char stroke_url[64];
+ char fill_url[64];
+
// Empty constructor
path_attributes() :
index(0),
fill_color(rgba(0,0,0)),
stroke_color(rgba(0,0,0)),
+ opacity(1.0),
fill_flag(true),
stroke_flag(false),
- even_odd_flag(false),
+ even_odd_flag(true),
line_join(miter_join),
line_cap(butt_cap),
miter_limit(4.0),
stroke_width(1.0),
transform()
{
+ stroke_url[0] = 0;
+ fill_url[0] = 0;
}
// Copy constructor
@@ -94,6 +120,7 @@
index(attr.index),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
+ opacity(attr.opacity),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
@@ -103,6 +130,8 @@
stroke_width(attr.stroke_width),
transform(attr.transform)
{
+ sprintf(stroke_url, "%s", attr.stroke_url);
+ sprintf(fill_url, "%s", attr.fill_url);
}
// Copy constructor with new index value
@@ -110,6 +139,7 @@
index(idx),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
+ opacity(attr.opacity),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
@@ -119,6 +149,8 @@
stroke_width(attr.stroke_width),
transform(attr.transform)
{
+ sprintf(stroke_url, "%s", attr.stroke_url);
+ sprintf(fill_url, "%s", attr.fill_url);
}
};
@@ -139,8 +171,14 @@
typedef conv_transform<curved_count> curved_trans;
typedef conv_contour<curved_trans> curved_trans_contour;
+ typedef agg::span_allocator<rgba8> span_allocator_type;
+
path_renderer();
-
+ ~path_renderer()
+ {
+ for(size_t i = 0; i < m_gradients.size(); i++)
+ delete m_gradients[i];
+ }
void remove_all();
// Use these functions as follows:
@@ -165,6 +203,29 @@
double x, double y, bool rel=false);
void curve4(double x2, double y2, // S, s
double x, double y, bool rel=false);
+ void elliptical_arc(double rx, double ry,
+ double angle,
+ bool large_arc_flag,
+ bool sweep_flag,
+ double x, double y,
+ bool rel = false); // A, a
+ void roundrect(double x1, double y1, // C, c
+ double x2, double y2,double rx, double ry,bool rel = false)
+ {
+ if(rel)
+ {
+ m_storage.rel_to_abs(&x1, &y1);
+ m_storage.rel_to_abs(&x2, &y2);
+
+ }
+ agg::rounded_rect rc;
+ rc.rect(x1, y1, x2, y2);
+ rc.radius(rx,ry);
+ rc.normalize_radius();
+ m_storage.concat_path(rc,0);
+
+
+ }
void close_subpath(); // Z, z
// template<class VertexSource>
@@ -189,7 +250,10 @@
void even_odd(bool flag);
void stroke_width(double w);
void fill_none();
+ void fill_url(const char* url);
void stroke_none();
+ void stroke_url(const char* url);
+ void opacity(double op);
void fill_opacity(double op);
void stroke_opacity(double op);
void line_join(line_join_e join);
@@ -221,21 +285,79 @@
agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2);
}
+ template<class Rasterizer, class Scanline, class RendererBase,class GradientFunction>
+ void render_gradient(Rasterizer& ras,
+ Scanline& sl,
+ RendererBase& rb, const trans_affine& mtx,
+ GradientFunction gradient_func, gradient::color_func_type &lut, int start,int end)
+ {
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ interpolator_type span_interpolator(mtx);
+
+ typedef agg::span_gradient<rgba8,
+ interpolator_type,
+ GradientFunction,
+ gradient::color_func_type> span_gradient_type;
+
+ span_gradient_type span_gradient(span_interpolator,
+ gradient_func,
+ lut,
+ start, end);
+
+ agg::render_scanlines_aa(ras, sl, rb, m_alloc, span_gradient);
+
+ }
+ template<class Rasterizer, class Scanline, class RendererBase>
+ void render_gradient(Rasterizer& ras,
+ Scanline& sl,
+ RendererBase& rb, const char * gradient_url,double opaque)
+ {
+ if (gradient* g = find_gradient(gradient_url))
+ {
+ gradient* gl = NULL;
+ if(g->count_colors() == 0)
+ {
+ std::string & xlink = g->xlink();
+ gl = find_gradient(xlink.c_str() + 1);
+ }
+ trans_affine mtxgr = g->transform();
+ mtxgr.multiply(m_transform);
+ mtxgr.invert();
+ if(gl)
+ gl->set_opaque(opaque);
+ else
+ g->set_opaque(opaque);
+ gradient::color_func_type &lut = gl ? gl->lut() : g->lut();
+ if(g->type() == gradient::GRADIENT_CIRCULAR)
+ {
+ gradient_circle gradient_func;
+ render_gradient(ras,sl,rb,mtxgr,gradient_func,lut, 0, gradient::lut_range);
+ }
+ else if(g->type() == gradient::GRADIENT_LINEAR)
+ { gradient_x gradient_func;
+ render_gradient(ras,sl,rb,mtxgr,gradient_func,lut,-gradient::lut_range,gradient::lut_range);
+ }
+ }
+
+ }
// 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>
+ template<class Rasterizer, class Scanline, class RendererBase>
void render(Rasterizer& ras,
Scanline& sl,
- Renderer& ren,
+ RendererBase& rb,
const trans_affine& mtx,
const rect_i& cb,
double opacity=1.0)
{
unsigned i;
+ typedef agg::renderer_scanline_aa_solid<RendererBase> renderer_solid;
+ renderer_solid ren(rb);
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++)
{
@@ -262,11 +384,17 @@
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.fill_url[0] != 0)
+ {
+ render_gradient(ras,sl,rb,attr.fill_url,attr.opacity);
+ }
+ else
+ {
+ color = attr.fill_color;
+ color.opacity(color.opacity() * opacity*attr.opacity);
+ ren.color(color);
+ agg::render_scanlines(ras, sl, ren);
+ }
}
if(attr.stroke_flag)
@@ -289,15 +417,29 @@
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);
+ if(attr.stroke_url[0] != 0)
+ {
+ render_gradient(ras,sl,rb,attr.stroke_url,attr.opacity);
+ }
+ else
+ {
+ color = attr.stroke_color;
+ color.opacity(color.opacity() * opacity * attr.opacity);
+ ren.color(color);
+ agg::render_scanlines(ras, sl, ren);
+ }
+
}
}
}
-
+ void start_gradient(bool radial = false);
+ void end_gradient();
+ gradient* current_gradient() const
+ { return m_cur_gradient; }
private:
+ void add_gradient(gradient* gradient);
+ gradient* gradient_at(int32 index) const;
+ gradient* find_gradient(const char* name) const;
path_attributes& cur_attr();
path_storage m_storage;
@@ -305,6 +447,10 @@
attr_storage m_attr_stack;
trans_affine m_transform;
+ span_allocator_type m_alloc;
+ std::vector<gradient*> m_gradients;
+ gradient* m_cur_gradient;
+
curved m_curved;
curved_count m_curved_count;
Index: svg_viewer/agg_svg_path_tokenizer.cpp
===================================================================
--- svg_viewer/agg_svg_path_tokenizer.cpp (revision 50)
+++ svg_viewer/agg_svg_path_tokenizer.cpp (working copy)
@@ -12,7 +12,15 @@
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
+//change from haiku
//
+// Copyright 2006, Haiku. All rights reserved.
+// Distributed under the terms of the MIT License.
+// Authors:
+//Stephan Aßmus <superstippi@gmx.de>
+//
+// Adrien Destugues: Fix parsing of numbers in svg files : the code used obsolete atod
+//instead of strtod and led to numbers in the form 2.5e-4 to make the parsing fail as 'e' was interpreted as the end of the number.
// SVG path tokenizer.
//
//----------------------------------------------------------------------------
@@ -116,22 +124,9 @@
//------------------------------------------------------------------------
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);
+ char* end;
+ m_last_number = strtod(m_path, &end);
+ m_path = end;
return true;
}
Index: svg_viewer/svg_test.cpp
===================================================================
--- svg_viewer/svg_test.cpp (revision 50)
+++ svg_viewer/svg_test.cpp (working copy)
@@ -1,3 +1,20 @@
+//----------------------------------------------------------------------------
+// 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
+//----------------------------------------------------------------------------
+//^
+// Gunnar Roth : pass base renderer instead of solid renderer to render function.
+
#include <stdio.h>
#include <stdlib.h>
#include "agg_basics.h"
@@ -113,7 +130,7 @@
m_path.expand(m_expand.value());
start_timer();
- m_path.render(ras, sl, ren, mtx, rb.clip_box(), 1.0);
+ m_path.render(ras, sl, rb, mtx, rb.clip_box(), 1.0);
double tm = elapsed_time();
unsigned vertex_count = m_path.vertex_count();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment