output: Implement styling for footnotes.
[pspp] / src / output / render.c
index 9a9370ad175997309f015172ecd476cc389eba57..f73137f0e35eafe8ab11b8981de11998f01c73cf 100644 (file)
@@ -25,6 +25,7 @@
 #include "libpspp/assertion.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
+#include "libpspp/pool.h"
 #include "output/render.h"
 #include "output/tab.h"
 #include "output/table-item.h"
@@ -59,7 +60,9 @@ struct render_page
     int n[TABLE_N_AXES];
     int h[TABLE_N_AXES][2];
 
-    /* cp[H] represents x positions within the table.
+    /* "Cell positions".
+
+       cp[H] represents x positions within the table.
        cp[H][0] = 0.
        cp[H][1] = the width of the leftmost vertical rule.
        cp[H][2] = cp[H][1] + the width of the leftmost column.
@@ -456,11 +459,17 @@ rule_to_render_type (unsigned char type)
 {
   switch (type)
     {
-    case TAL_0:
+    case TAL_NONE:
       return RENDER_LINE_NONE;
-    case TAL_1:
+    case TAL_SOLID:
       return RENDER_LINE_SINGLE;
-    case TAL_2:
+    case TAL_DASHED:
+      return RENDER_LINE_DASHED;
+    case TAL_THICK:
+      return RENDER_LINE_THICK;
+    case TAL_THIN:
+      return RENDER_LINE_THIN;
+    case TAL_DOUBLE:
       return RENDER_LINE_DOUBLE;
     default:
       NOT_REACHED ();
@@ -476,33 +485,31 @@ measure_rule (const struct render_params *params, const struct table *table,
   enum table_axis b = !a;
   unsigned int rules;
   int d[TABLE_N_AXES];
-  int width;
 
   /* Determine all types of rules that are present, as a bitmap in 'rules'
      where rule type 't' is present if bit 2**t is set. */
+  struct cell_color color;
   rules = 0;
   d[a] = z;
   for (d[b] = 0; d[b] < table->n[b]; d[b]++)
-    rules |= 1u << table_get_rule (table, a, d[H], d[V]);
+    rules |= 1u << table_get_rule (table, a, d[H], d[V], &color);
 
   /* Turn off TAL_NONE because it has width 0 and we needn't bother.  However,
      if the device doesn't support margins, make sure that there is at least a
      small gap between cells (but we don't need any at the left or right edge
      of the table). */
-  if (rules & (1u << TAL_0))
+  if (rules & (1u << TAL_NONE))
     {
-      rules &= ~(1u << TAL_0);
+      rules &= ~(1u << TAL_NONE);
       if (z > 0 && z < table->n[a] && !params->supports_margins && a == H)
-        rules |= 1u << TAL_1;
+        rules |= 1u << TAL_SOLID;
     }
 
   /* Calculate maximum width of the rules that are present. */
-  width = 0;
-  if (rules & (1u << TAL_1)
-      || (z > 0 && z < table->n[a] && rules & (1u << TAL_0)))
-    width = params->line_widths[a][RENDER_LINE_SINGLE];
-  if (rules & (1u << TAL_2))
-    width = MAX (width, params->line_widths[a][RENDER_LINE_DOUBLE]);
+  int width = 0;
+  for (size_t i = 0; i < N_LINES; i++)
+    if (rules & (1u << i))
+      width = MAX (width, params->line_widths[a][rule_to_render_type (i)]);
   return width;
 }
 
@@ -864,10 +871,11 @@ render_page_get_best_breakpoint (const struct render_page *page, int height)
 
 static inline enum render_line_style
 get_rule (const struct render_page *page, enum table_axis axis,
-          const int d[TABLE_N_AXES])
+          const int d[TABLE_N_AXES], struct cell_color *color)
 {
   return rule_to_render_type (table_get_rule (page->table,
-                                              axis, d[H] / 2, d[V] / 2));
+                                              axis, d[H] / 2, d[V] / 2,
+                                              color));
 }
 
 static bool
@@ -898,6 +906,7 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES],
              const int d[TABLE_N_AXES])
 {
   enum render_line_style styles[TABLE_N_AXES][2];
+  struct cell_color colors[TABLE_N_AXES][2];
   enum table_axis a;
 
   for (a = 0; a < TABLE_N_AXES; a++)
@@ -919,14 +928,17 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES],
               e[H] = d[H];
               e[V] = d[V];
               e[b]--;
-              styles[a][0] = get_rule (page, a, e);
+              styles[a][0] = get_rule (page, a, e, &colors[a][0]);
             }
 
           if (d[b] / 2 < page->table->n[b])
-            styles[a][1] = get_rule (page, a, d);
+            styles[a][1] = get_rule (page, a, d, &colors[a][1]);
         }
       else
-        styles[a][0] = styles[a][1] = get_rule (page, a, d);
+        {
+          styles[a][0] = styles[a][1] = get_rule (page, a, d, &colors[a][0]);
+          colors[a][1] = colors[a][0];
+        }
     }
 
   if (styles[H][0] != RENDER_LINE_NONE || styles[H][1] != RENDER_LINE_NONE
@@ -944,7 +956,7 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES],
        }
       bb[V][0] = ofs[V] + page->cp[V][d[V]];
       bb[V][1] = ofs[V] + page->cp[V][d[V] + 1];
-      page->params->draw_line (page->params->aux, bb, styles);
+      page->params->draw_line (page->params->aux, bb, styles, colors);
     }
 }
 
@@ -967,6 +979,22 @@ render_cell (const struct render_page *page, const int ofs[TABLE_N_AXES],
   bb[V][0] = clip[V][0] = ofs[V] + page->cp[V][cell->d[V][0] * 2 + 1];
   bb[V][1] = clip[V][1] = ofs[V] + page->cp[V][cell->d[V][1] * 2];
 
+  int valign = (cell->n_contents
+                ? cell->contents->options & TAB_VALIGN
+                : TAB_TOP);
+  if (valign != TAB_TOP)
+    {
+      int height = page->params->measure_cell_height (
+        page->params->aux, cell, bb[H][1] - bb[H][0]);
+      int extra = bb[V][1] - bb[V][0] - height;
+      if (extra > 0)
+        {
+          if (valign == TAB_MIDDLE)
+            extra /= 2;
+          bb[V][0] += extra;
+        }
+    }
+
   of = find_overflow (page, cell->d[H][0], cell->d[V][0]);
   if (of)
     {
@@ -989,7 +1017,14 @@ render_cell (const struct render_page *page, const int ofs[TABLE_N_AXES],
         }
     }
 
-  page->params->draw_cell (page->params->aux, cell, bb, clip);
+  int spill[TABLE_N_AXES][2];
+  for (enum table_axis axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      spill[axis][0] = rule_width (page, axis, cell->d[axis][0]) / 2;
+      spill[axis][1] = rule_width (page, axis, cell->d[axis][1]) / 2;
+    }
+
+  page->params->draw_cell (page->params->aux, cell, bb, spill, clip);
 }
 
 /* Draws the cells of PAGE indicated in BB. */
@@ -997,19 +1032,9 @@ static void
 render_page_draw_cells (const struct render_page *page,
                         int ofs[TABLE_N_AXES], int bb[TABLE_N_AXES][2])
 {
-  int x, y;
-
-  for (y = bb[V][0]; y < bb[V][1]; y++)
-    for (x = bb[H][0]; x < bb[H][1]; )
-      if (is_rule (x) || is_rule (y))
-        {
-          int d[TABLE_N_AXES];
-          d[H] = x;
-          d[V] = y;
-          render_rule (page, ofs, d);
-          x++;
-        }
-      else
+  for (int y = bb[V][0]; y < bb[V][1]; y++)
+    for (int x = bb[H][0]; x < bb[H][1]; )
+      if (!is_rule (x) && !is_rule (y))
         {
           struct table_cell cell;
 
@@ -1019,6 +1044,18 @@ render_page_draw_cells (const struct render_page *page,
           x = rule_ofs (cell.d[H][1]);
           table_cell_free (&cell);
         }
+      else
+        x++;
+
+  for (int y = bb[V][0]; y < bb[V][1]; y++)
+    for (int x = bb[H][0]; x < bb[H][1]; x++)
+      if (is_rule (x) || is_rule (y))
+        {
+          int d[TABLE_N_AXES];
+          d[H] = x;
+          d[V] = y;
+          render_rule (page, ofs, d);
+        }
 }
 
 /* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
@@ -1388,6 +1425,11 @@ add_footnote_page (struct render_pager *p, const struct table_item *item)
       {
         tab_text_format (t, 0, i, TAB_LEFT, "%s.", f[i]->marker);
         tab_text (t, 1, i, TAB_LEFT, f[i]->content);
+        if (f[i]->style)
+          {
+            tab_add_style (t, 0, i, f[i]->style);
+            tab_add_style (t, 1, i, f[i]->style);
+          }
       }
   render_pager_add_table (p, &t->table);
 
@@ -1404,6 +1446,12 @@ add_text_page (struct render_pager *p, const struct table_item_text *t)
   tab_text (tab, 0, 0, TAB_LEFT, t->content);
   for (size_t i = 0; i < t->n_footnotes; i++)
     tab_add_footnote (tab, 0, 0, t->footnotes[i]);
+  if (t->style)
+    {
+      tab->styles[0] = pool_clone (tab->container, t->style, sizeof *t->style);
+      if (t->style->font)
+        tab->styles[0]->font = pool_strdup (tab->container, t->style->font);
+    }
   render_pager_add_table (p, &tab->table);
 }