[librsvg: 84/90] Push/pop the cairo_t while drawing a mask's contents
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 84/90] Push/pop the cairo_t while drawing a mask's contents
- Date: Tue, 26 Mar 2019 19:19:08 +0000 (UTC)
commit 465c2073e7d7be0018c2fb15b9df04e0eef386ff
Author: Federico Mena Quintero <federico gnome org>
Date: Fri Mar 22 13:03:14 2019 -0600
Push/pop the cairo_t while drawing a mask's contents
This includes a new test, nested_masks in
librsvg_crate/tests/primitives.rs, which captures the parts that were
broken in 761175-recursive-masks.svg.
The problem is that masks were always drawn *outside* of the nested
cr. The mask was drawn to a temporary surface, but the
DrawingCtx was not aware that the mask was using a temporary cr for
that surface. So, the test for the cr_stack depth in
CompositingAffines::new() wasn't aware of that temporary cr.
We need to unify the "draw stuff to a temporary surface" abstraction.
765 pass, 1 fail
librsvg_crate/tests/primitives.rs | 70 +++++++++++++++++++++++++++++++++++++--
rsvg_internals/src/drawing_ctx.rs | 16 +++++++--
rsvg_internals/src/mask.rs | 8 ++---
3 files changed, 83 insertions(+), 11 deletions(-)
---
diff --git a/librsvg_crate/tests/primitives.rs b/librsvg_crate/tests/primitives.rs
index 21fc65c0..d88ff6c0 100644
--- a/librsvg_crate/tests/primitives.rs
+++ b/librsvg_crate/tests/primitives.rs
@@ -186,10 +186,74 @@ fn compound_opacity() {
cr.paint_with_alpha(0.5);
}
- let mut file = File::create("/tmp/reference.png").unwrap();
- reference_surf.write_to_png(&mut file).unwrap();
-
let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();
compare_to_surface(&output_surf, &reference_surf, "compound_opacity");
}
+
+#[test]
+fn nested_masks() {
+ let svg = load_svg(
+ br##"<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="321.00" height="27.00" viewBox="0 0 6420 540">
+ <defs>
+ <mask id="Mask_big_ex_small" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540">
+ <g>
+ <use xlink:href="#big" fill="white"/>
+ <use xlink:href="#small" fill="black"/>
+ </g>
+ </mask>
+ <g id="big_ex_small">
+ <use xlink:href="#big" mask="url(#Mask_big_ex_small)"/>
+ </g>
+ <mask id="Region0" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
+ <use xlink:href="#big_ex_small" fill="white"/>
+ </mask>
+ <rect id="big" x="0" y="0" width="6420" height="540"/>
+ <rect id="small" x="2760" y="20" width="900" height="480"/>
+ </defs>
+ <g mask="url(#Region0)">
+ <g transform="matrix(1.66667 0 0 1.66667 0 0)">
+ <rect x="0" y="0" width="6420" height="540" fill="black"/>
+ </g>
+ </g>
+</svg>
+
+"##,
+ );
+
+ let output_surf = render_to_viewport(
+ &svg,
+ SurfaceSize(321 + 20, 27 + 20),
+ |cr| cr.translate(10.0, 10.0),
+ cairo::Rectangle {
+ x: 0.0,
+ y: 0.0,
+ width: 321.0,
+ height: 27.0,
+ },
+ )
+ .unwrap();
+
+ let reference_surf =
+ cairo::ImageSurface::create(cairo::Format::ARgb32, 321 + 20, 27 + 20).unwrap();
+
+ {
+ let cr = cairo::Context::new(&reference_surf);
+
+ cr.translate(10.0, 10.0);
+ cr.scale(321.0 / 6420.0, 27.0 / 540.0);
+
+ cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
+ cr.rectangle(0.0, 0.0, 6420.0, 540.0);
+ cr.fill();
+
+ cr.set_operator(cairo::Operator::Clear);
+ cr.rectangle(2760.0, 20.0, 900.0, 480.0);
+ cr.fill();
+ }
+
+ let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();
+
+ compare_to_surface(&output_surf, &reference_surf, "nested_masks");
+}
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index f0936f6e..a6fb0ae6 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -205,6 +205,17 @@ impl DrawingCtx {
self.cr = cr.clone();
}
+ // Temporary hack while we unify surface/cr/affine creation
+ pub fn push_cairo_context(&mut self, cr: cairo::Context) {
+ self.cr_stack.push(self.cr.clone());
+ self.cr = cr;
+ }
+
+ // Temporary hack while we unify surface/cr/affine creation
+ pub fn pop_cairo_context(&mut self) {
+ self.cr = self.cr_stack.pop().unwrap();
+ }
+
pub fn create_surface_for_toplevel_viewport(
&self,
) -> Result<cairo::ImageSurface, RenderingError> {
@@ -483,8 +494,7 @@ impl DrawingCtx {
cr.set_matrix(affines.for_temporary_surface);
- dc.cr_stack.push(dc.cr.clone());
- dc.cr = cr;
+ dc.push_cairo_context(cr);
// Create temporary bbox with the cr's affine
@@ -508,7 +518,7 @@ impl DrawingCtx {
dc.cr.get_target()
};
- dc.cr = dc.cr_stack.pop().unwrap();
+ dc.pop_cairo_context();
// Set temporary surface as source
diff --git a/rsvg_internals/src/mask.rs b/rsvg_internals/src/mask.rs
index da5250a9..e1fd01bd 100644
--- a/rsvg_internals/src/mask.rs
+++ b/rsvg_internals/src/mask.rs
@@ -87,13 +87,11 @@ impl NodeMask {
// Use a scope because mask_cr needs to release the
// reference to the surface before we access the pixels
{
- let save_cr = draw_ctx.get_cairo_context();
-
let mask_cr = cairo::Context::new(&mask_content_surface);
mask_cr.set_matrix(affines.for_temporary_surface);
mask_cr.transform(mask_node.get_transform());
- draw_ctx.set_cairo_context(&mask_cr);
+ draw_ctx.push_cairo_context(mask_cr);
if mask_units == CoordUnits::ObjectBoundingBox {
draw_ctx.clip(
@@ -117,7 +115,7 @@ impl NodeMask {
bbox_rect.y,
);
- mask_cr.transform(bbtransform);
+ draw_ctx.get_cairo_context().transform(bbtransform);
draw_ctx.push_view_box(1.0, 1.0)
} else {
@@ -128,7 +126,7 @@ impl NodeMask {
mask_node.draw_children(&cascaded, dc, false)
});
- draw_ctx.set_cairo_context(&save_cr);
+ draw_ctx.pop_cairo_context();
res
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]