[librsvg] (#471): Fix blurry markers when rendering at larger than 1:1 scale
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] (#471): Fix blurry markers when rendering at larger than 1:1 scale
- Date: Sat, 29 Jun 2019 01:41:12 +0000 (UTC)
commit 7af8239a30f139179011b4d3072ac69a7e573a27
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Jun 18 15:07:04 2019 -0500
(#471): Fix blurry markers when rendering at larger than 1:1 scale
Apparently I didn't understand that
cairo_matrix.scale(x, y)
is not the same as
scale = cairo_matrix_init_scale(x, y);
cairo_matrix = Matrix::multiply(cairo_matrix, scale)
and we needed the latter.
This includes a new test for rendering markers when the initial affine
is not at 1:1 scale.
This commit also makes the markers code modify the cr's transformation
with its own methods, instead of messing with the affine by hand.
librsvg_crate/tests/primitives.rs | 62 +++++++++++++++++++++++++++++++++++++++
rsvg_internals/src/drawing_ctx.rs | 6 ++--
rsvg_internals/src/marker.rs | 60 +++++++++++++++++--------------------
3 files changed, 92 insertions(+), 36 deletions(-)
---
diff --git a/librsvg_crate/tests/primitives.rs b/librsvg_crate/tests/primitives.rs
index 13f6f15a..c3941292 100644
--- a/librsvg_crate/tests/primitives.rs
+++ b/librsvg_crate/tests/primitives.rs
@@ -146,6 +146,68 @@ fn simple_opacity_with_scale() {
);
}
+#[test]
+// https://gitlab.gnome.org/GNOME/librsvg/issues/471
+fn markers_with_scale() {
+ let svg = load_svg(
+ br#"<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
+ <marker id="marker1" refX="10" refY="10" markerWidth="20" markerHeight="20" orient="auto">
+ <path id="marker-path" d="M 20 10 L 0 16 V 4 Z" fill="blue" opacity="0.5"/>
+ </marker>
+ <path d="M 30 100 L 170 100"
+ fill="none" stroke="green"
+ marker-start="url(#marker1)" marker-end="url(#marker1)"/>
+</svg>
+
+"#,
+ );
+
+ let output_surf = render_to_viewport(
+ &svg,
+ SurfaceSize(800, 800),
+ |cr| {
+ cr.scale(4.0, 4.0);
+ },
+ cairo::Rectangle {
+ x: 0.0,
+ y: 0.0,
+ width: 200.0,
+ height: 200.0,
+ },
+ )
+ .unwrap();
+
+ let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 800, 800).unwrap();
+
+ {
+ let cr = cairo::Context::new(&reference_surf);
+
+ cr.scale(4.0, 4.0);
+
+ cr.move_to(30.0, 100.0);
+ cr.line_to(170.0, 100.0);
+ cr.set_source_rgb(0.0, 0.5, 0.0);
+ cr.set_line_width(1.0);
+ cr.stroke();
+
+ for (x, y) in &[(30.0, 100.0), (170.0, 100.0)] {
+ cr.move_to(x + 20.0 - 10.0, y + 10.0 - 10.0);
+ cr.line_to(x + 0.0 - 10.0, y + 16.0 - 10.0);
+ cr.line_to(x + 0.0 - 10.0, y + 4.0 - 10.0);
+ cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
+ cr.fill();
+ }
+ }
+
+ let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();
+
+ compare_to_surface(
+ &output_surf,
+ &reference_surf,
+ "markers_with_scale",
+ );
+}
+
#[test]
fn opacity_inside_transformed_group() {
let svg = load_svg(
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index ce0a6874..0bb1b2ca 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -879,6 +879,7 @@ impl DrawingCtx {
}
}
+#[derive(Debug)]
pub struct CompositingAffines {
pub outside_temporary_surface: cairo::Matrix,
pub initial: cairo::Matrix,
@@ -907,9 +908,8 @@ impl CompositingAffines {
let for_temporary_surface = if is_topmost_temporary_surface {
let untransformed = cairo::Matrix::multiply(¤t, &initial_inverse);
- let mut scaled_to_temp_surface = untransformed;
- scaled_to_temp_surface.scale(scale_x, scale_y);
- scaled_to_temp_surface
+ let scale = cairo::Matrix::new(scale_x, 0.0, 0.0, scale_y, 0.0, 0.0);
+ cairo::Matrix::multiply(&untransformed, &scale)
} else {
current
};
diff --git a/rsvg_internals/src/marker.rs b/rsvg_internals/src/marker.rs
index 39277f79..5e453621 100644
--- a/rsvg_internals/src/marker.rs
+++ b/rsvg_internals/src/marker.rs
@@ -140,49 +140,43 @@ impl NodeMarker {
return Ok(());
}
- let cr = draw_ctx.get_cairo_context();
-
- let mut affine = cr.get_matrix();
-
- affine.translate(xpos, ypos);
-
- let rotation = match self.orient.get() {
- MarkerOrient::Auto => computed_angle,
- MarkerOrient::Angle(a) => a,
- };
+ draw_ctx.with_saved_cr(&mut |dc| {
+ let cr = dc.get_cairo_context();
- affine.rotate(rotation.radians());
+ cr.translate(xpos, ypos);
- if self.units.get() == MarkerUnits::StrokeWidth {
- affine.scale(line_width, line_width);
- }
+ let rotation = match self.orient.get() {
+ MarkerOrient::Auto => computed_angle,
+ MarkerOrient::Angle(a) => a,
+ };
- let params = if let Some(vbox) = self.vbox.get() {
- let (_, _, w, h) = self.aspect.get().compute(
- &vbox,
- &Rectangle::new(0.0, 0.0, marker_width, marker_height),
- );
+ cr.rotate(rotation.radians());
- if vbox.width.approx_eq_cairo(&0.0) || vbox.height.approx_eq_cairo(&0.0) {
- return Ok(());
+ if self.units.get() == MarkerUnits::StrokeWidth {
+ cr.scale(line_width, line_width);
}
- affine.scale(w / vbox.width, h / vbox.height);
+ let params = if let Some(vbox) = self.vbox.get() {
+ let (_, _, w, h) = self.aspect.get().compute(
+ &vbox,
+ &Rectangle::new(0.0, 0.0, marker_width, marker_height),
+ );
- draw_ctx.push_view_box(vbox.width, vbox.height)
- } else {
- draw_ctx.push_view_box(marker_width, marker_height)
- };
+ if vbox.width.approx_eq_cairo(&0.0) || vbox.height.approx_eq_cairo(&0.0) {
+ return Ok(());
+ }
- affine.translate(
- -self.ref_x.get().normalize(&values, ¶ms),
- -self.ref_y.get().normalize(&values, ¶ms),
- );
+ cr.scale(w / vbox.width, h / vbox.height);
- draw_ctx.with_saved_cr(&mut |dc| {
- let cr = dc.get_cairo_context();
+ dc.push_view_box(vbox.width, vbox.height)
+ } else {
+ dc.push_view_box(marker_width, marker_height)
+ };
- cr.set_matrix(affine);
+ cr.translate(
+ -self.ref_x.get().normalize(&values, ¶ms),
+ -self.ref_y.get().normalize(&values, ¶ms),
+ );
if !values.is_overflow() {
if let Some(vbox) = self.vbox.get() {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]