[librsvg: 84/90] Push/pop the cairo_t while drawing a mask's contents



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]