Merge branch 'master' of https://github.com/mapnik/mapnik into cmake-support
This commit is contained in:
commit
4879efce58
8 changed files with 301 additions and 188 deletions
|
@ -10,8 +10,6 @@ env:
|
||||||
- CCACHE_COMPRESS=1
|
- CCACHE_COMPRESS=1
|
||||||
- PREFIX=/tmp/mapnik
|
- PREFIX=/tmp/mapnik
|
||||||
- PYTHON=python3
|
- PYTHON=python3
|
||||||
- secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
|
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.ccache
|
- $HOME/.ccache
|
||||||
|
|
|
@ -33,18 +33,45 @@ namespace x3 = boost::spirit::x3;
|
||||||
// units
|
// units
|
||||||
struct css_unit_value : x3::symbols<double>
|
struct css_unit_value : x3::symbols<double>
|
||||||
{
|
{
|
||||||
const double DPI = 90;
|
constexpr static double DPI = 96;
|
||||||
css_unit_value()
|
css_unit_value()
|
||||||
{
|
{
|
||||||
add
|
add
|
||||||
("px", 1.0)
|
("px", 1.0) // pixels
|
||||||
("pt", DPI/72.0)
|
("pt", DPI/72.0) // points
|
||||||
("pc", DPI/6.0)
|
("pc", DPI/6.0) // picas
|
||||||
("mm", DPI/25.4)
|
("mm", DPI/25.4) // milimeters
|
||||||
("cm", DPI/2.54)
|
("Q" , DPI/101.6)// quarter-milimeters
|
||||||
("in", static_cast<double>(DPI))
|
("cm", DPI/2.54) // centimeters
|
||||||
//("em", 1.0/16.0) // default pixel size for body (usually 16px)
|
("in", static_cast<double>(DPI)) // inches
|
||||||
// ^^ this doesn't work currently as 'e' in 'em' interpreted as part of scientific notation.
|
;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct css_absolute_size : x3::symbols<double>
|
||||||
|
{
|
||||||
|
constexpr static double EM = 10.0; // 1em == 10px
|
||||||
|
css_absolute_size()
|
||||||
|
{
|
||||||
|
add
|
||||||
|
("xx-small", 0.6 * EM)
|
||||||
|
("x-small", 0.75 * EM)
|
||||||
|
("small", 0.88 * EM)
|
||||||
|
("medium", 1.0 * EM)
|
||||||
|
("large", 1.2 * EM)
|
||||||
|
("x-large", 1.5 * EM)
|
||||||
|
("xx-large", 2.0 * EM)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct css_relative_size : x3::symbols<double>
|
||||||
|
{
|
||||||
|
css_relative_size()
|
||||||
|
{
|
||||||
|
add
|
||||||
|
("larger", 1.2)
|
||||||
|
("smaller", 0.8)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,9 @@
|
||||||
// stl
|
// stl
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <deque>
|
||||||
|
// boost
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace boost { namespace property_tree { namespace detail { namespace rapidxml {
|
namespace boost { namespace property_tree { namespace detail { namespace rapidxml {
|
||||||
template <typename T> class xml_node;
|
template <typename T> class xml_node;
|
||||||
|
@ -41,6 +44,14 @@ template <typename T> class xml_node;
|
||||||
|
|
||||||
namespace mapnik { namespace svg {
|
namespace mapnik { namespace svg {
|
||||||
|
|
||||||
|
struct viewbox
|
||||||
|
{
|
||||||
|
double x0;
|
||||||
|
double y0;
|
||||||
|
double width;
|
||||||
|
double height;
|
||||||
|
};
|
||||||
|
|
||||||
class svg_parser_error_handler
|
class svg_parser_error_handler
|
||||||
{
|
{
|
||||||
using error_message_container = std::vector<std::string> ;
|
using error_message_container = std::vector<std::string> ;
|
||||||
|
@ -88,7 +99,10 @@ public:
|
||||||
std::map<std::string, gradient> gradient_map_;
|
std::map<std::string, gradient> gradient_map_;
|
||||||
std::map<std::string, boost::property_tree::detail::rapidxml::xml_node<char> const*> node_cache_;
|
std::map<std::string, boost::property_tree::detail::rapidxml::xml_node<char> const*> node_cache_;
|
||||||
mapnik::css_data css_data_;
|
mapnik::css_data css_data_;
|
||||||
|
boost::optional<viewbox> vbox_{};
|
||||||
|
double normalized_diagonal_ = 0.0;
|
||||||
agg::trans_affine viewbox_tr_{};
|
agg::trans_affine viewbox_tr_{};
|
||||||
|
std::deque<double> font_sizes_{};
|
||||||
error_handler err_handler_;
|
error_handler err_handler_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ public:
|
||||||
if (m_gradient_lut.build_lut())
|
if (m_gradient_lut.build_lut())
|
||||||
{
|
{
|
||||||
agg::trans_affine transform = mtx;
|
agg::trans_affine transform = mtx;
|
||||||
|
double scale = mtx.scale();
|
||||||
transform.invert();
|
transform.invert();
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
tr = grad.get_transform();
|
tr = grad.get_transform();
|
||||||
|
@ -185,9 +186,8 @@ public:
|
||||||
{
|
{
|
||||||
bounding_rect_single(curved_trans, path_id, &bx1, &by1, &bx2, &by2);
|
bounding_rect_single(curved_trans, path_id, &bx1, &by1, &bx2, &by2);
|
||||||
}
|
}
|
||||||
|
transform.translate(-bx1/scale,-by1/scale);
|
||||||
transform.translate(-bx1,-by1);
|
transform.scale(scale/(bx2-bx1),scale/(by2-by1));
|
||||||
transform.scale(1.0/(bx2-bx1),1.0/(by2-by1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grad.get_gradient_type() == RADIAL)
|
if (grad.get_gradient_type() == RADIAL)
|
||||||
|
|
|
@ -39,10 +39,6 @@ MAPNIK_DISABLE_WARNING_PUSH
|
||||||
#include "agg_rounded_rect.h"
|
#include "agg_rounded_rect.h"
|
||||||
#include "agg_span_gradient.h"
|
#include "agg_span_gradient.h"
|
||||||
#include "agg_color_rgba.h"
|
#include "agg_color_rgba.h"
|
||||||
MAPNIK_DISABLE_WARNING_POP
|
|
||||||
|
|
||||||
#include <mapnik/warning.hpp>
|
|
||||||
MAPNIK_DISABLE_WARNING_PUSH
|
|
||||||
#include <mapnik/warning_ignore.hpp>
|
#include <mapnik/warning_ignore.hpp>
|
||||||
#include <boost/spirit/home/x3.hpp>
|
#include <boost/spirit/home/x3.hpp>
|
||||||
#include <boost/fusion/adapted/struct.hpp>
|
#include <boost/fusion/adapted/struct.hpp>
|
||||||
|
@ -62,14 +58,6 @@ namespace mapnik { namespace svg {
|
||||||
|
|
||||||
using util::name_to_int;
|
using util::name_to_int;
|
||||||
using util::operator"" _case;
|
using util::operator"" _case;
|
||||||
|
|
||||||
struct viewbox
|
|
||||||
{
|
|
||||||
double x0;
|
|
||||||
double y0;
|
|
||||||
double width;
|
|
||||||
double height;
|
|
||||||
};
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT (
|
BOOST_FUSION_ADAPT_STRUCT (
|
||||||
|
@ -118,7 +106,7 @@ static std::array<unsigned, 9> const unsupported_elements
|
||||||
"pattern"_case}
|
"pattern"_case}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::array<unsigned, 43> const unsupported_attributes
|
static std::array<unsigned, 42> const unsupported_attributes
|
||||||
{ {"alignment-baseline"_case,
|
{ {"alignment-baseline"_case,
|
||||||
"baseline-shift"_case,
|
"baseline-shift"_case,
|
||||||
"clip"_case,
|
"clip"_case,
|
||||||
|
@ -136,7 +124,6 @@ static std::array<unsigned, 43> const unsupported_attributes
|
||||||
"flood-color"_case,
|
"flood-color"_case,
|
||||||
"flood-opacity"_case,
|
"flood-opacity"_case,
|
||||||
"font-family"_case,
|
"font-family"_case,
|
||||||
"font-size"_case,
|
|
||||||
"font-size-adjust"_case,
|
"font-size-adjust"_case,
|
||||||
"font-stretch"_case,
|
"font-stretch"_case,
|
||||||
"font-style"_case,
|
"font-style"_case,
|
||||||
|
@ -257,31 +244,77 @@ double parse_double(T & err_handler, const char* str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/coords.html#Units
|
// https://www.w3.org/TR/SVG/coords.html#Units
|
||||||
template <typename T, int DPI = 90>
|
template <typename T>
|
||||||
double parse_svg_value(T & err_handler, const char* str, bool & is_percent)
|
double parse_svg_value(T & parser, char const* str, bool & is_percent)
|
||||||
{
|
{
|
||||||
namespace x3 = boost::spirit::x3;
|
namespace x3 = boost::spirit::x3;
|
||||||
double val = 0.0;
|
double val = 0.0;
|
||||||
css_unit_value units;
|
css_unit_value units;
|
||||||
const char* cur = str; // phrase_parse mutates the first iterator
|
const char* cur = str; // phrase_parse mutates the first iterator
|
||||||
const char* end = str + std::strlen(str);
|
const char* end = str + std::strlen(str);
|
||||||
|
double font_size = parser.font_sizes_.back();
|
||||||
auto apply_value = [&](auto const& ctx) { val = _attr(ctx); is_percent = false; };
|
bool is_percent_;
|
||||||
|
auto apply_value = [&](auto const& ctx) { val = _attr(ctx); is_percent_ = false; };
|
||||||
auto apply_units = [&](auto const& ctx) { val *= _attr(ctx); };
|
auto apply_units = [&](auto const& ctx) { val *= _attr(ctx); };
|
||||||
auto apply_percent = [&](auto const& ctx) { val *= 0.01; is_percent = true; };
|
auto apply_em = [&](auto const& ctx) { val *= font_size;};
|
||||||
|
auto apply_percent = [&](auto const& ctx) { val *= 0.01; is_percent_ = true; };
|
||||||
|
|
||||||
if (!x3::phrase_parse(cur, end,
|
if (!x3::phrase_parse(cur, end,
|
||||||
x3::double_[apply_value]
|
x3::double_[apply_value]
|
||||||
> - (units[apply_units]
|
> - (units[apply_units]
|
||||||
|
|
|
||||||
|
x3::lit("em")[apply_em]
|
||||||
|
|
|
|
||||||
x3::lit('%')[apply_percent]),
|
x3::lit('%')[apply_percent]),
|
||||||
x3::space) || (cur != end))
|
x3::space) || (cur != end))
|
||||||
{
|
{
|
||||||
err_handler.on_error("SVG parse error: failed to parse <number> with value \"" + std::string(str) + "\"");
|
val = 0.0; // restore to default on parsing failure
|
||||||
|
parser.err_handler().on_error("SVG parse error: failed to parse <number> with value \"" + std::string(str) + "\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
is_percent = is_percent_; // update only on success
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool parse_font_size(T & parser, char const* str)
|
||||||
|
{
|
||||||
|
namespace x3 = boost::spirit::x3;
|
||||||
|
double val = 0.0;
|
||||||
|
css_unit_value units;
|
||||||
|
css_absolute_size absolute;
|
||||||
|
css_relative_size relative;
|
||||||
|
|
||||||
|
std::size_t size = parser.font_sizes_.size();
|
||||||
|
double parent_font_size = size > 1 ? parser.font_sizes_[size - 2] : 10.0 ;
|
||||||
|
const char* cur = str; // phrase_parse mutates the first iterator
|
||||||
|
const char* end = str + std::strlen(str);
|
||||||
|
|
||||||
|
auto apply_value = [&](auto const& ctx) { val = _attr(ctx);};
|
||||||
|
auto apply_relative =[&](auto const& ctx) { val = parent_font_size * _attr(ctx);};
|
||||||
|
auto apply_units = [&](auto const& ctx) { val *= _attr(ctx); };
|
||||||
|
auto apply_percent = [&](auto const& ctx) { val = val * parent_font_size / 100.0;};
|
||||||
|
auto apply_em = [&](auto const& ctx) { val = val * parent_font_size;};
|
||||||
|
if (!x3::phrase_parse(cur, end,
|
||||||
|
absolute[apply_value]
|
||||||
|
|
|
||||||
|
relative[apply_relative]
|
||||||
|
|
|
||||||
|
x3::double_[apply_value]
|
||||||
|
> -(units[apply_units]
|
||||||
|
| x3::lit("em")[apply_em]
|
||||||
|
| x3::lit('%')[apply_percent]),
|
||||||
|
x3::space) || (cur != end))
|
||||||
|
{
|
||||||
|
parser.err_handler().on_error("SVG parse error: failed to parse <font-size> with value \"" + std::string(str) + "\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parser.font_sizes_.empty()) parser.font_sizes_.back() = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename V>
|
template <typename T, typename V>
|
||||||
bool parse_viewbox(T & err_handler, char const* str, V & viewbox)
|
bool parse_viewbox(T & err_handler, char const* str, V & viewbox)
|
||||||
{
|
{
|
||||||
|
@ -371,7 +404,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
auto itr = css.find(element_name);
|
auto itr = css.find(element_name);
|
||||||
if (itr != css.end())
|
if (itr != css.end())
|
||||||
{
|
{
|
||||||
//std::cerr << "-> element key:" << element_name << std::endl;
|
|
||||||
for (auto const& def : std::get<1>(*itr))
|
for (auto const& def : std::get<1>(*itr))
|
||||||
{
|
{
|
||||||
style[std::get<0>(def)] = std::get<1>(def);
|
style[std::get<0>(def)] = std::get<1>(def);
|
||||||
|
@ -396,8 +428,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
auto range = css.equal_range(solitary_class_key);
|
auto range = css.equal_range(solitary_class_key);
|
||||||
for (auto itr = range.first; itr != range.second; ++itr)
|
for (auto itr = range.first; itr != range.second; ++itr)
|
||||||
{
|
{
|
||||||
//std::cerr << "<" << element_name << ">";
|
|
||||||
//std::cerr << "--> solitary class key:" << solitary_class_key << std::endl;
|
|
||||||
for (auto const& def : std::get<1>(*itr))
|
for (auto const& def : std::get<1>(*itr))
|
||||||
{
|
{
|
||||||
style[std::get<0>(def)] = std::get<1>(def);
|
style[std::get<0>(def)] = std::get<1>(def);
|
||||||
|
@ -407,8 +437,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
range = css.equal_range(class_key);
|
range = css.equal_range(class_key);
|
||||||
for (auto itr = range.first; itr != range.second; ++itr)
|
for (auto itr = range.first; itr != range.second; ++itr)
|
||||||
{
|
{
|
||||||
//std::cerr << "<" << element_name << ">";
|
|
||||||
//std::cerr << "---> class key:" << class_key << std::endl;
|
|
||||||
for (auto const& def : std::get<1>(*itr))
|
for (auto const& def : std::get<1>(*itr))
|
||||||
{
|
{
|
||||||
style[std::get<0>(def)] = std::get<1>(def);
|
style[std::get<0>(def)] = std::get<1>(def);
|
||||||
|
@ -416,10 +444,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// std::cerr << "Failed to parse styles..." << std::endl;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto const* id_attr = node->first_attribute("id");
|
auto const* id_attr = node->first_attribute("id");
|
||||||
|
@ -432,8 +456,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
itr = css.find(id_key);
|
itr = css.find(id_key);
|
||||||
if (itr != css.end())
|
if (itr != css.end())
|
||||||
{
|
{
|
||||||
//std::cerr << "<" << element_name << ">";
|
|
||||||
//std::cerr << "----> ID key:" << id_key << std::endl;
|
|
||||||
for (auto const& def : std::get<1>(*itr))
|
for (auto const& def : std::get<1>(*itr))
|
||||||
{
|
{
|
||||||
style[std::get<0>(def)] = std::get<1>(def);
|
style[std::get<0>(def)] = std::get<1>(def);
|
||||||
|
@ -449,7 +471,6 @@ void process_css(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
auto const& r = std::get<1>(def);
|
auto const& r = std::get<1>(def);
|
||||||
std::string val{r.begin(), r.end()};
|
std::string val{r.begin(), r.end()};
|
||||||
//std::cerr << "PARSE ATTR:" << std::get<0>(def) << ":" << val << std::endl;
|
|
||||||
parse_attr(parser, std::get<0>(def).c_str(), val.c_str());
|
parse_attr(parser, std::get<0>(def).c_str(), val.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,10 +480,12 @@ void traverse_tree(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
if (parser.ignore_) return;
|
if (parser.ignore_) return;
|
||||||
auto name = name_to_int(node->name());
|
auto name = name_to_int(node->name());
|
||||||
|
|
||||||
switch (node->type())
|
switch (node->type())
|
||||||
{
|
{
|
||||||
case rapidxml::node_element:
|
case rapidxml::node_element:
|
||||||
{
|
{
|
||||||
|
parser.font_sizes_.push_back(parser.font_sizes_.back());
|
||||||
switch(name)
|
switch(name)
|
||||||
{
|
{
|
||||||
case "defs"_case:
|
case "defs"_case:
|
||||||
|
@ -574,6 +597,7 @@ void traverse_tree(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
|
|
||||||
void end_element(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
void end_element(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
|
parser.font_sizes_.pop_back();
|
||||||
auto name = name_to_int(node->name());
|
auto name = name_to_int(node->name());
|
||||||
if (!parser.is_defs_ && (name == "g"_case))
|
if (!parser.is_defs_ && (name == "g"_case))
|
||||||
{
|
{
|
||||||
|
@ -582,6 +606,13 @@ void end_element(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
parser.path_.pop_attr();
|
parser.path_.pop_attr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (name == "svg"_case)
|
||||||
|
{
|
||||||
|
if (node->first_node() != nullptr)
|
||||||
|
{
|
||||||
|
parser.path_.pop_attr();
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (name == "defs"_case)
|
else if (name == "defs"_case)
|
||||||
{
|
{
|
||||||
if (node->first_node() != nullptr)
|
if (node->first_node() != nullptr)
|
||||||
|
@ -629,7 +660,9 @@ void parse_element(svg_parser & parser, char const* name, rapidxml::xml_node<cha
|
||||||
parse_ellipse(parser, node);
|
parse_ellipse(parser, node);
|
||||||
break;
|
break;
|
||||||
case "svg"_case:
|
case "svg"_case:
|
||||||
|
parser.path_.push_attr();
|
||||||
parse_dimensions(parser, node);
|
parse_dimensions(parser, node);
|
||||||
|
parse_attr(parser, node);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
handle_unsupported(parser, unsupported_elements, name, "element");
|
handle_unsupported(parser, unsupported_elements, name, "element");
|
||||||
|
@ -762,9 +795,13 @@ void parse_attr(svg_parser & parser, char const* name, char const* value )
|
||||||
parse_stroke(parser, value);
|
parse_stroke(parser, value);
|
||||||
break;
|
break;
|
||||||
case "stroke-width"_case:
|
case "stroke-width"_case:
|
||||||
bool percent;
|
{
|
||||||
parser.path_.stroke_width(parse_svg_value(parser.err_handler(), value, percent));
|
bool percent = false;
|
||||||
|
double stroke_width = parse_svg_value(parser, value, percent);
|
||||||
|
if (percent && parser.vbox_) stroke_width *= parser.normalized_diagonal_;
|
||||||
|
parser.path_.stroke_width(stroke_width);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case "stroke-opacity"_case:
|
case "stroke-opacity"_case:
|
||||||
parser.path_.stroke_opacity(parse_double(parser.err_handler(), value));
|
parser.path_.stroke_opacity(parse_double(parser.err_handler(), value));
|
||||||
break;
|
break;
|
||||||
|
@ -805,6 +842,11 @@ void parse_attr(svg_parser & parser, char const* name, char const* value )
|
||||||
parser.path_.display(false);
|
parser.path_.display(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "font-size"_case:
|
||||||
|
{
|
||||||
|
parse_font_size(parser, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
handle_unsupported(parser, unsupported_attributes, name, "attribute");
|
handle_unsupported(parser, unsupported_attributes, name, "attribute");
|
||||||
break;
|
break;
|
||||||
|
@ -837,9 +879,9 @@ void parse_attr(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
|
|
||||||
void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
double width = 0;
|
// https://www.w3.org/TR/SVG11/struct.html#SVGElement
|
||||||
double height = 0;
|
double width = 1; // 100%
|
||||||
double aspect_ratio = 1;
|
double height = 1; // 100%
|
||||||
viewbox vbox = {0, 0, 0, 0};
|
viewbox vbox = {0, 0, 0, 0};
|
||||||
bool has_percent_height = true;
|
bool has_percent_height = true;
|
||||||
bool has_percent_width = true;
|
bool has_percent_width = true;
|
||||||
|
@ -847,97 +889,100 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
auto const* width_attr = node->first_attribute("width");
|
auto const* width_attr = node->first_attribute("width");
|
||||||
if (width_attr)
|
if (width_attr)
|
||||||
{
|
{
|
||||||
width = parse_svg_value(parser.err_handler(), width_attr->value(), has_percent_width);
|
width = parse_svg_value(parser, width_attr->value(), has_percent_width);
|
||||||
}
|
}
|
||||||
auto const* height_attr = node->first_attribute("height");
|
auto const* height_attr = node->first_attribute("height");
|
||||||
if (height_attr)
|
if (height_attr)
|
||||||
{
|
{
|
||||||
height = parse_svg_value(parser.err_handler(), height_attr->value(), has_percent_height);
|
height = parse_svg_value(parser, height_attr->value(), has_percent_height);
|
||||||
}
|
}
|
||||||
|
parser.vbox_ = viewbox{0, 0, width, height} ;
|
||||||
auto const* viewbox_attr = node->first_attribute("viewBox");
|
auto const* viewbox_attr = node->first_attribute("viewBox");
|
||||||
if (viewbox_attr && parse_viewbox(parser.err_handler(), viewbox_attr->value(), vbox))
|
if (viewbox_attr && parse_viewbox(parser.err_handler(), viewbox_attr->value(), vbox))
|
||||||
{
|
{
|
||||||
if (!has_percent_width && !has_percent_height)
|
agg::trans_affine t{};
|
||||||
|
parser.vbox_ = vbox;
|
||||||
|
parser.normalized_diagonal_ = std::sqrt(vbox.width * vbox.width + vbox.height * vbox.height)/std::sqrt(2.0);
|
||||||
|
|
||||||
|
if (has_percent_width) width = vbox.width * width;
|
||||||
|
else if (!width_attr || width == 0) width = vbox.width;
|
||||||
|
if (has_percent_height) height = vbox.height * height;
|
||||||
|
else if (!height_attr || height == 0) height = vbox.height;
|
||||||
|
|
||||||
|
if (width > 0 && height > 0 && vbox.width > 0 && vbox.height > 0)
|
||||||
{
|
{
|
||||||
if (width > 0 && height > 0 && vbox.width > 0 && vbox.height > 0)
|
std::pair<unsigned,bool> preserve_aspect_ratio {xMidYMid, true};
|
||||||
|
auto const* aspect_ratio_attr = node->first_attribute("preserveAspectRatio");
|
||||||
|
if (aspect_ratio_attr)
|
||||||
{
|
{
|
||||||
agg::trans_affine t{};
|
preserve_aspect_ratio = parse_preserve_aspect_ratio(parser.err_handler(), aspect_ratio_attr->value());
|
||||||
std::pair<unsigned,bool> preserve_aspect_ratio {xMidYMid, true};
|
|
||||||
auto const* aspect_ratio_attr = node->first_attribute("preserveAspectRatio");
|
|
||||||
if (aspect_ratio_attr)
|
|
||||||
{
|
|
||||||
preserve_aspect_ratio = parse_preserve_aspect_ratio(parser.err_handler(), aspect_ratio_attr->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
double sx = width / vbox.width;
|
|
||||||
double sy = height / vbox.height;
|
|
||||||
double scale = preserve_aspect_ratio.second ? std::min(sx, sy) : std::max(sx, sy);
|
|
||||||
switch (preserve_aspect_ratio.first)
|
|
||||||
{
|
|
||||||
case none:
|
|
||||||
t = agg::trans_affine_scaling(sx, sy) * t;
|
|
||||||
break;
|
|
||||||
case xMinYMin:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
break;
|
|
||||||
case xMinYMid:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(0, -0.5 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
case xMinYMax:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(0, -1.0 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
case xMidYMin:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale), 0.0) * t;
|
|
||||||
break;
|
|
||||||
case xMidYMid: // (the default)
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
|
||||||
-0.5 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
case xMidYMax:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
|
||||||
-1.0 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
case xMaxYMin:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale), 0.0) * t;
|
|
||||||
break;
|
|
||||||
case xMaxYMid:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
|
||||||
-0.5 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
case xMaxYMax:
|
|
||||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
|
||||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
|
||||||
-1.0 * (vbox.height - height / scale)) * t;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
t = agg::trans_affine_translation(-vbox.x0, -vbox.y0) * t;
|
|
||||||
parser.viewbox_tr_ = t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double sx = width / vbox.width;
|
||||||
|
double sy = height / vbox.height;
|
||||||
|
double scale = preserve_aspect_ratio.second ? std::min(sx, sy) : std::max(sx, sy);
|
||||||
|
switch (preserve_aspect_ratio.first)
|
||||||
|
{
|
||||||
|
case none:
|
||||||
|
t = agg::trans_affine_scaling(sx, sy) * t;
|
||||||
|
break;
|
||||||
|
case xMinYMin:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
break;
|
||||||
|
case xMinYMid:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(0, -0.5 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
case xMinYMax:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(0, -1.0 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
case xMidYMin:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale), 0.0) * t;
|
||||||
|
break;
|
||||||
|
case xMidYMid: // (the default)
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||||
|
-0.5 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
case xMidYMax:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||||
|
-1.0 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
case xMaxYMin:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale), 0.0) * t;
|
||||||
|
break;
|
||||||
|
case xMaxYMid:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||||
|
-0.5 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
case xMaxYMax:
|
||||||
|
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||||
|
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||||
|
-1.0 * (vbox.height - height / scale)) * t;
|
||||||
|
break;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (has_percent_width && !has_percent_height)
|
t = agg::trans_affine_translation(-vbox.x0, -vbox.y0) * t;
|
||||||
{
|
parser.viewbox_tr_ = t;
|
||||||
aspect_ratio = vbox.width / vbox.height;
|
}
|
||||||
width = aspect_ratio * height;
|
else if (width == 0 || height == 0 || has_percent_width || has_percent_height)
|
||||||
}
|
{
|
||||||
else if (!has_percent_width && has_percent_height)
|
std::stringstream ss;
|
||||||
{
|
ss << "SVG parse error: can't infer valid image dimensions from width:\"";
|
||||||
aspect_ratio = vbox.width/vbox.height;
|
if (has_percent_width) ss << width * 100 << "%";
|
||||||
height = height / aspect_ratio;
|
else ss << width;
|
||||||
}
|
ss << "\" height:\"";
|
||||||
else if (has_percent_width && has_percent_height)
|
if (has_percent_height) ss << height * 100 << "%";
|
||||||
{
|
else ss << height;
|
||||||
width = vbox.width;
|
ss << "\"";
|
||||||
height = vbox.height;
|
parser.err_handler().on_error(ss.str());
|
||||||
}
|
parser.path_.set_dimensions(0, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
parser.path_.set_dimensions(width, height);
|
parser.path_.set_dimensions(width, height);
|
||||||
}
|
}
|
||||||
|
@ -990,25 +1035,25 @@ void parse_use(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
attr = node->first_attribute("x");
|
attr = node->first_attribute("x");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
x = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
x = parse_svg_value(parser, attr->value(), percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("y");
|
attr = node->first_attribute("y");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
y = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
y = parse_svg_value(parser, attr->value(), percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("width");
|
attr = node->first_attribute("width");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
w = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
w = parse_svg_value(parser, attr->value(), percent);
|
||||||
if (percent) w *= parser.path_.width();
|
if (percent) w *= parser.path_.width();
|
||||||
}
|
}
|
||||||
attr = node->first_attribute("height");
|
attr = node->first_attribute("height");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
h = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
h = parse_svg_value(parser, attr->value(), percent);
|
||||||
if (percent) h *= parser.path_.height();
|
if (percent) h *= parser.path_.height();
|
||||||
}
|
}
|
||||||
if (w < 0.0)
|
if (w < 0.0)
|
||||||
|
@ -1073,19 +1118,32 @@ void parse_line(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
double y1 = 0.0;
|
double y1 = 0.0;
|
||||||
double x2 = 0.0;
|
double x2 = 0.0;
|
||||||
double y2 = 0.0;
|
double y2 = 0.0;
|
||||||
bool percent;
|
bool percent = false;
|
||||||
auto const* x1_attr = node->first_attribute("x1");
|
auto const* x1_attr = node->first_attribute("x1");
|
||||||
if (x1_attr) x1 = parse_svg_value(parser.err_handler(), x1_attr->value(), percent);
|
if (x1_attr)
|
||||||
|
{
|
||||||
|
x1 = parse_svg_value(parser, x1_attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) x1 *= parser.vbox_->width;
|
||||||
|
}
|
||||||
auto const* y1_attr = node->first_attribute("y1");
|
auto const* y1_attr = node->first_attribute("y1");
|
||||||
if (y1_attr) y1 = parse_svg_value(parser.err_handler(), y1_attr->value(), percent);
|
if (y1_attr)
|
||||||
|
{
|
||||||
|
y1 = parse_svg_value(parser, y1_attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) y1 *= parser.vbox_->height;
|
||||||
|
}
|
||||||
|
|
||||||
auto const* x2_attr = node->first_attribute("x2");
|
auto const* x2_attr = node->first_attribute("x2");
|
||||||
if (x2_attr) x2 = parse_svg_value(parser.err_handler(), x2_attr->value(), percent);
|
if (x2_attr)
|
||||||
|
{
|
||||||
|
x2 = parse_svg_value(parser, x2_attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) x2 *= parser.vbox_->width;
|
||||||
|
}
|
||||||
auto const* y2_attr = node->first_attribute("y2");
|
auto const* y2_attr = node->first_attribute("y2");
|
||||||
if (y2_attr) y2 = parse_svg_value(parser.err_handler(), y2_attr->value(), percent);
|
if (y2_attr)
|
||||||
|
{
|
||||||
|
y2 = parse_svg_value(parser, y2_attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) y2 *= parser.vbox_->height;
|
||||||
|
}
|
||||||
parser.path_.begin_path();
|
parser.path_.begin_path();
|
||||||
parser.path_.move_to(x1, y1);
|
parser.path_.move_to(x1, y1);
|
||||||
parser.path_.line_to(x2, y2);
|
parser.path_.line_to(x2, y2);
|
||||||
|
@ -1097,27 +1155,29 @@ void parse_circle(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
double cx = 0.0;
|
double cx = 0.0;
|
||||||
double cy = 0.0;
|
double cy = 0.0;
|
||||||
double r = 0.0;
|
double r = 0.0;
|
||||||
bool percent;
|
bool percent = false;
|
||||||
auto * attr = node->first_attribute("cx");
|
auto * attr = node->first_attribute("cx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
cx = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
cx = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) cx *= parser.vbox_->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("cy");
|
attr = node->first_attribute("cy");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
cy = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
cy = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) cy *= parser.vbox_->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("r");
|
attr = node->first_attribute("r");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
r = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
r = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) r *= parser.normalized_diagonal_;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.path_.begin_path();
|
if (r != 0.0)
|
||||||
if(r != 0.0)
|
|
||||||
{
|
{
|
||||||
if (r < 0.0)
|
if (r < 0.0)
|
||||||
{
|
{
|
||||||
|
@ -1127,11 +1187,12 @@ void parse_circle(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
parser.path_.begin_path();
|
||||||
agg::ellipse c(cx, cy, r, r);
|
agg::ellipse c(cx, cy, r, r);
|
||||||
parser.path_.storage().concat_path(c);
|
parser.path_.storage().concat_path(c);
|
||||||
|
parser.path_.end_path();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parser.path_.end_path();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_ellipse(svg_parser & parser, rapidxml::xml_node<char> const * node)
|
void parse_ellipse(svg_parser & parser, rapidxml::xml_node<char> const * node)
|
||||||
|
@ -1140,29 +1201,33 @@ void parse_ellipse(svg_parser & parser, rapidxml::xml_node<char> const * node)
|
||||||
double cy = 0.0;
|
double cy = 0.0;
|
||||||
double rx = 0.0;
|
double rx = 0.0;
|
||||||
double ry = 0.0;
|
double ry = 0.0;
|
||||||
bool percent;
|
bool percent = false;
|
||||||
auto * attr = node->first_attribute("cx");
|
auto * attr = node->first_attribute("cx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
cx = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
cx = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) cx *= parser.vbox_->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("cy");
|
attr = node->first_attribute("cy");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
cy = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
cy = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) cy *= parser.vbox_->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("rx");
|
attr = node->first_attribute("rx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
rx = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
rx = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) rx *= parser.normalized_diagonal_;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("ry");
|
attr = node->first_attribute("ry");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
ry = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
ry = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) ry *= parser.normalized_diagonal_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx != 0.0 && ry != 0.0)
|
if (rx != 0.0 && ry != 0.0)
|
||||||
|
@ -1198,35 +1263,40 @@ void parse_rect(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
double h = 0.0;
|
double h = 0.0;
|
||||||
double rx = 0.0;
|
double rx = 0.0;
|
||||||
double ry = 0.0;
|
double ry = 0.0;
|
||||||
bool percent;
|
bool percent = false;
|
||||||
auto * attr = node->first_attribute("x");
|
auto * attr = node->first_attribute("x");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
x = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
x = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) x *= parser.vbox_->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("y");
|
attr = node->first_attribute("y");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
y = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
y = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) y *= parser.vbox_->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("width");
|
attr = node->first_attribute("width");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
w = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
w = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) w *= parser.vbox_->width;
|
||||||
}
|
}
|
||||||
attr = node->first_attribute("height");
|
attr = node->first_attribute("height");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
h = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
h = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) h *= parser.vbox_->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rounded = true;
|
bool rounded = true;
|
||||||
attr = node->first_attribute("rx");
|
attr = node->first_attribute("rx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
rx = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
rx = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) rx *= parser.vbox_->width;
|
||||||
if ( rx > 0.5 * w ) rx = 0.5 * w;
|
if ( rx > 0.5 * w ) rx = 0.5 * w;
|
||||||
}
|
}
|
||||||
else rounded = false;
|
else rounded = false;
|
||||||
|
@ -1234,7 +1304,8 @@ void parse_rect(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
attr = node->first_attribute("ry");
|
attr = node->first_attribute("ry");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
ry = parse_svg_value(parser.err_handler(), attr->value(), percent);
|
ry = parse_svg_value(parser, attr->value(), percent);
|
||||||
|
if (percent && parser.vbox_) ry *= parser.vbox_->height;
|
||||||
if ( ry > 0.5 * h ) ry = 0.5 * h;
|
if ( ry > 0.5 * h ) ry = 0.5 * h;
|
||||||
if (!rounded)
|
if (!rounded)
|
||||||
{
|
{
|
||||||
|
@ -1300,14 +1371,14 @@ void parse_rect(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||||
void parse_gradient_stop(svg_parser & parser, mapnik::gradient& gr, rapidxml::xml_node<char> const* node)
|
void parse_gradient_stop(svg_parser & parser, mapnik::gradient& gr, rapidxml::xml_node<char> const* node)
|
||||||
{
|
{
|
||||||
double offset = 0.0;
|
double offset = 0.0;
|
||||||
mapnik::color stop_color;
|
mapnik::color stop_color{0,0,0,255};
|
||||||
double opacity = 1.0;
|
double opacity = 1.0;
|
||||||
|
|
||||||
auto * attr = node->first_attribute("offset");
|
auto * attr = node->first_attribute("offset");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
bool percent = false;
|
bool percent = false;
|
||||||
offset = parse_svg_value(parser.err_handler(),attr->value(), percent);
|
offset = parse_svg_value(parser,attr->value(), percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("style");
|
attr = node->first_attribute("style");
|
||||||
|
@ -1406,39 +1477,38 @@ void parse_radial_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
|
||||||
double fx = 0.0;
|
double fx = 0.0;
|
||||||
double fy = 0.0;
|
double fy = 0.0;
|
||||||
double r = 0.5;
|
double r = 0.5;
|
||||||
bool has_percent=true;
|
bool has_percent = false;
|
||||||
|
|
||||||
attr = node->first_attribute("cx");
|
attr = node->first_attribute("cx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
cx = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
cx = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("cy");
|
attr = node->first_attribute("cy");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
cy = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
cy = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("fx");
|
attr = node->first_attribute("fx");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
fx = parse_svg_value(parser.err_handler(),attr->value(), has_percent);
|
fx = parse_svg_value(parser,attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
else
|
else fx = cx;
|
||||||
fx = cx;
|
|
||||||
|
|
||||||
attr = node->first_attribute("fy");
|
attr = node->first_attribute("fy");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
fy = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
fy = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
else fy = cy;
|
else fy = cy;
|
||||||
|
|
||||||
attr = node->first_attribute("r");
|
attr = node->first_attribute("r");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
r = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
r = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
// this logic for detecting %'s will not support mixed coordinates.
|
// this logic for detecting %'s will not support mixed coordinates.
|
||||||
if (has_percent && gr.get_units() == USER_SPACE_ON_USE)
|
if (has_percent && gr.get_units() == USER_SPACE_ON_USE)
|
||||||
|
@ -1471,40 +1541,39 @@ void parse_linear_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
|
||||||
if (!parse_common_gradient(parser, id, gr, node)) return;
|
if (!parse_common_gradient(parser, id, gr, node)) return;
|
||||||
|
|
||||||
double x1 = 0.0;
|
double x1 = 0.0;
|
||||||
double x2 = 1.0;
|
|
||||||
double y1 = 0.0;
|
double y1 = 0.0;
|
||||||
|
double x2 = 1.0;
|
||||||
double y2 = 0.0;
|
double y2 = 0.0;
|
||||||
|
|
||||||
bool has_percent=true;
|
bool has_percent = true;
|
||||||
attr = node->first_attribute("x1");
|
attr = node->first_attribute("x1");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
x1 = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
x1 = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
|
||||||
|
|
||||||
attr = node->first_attribute("x2");
|
|
||||||
if (attr != nullptr)
|
|
||||||
{
|
|
||||||
x2 = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("y1");
|
attr = node->first_attribute("y1");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
y1 = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
y1 = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = node->first_attribute("x2");
|
||||||
|
if (attr != nullptr)
|
||||||
|
{
|
||||||
|
x2 = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = node->first_attribute("y2");
|
attr = node->first_attribute("y2");
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
y2 = parse_svg_value(parser.err_handler(), attr->value(), has_percent);
|
y2 = parse_svg_value(parser, attr->value(), has_percent);
|
||||||
}
|
}
|
||||||
// this logic for detecting %'s will not support mixed coordinates.
|
// this logic for detecting %'s will not support mixed coordinates.
|
||||||
if (has_percent && gr.get_units() == USER_SPACE_ON_USE)
|
if (has_percent && gr.get_units() == USER_SPACE_ON_USE)
|
||||||
{
|
{
|
||||||
gr.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
gr.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
gr.set_gradient_type(LINEAR);
|
gr.set_gradient_type(LINEAR);
|
||||||
gr.set_control_points(x1, y1, x2, y2);
|
gr.set_control_points(x1, y1, x2, y2);
|
||||||
|
|
||||||
|
@ -1526,7 +1595,10 @@ svg_parser::svg_parser(svg_converter_type & path, bool strict)
|
||||||
is_defs_(false),
|
is_defs_(false),
|
||||||
ignore_(false),
|
ignore_(false),
|
||||||
css_style_(false),
|
css_style_(false),
|
||||||
err_handler_(strict) {}
|
err_handler_(strict)
|
||||||
|
{
|
||||||
|
font_sizes_.push_back(10.0);
|
||||||
|
}
|
||||||
|
|
||||||
svg_parser::~svg_parser() {}
|
svg_parser::~svg_parser() {}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1f20cf257f35224d3c139a6015b1cf70814b0d24
|
Subproject commit 7dd395c33a5cb5ae6b8c33bf9cd81ee296606f88
|
|
@ -149,6 +149,7 @@ TEST_CASE("SVG parser") {
|
||||||
std::string svg_name("./test/data/svg/color_fail.svg");
|
std::string svg_name("./test/data/svg/color_fail.svg");
|
||||||
char const* expected_errors[] =
|
char const* expected_errors[] =
|
||||||
{
|
{
|
||||||
|
"SVG parse error: can't infer valid image dimensions from width:\"100%\" height:\"100%\"",
|
||||||
"SVG parse error: failed to parse <color> with value \"fail\"",
|
"SVG parse error: failed to parse <color> with value \"fail\"",
|
||||||
"SVG parse error: failed to parse <number> with value \"fail\""
|
"SVG parse error: failed to parse <number> with value \"fail\""
|
||||||
};
|
};
|
||||||
|
@ -180,6 +181,7 @@ TEST_CASE("SVG parser") {
|
||||||
std::string svg_name("./test/data/svg/errors.svg");
|
std::string svg_name("./test/data/svg/errors.svg");
|
||||||
char const* expected_errors[] =
|
char const* expected_errors[] =
|
||||||
{
|
{
|
||||||
|
"SVG parse error: can't infer valid image dimensions from width:\"100%\" height:\"100%\"",
|
||||||
"SVG validation error: invalid <rect> width \"-100\"",
|
"SVG validation error: invalid <rect> width \"-100\"",
|
||||||
"SVG parse error: failed to parse <number> with value \"FAIL\"",
|
"SVG parse error: failed to parse <number> with value \"FAIL\"",
|
||||||
"SVG validation error: invalid <rect> height \"-100\"",
|
"SVG validation error: invalid <rect> height \"-100\"",
|
||||||
|
|
|
@ -90,8 +90,8 @@ struct main_marker_visitor
|
||||||
double svg_width = w * scale_factor_;
|
double svg_width = w * scale_factor_;
|
||||||
double svg_height = h * scale_factor_;
|
double svg_height = h * scale_factor_;
|
||||||
|
|
||||||
int output_width = static_cast<int>(std::round(svg_width));
|
int output_width = std::max(1, static_cast<int>(std::round(svg_width)));
|
||||||
int output_height = static_cast<int>(std::round(svg_height));
|
int output_height = std::max(1, static_cast<int>(std::round(svg_height)));
|
||||||
if (verbose_)
|
if (verbose_)
|
||||||
{
|
{
|
||||||
std::clog << "SVG width of '" << w << "' and height of '" << h << "'\n";
|
std::clog << "SVG width of '" << w << "' and height of '" << h << "'\n";
|
||||||
|
@ -102,7 +102,7 @@ struct main_marker_visitor
|
||||||
pixfmt pixf(buf);
|
pixfmt pixf(buf);
|
||||||
renderer_base renb(pixf);
|
renderer_base renb(pixf);
|
||||||
|
|
||||||
mapnik::box2d<double> const& bbox = {0, 0, svg_width, svg_height};
|
mapnik::box2d<double> bbox = {0, 0, svg_width, svg_height};
|
||||||
// center the svg marker on '0,0'
|
// center the svg marker on '0,0'
|
||||||
agg::trans_affine mtx = agg::trans_affine_translation(-0.5 * w, -0.5 * h);
|
agg::trans_affine mtx = agg::trans_affine_translation(-0.5 * w, -0.5 * h);
|
||||||
// Scale the image
|
// Scale the image
|
||||||
|
|
Loading…
Reference in a new issue