From c7821889c9dd893b1020731a971b3e77f5f0b077 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 12 Mar 2013 18:09:59 -0700 Subject: [PATCH 1/2] refactor svg parsing so that libxml is not needed in the hpp file --- include/mapnik/svg/svg_parser.hpp | 26 +-- src/svg/svg_parser.cpp | 356 ++++++++++++++++-------------- 2 files changed, 191 insertions(+), 191 deletions(-) diff --git a/include/mapnik/svg/svg_parser.hpp b/include/mapnik/svg/svg_parser.hpp index 333949ec4..0806aa233 100644 --- a/include/mapnik/svg/svg_parser.hpp +++ b/include/mapnik/svg/svg_parser.hpp @@ -30,9 +30,6 @@ #include #include -// boost -#include - // stl #include @@ -45,34 +42,13 @@ namespace mapnik { namespace svg { ~svg_parser(); void parse(std::string const& filename); void parse_from_string(std::string const& svg); - private: - bool parse_reader(xmlTextReaderPtr reader); - void process_node(xmlTextReaderPtr reader); - void start_element(xmlTextReaderPtr reader); - void end_element(xmlTextReaderPtr reader); - void parse_path(xmlTextReaderPtr reader); - void parse_dimensions(xmlTextReaderPtr reader); - void parse_polygon(xmlTextReaderPtr reader); - void parse_polyline(xmlTextReaderPtr reader); - void parse_line(xmlTextReaderPtr reader); - void parse_rect(xmlTextReaderPtr reader); - void parse_circle(xmlTextReaderPtr reader); - void parse_ellipse(xmlTextReaderPtr reader); - void parse_linear_gradient(xmlTextReaderPtr reader); - void parse_radial_gradient(xmlTextReaderPtr reader); - bool parse_common_gradient(xmlTextReaderPtr reader); - void parse_gradient_stop(xmlTextReaderPtr reader); - void parse_pattern(xmlTextReaderPtr reader); - void parse_attr(xmlTextReaderPtr reader); - void parse_attr(const xmlChar * name, const xmlChar * value ); - private: svg_converter_type & path_; bool is_defs_; std::map gradient_map_; std::pair temporary_gradient_; }; - }} +}} #endif // MAPNIK_SVG_PARSER_HPP diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp index eae0d54a1..7fb4a1956 100644 --- a/src/svg/svg_parser.cpp +++ b/src/svg/svg_parser.cpp @@ -42,8 +42,31 @@ #include #include +// xml2 +#include + + namespace mapnik { namespace svg { +bool parse_reader(svg_parser & parser,xmlTextReaderPtr reader); +void process_node(svg_parser & parser,xmlTextReaderPtr reader); +void start_element(svg_parser & parser,xmlTextReaderPtr reader); +void end_element(svg_parser & parser,xmlTextReaderPtr reader); +void parse_path(svg_parser & parser,xmlTextReaderPtr reader); +void parse_dimensions(svg_parser & parser,xmlTextReaderPtr reader); +void parse_polygon(svg_parser & parser,xmlTextReaderPtr reader); +void parse_polyline(svg_parser & parser,xmlTextReaderPtr reader); +void parse_line(svg_parser & parser,xmlTextReaderPtr reader); +void parse_rect(svg_parser & parser,xmlTextReaderPtr reader); +void parse_circle(svg_parser & parser,xmlTextReaderPtr reader); +void parse_ellipse(svg_parser & parser,xmlTextReaderPtr reader); +void parse_linear_gradient(svg_parser & parser,xmlTextReaderPtr reader); +void parse_radial_gradient(svg_parser & parser,xmlTextReaderPtr reader); +bool parse_common_gradient(svg_parser & parser,xmlTextReaderPtr reader); +void parse_gradient_stop(svg_parser & parser,xmlTextReaderPtr reader); +void parse_pattern(svg_parser & parser,xmlTextReaderPtr reader); +void parse_attr(svg_parser & parser,xmlTextReaderPtr reader); +void parse_attr(svg_parser & parser,const xmlChar * name, const xmlChar * value ); typedef std::vector > color_lookup_type; @@ -124,48 +147,13 @@ bool parse_style (const char* str, pairs_type & v) return phrase_parse(str, str + std::strlen(str), kv_parser, skip_type(), v); } -svg_parser::svg_parser(svg_converter > & path) - : path_(path), - is_defs_(false) -{} - -svg_parser::~svg_parser() {} - -void svg_parser::parse(std::string const& filename) -{ - xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str()); - if (reader == NULL) - { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'"; - } - else if (!parse_reader(reader)) - { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'"; - } -} - -void svg_parser::parse_from_string(std::string const& svg) -{ - xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL, - (XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING)); - if (reader == NULL) - { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; - } - else if (!parse_reader(reader)) - { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; - } -} - -bool svg_parser::parse_reader(xmlTextReaderPtr reader) +bool parse_reader(svg_parser & parser, xmlTextReaderPtr reader) { int ret = xmlTextReaderRead(reader); try { while (ret == 1) { - process_node(reader); + process_node(parser,reader); ret = xmlTextReaderRead(reader); } } @@ -183,23 +171,8 @@ bool svg_parser::parse_reader(xmlTextReaderPtr reader) return true; } -void svg_parser::process_node(xmlTextReaderPtr reader) -{ - int node_type = xmlTextReaderNodeType(reader); - switch (node_type) - { - case 1: //start element - start_element(reader); - break; - case 15:// end element - end_element(reader); - break; - default: - break; - } -} -void svg_parser::start_element(xmlTextReaderPtr reader) +void start_element(svg_parser & parser, xmlTextReaderPtr reader) { const xmlChar *name; name = xmlTextReaderConstName(reader); @@ -207,67 +180,67 @@ void svg_parser::start_element(xmlTextReaderPtr reader) if (xmlStrEqual(name, BAD_CAST "defs")) { if (xmlTextReaderIsEmptyElement(reader) == 0) - is_defs_ = true; + parser.is_defs_ = true; } // the gradient tags *should* be in defs, but illustrator seems not to put them in there so // accept them anywhere else if (xmlStrEqual(name, BAD_CAST "linearGradient")) { - parse_linear_gradient(reader); + parse_linear_gradient(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "radialGradient")) { - parse_radial_gradient(reader); + parse_radial_gradient(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "stop")) { - parse_gradient_stop(reader); + parse_gradient_stop(parser,reader); } - if ( !is_defs_ ) + if ( !parser.is_defs_ ) { if (xmlStrEqual(name, BAD_CAST "g")) { - path_.push_attr(); - parse_attr(reader); + parser.path_.push_attr(); + parse_attr(parser,reader); } else { - path_.push_attr(); - parse_attr(reader); - if (path_.display()) + parser.path_.push_attr(); + parse_attr(parser,reader); + if (parser.path_.display()) { if (xmlStrEqual(name, BAD_CAST "path")) { - parse_path(reader); + parse_path(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "polygon") ) { - parse_polygon(reader); + parse_polygon(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "polyline")) { - parse_polyline(reader); + parse_polyline(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "line")) { - parse_line(reader); + parse_line(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "rect")) { - parse_rect(reader); + parse_rect(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "circle")) { - parse_circle(reader); + parse_circle(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "ellipse")) { - parse_ellipse(reader); + parse_ellipse(parser,reader); } else if (xmlStrEqual(name, BAD_CAST "svg")) { - parse_dimensions(reader); + parse_dimensions(parser,reader); } #ifdef MAPNIK_LOG else if (!xmlStrEqual(name, BAD_CAST "svg")) @@ -276,45 +249,61 @@ void svg_parser::start_element(xmlTextReaderPtr reader) } #endif } - path_.pop_attr(); + parser.path_.pop_attr(); } } } -void svg_parser::end_element(xmlTextReaderPtr reader) +void end_element(svg_parser & parser, xmlTextReaderPtr reader) { const xmlChar *name; name = xmlTextReaderConstName(reader); - if (!is_defs_ && xmlStrEqual(name, BAD_CAST "g")) + if (!parser.is_defs_ && xmlStrEqual(name, BAD_CAST "g")) { - path_.pop_attr(); + parser.path_.pop_attr(); } else if (xmlStrEqual(name, BAD_CAST "defs")) { - is_defs_ = false; + parser.is_defs_ = false; } else if ((xmlStrEqual(name, BAD_CAST "linearGradient")) || (xmlStrEqual(name, BAD_CAST "radialGradient"))) { - gradient_map_[temporary_gradient_.first] = temporary_gradient_.second; + parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second; } } -void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) +void process_node(svg_parser & parser, xmlTextReaderPtr reader) +{ + int node_type = xmlTextReaderNodeType(reader); + switch (node_type) + { + case 1: //start element + start_element(parser,reader); + break; + case 15:// end element + end_element(parser,reader); + break; + default: + break; + } +} + +void parse_attr(svg_parser & parser, const xmlChar * name, const xmlChar * value ) { if (xmlStrEqual(name, BAD_CAST "transform")) { agg::trans_affine tr; mapnik::svg::parse_transform((const char*) value,tr); - path_.transform().premultiply(tr); + parser.path_.transform().premultiply(tr); } else if (xmlStrEqual(name, BAD_CAST "fill")) { if (xmlStrEqual(value, BAD_CAST "none")) { - path_.fill_none(); + parser.path_.fill_none(); } else if (boost::starts_with((const char*)value, "url(#")) { @@ -322,9 +311,9 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) std::string id = std::string((const char*)&value[5]); // get rid of the trailing ) id.erase(id.end()-1); - if (gradient_map_.count(id) > 0) + if (parser.gradient_map_.count(id) > 0) { - path_.add_fill_gradient(gradient_map_[id]); + parser.path_.add_fill_gradient(parser.gradient_map_[id]); } else { @@ -333,25 +322,25 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) } else { - path_.fill(parse_color((const char*) value)); + parser.path_.fill(parse_color((const char*) value)); } } else if (xmlStrEqual(name, BAD_CAST "fill-opacity")) { - path_.fill_opacity(parse_double((const char*) value)); + parser.path_.fill_opacity(parse_double((const char*) value)); } else if (xmlStrEqual(name, BAD_CAST "fill-rule")) { if (xmlStrEqual(value, BAD_CAST "evenodd")) { - path_.even_odd(true); + parser.path_.even_odd(true); } } else if (xmlStrEqual(name, BAD_CAST "stroke")) { if (xmlStrEqual(value, BAD_CAST "none")) { - path_.stroke_none(); + parser.path_.stroke_none(); } else if (boost::starts_with((const char*)value, "url(#")) { @@ -359,9 +348,9 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) std::string id = std::string((const char*)&value[5]); // get rid of the trailing ) id.erase(id.end()-1); - if (gradient_map_.count(id) > 0) + if (parser.gradient_map_.count(id) > 0) { - path_.add_stroke_gradient(gradient_map_[id]); + parser.path_.add_stroke_gradient(parser.gradient_map_[id]); } else { @@ -370,61 +359,61 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) } else { - path_.stroke(parse_color((const char*) value)); + parser.path_.stroke(parse_color((const char*) value)); } } else if (xmlStrEqual(name, BAD_CAST "stroke-width")) { - path_.stroke_width(parse_double((const char*)value)); + parser.path_.stroke_width(parse_double((const char*)value)); } else if (xmlStrEqual(name, BAD_CAST "stroke-opacity")) { - path_.stroke_opacity(parse_double((const char*)value)); + parser.path_.stroke_opacity(parse_double((const char*)value)); } else if(xmlStrEqual(name,BAD_CAST "stroke-width")) { - path_.stroke_width(parse_double((const char*) value)); + parser.path_.stroke_width(parse_double((const char*) value)); } else if(xmlStrEqual(name,BAD_CAST "stroke-linecap")) { if(xmlStrEqual(value,BAD_CAST "butt")) - path_.line_cap(agg::butt_cap); + parser.path_.line_cap(agg::butt_cap); else if(xmlStrEqual(value,BAD_CAST "round")) - path_.line_cap(agg::round_cap); + parser.path_.line_cap(agg::round_cap); else if(xmlStrEqual(value,BAD_CAST "square")) - path_.line_cap(agg::square_cap); + parser.path_.line_cap(agg::square_cap); } else if(xmlStrEqual(name,BAD_CAST "stroke-linejoin")) { if(xmlStrEqual(value,BAD_CAST "miter")) - path_.line_join(agg::miter_join); + parser.path_.line_join(agg::miter_join); else if(xmlStrEqual(value,BAD_CAST "round")) - path_.line_join(agg::round_join); + parser.path_.line_join(agg::round_join); else if(xmlStrEqual(value,BAD_CAST "bevel")) - path_.line_join(agg::bevel_join); + parser.path_.line_join(agg::bevel_join); } else if(xmlStrEqual(name,BAD_CAST "stroke-miterlimit")) { - path_.miter_limit(parse_double((const char*)value)); + parser.path_.miter_limit(parse_double((const char*)value)); } else if(xmlStrEqual(name, BAD_CAST "opacity")) { double opacity = parse_double((const char*)value); - path_.opacity(opacity); + parser.path_.opacity(opacity); } else if (xmlStrEqual(name, BAD_CAST "visibility")) { - path_.visibility(!xmlStrEqual(value, BAD_CAST "hidden")); + parser.path_.visibility(!xmlStrEqual(value, BAD_CAST "hidden")); } else if (xmlStrEqual(name, BAD_CAST "display") && xmlStrEqual(value, BAD_CAST "none")) { - path_.display(false); + parser.path_.display(false); } } -void svg_parser::parse_attr(xmlTextReaderPtr reader) +void parse_attr(svg_parser & parser, xmlTextReaderPtr reader) { const xmlChar *name, *value; @@ -443,19 +432,19 @@ void svg_parser::parse_attr(xmlTextReaderPtr reader) parse_style((const char*)value, vec); BOOST_FOREACH(value_type kv , vec ) { - parse_attr(BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str()); + parse_attr(parser,BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str()); } } else { - parse_attr(name,value); + parse_attr(parser,name,value); } } while(xmlTextReaderMoveToNextAttribute(reader) == 1); } xmlTextReaderMoveToElement(reader); } -void svg_parser::parse_dimensions(xmlTextReaderPtr reader) +void parse_dimensions(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; double width = 0; @@ -473,10 +462,10 @@ void svg_parser::parse_dimensions(xmlTextReaderPtr reader) height = parse_double((const char*)value2); xmlFree(value2); } - path_.set_dimensions(width,height); + parser.path_.set_dimensions(width,height); } -void svg_parser::parse_path(xmlTextReaderPtr reader) +void parse_path(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; @@ -490,9 +479,9 @@ void svg_parser::parse_path(xmlTextReaderPtr reader) } else { - path_.begin_path(); + parser.path_.begin_path(); - if (!mapnik::svg::parse_path((const char*) value, path_)) + if (!mapnik::svg::parse_path((const char*) value, parser.path_)) { xmlFree(value); xmlChar *id_value; @@ -508,51 +497,51 @@ void svg_parser::parse_path(xmlTextReaderPtr reader) throw std::runtime_error("unable to parse invalid svg "); } } - path_.end_path(); + parser.path_.end_path(); xmlFree(value); } } } -void svg_parser::parse_polygon(xmlTextReaderPtr reader) +void parse_polygon(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; value = xmlTextReaderGetAttribute(reader, BAD_CAST "points"); if (value) { - path_.begin_path(); - if (!mapnik::svg::parse_points((const char*) value, path_)) + parser.path_.begin_path(); + if (!mapnik::svg::parse_points((const char*) value, parser.path_)) { xmlFree(value); throw std::runtime_error("Failed to parse "); } - path_.close_subpath(); - path_.end_path(); + parser.path_.close_subpath(); + parser.path_.end_path(); xmlFree(value); } } -void svg_parser::parse_polyline(xmlTextReaderPtr reader) +void parse_polyline(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; value = xmlTextReaderGetAttribute(reader, BAD_CAST "points"); if (value) { - path_.begin_path(); - if (!mapnik::svg::parse_points((const char*) value, path_)) + parser.path_.begin_path(); + if (!mapnik::svg::parse_points((const char*) value, parser.path_)) { xmlFree(value); throw std::runtime_error("Failed to parse "); } - path_.end_path(); + parser.path_.end_path(); xmlFree(value); } } -void svg_parser::parse_line(xmlTextReaderPtr reader) +void parse_line(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; double x1 = 0.0; @@ -588,14 +577,14 @@ void svg_parser::parse_line(xmlTextReaderPtr reader) xmlFree(value); } - path_.begin_path(); - path_.move_to(x1, y1); - path_.line_to(x2, y2); - path_.end_path(); + parser.path_.begin_path(); + parser.path_.move_to(x1, y1); + parser.path_.line_to(x2, y2); + parser.path_.end_path(); } -void svg_parser::parse_circle(xmlTextReaderPtr reader) +void parse_circle(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; double cx = 0.0; @@ -622,19 +611,19 @@ void svg_parser::parse_circle(xmlTextReaderPtr reader) xmlFree(value); } - path_.begin_path(); + parser.path_.begin_path(); if(r != 0.0) { if(r < 0.0) throw std::runtime_error("parse_circle: Invalid radius"); agg::ellipse c(cx, cy, r, r); - path_.storage().concat_path(c); + parser.path_.storage().concat_path(c); } - path_.end_path(); + parser.path_.end_path(); } -void svg_parser::parse_ellipse(xmlTextReaderPtr reader) +void parse_ellipse(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; double cx = 0.0; @@ -670,21 +659,21 @@ void svg_parser::parse_ellipse(xmlTextReaderPtr reader) xmlFree(value); } - path_.begin_path(); + parser.path_.begin_path(); if(rx != 0.0 && ry != 0.0) { if(rx < 0.0) throw std::runtime_error("parse_ellipse: Invalid rx"); if(ry < 0.0) throw std::runtime_error("parse_ellipse: Invalid ry"); agg::ellipse c(cx, cy, rx, ry); - path_.storage().concat_path(c); + parser.path_.storage().concat_path(c); } - path_.end_path(); + parser.path_.end_path(); } -void svg_parser::parse_rect(xmlTextReaderPtr reader) +void parse_rect(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; double x = 0.0; @@ -752,24 +741,24 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader) if(h < 0.0) throw std::runtime_error("parse_rect: Invalid height"); if(rx < 0.0) throw std::runtime_error("parse_rect: Invalid rx"); if(ry < 0.0) throw std::runtime_error("parse_rect: Invalid ry"); - path_.begin_path(); + parser.path_.begin_path(); if(rounded) { agg::rounded_rect r; r.rect(x,y,x+w,y+h); r.radius(rx,ry); - path_.storage().concat_path(r); + parser.path_.storage().concat_path(r); } else { - path_.move_to(x, y); - path_.line_to(x + w, y); - path_.line_to(x + w, y + h); - path_.line_to(x, y + h); - path_.close_subpath(); + parser.path_.move_to(x, y); + parser.path_.line_to(x + w, y); + parser.path_.line_to(x + w, y + h); + parser.path_.line_to(x, y + h); + parser.path_.close_subpath(); } - path_.end_path(); + parser.path_.end_path(); } } @@ -780,7 +769,7 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader) offset="1" id="stop3763" /> */ -void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader) +void parse_gradient_stop(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; @@ -848,7 +837,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader) stop_color.set_alpha(opacity*255); - temporary_gradient_.second.add_stop(offset, stop_color); + parser.temporary_gradient_.second.add_stop(offset, stop_color); /* MAPNIK_LOG_DEBUG(svg_parser) << "\tFound Stop: " << offset << " " @@ -859,7 +848,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader) */ } -bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) +bool parse_common_gradient(svg_parser & parser, xmlTextReaderPtr reader) { xmlChar *value; @@ -870,7 +859,7 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) // start a new gradient gradient new_grad; id = std::string((const char *) value); - temporary_gradient_ = std::make_pair(id, new_grad); + parser.temporary_gradient_ = std::make_pair(id, new_grad); xmlFree(value); } else @@ -886,9 +875,9 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) if (value[0] == '#') { std::string linkid = (const char *) &value[1]; - if (gradient_map_.count(linkid)) + if (parser.gradient_map_.count(linkid)) { - temporary_gradient_.second = gradient_map_[linkid]; + parser.temporary_gradient_.second = parser.gradient_map_[linkid]; } else { @@ -903,11 +892,11 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) { if (xmlStrEqual(value, BAD_CAST "userSpaceOnUse")) { - temporary_gradient_.second.set_units(USER_SPACE_ON_USE); + parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE); } else { - temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX); + parser.temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX); } xmlFree(value); } @@ -917,7 +906,7 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) { agg::trans_affine tr; mapnik::svg::parse_transform((const char*) value,tr); - temporary_gradient_.second.set_transform(tr); + parser.temporary_gradient_.second.set_transform(tr); xmlFree(value); } @@ -936,9 +925,9 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader) r="5.1999998" gradientUnits="userSpaceOnUse" /> */ -void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader) +void parse_radial_gradient(svg_parser & parser, xmlTextReaderPtr reader) { - if (!parse_common_gradient(reader)) + if (!parse_common_gradient(parser,reader)) return; xmlChar *value; @@ -988,22 +977,22 @@ void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader) xmlFree(value); } // this logic for detecting %'s will not support mixed coordinates. - if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) + if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) { - temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX); + parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX); } - temporary_gradient_.second.set_gradient_type(RADIAL); - temporary_gradient_.second.set_control_points(fx,fy,cx,cy,r); + parser.temporary_gradient_.second.set_gradient_type(RADIAL); + parser.temporary_gradient_.second.set_control_points(fx,fy,cx,cy,r); // add this here in case we have no end tag, will be replaced if we do - gradient_map_[temporary_gradient_.first] = temporary_gradient_.second; + parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second; //MAPNIK_LOG_DEBUG(svg_parser) << "Found Radial Gradient: " << " " << cx << " " << cy << " " << fx << " " << fy << " " << r; } -void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader) +void parse_linear_gradient(svg_parser & parser, xmlTextReaderPtr reader) { - if (!parse_common_gradient(reader)) + if (!parse_common_gradient(parser,reader)) return; xmlChar *value; @@ -1041,22 +1030,57 @@ void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader) xmlFree(value); } // this logic for detecting %'s will not support mixed coordinates. - if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) + if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) { - temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX); + parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX); } - temporary_gradient_.second.set_gradient_type(LINEAR); - temporary_gradient_.second.set_control_points(x1,y1,x2,y2); + parser.temporary_gradient_.second.set_gradient_type(LINEAR); + parser.temporary_gradient_.second.set_control_points(x1,y1,x2,y2); // add this here in case we have no end tag, will be replaced if we do - gradient_map_[temporary_gradient_.first] = temporary_gradient_.second; + parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second; //MAPNIK_LOG_DEBUG(svg_parser) << "Found Linear Gradient: " << "(" << x1 << " " << y1 << "),(" << x2 << " " << y2 << ")"; } -void svg_parser::parse_pattern(xmlTextReaderPtr reader) +void parse_pattern(svg_parser & parser, xmlTextReaderPtr reader) { //const xmlChar *value; } +svg_parser::svg_parser(svg_converter > & path) + : path_(path), + is_defs_(false) {} + +svg_parser::~svg_parser() {} + +void svg_parser::parse(std::string const& filename) +{ + xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str()); + if (reader == NULL) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'"; + } + else if (!parse_reader(*this,reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'"; + } +} + +void svg_parser::parse_from_string(std::string const& svg) +{ + xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL, + (XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING)); + if (reader == NULL) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } + else if (!parse_reader(*this,reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } +} + + }} From 6cbceafc45eda71ae379a3dfd7c52712ebe8422b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 12 Mar 2013 18:12:54 -0700 Subject: [PATCH 2/2] avoid direct freetype usage in core/public hpp file so that mapnik C++ depedencies do no need to known the freetype include paths --- include/mapnik/cairo_context.hpp | 20 +-- include/mapnik/font_engine_freetype.hpp | 154 ++---------------------- include/mapnik/font_util.hpp | 145 ++++++++++++++++++++++ src/agg/process_shield_symbolizer.cpp | 1 + src/agg/process_text_symbolizer.cpp | 1 + src/cairo_context.cpp | 19 +++ src/font_engine_freetype.cpp | 45 ++++++- src/grid/process_shield_symbolizer.cpp | 1 + src/grid/process_text_symbolizer.cpp | 1 + 9 files changed, 225 insertions(+), 162 deletions(-) create mode 100644 include/mapnik/font_util.hpp diff --git a/include/mapnik/cairo_context.hpp b/include/mapnik/cairo_context.hpp index 3d35fea64..5858cf501 100644 --- a/include/mapnik/cairo_context.hpp +++ b/include/mapnik/cairo_context.hpp @@ -72,23 +72,9 @@ void check_object_status_and_throw_exception(const T& object) class cairo_face : private mapnik::noncopyable { public: - cairo_face(boost::shared_ptr const& engine, face_ptr const& face) - : face_(face) - { - static cairo_user_data_key_t key; - c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING); - cairo_font_face_set_user_data(c_face_, &key, new handle(engine, face), destroy); - } - ~cairo_face() - { - if (c_face_) cairo_font_face_destroy(c_face_); - } - - cairo_font_face_t * face() const - { - return c_face_; - } - + cairo_face(boost::shared_ptr const& engine, face_ptr const& face); + ~cairo_face(); + cairo_font_face_t * face() const; private: class handle { diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 8fa4a62d7..5667dce83 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -38,15 +38,6 @@ #include #include -// freetype2 -extern "C" -{ -#include -#include FT_FREETYPE_H -#include FT_GLYPH_H -#include FT_STROKER_H -} - // boost #include #include @@ -64,12 +55,16 @@ extern "C" // uci #include +struct FT_LibraryRec_; + namespace mapnik { class font_face; class text_path; class string_info; struct char_properties; +class stroker; +struct glyph_t; typedef boost::shared_ptr face_ptr; @@ -95,59 +90,7 @@ private: typedef boost::shared_ptr glyph_ptr; -class font_face : mapnik::noncopyable -{ -public: - font_face(FT_Face face) - : face_(face) {} - std::string family_name() const - { - return std::string(face_->family_name); - } - - std::string style_name() const - { - return std::string(face_->style_name); - } - - FT_GlyphSlot glyph() const - { - return face_->glyph; - } - - FT_Face get_face() const - { - return face_; - } - - unsigned get_char(unsigned c) const - { - return FT_Get_Char_Index(face_, c); - } - - bool set_pixel_sizes(unsigned size) - { - if (! FT_Set_Pixel_Sizes( face_, 0, size )) - return true; - return false; - } - - bool set_character_sizes(double size) - { - if ( !FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0)) - return true; - return false; - } - - ~font_face() - { - FT_Done_Face(face_); - } - -private: - FT_Face face_; -}; class MAPNIK_DECL font_face_set : private mapnik::noncopyable { @@ -159,83 +102,18 @@ public: : faces_(), dimension_cache_() {} - void add(face_ptr face) - { - faces_.push_back(face); - dimension_cache_.clear(); //Make sure we don't use old cached data - } - - size_type size() const - { - return faces_.size(); - } - - glyph_ptr get_glyph(unsigned c) const - { - BOOST_FOREACH ( face_ptr const& face, faces_) - { - FT_UInt g = face->get_char(c); - if (g) return boost::make_shared(face, g); - } - - // Final fallback to empty square if nothing better in any font - return boost::make_shared(*faces_.begin(), 0); - } - + void add(face_ptr face); + size_type size() const; + glyph_ptr get_glyph(unsigned c) const; char_info character_dimensions(unsigned c); - void get_string_info(string_info & info, UnicodeString const& ustr, char_properties *format); - - void set_pixel_sizes(unsigned size) - { - BOOST_FOREACH ( face_ptr const& face, faces_) - { - face->set_pixel_sizes(size); - } - } - - void set_character_sizes(double size) - { - BOOST_FOREACH ( face_ptr const& face, faces_) - { - face->set_character_sizes(size); - } - } + void set_pixel_sizes(unsigned size); + void set_character_sizes(double size); private: container_type faces_; std::map dimension_cache_; }; -// FT_Stroker wrapper -class stroker : mapnik::noncopyable -{ -public: - explicit stroker(FT_Stroker s) - : s_(s) {} - - void init(double radius) - { - FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)), - FT_STROKER_LINECAP_ROUND, - FT_STROKER_LINEJOIN_ROUND, - 0); - } - - FT_Stroker const& get() const - { - return s_; - } - - ~stroker() - { - FT_Stroker_Done(s_); - } -private: - FT_Stroker s_; -}; - - - typedef boost::shared_ptr face_set_ptr; typedef boost::shared_ptr stroker_ptr; @@ -263,7 +141,7 @@ public: virtual ~freetype_engine(); freetype_engine(); private: - FT_Library library_; + FT_LibraryRec_ * library_; #ifdef MAPNIK_THREADSAFE static boost::mutex mutex_; #endif @@ -360,18 +238,6 @@ private: template struct text_renderer : private mapnik::noncopyable { - struct glyph_t : mapnik::noncopyable - { - FT_Glyph image; - char_properties *properties; - glyph_t(FT_Glyph image_, char_properties *properties_) - : image(image_), - properties(properties_) {} - ~glyph_t() - { - FT_Done_Glyph(image); - } - }; typedef boost::ptr_vector glyphs_t; typedef T pixmap_type; diff --git a/include/mapnik/font_util.hpp b/include/mapnik/font_util.hpp new file mode 100644 index 000000000..6e04988a2 --- /dev/null +++ b/include/mapnik/font_util.hpp @@ -0,0 +1,145 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + + +#ifndef MAPNIK_FONT_UTIL_HPP +#define MAPNIK_FONT_UTIL_HPP + +// mapnik +#include + +#include + +// freetype2 +extern "C" +{ +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_STROKER_H +} + +namespace mapnik +{ +struct char_properties; + +struct glyph_t : mapnik::noncopyable +{ + FT_Glyph image; + char_properties *properties; + glyph_t(FT_Glyph image_, char_properties *properties_) + : image(image_), + properties(properties_) {} + ~glyph_t() + { + FT_Done_Glyph(image); + } +}; + + +// FT_Stroker wrapper +class stroker : mapnik::noncopyable +{ +public: + explicit stroker(FT_Stroker s) + : s_(s) {} + + void init(double radius) + { + FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)), + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINEJOIN_ROUND, + 0); + } + + FT_Stroker const& get() const + { + return s_; + } + + ~stroker() + { + FT_Stroker_Done(s_); + } +private: + FT_Stroker s_; +}; + + +class font_face : mapnik::noncopyable +{ +public: + font_face(FT_Face face) + : face_(face) {} + + std::string family_name() const + { + return std::string(face_->family_name); + } + + std::string style_name() const + { + return std::string(face_->style_name); + } + + FT_GlyphSlot glyph() const + { + return face_->glyph; + } + + FT_Face get_face() const + { + return face_; + } + + unsigned get_char(unsigned c) const + { + return FT_Get_Char_Index(face_, c); + } + + bool set_pixel_sizes(unsigned size) + { + if (! FT_Set_Pixel_Sizes( face_, 0, size )) + return true; + return false; + } + + bool set_character_sizes(double size) + { + if ( !FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0)) + return true; + return false; + } + + ~font_face() + { + FT_Done_Face(face_); + } + +private: + FT_Face face_; +}; + +} + + +#endif // MAPNIK_FONT_UTIL_HPP diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index d522e9be0..753dccd14 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // boost #include diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 287bb18b6..0ee0e9559 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace mapnik { diff --git a/src/cairo_context.cpp b/src/cairo_context.cpp index 598a47592..83aea2783 100644 --- a/src/cairo_context.cpp +++ b/src/cairo_context.cpp @@ -21,9 +21,28 @@ *****************************************************************************/ #include +#include namespace mapnik { +cairo_face::cairo_face(boost::shared_ptr const& engine, face_ptr const& face) + : face_(face) +{ + static cairo_user_data_key_t key; + c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING); + cairo_font_face_set_user_data(c_face_, &key, new handle(engine, face), destroy); +} + +cairo_face::~cairo_face() +{ + if (c_face_) cairo_font_face_destroy(c_face_); +} + +cairo_font_face_t * cairo_face::face() const +{ + return c_face_; +} + cairo_context::cairo_context(cairo_ptr const& cairo) : cairo_(cairo) {} diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index a6af3137b..48222fd67 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -28,6 +28,7 @@ #include #include #include +#include // boost @@ -48,7 +49,10 @@ namespace mapnik { -freetype_engine::freetype_engine() + +freetype_engine::freetype_engine() : + library_(NULL) + { FT_Error error = FT_Init_FreeType( &library_ ); if (error) @@ -234,6 +238,29 @@ stroker_ptr freetype_engine::create_stroker() return stroker_ptr(); } +void font_face_set::add(face_ptr face) +{ + faces_.push_back(face); + dimension_cache_.clear(); //Make sure we don't use old cached data +} + +font_face_set::size_type font_face_set::size() const +{ + return faces_.size(); +} + +glyph_ptr font_face_set::get_glyph(unsigned c) const +{ + BOOST_FOREACH ( face_ptr const& face, faces_) + { + FT_UInt g = face->get_char(c); + if (g) return boost::make_shared(face, g); + } + + // Final fallback to empty square if nothing better in any font + return boost::make_shared(*faces_.begin(), 0); +} + char_info font_face_set::character_dimensions(unsigned int c) { //Check if char is already in cache @@ -329,6 +356,22 @@ void font_face_set::get_string_info(string_info & info, UnicodeString const& ust ubidi_close(bidi); } +void font_face_set::set_pixel_sizes(unsigned size) +{ + BOOST_FOREACH ( face_ptr const& face, faces_) + { + face->set_pixel_sizes(size); + } +} + +void font_face_set::set_character_sizes(double size) +{ + BOOST_FOREACH ( face_ptr const& face, faces_) + { + face->set_character_sizes(size); + } +} + template void composite_bitmap(T & pixmap, diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 5d80ed1ac..0fab6d5e1 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include // agg #include "agg_trans_affine.h" diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 2c6322062..40e6ed5a3 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace mapnik {