render: Simplify 'pages' array in struct render_pager.
[pspp] / src / output / table.c
index c27d208f72b09b4fcf5aa435b3738035618d5388..44c33b9d10b36ceabb6df4125d1038567f16076d 100644 (file)
 
 #include "gl/xalloc.h"
 
+/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
+#define H TABLE_HORZ
+#define V TABLE_VERT
+
 /* Increases TABLE's reference count, indicating that it has an additional
    owner.  An table that is shared among multiple owners must not be
    modified. */
@@ -87,6 +91,87 @@ table_area_style_free (struct table_area_style *style)
     }
 }
 
+struct footnote *
+footnote_clone (const struct footnote *old)
+{
+  struct footnote *new = xmalloc (sizeof *new);
+  *new = (struct footnote) {
+    .idx = old->idx,
+    .content = old->content ? xstrdup (old->content) : NULL,
+    .marker = old->marker ? xstrdup (old->marker) : NULL,
+    .style = old->style ? table_area_style_clone (NULL, old->style) : NULL,
+  };
+  return new;
+}
+
+void
+footnote_destroy (struct footnote *f)
+{
+  if (f)
+    {
+      free (f->content);
+      free (f->marker);
+      if (f->style)
+        {
+          table_area_style_uninit (f->style);
+          free (f->style);
+        }
+      free (f);
+    }
+}
+
+struct table_cell *
+table_cell_clone (const struct table_cell *old)
+{
+  struct table_cell *new = xmalloc (sizeof *new);
+  *new = *old;
+  new->text = xstrdup (new->text);
+
+  if (old->n_subscripts)
+    {
+      new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
+      for (size_t i = 0; i < old->n_subscripts; i++)
+        new->subscripts[i] = xstrdup (old->subscripts[i]);
+    }
+  else
+    new->subscripts = NULL;
+
+  if (old->n_footnotes)
+    {
+      new->footnotes = xnmalloc (old->n_footnotes, sizeof *new->footnotes);
+      for (size_t i = 0; i < old->n_footnotes; i++)
+        new->footnotes[i] = footnote_clone (old->footnotes[i]);
+    }
+  else
+    new->footnotes = NULL;
+
+  if (old->style)
+    new->style = table_area_style_clone (NULL, old->style);
+
+  return new;
+}
+
+void
+table_cell_destroy (struct table_cell *cell)
+{
+  if (!cell)
+    return;
+
+  free (cell->text);
+  for (size_t i = 0; i < cell->n_subscripts; i++)
+    free (cell->subscripts[i]);
+  free (cell->subscripts);
+  for (size_t i = 0; i < cell->n_footnotes; i++)
+    footnote_destroy (cell->footnotes[i]);
+  free (cell->footnotes);
+  if (cell->style)
+    {
+      table_area_style_uninit (cell->style);
+      free (cell->style);
+    }
+  free (cell);
+}
+
 void
 table_cell_format_footnote_markers (const struct table_cell *cell,
                                     struct string *s)
@@ -99,13 +184,13 @@ table_cell_format_footnote_markers (const struct table_cell *cell,
     }
 }
 
-static const struct footnote **
-add_footnotes (const struct footnote **refs, size_t n_refs,
-               const struct footnote **footnotes, size_t *allocated, size_t *n)
+static struct footnote **
+add_footnotes (struct footnote **refs, size_t n_refs,
+               struct footnote **footnotes, size_t *allocated, size_t *n)
 {
   for (size_t i = 0; i < n_refs; i++)
     {
-      const struct footnote *f = refs[i];
+      struct footnote *f = refs[i];
       if (f->idx >= *allocated)
         {
           size_t new_allocated = (f->idx + 1) * 2;
@@ -122,17 +207,17 @@ add_footnotes (const struct footnote **refs, size_t n_refs,
 
 size_t
 table_collect_footnotes (const struct table_item *item,
-                         const struct footnote ***footnotesp)
+                         struct footnote ***footnotesp)
 {
-  const struct footnote **footnotes = NULL;
+  struct footnote **footnotes = NULL;
   size_t allocated = 0;
   size_t n = 0;
 
   struct table *t = item->table;
-  for (int y = 0; y < table_nr (t); y++)
+  for (int y = 0; y < t->n[V]; y++)
     {
       struct table_cell cell;
-      for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
+      for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1])
         {
           table_get_cell (t, x, y, &cell);
 
@@ -142,7 +227,7 @@ table_collect_footnotes (const struct table_item *item,
         }
     }
 
-  const struct table_item_text *title = table_item_get_title (item);
+  const struct table_cell *title = table_item_get_title (item);
   if (title)
     footnotes = add_footnotes (title->footnotes, title->n_footnotes,
                                footnotes, &allocated, &n);
@@ -156,7 +241,7 @@ table_collect_footnotes (const struct table_item *item,
                                    footnotes, &allocated, &n);
     }
 
-  const struct table_item_text *caption = table_item_get_caption (item);
+  const struct table_cell *caption = table_item_get_caption (item);
   if (caption)
     footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
                                footnotes, &allocated, &n);
@@ -170,22 +255,6 @@ table_collect_footnotes (const struct table_item *item,
   return n_nonnull;
 }
 \f
-/* Returns a table that contains a single cell, whose contents are the
-   left-aligned TEXT.  */
-struct table *
-table_from_string (const char *text)
-{
-  struct table *t = table_create (1, 1, 0, 0, 0, 0);
-  t->styles[0] = pool_alloc (t->container, sizeof *t->styles[0]);
-  *t->styles[0] = (struct table_area_style) {
-    TABLE_AREA_STYLE_INITIALIZER__,
-    .cell_style.halign = TABLE_HALIGN_LEFT,
-    .cell_style.valign = TABLE_VALIGN_TOP
-  };
-  table_text (t, 0, 0, 0 << TAB_STYLE_SHIFT, text);
-  return t;
-}
-\f
 const char *
 table_halign_to_string (enum table_halign halign)
 {
@@ -312,6 +381,22 @@ font_style_dump (const struct font_style *f)
     fputs (" underline", stdout);
 }
 
+bool
+font_style_equal (const struct font_style *a, const struct font_style *b)
+{
+  return (a->bold == b->bold
+          && a->italic == b->italic
+          && a->underline == b->underline
+          && a->markup == b->markup
+          && cell_color_equal (&a->fg[0], &b->fg[0])
+          && cell_color_equal (&a->fg[1], &b->fg[1])
+          && cell_color_equal (&a->bg[0], &b->bg[0])
+          && cell_color_equal (&a->bg[1], &b->bg[1])
+          && !strcmp (a->typeface ? a->typeface : "",
+                      b->typeface ? b->typeface : "")
+          && a->size == b->size);
+}
+
 void
 cell_style_dump (const struct cell_style *c)
 {
@@ -374,27 +459,27 @@ table_vline (struct table *t, int style, int x, int y1, int y2)
 {
   if (debugging)
     {
-      if (x < 0 || x > table_nc (t)
-          || y1 < 0 || y1 >= table_nr (t)
-          || y2 < 0 || y2 >= table_nr (t))
+      if (x < 0 || x > t->n[H]
+          || y1 < 0 || y1 >= t->n[V]
+          || y2 < 0 || y2 >= t->n[V])
         {
           printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
-                  x, y1, y2, table_nc (t), table_nr (t));
+                  x, y1, y2, t->n[H], t->n[V]);
           return;
         }
     }
 
   assert (x >= 0);
-  assert (x <= table_nc (t));
+  assert (x <= t->n[H]);
   assert (y1 >= 0);
   assert (y2 >= y1);
-  assert (y2 <= table_nr (t));
+  assert (y2 <= t->n[V]);
 
   if (style != -1)
     {
       int y;
       for (y = y1; y <= y2; y++)
-        t->rv[x + (table_nc (t) + 1) * y] = style;
+        t->rv[x + (t->n[H] + 1) * y] = style;
     }
 }
 
@@ -405,27 +490,27 @@ table_hline (struct table *t, int style, int x1, int x2, int y)
 {
   if (debugging)
     {
-      if (y < 0 || y > table_nr (t)
-          || x1 < 0 || x1 >= table_nc (t)
-          || x2 < 0 || x2 >= table_nc (t))
+      if (y < 0 || y > t->n[V]
+          || x1 < 0 || x1 >= t->n[H]
+          || x2 < 0 || x2 >= t->n[H])
         {
           printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
-                  x1, x2, y, table_nc (t), table_nr (t));
+                  x1, x2, y, t->n[H], t->n[V]);
           return;
         }
     }
 
   assert (y >= 0);
-  assert (y <= table_nr (t));
+  assert (y <= t->n[V]);
   assert (x2 >= x1);
   assert (x1 >= 0);
-  assert (x2 < table_nc (t));
+  assert (x2 < t->n[H]);
 
   if (style != -1)
     {
       int x;
       for (x = x1; x <= x2; x++)
-        t->rh[x + table_nc (t) * y] = style;
+        t->rh[x + t->n[H] * y] = style;
     }
 }
 
@@ -441,13 +526,13 @@ table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
 {
   if (debugging)
     {
-      if (x1 < 0 || x1 >= table_nc (t)
-          || x2 < 0 || x2 >= table_nc (t)
-          || y1 < 0 || y1 >= table_nr (t)
-          || y2 < 0 || y2 >= table_nr (t))
+      if (x1 < 0 || x1 >= t->n[H]
+          || x2 < 0 || x2 >= t->n[H]
+          || y1 < 0 || y1 >= t->n[V]
+          || y2 < 0 || y2 >= t->n[V])
         {
           printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
-                  x1, y1, x2, y2, table_nc (t), table_nr (t));
+                  x1, y1, x2, y2, t->n[H], t->n[V]);
           NOT_REACHED ();
         }
     }
@@ -456,16 +541,16 @@ table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
   assert (y2 >= y1);
   assert (x1 >= 0);
   assert (y1 >= 0);
-  assert (x2 < table_nc (t));
-  assert (y2 < table_nr (t));
+  assert (x2 < t->n[H]);
+  assert (y2 < t->n[V]);
 
   if (f_h != -1)
     {
       int x;
       for (x = x1; x <= x2; x++)
         {
-          t->rh[x + table_nc (t) * y1] = f_h;
-          t->rh[x + table_nc (t) * (y2 + 1)] = f_h;
+          t->rh[x + t->n[H] * y1] = f_h;
+          t->rh[x + t->n[H] * (y2 + 1)] = f_h;
         }
     }
   if (f_v != -1)
@@ -473,8 +558,8 @@ table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
       int y;
       for (y = y1; y <= y2; y++)
         {
-          t->rv[x1 + (table_nc (t) + 1) * y] = f_v;
-          t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v;
+          t->rv[x1 + (t->n[H] + 1) * y] = f_v;
+          t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
         }
     }
 
@@ -487,7 +572,7 @@ table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
           int x;
 
           for (x = x1; x <= x2; x++)
-            t->rh[x + table_nc (t) * y] = i_h;
+            t->rh[x + t->n[H] * y] = i_h;
         }
     }
   if (i_v != -1)
@@ -499,7 +584,7 @@ table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
           int y;
 
           for (y = y1; y <= y2; y++)
-            t->rv[x + (table_nc (t) + 1) * y] = i_v;
+            t->rv[x + (t->n[H] + 1) * y] = i_v;
         }
     }
 }
@@ -511,21 +596,21 @@ do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
 {
   assert (c >= 0);
   assert (r >= 0);
-  assert (c < table_nc (table));
-  assert (r < table_nr (table));
+  assert (c < table->n[H]);
+  assert (r < table->n[V]);
 
   if (debugging)
     {
-      if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table))
+      if (c < 0 || r < 0 || c >= table->n[H] || r >= table->n[V])
         {
           printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
-                  c, r, table_nc (table), table_nr (table));
+                  c, r, table->n[H], table->n[V]);
           return;
         }
     }
 
-  table->cc[c + r * table_nc (table)] = text;
-  table->ct[c + r * table_nc (table)] = opt;
+  table->cc[c + r * table->n[H]] = text;
+  table->ct[c + r * table->n[H]] = opt;
 }
 
 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
@@ -559,19 +644,19 @@ add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
   assert (y1 >= 0);
   assert (y2 >= y1);
   assert (x2 >= x1);
-  assert (y2 < table_nr (table));
-  assert (x2 < table_nc (table));
+  assert (y2 < table->n[V]);
+  assert (x2 < table->n[H]);
 
   if (debugging)
     {
-      if (x1 < 0 || x1 >= table_nc (table)
-          || y1 < 0 || y1 >= table_nr (table)
-          || x2 < x1 || x2 >= table_nc (table)
-          || y2 < y1 || y2 >= table_nr (table))
+      if (x1 < 0 || x1 >= table->n[H]
+          || y1 < 0 || y1 >= table->n[V]
+          || x2 < x1 || x2 >= table->n[H]
+          || y2 < y1 || y2 >= table->n[V])
         {
           printf ("table_joint_text(): bad cell "
                   "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
-                  x1, y1, x2, y2, table_nc (table), table_nr (table));
+                  x1, y1, x2, y2, table->n[H], table->n[V]);
           return NULL;
         }
     }
@@ -586,9 +671,9 @@ add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
     .options = opt,
   };
 
-  void **cc = &table->cc[x1 + y1 * table_nc (table)];
-  unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)];
-  const int ofs = table_nc (table) - (x2 - x1);
+  void **cc = &table->cc[x1 + y1 * table->n[H]];
+  unsigned short *ct = &table->ct[x1 + y1 * table->n[H]];
+  const int ofs = table->n[H] - (x2 - x1);
   for (int y = y1; y < y2; y++)
     {
       for (int x = x1; x < x2; x++)
@@ -620,7 +705,7 @@ table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
 static struct table_cell *
 get_joined_cell (struct table *table, int x, int y)
 {
-  int index = x + y * table_nc (table);
+  int index = x + y * table->n[H];
   unsigned short opt = table->ct[index];
   struct table_cell *cell;
 
@@ -650,15 +735,6 @@ table_add_subscripts (struct table *table, int x, int y,
     cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
 }
 
-/* Sets the superscript for column X, row Y in TABLE. */
-void
-table_add_superscript (struct table *table, int x, int y,
-                       const char *superscript)
-{
-  get_joined_cell (table, x, y)->superscript
-    = pool_strdup (table->container, superscript);
-}
-
 /* Create a footnote in TABLE with MARKER (e.g. "a") as its marker and CONTENT
    as its content.  The footnote will be styled as STYLE, which is mandatory.
    IDX must uniquely identify the footnote within TABLE.
@@ -682,8 +758,7 @@ table_create_footnote (struct table *table, size_t idx, const char *content,
 /* Attaches a reference to footnote F to the cell at column X, row Y in
    TABLE. */
 void
-table_add_footnote (struct table *table, int x, int y,
-                    const struct footnote *f)
+table_add_footnote (struct table *table, int x, int y, struct footnote *f)
 {
   assert (f->style);
 
@@ -701,7 +776,7 @@ table_add_footnote (struct table *table, int x, int y,
    TABLE->container or have a lifetime that will outlive TABLE. */
 void
 table_add_style (struct table *table, int x, int y,
-                 const struct table_area_style *style)
+                 struct table_area_style *style)
 {
   get_joined_cell (table, x, y)->style = style;
 }
@@ -710,55 +785,22 @@ table_add_style (struct table *table, int x, int y,
 bool
 table_cell_is_empty (const struct table *table, int c, int r)
 {
-  return table->cc[c + r * table_nc (table)] == NULL;
-}
-\f
-/* Editing. */
-
-/* Writes STRING to the output.  OPTIONS may be any valid combination of TAB_*
-   bits.
-
-   This function is obsolete.  Please do not add new uses of it.  Instead, use
-   a text_item (see output/text-item.h). */
-void
-table_output_text (int options UNUSED, const char *string)
-{
-  text_item_submit (text_item_create (TEXT_ITEM_LOG, string));
-}
-
-/* Same as table_output_text(), but FORMAT is passed through printf-like
-   formatting before output. */
-void
-table_output_text_format (int options, const char *format, ...)
-{
-  va_list args;
-  char *text;
-
-  va_start (args, format);
-  text = xvasprintf (format, args);
-  va_end (args);
-
-  table_output_text (options, text);
-
-  free (text);
+  return table->cc[c + r * table->n[H]] == NULL;
 }
 \f
 /* Initializes CELL with the contents of the table cell at column X and row Y
-   within TABLE.  When CELL is no longer needed, the caller is responsible for
-   freeing it by calling table_cell_free(CELL).
-
-   The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
+   within TABLE. */
 void
 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
 {
   assert (x >= 0 && x < t->n[TABLE_HORZ]);
   assert (y >= 0 && y < t->n[TABLE_VERT]);
 
-  int index = x + y * table_nc (t);
+  int index = x + y * t->n[H];
   unsigned short opt = t->ct[index];
   const void *cc = t->cc[index];
 
-  const struct table_area_style *style
+  struct table_area_style *style
     = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
   if (opt & TAB_JOIN)
     {
@@ -824,8 +866,8 @@ table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
 
   uint8_t raw = (axis == TABLE_VERT
-                 ? table->rh[x + table_nc (table) * y]
-                 : table->rv[x + (table_nc (table) + 1) * y]);
+                 ? table->rh[x + table->n[H] * y]
+                 : table->rv[x + (table->n[H] + 1) * y]);
   struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
                                             >> TAB_RULE_STYLE_SHIFT];
   *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;