SVG - improve handling of gradientUnits and gradientTransform attributes (radial gradient) + correct default values [skip ci]

This commit is contained in:
Artem Pavlenko 2024-02-15 11:46:17 +00:00
parent 1c6d14eb85
commit dcfb2d692c
4 changed files with 33 additions and 25 deletions

View file

@ -64,6 +64,8 @@ MAPNIK_DISABLE_WARNING_PUSH
#include "agg_span_interpolator_linear.h"
MAPNIK_DISABLE_WARNING_POP
#include <ostream>
namespace mapnik {
namespace svg {
@ -222,16 +224,14 @@ class renderer_agg : util::noncopyable
}
if (m_gradient_lut.build_lut())
{
agg::trans_affine transform = mtx;
double scale = mtx.scale();
transform.invert();
agg::trans_affine tr;
tr = grad.get_transform();
tr.invert();
agg::trans_affine tr = mtx;
agg::trans_affine transform = grad.get_transform();
transform *= tr;
transform.invert();
if (grad.get_units() != USER_SPACE_ON_USE)
{
double scale = mtx.scale();
double bx1 = symbol_bbox.minx();
double by1 = symbol_bbox.miny();
double bx2 = symbol_bbox.maxx();
@ -244,7 +244,17 @@ class renderer_agg : util::noncopyable
transform.translate(-bx1 / scale, -by1 / scale);
transform.scale(scale / (bx2 - bx1), scale / (by2 - by1));
}
else
{
double scaledown = 255;
x1 /= scaledown; // fx
y1 /= scaledown; // fy
x2 /= scaledown; // cx
y2 /= scaledown; // cy
radius /= scaledown;
transform.translate(-symbol_bbox.minx(), -symbol_bbox.miny());
transform.scale(1 / scaledown, 1 / scaledown);
}
if (grad.get_gradient_type() == RADIAL)
{
using gradient_adaptor_type = agg::gradient_radial_focus;
@ -253,7 +263,6 @@ class renderer_agg : util::noncopyable
// the agg radial gradient assumes it is centred on 0
transform.translate(-x2, -y2);
// scale everything up since agg turns things into integers a bit too soon
int scaleup = 255;
radius *= scaleup;
@ -261,7 +270,6 @@ class renderer_agg : util::noncopyable
y1 *= scaleup;
x2 *= scaleup;
y2 *= scaleup;
transform.scale(scaleup, scaleup);
interpolator_type span_interpolator(transform);

View file

@ -70,8 +70,8 @@ gradient& gradient::operator=(gradient rhs)
bool gradient::operator==(gradient const& other) const
{
return transform_ == other.transform_ && x1_ == other.x1_ && y1_ == other.y1_ && x2_ == other.x2_ &&
y2_ == other.y2_ && r_ == other.r_ && std::equal(stops_.begin(), stops_.end(), other.stops_.begin()) &&
units_ == other.units_ && gradient_type_ == other.gradient_type_;
y2_ == other.y2_ && r_ == other.r_ && std::equal(stops_.begin(), stops_.end(), other.stops_.begin()) &&
units_ == other.units_ && gradient_type_ == other.gradient_type_;
}
void gradient::set_gradient_type(gradient_e grad)

View file

@ -1533,8 +1533,8 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
return;
double cx = 0.5;
double cy = 0.5;
double fx = 0.0;
double fy = 0.0;
double fx = 0.5;
double fy = 0.5;
double r = 0.5;
bool has_percent = false;
@ -1543,12 +1543,20 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
{
cx = parse_svg_value(parser, attr->value(), has_percent);
}
else if (gr.get_units() == USER_SPACE_ON_USE)
{
cx = 0.5 * (parser.vbox_ ? parser.vbox_->width : parser.path_.width()); // 50%
}
attr = node->first_attribute("cy");
if (attr != nullptr)
{
cy = parse_svg_value(parser, attr->value(), has_percent);
}
else if (gr.get_units() == USER_SPACE_ON_USE)
{
cy = 0.5 * (parser.vbox_ ? parser.vbox_->height : parser.path_.height()); // 50%
}
attr = node->first_attribute("fx");
if (attr != nullptr)
@ -1573,19 +1581,11 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
{
r = parse_svg_value(parser, attr->value(), has_percent);
}
// this logic for detecting %'s will not support mixed coordinates.
if (gr.get_units() == USER_SPACE_ON_USE)
else if (gr.get_units() == USER_SPACE_ON_USE)
{
if (!has_percent && parser.path_.width() > 0 && parser.path_.height() > 0)
{
fx /= parser.path_.width();
fy /= parser.path_.height();
cx /= parser.path_.width();
cy /= parser.path_.height();
r /= parser.path_.width();
}
gr.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
r = 0.5 * parser.normalized_diagonal_; // 50%
}
gr.set_gradient_type(RADIAL);
gr.set_control_points(fx, fy, cx, cy, r);

@ -1 +1 @@
Subproject commit ac363ee887d2a55039fd19390c186663d8f0f206
Subproject commit 540561debb38280deb1b9598de1724e0ebd8df49