[librsvg/librsvg-2.42] (#276) - Guard against getting a cairo_t in an error state at the toplevel API



commit b99692db46e2a6c61d37a70165198ad029c4ec69
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Jun 1 09:59:24 2018 -0500

    (#276) - Guard against getting a cairo_t in an error state at the toplevel API
    
    The cairo-dock program was passing a cairo_t in an error state to
    rsvg_handle_render_cairo(), and so we failed deep in the innards of
    librsvg when cairo-rs validates the cairo::Context's status.
    
    Cairo-dock was doing something like
    
      surf = cairo_image_surface_create (... an invalid size ...);
      cr = cairo_create (surf);
    
      rsvg_handle_render_cairo (handle, cr);    // we now catch the error right here
    
    We catch invalid cr's, emit a warning, and return FALSE from
    rsvg_handle_render_cairo*().
    
    https://gitlab.gnome.org/GNOME/librsvg/issues/276

 librsvg/rsvg-cairo-render.c | 11 +++++++++++
 tests/api.c                 | 27 +++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)
---
diff --git a/librsvg/rsvg-cairo-render.c b/librsvg/rsvg-cairo-render.c
index 112d59f9..c8c66efc 100644
--- a/librsvg/rsvg-cairo-render.c
+++ b/librsvg/rsvg-cairo-render.c
@@ -224,16 +224,27 @@ rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id)
 {
     RsvgDrawingCtx *draw;
     RsvgNode *drawsub = NULL;
+    cairo_status_t status;
 
     g_return_val_if_fail (handle != NULL, FALSE);
 
     if (handle->priv->state != RSVG_HANDLE_STATE_CLOSED_OK)
         return FALSE;
 
+    status = cairo_status (cr);
+
+    if (status != CAIRO_STATUS_SUCCESS) {
+        g_warning ("cannot render on a cairo_t with a failure status (status=%d, %s)",
+                   (int) status,
+                   cairo_status_to_string (status));
+        return FALSE;
+    }
+
     if (id && *id)
         drawsub = rsvg_defs_lookup (handle->priv->defs, id);
 
     if (drawsub == NULL && id != NULL) {
+        g_warning ("element id=\"%s\" does not exist", id);
         /* todo: there's no way to signal that @id doesn't exist */
         return FALSE;
     }
diff --git a/tests/api.c b/tests/api.c
index 018cdee8..75b5d7af 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -465,6 +465,32 @@ dimensions_and_position (void)
     g_object_unref (handle);
 }
 
+static void
+detects_cairo_context_in_error (void)
+{
+    if (g_test_subprocess ()) {
+        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);
+
+        /* this is wrong; it is to simulate creating a surface and a cairo_t in error */
+        cairo_surface_t *surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -1, -1);
+        cairo_t *cr = cairo_create (surf);
+
+        /* rsvg_handle_render_cairo() should return FALSE when it gets a cr in an error state */
+        g_assert (!rsvg_handle_render_cairo (handle, cr));
+
+        return;
+    }
+
+    g_test_trap_subprocess (NULL, 0, 0);
+    g_test_trap_assert_failed ();
+    g_test_trap_assert_stderr ("*WARNING*cannot render on a cairo_t with a failure status*");
+}
+
 int
 main (int argc, char **argv)
 {
@@ -491,6 +517,7 @@ main (int argc, char **argv)
     g_test_add_func ("/api/handle_get_pixbuf", handle_get_pixbuf);
     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);
 
     return g_test_run ();
 }


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