Refactoring.
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 14 Dec 2020 05:27:49 +0000 (21:27 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 14 Dec 2020 05:27:49 +0000 (21:27 -0800)
src/output/cairo-pager.c
src/output/cairo-pager.h

index 224ad0381f2f1ae4fda152f69b59657d5c90c6d7..8a0f948cc86ab89a70495b2add3273cc64c2c211 100644 (file)
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
+
+/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
+#define H TABLE_HORZ
+#define V TABLE_VERT
 \f
 struct xr_page_style *
 xr_page_style_ref (const struct xr_page_style *ps_)
@@ -38,6 +42,25 @@ xr_page_style_ref (const struct xr_page_style *ps_)
   return ps;
 }
 
+struct xr_page_style *
+xr_page_style_unshare (struct xr_page_style *old)
+{
+  assert (old->ref_cnt > 0);
+  if (old->ref_cnt == 1)
+    return old;
+
+  xr_page_style_unref (old);
+
+  struct xr_page_style *new = xmemdup (old, sizeof *old);
+  new->ref_cnt = 1;
+  for (int i = 0; i < 2; i++)
+    page_heading_copy (&new->headings[i], &old->headings[i]);
+  if (old->font)
+    new->font = pango_font_description_copy (old->font);
+
+  return new;
+}
+
 void
 xr_page_style_unref (struct xr_page_style *ps)
 {
@@ -177,40 +200,42 @@ xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
 }
 
 static void
-xr_measure_headings (struct xr_pager *p)
+xr_measure_headings (const struct xr_page_style *ps, int heading_heights[2])
 {
-  const struct xr_page_style *ps = p->page_style;
-
   cairo_surface_t *surface = cairo_recording_surface_create (
     CAIRO_CONTENT_COLOR, NULL);
   cairo_t *cairo = cairo_create (surface);
   for (int i = 0; i < 2; i++)
     {
-      int h = xr_render_page_heading (cairo, ps->font, &ps->headings[i], -1,
-                                      ps->size[TABLE_HORZ], false, 0);
-
-      /* If the heading is nonempty, add a margin above or below it. */
-      if (h)
-        h += ps->object_spacing;
-
-      p->heading_heights[i] = h;
+      int *h = &heading_heights[i];
+      *h = xr_render_page_heading (cairo, ps->font, &ps->headings[i], -1,
+                                   ps->size[H], false, 0);
+      if (*h)
+        *h += ps->object_spacing;
     }
   cairo_destroy (cairo);
   cairo_surface_destroy (surface);
-
-  int total = p->heading_heights[0] + p->heading_heights[1];
-  if (total >= ps->size[TABLE_VERT])
-    p->heading_heights[0] = p->heading_heights[1] = 0;
 }
 
 struct xr_pager *
-xr_pager_create (const struct xr_page_style *ps)
+xr_pager_create (const struct xr_page_style *ps_)
 {
-  struct xr_pager *p = xmalloc (sizeof *p);
-  *p = (struct xr_pager) { .page_style = xr_page_style_ref (ps) };
+  struct xr_page_style *ps = xr_page_style_ref (ps_);
 
-  xr_measure_headings (p);
+  int heading_heights[2];
+  xr_measure_headings (ps, heading_heights);
+  int total = heading_heights[0] + heading_heights[1];
+  if (total > 0 && total < ps->size[V])
+    {
+      ps = xr_page_style_unshare (ps);
+
+      for (int i = 0; i < 2; i++)
+        ps->margins[V][i] += heading_heights[i];
+      ps->size[V] -= total;
+    }
 
+  struct xr_pager *p = xmalloc (sizeof *p);
+  *p = (struct xr_pager) { .page_style = ps };
   return p;
 }
 
@@ -266,26 +291,23 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
       cairo_save (cr);
       cairo_set_source_rgba (cr, bg->r / 255.0, bg->g / 255.0,
                           bg->b / 255.0, bg->alpha / 255.0);
-      cairo_rectangle (cr, 0, 0, ps->size[TABLE_HORZ], ps->size[TABLE_VERT]);
+      cairo_rectangle (cr, 0, 0, ps->size[H], ps->size[V]);
       cairo_fill (cr);
       cairo_restore (cr);
     }
   cairo_translate (cr,
-                   xr_to_pt (ps->margins[TABLE_HORZ][0]),
-                   xr_to_pt (ps->margins[TABLE_VERT][0]));
+                   xr_to_pt (ps->margins[H][0]),
+                   xr_to_pt (ps->margins[V][0]));
 
   int page_number = p->page_index++ + ps->initial_page_number;
   if (p->heading_heights[0])
     xr_render_page_heading (cr, ps->font, &ps->headings[0], page_number,
-                            ps->size[TABLE_HORZ], true, 0);
+                            ps->size[H], true, -p->heading_heights[0]);
 
   if (p->heading_heights[1])
-    xr_render_page_heading (
-      cr, ps->font, &ps->headings[1], page_number,
-      ps->size[TABLE_HORZ], true,
-      ps->size[TABLE_VERT] - p->heading_heights[1] + ps->object_spacing);
-
-  cairo_translate (cr, 0, xr_to_pt (p->heading_heights[0]));
+    xr_render_page_heading (cr, ps->font, &ps->headings[1], page_number,
+                            ps->size[H], true,
+                            ps->size[V] + ps->object_spacing);
 
   xr_pager_run (p);
 }
@@ -293,9 +315,7 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
 bool
 xr_pager_needs_new_page (struct xr_pager *p)
 {
-  int vsize = (p->page_style->size[TABLE_VERT]
-               - p->heading_heights[0] - p->heading_heights[1]);
-  if (p->item && p->y >= vsize)
+  if (p->item && p->y >= p->page_style->size[V])
     {
       cairo_destroy (p->cr);
       p->cr = NULL;
@@ -308,9 +328,7 @@ xr_pager_needs_new_page (struct xr_pager *p)
 static void
 xr_pager_run (struct xr_pager *p)
 {
-  int vsize = (p->page_style->size[TABLE_VERT]
-               - p->heading_heights[0] - p->heading_heights[1]);
-  if (p->item && p->cr && p->y < vsize)
+  if (p->item && p->cr && p->y < p->page_style->size[V])
     {
       if (!p->fsm)
         {
@@ -330,7 +348,8 @@ xr_pager_run (struct xr_pager *p)
       for (;;)
         {
           int spacing = p->page_style->object_spacing;
-          int chunk = xr_fsm_draw_slice (p->fsm, p->cr, vsize - p->y);
+          int chunk = xr_fsm_draw_slice (p->fsm, p->cr,
+                                         p->page_style->size[V] - p->y);
           p->y += chunk + spacing;
           cairo_translate (p->cr, 0, xr_to_pt (chunk + spacing));
 
index 2e722be6cf4fc324142661adb1bd643a853afa9e..b0cdfdf9144e4ce84c91db657a943230dbea7318 100644 (file)
@@ -45,6 +45,7 @@ struct xr_page_style
     int object_spacing;
   };
 struct xr_page_style *xr_page_style_ref (const struct xr_page_style *);
+struct xr_page_style *xr_page_style_unshare (struct xr_page_style *);
 void xr_page_style_unref (struct xr_page_style *);
 bool xr_page_style_equals (const struct xr_page_style *,
                            const struct xr_page_style *);
@@ -56,7 +57,8 @@ xr_page_style_paper_size (const struct xr_page_style *ps, enum table_axis a)
   return ps->size[a] + ps->margins[a][0] + ps->margins[a][1];
 }
 
-struct xr_pager *xr_pager_create (const struct xr_page_style *);
+struct xr_pager *xr_pager_create (const struct xr_page_style *,
+                                  const struct xr_fsm_style *);
 void xr_pager_destroy (struct xr_pager *);
 
 bool xr_pager_has_item (const struct xr_pager *);