[librsvg: 67/90] Nested temporary surfaces should not be offset with respect to each other



commit 7b07dd55b23c6ce4cb73a951b04beacf5e43b40c
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Mar 21 12:41:57 2019 -0600

    Nested temporary surfaces should not be offset with respect to each other
    
    This has a new test, compound_opacity, which captures the failing
    parts of masking-opacity-01-b.svg.
    
    760 pass, 6 fail

 librsvg_crate/tests/primitives.rs | 61 +++++++++++++++++++++++++++++++++++++++
 rsvg_internals/src/drawing_ctx.rs | 22 +++++++++-----
 2 files changed, 76 insertions(+), 7 deletions(-)
---
diff --git a/librsvg_crate/tests/primitives.rs b/librsvg_crate/tests/primitives.rs
index e5c01699..21fc65c0 100644
--- a/librsvg_crate/tests/primitives.rs
+++ b/librsvg_crate/tests/primitives.rs
@@ -10,6 +10,8 @@ use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceT
 
 use self::utils::{load_svg, render_to_viewport, compare_to_surface, SurfaceSize};
 
+use std::fs::File;
+
 #[test]
 fn simple_opacity_with_transform() {
     let svg = load_svg(
@@ -132,3 +134,62 @@ fn opacity_inside_transformed_group() {
 
     compare_to_surface(&output_surf, &reference_surf, "opacity_inside_transformed_group");
 }
+
+#[test]
+fn compound_opacity() {
+    let svg = load_svg(
+        br##"<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" baseProfile="basic" id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>
+  <g>
+    <g opacity="0.5">
+      <rect x="60" y="230" width="80" height="40" fill="#0000ff" opacity=".5"/>
+      <rect x="70" y="240" width="80" height="40" fill="#00ff00" opacity=".5"/>
+    </g>
+  </g>
+</svg>
+"##,
+    );
+
+    let output_surf = render_to_viewport(
+        &svg,
+        SurfaceSize(500, 380),
+        |cr| cr.translate(10.0, 10.0),
+        cairo::Rectangle {
+            x: 0.0,
+            y: 0.0,
+            width: 480.0,
+            height: 360.0,
+        },
+    )
+    .unwrap();
+
+    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 380).unwrap();
+
+    {
+        let cr = cairo::Context::new(&reference_surf);
+
+        cr.translate(10.0, 10.0);
+
+        cr.push_group();
+
+        cr.rectangle(60.0, 230.0, 80.0, 40.0);
+        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
+        cr.fill();
+
+        cr.rectangle(70.0, 240.0, 80.0, 40.0);
+        cr.set_source_rgba(0.0, 1.0, 0.0, 0.5);
+        cr.fill();
+
+        cr.pop_group_to_source();
+        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");
+}
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 236697fe..e59b9210 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -463,6 +463,15 @@ impl DrawingCtx {
                     && enable_background == EnableBackground::Accumulate);
 
                 if needs_temporary_surface {
+                    let stack_was_empty = dc.cr_stack.len() == 0;
+
+                    let affine = if stack_was_empty {
+                        affine
+                    } else {
+                        let initial_inverse = dc.initial_affine_with_offset().try_invert().unwrap();
+                        cairo::Matrix::multiply(&affine, &initial_inverse)
+                    };
+
                     let cr = if filter.is_some() {
                         cairo::Context::new(&dc.create_surface_for_toplevel_viewport()?)
                     } else {
@@ -471,8 +480,6 @@ impl DrawingCtx {
                         )
                     };
 
-                    let stack_was_empty = dc.cr_stack.len() == 0;
-
                     let temporary_affine = if stack_was_empty {
                         let initial_inverse = dc.initial_affine_with_offset().try_invert().unwrap();
                         let untransformed = cairo::Matrix::multiply(&affine, &initial_inverse);
@@ -505,13 +512,15 @@ impl DrawingCtx {
 
                     dc.cr = dc.cr_stack.pop().unwrap();
 
-                    let save_matrix = dc.cr.get_matrix();
+                    let paint_affine = if stack_was_empty {
+                        dc.initial_affine_with_offset()
+                    } else {
+                        cairo::Matrix::identity()
+                    };
 
-                    dc.cr.set_matrix(dc.initial_affine_with_offset());
+                    dc.cr.set_matrix(paint_affine);
                     dc.cr.set_source_surface(&source_surface, 0.0, 0.0);
 
-                    assert!(affine == save_matrix);
-
                     dc.cr.set_matrix(affine);
                     dc.clip_to_node(&clip_in_object_space)?;
 
@@ -535,7 +544,6 @@ impl DrawingCtx {
                             );
                         }
                     } else {
-                        let paint_affine = dc.initial_affine_with_offset();
                         dc.cr.set_matrix(paint_affine);
 
                         if opacity < 1.0 {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]