[librsvg: 21/53] Start comparing to the reference images




commit fb37a68896f1e47101854adf258ac23d275dbb87
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Oct 14 18:40:20 2020 -0500

    Start comparing to the reference images
    
    A bunch succeed, a bunch fail.  Still missing:
    
    * Set the "testing" flag.
    * Create and set an FcConfig.
    * Environment vars for language tests.

 Cargo.lock             |   1 +
 tests/Cargo.toml       |   1 +
 tests/src/reference.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 136 insertions(+), 10 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 03227de2..fe05794d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -788,6 +788,7 @@ dependencies = [
  "lopdf",
  "png",
  "predicates",
+ "rsvg_internals",
  "tempfile",
  "test-generator",
 ]
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
index 932b4ab6..256c13f7 100644
--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -15,5 +15,6 @@ librsvg = { path = "../librsvg_crate" }
 lopdf = "0.25.0"
 png = "0.16.1"
 predicates = "1.0.2"
+rsvg_internals = { path = "../rsvg_internals" }
 tempfile = "3"
 test-generator = "0.3"
diff --git a/tests/src/reference.rs b/tests/src/reference.rs
index d9ffca17..4efeb420 100644
--- a/tests/src/reference.rs
+++ b/tests/src/reference.rs
@@ -10,36 +10,73 @@
 use test_generator::test_resources;
 
 use cairo;
-use librsvg::{CairoRenderer, IntrinsicDimensions, Length, LengthUnit, Loader};
+use librsvg::{CairoRenderer, IntrinsicDimensions, Length, Loader};
+use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
 use std::fs::File;
 use std::io::BufReader;
 use std::path::PathBuf;
 
 use crate::utils::fixture_path;
 
+use self::duplicated_from_librsvg_crate::compare_to_file;
+
 // The original reference images from the SVG1.1 test suite are at 72 DPI.
 const TEST_SUITE_DPI: f64 = 72.0;
 
+// https://gitlab.gnome.org/GNOME/librsvg/issues/91
+//
+// We were computing some offsets incorrectly if the initial transformation matrix
+// passed to rsvg_handle_render_cairo() was not the identity matrix.  So,
+// we create a surface with a "frame" around the destination for the image,
+// and then only consider the pixels inside the frame.  This will require us
+// to have a non-identity transformation (i.e. a translation matrix), which
+// will test for this bug.
+//
+// The frame size is meant to be a ridiculous number to simulate an arbitrary
+// offset.
+const FRAME_SIZE: i32 = 47;
+
 fn reference_test(name: &str) {
     let path = fixture_path(name);
-    if path.file_stem().unwrap().to_string_lossy().starts_with("ignore") {
+    let path_base_name = path.file_stem().unwrap().to_string_lossy().to_owned();
+    if path_base_name.starts_with("ignore") {
         return;
     }
 
     let reference = reference_path(&path);
 
     let handle = Loader::new()
-        .read_path(path)
+        .read_path(&path)
         .unwrap_or_else(|e| panic!("could not load: {}", e));
 
     let renderer = CairoRenderer::new(&handle).with_dpi(TEST_SUITE_DPI, TEST_SUITE_DPI);
-
     let (width, height) = image_size(renderer.intrinsic_dimensions(), TEST_SUITE_DPI);
 
-    let mut reference_file = BufReader::new(File::open(reference).unwrap());
-    let expected = cairo::ImageSurface::create_from_png(&mut reference_file).unwrap();
+    let surface = cairo::ImageSurface::create(
+        cairo::Format::ARgb32,
+        width + 2 * FRAME_SIZE,
+        height + 2 * FRAME_SIZE,
+    ).unwrap();
+
+    {
+        let cr = cairo::Context::new(&surface);
+        cr.translate(f64::from(FRAME_SIZE), f64::from(FRAME_SIZE));
+        renderer.render_document(
+            &cr,
+            &cairo::Rectangle {
+                x: 0.0,
+                y: 0.0,
+                width: f64::from(width),
+                height: f64::from(height),
+            }
+        ).unwrap();
+    }
+
+    let surface = extract_rectangle(&surface, FRAME_SIZE, FRAME_SIZE, width, height).unwrap();
+
+    let output_surf = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();
 
-    assert!(width == expected.get_width() && height == expected.get_height());
+    compare_to_file(&output_surf, &path_base_name, &reference);
 }
 
 /// Turns `/foo/bar/baz.svg` into `/foo/bar/baz-ref.svg`.
@@ -52,6 +89,14 @@ fn reference_path(path: &PathBuf) -> PathBuf {
     path.with_file_name(reference_filename)
 }
 
+fn extract_rectangle(source: &cairo::ImageSurface, x: i32, y: i32, w: i32, h: i32) -> 
Result<cairo::ImageSurface, cairo::Status> {
+    let dest = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
+    let cr = cairo::Context::new(&dest);
+    cr.set_source_surface(&source, f64::from(-x), f64::from(-y));
+    cr.paint();
+    Ok(dest)
+}
+
 /// Computes the (width, height) pixel size at which an SVG should be rendered, based on its intrinsic 
dimensions.
 ///
 /// # Panics:
@@ -67,7 +112,7 @@ fn image_size(dim: IntrinsicDimensions, dpi: f64) -> (i32, i32) {
         vbox,
     } = dim;
 
-    use LengthUnit::*;
+    use librsvg::LengthUnit::*;
 
     if let (Some(width), Some(height)) = (width, height) {
         if !(has_supported_unit(&width) && has_supported_unit(&height)) {
@@ -113,7 +158,7 @@ fn checked_i32(x: f64) -> i32 {
 }
 
 fn has_supported_unit(l: &Length) -> bool {
-    use LengthUnit::*;
+    use librsvg::LengthUnit::*;
 
     match l.unit {
         Percent | Px | In | Cm | Mm | Pt | Pc => true,
@@ -127,7 +172,7 @@ const MM_PER_INCH: f64 = 25.4;
 const PICA_PER_INCH: f64 = 6.0;
 
 fn normalize(l: &Length, dpi: f64) -> f64 {
-    use LengthUnit::*;
+    use librsvg::LengthUnit::*;
 
     match l.unit {
         Px => l.length,
@@ -140,6 +185,85 @@ fn normalize(l: &Length, dpi: f64) -> f64 {
     }
 }
 
+// FIXME: see how to share this code
+mod duplicated_from_librsvg_crate {
+    use super::*;
+    use std::env;
+    use std::fs;
+    use rsvg_internals::{compare_surfaces, BufferDiff};
+
+    fn output_dir() -> PathBuf {
+        let path = PathBuf::from(
+            env::var_os("OUT_DIR")
+                .expect(r#"OUT_DIR is not set, please set it or run under "cargo test""#),
+        );
+
+        fs::create_dir_all(&path).expect("could not create output directory for tests");
+
+        println!("outputting to {}", path.to_string_lossy());
+
+        path
+    }
+
+    // FIXME: this is slightly different from librsvg_crate
+    pub fn compare_to_file(
+        output_surf: &SharedImageSurface,
+        output_base_name: &str,
+        reference_path: &PathBuf,
+    ) {
+        let file = File::open(reference_path).unwrap();
+
+        let mut reference_file = BufReader::new(file);
+
+        let reference = cairo::ImageSurface::create_from_png(&mut reference_file).unwrap();
+        let reference_surf = SharedImageSurface::wrap(reference, SurfaceType::SRgb).unwrap();
+
+        compare_to_surface(output_surf, &reference_surf, output_base_name);
+    }
+
+    fn compare_to_surface(
+        output_surf: &SharedImageSurface,
+        reference_surf: &SharedImageSurface,
+        output_base_name: &str,
+    ) {
+        let output_path = output_dir().join(&format!("{}-out.png", output_base_name));
+
+        let mut output_file = File::create(output_path).unwrap();
+        output_surf
+            .clone()
+            .into_image_surface()
+            .unwrap()
+            .write_to_png(&mut output_file)
+            .unwrap();
+
+        let diff = compare_surfaces(output_surf, reference_surf).unwrap();
+        evaluate_diff(&diff, output_base_name);
+    }
+
+    const MAX_DIFF: u8 = 2;
+
+    fn evaluate_diff(diff: &BufferDiff, output_base_name: &str) {
+        match diff {
+            BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),
+
+            BufferDiff::Diff(diff) => {
+                let surf = diff.surface.clone().into_image_surface().unwrap();
+                let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
+                let mut output_file = File::create(diff_path).unwrap();
+                surf.write_to_png(&mut output_file).unwrap();
+
+                if diff.num_pixels_changed != 0 && diff.max_diff > MAX_DIFF {
+                    println!(
+                        "{}: {} pixels changed with maximum difference of {}",
+                        output_base_name, diff.num_pixels_changed, diff.max_diff,
+                    );
+                    panic!("surfaces are too different");
+                }
+            }
+        }
+    }
+}
+
 #[test_resources("tests/fixtures/reftests/*.svg")]
 fn reftests(name: &str) {
     reference_test(name);


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