cairo: Avoid using cairo_t for a destroyed cairo_surface_t.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 26 Dec 2020 05:54:48 +0000 (21:54 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 26 Dec 2020 06:04:43 +0000 (22:04 -0800)
xr_pager_destroy() would destroy the latest cairo_t, if there was one.
Generally there wasn't, since in the common case it got destroyed by
xr_pager_run() when the fsm emptied out, but in the case of the last page
in a produced output file, xr_destroy() would call xr_pager_destroy()
after first destroying the surface_t it was drawing on.  I don't think this
is an actual bug, because everything is properly reference-counted inside
Cairo (the cairo_t holds a reference on its cairo_surface_t) but I found it
confusing.

src/output/cairo-pager.c
src/output/cairo-pager.h
src/output/cairo.c

index f23ad5faa28ca99efcf2c8c5272057dc17ac1e77..e771e1a03b11d3fb1fd4c7952f8d45ca56bf33ba 100644 (file)
@@ -298,17 +298,23 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
   xr_pager_run (p);
 }
 
+void
+xr_pager_finish_page (struct xr_pager *p)
+{
+  if (p->cr)
+    {
+      cairo_restore (p->cr);
+      cairo_destroy (p->cr);
+      p->cr = NULL;
+    }
+}
+
 bool
 xr_pager_needs_new_page (struct xr_pager *p)
 {
   if (p->item && (!p->cr || p->y >= p->fsm_style->size[V]))
     {
-      if (p->cr)
-        {
-          cairo_restore (p->cr);
-          cairo_destroy (p->cr);
-          p->cr = NULL;
-        }
+      xr_pager_finish_page (p);
       return true;
     }
   else
index 87dcd367f74fa8aff0b99604f871b1f98ac28aba..47b49199dfec604304c08fd18abb411182e334bd 100644 (file)
@@ -63,6 +63,7 @@ void xr_pager_add_item (struct xr_pager *, const struct output_item *);
 
 bool xr_pager_has_page (const struct xr_pager *);
 void xr_pager_add_page (struct xr_pager *, cairo_t *);
+void xr_pager_finish_page (struct xr_pager *);
 bool xr_pager_needs_new_page (struct xr_pager *);
 
 #endif  /* HAVE_CAIRO */
index fdcf67fd3ae91305e1974e362fb35cde918ad19b..00ac472f7c4d0229fd146b6d84585dfce28acdda 100644 (file)
@@ -396,6 +396,8 @@ xr_report_error (cairo_status_t status, const char *file_name)
 static void
 xr_finish_page (struct xr_driver *xr)
 {
+  xr_pager_finish_page (xr->pager);
+
   /* For 'trim' true:
 
     - If the destination is PDF or PostScript, set the dest surface size, copy
@@ -525,6 +527,8 @@ xr_destroy (struct output_driver *driver)
   if (xr->pager)
     xr_finish_page (xr);
 
+  xr_pager_destroy (xr->pager);
+
   if (xr->drawing_surface && xr->drawing_surface != xr->dest_surface)
     cairo_surface_destroy (xr->drawing_surface);
   if (xr->dest_surface)
@@ -538,7 +542,6 @@ xr_destroy (struct output_driver *driver)
       cairo_surface_destroy (xr->dest_surface);
     }
 
-  xr_pager_destroy (xr->pager);
   xr_page_style_unref (xr->page_style);
   xr_fsm_style_unref (xr->fsm_style);
   free (xr);