[librsvg] (#309): Don't panic if rendering to a non-image surface



commit e7de8f25b8049c186975ef510e2bd41d62397ae7
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Jul 20 10:27:42 2018 -0700

    (#309): Don't panic if rendering to a non-image surface
    
    The somewhat convoluted code in with_discrete_layer() was trying to
    create a cairo::ImageSurface from the incoming cr's target, which may
    in fact not be an image surface.
    
    We now have a test for this, too.
    
    https://gitlab.gnome.org/GNOME/librsvg/issues/309

 rsvg_internals/src/drawing_ctx.rs | 48 ++++++++++++++++++---------------------
 tests/api.c                       | 33 +++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 26 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index d90b072a..afa8ae71 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -301,39 +301,35 @@ impl<'a> DrawingCtx<'a> {
                 && comp_op == CompOp::SrcOver
                 && enable_background == EnableBackground::Accumulate);
 
-            let child_surface = {
-                if needs_temporary_surface {
-                    // FIXME: in the following, we unwrap() the result of
-                    // ImageSurface::create().  We have to decide how to handle
-                    // out-of-memory here.
-                    let surface = cairo::ImageSurface::create(
-                        cairo::Format::ARgb32,
-                        self.rect.width as i32,
-                        self.rect.height as i32,
-                    ).unwrap();
-
-                    if filter.is_some() {
-                        self.surfaces_stack.push(surface.clone());
-                    }
-
-                    let cr = cairo::Context::new(&surface);
-                    cr.set_matrix(affine);
+            if needs_temporary_surface {
+                // FIXME: in the following, we unwrap() the result of
+                // ImageSurface::create().  We have to decide how to handle
+                // out-of-memory here.
+                let surface = cairo::ImageSurface::create(
+                    cairo::Format::ARgb32,
+                    self.rect.width as i32,
+                    self.rect.height as i32,
+                ).unwrap();
+
+                if filter.is_some() {
+                    self.surfaces_stack.push(surface.clone());
+                }
 
-                    self.cr_stack.push(self.cr.clone());
-                    self.cr = cr.clone();
+                let cr = cairo::Context::new(&surface);
+                cr.set_matrix(affine);
 
-                    self.bbox_stack.push(self.bbox);
-                    self.bbox = BoundingBox::new(&affine);
+                self.cr_stack.push(self.cr.clone());
+                self.cr = cr.clone();
 
-                    surface
-                } else {
-                    cairo::ImageSurface::from(original_cr.get_target()).unwrap()
-                }
-            };
+                self.bbox_stack.push(self.bbox);
+                self.bbox = BoundingBox::new(&affine);
+            }
 
             draw_fn(self);
 
             if needs_temporary_surface {
+                let child_surface = cairo::ImageSurface::from(self.cr.get_target()).unwrap();
+
                 let filter_result_surface = filter
                     .and_then(|_| {
                         // About the following unwrap(), see the FIXME above.  We should be pushing
diff --git a/tests/api.c b/tests/api.c
index 75b5d7af..73412041 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -491,6 +491,38 @@ detects_cairo_context_in_error (void)
     g_test_trap_assert_stderr ("*WARNING*cannot render on a cairo_t with a failure status*");
 }
 
+static void
+can_draw_to_non_image_surface (void)
+{
+    cairo_rectangle_t rect;
+    cairo_surface_t *surface;
+    cairo_t *cr;
+
+    char *filename = get_test_filename ("example.svg");
+    GError *error = NULL;
+
+    RsvgHandle *handle = rsvg_handle_new_from_file (filename, &error);
+    g_assert (handle != NULL);
+    g_assert (error == NULL);
+
+    rect.x = 0.0;
+    rect.y = 0.0;
+    rect.width = 100.0;
+    rect.height = 100.0;
+
+    /* We create a surface that is not a Cairo image surface,
+     * so we can test that in fact we can render to non-image surfaces.
+     */
+    surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &rect);
+    cr = cairo_create (surface);
+
+    g_assert (rsvg_handle_render_cairo (handle, cr));
+
+    g_object_unref (handle);
+
+    cairo_destroy (cr);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -518,6 +550,7 @@ main (int argc, char **argv)
     g_test_add_func ("/api/handle_get_pixbuf_sub", handle_get_pixbuf_sub);
     g_test_add_func ("/api/dimensions_and_position", dimensions_and_position);
     g_test_add_func ("/api/detects_cairo_context_in_error", detects_cairo_context_in_error);
+    g_test_add_func ("/api/can_draw_to_non_image_surface", can_draw_to_non_image_surface);
 
     return g_test_run ();
 }


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