1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2011, 2014, 2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/table.h"
20 #include "output/table-provider.h"
26 #include "data/format.h"
27 #include "libpspp/assertion.h"
28 #include "libpspp/cast.h"
29 #include "libpspp/compiler.h"
30 #include "libpspp/pool.h"
31 #include "libpspp/str.h"
32 #include "output/table-item.h"
33 #include "output/table.h"
34 #include "output/text-item.h"
36 #include "gl/xalloc.h"
38 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
42 /* Increases TABLE's reference count, indicating that it has an additional
43 owner. An table that is shared among multiple owners must not be
46 table_ref (const struct table *table_)
48 struct table *table = CONST_CAST (struct table *, table_);
53 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
54 If TABLE no longer has any owners, it is freed. */
56 table_unref (struct table *table)
60 assert (table->ref_cnt > 0);
61 if (--table->ref_cnt == 0)
62 pool_destroy (table->container);
66 /* Returns true if TABLE has more than one owner. A table item that is shared
67 among multiple owners must not be modified. */
69 table_is_shared (const struct table *table)
71 return table->ref_cnt > 1;
74 struct table_area_style *
75 table_area_style_clone (struct pool *pool, const struct table_area_style *old)
77 struct table_area_style *new = pool_malloc (pool, sizeof *new);
79 if (new->font_style.typeface)
80 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
85 table_area_style_free (struct table_area_style *style)
89 free (style->font_style.typeface);
95 footnote_clone (const struct footnote *old)
97 struct footnote *new = xmalloc (sizeof *new);
98 *new = (struct footnote) {
100 .content = old->content ? xstrdup (old->content) : NULL,
101 .marker = old->marker ? xstrdup (old->marker) : NULL,
102 .style = old->style ? table_area_style_clone (NULL, old->style) : NULL,
108 footnote_destroy (struct footnote *f)
116 table_area_style_uninit (f->style);
124 table_cell_clone (const struct table_cell *old)
126 struct table_cell *new = xmalloc (sizeof *new);
128 new->text = xstrdup (new->text);
130 if (old->n_subscripts)
132 new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
133 for (size_t i = 0; i < old->n_subscripts; i++)
134 new->subscripts[i] = xstrdup (old->subscripts[i]);
137 new->subscripts = NULL;
139 if (old->n_footnotes)
141 new->footnotes = xnmalloc (old->n_footnotes, sizeof *new->footnotes);
142 for (size_t i = 0; i < old->n_footnotes; i++)
143 new->footnotes[i] = footnote_clone (old->footnotes[i]);
146 new->footnotes = NULL;
149 new->style = table_area_style_clone (NULL, old->style);
155 table_cell_destroy (struct table_cell *cell)
161 for (size_t i = 0; i < cell->n_subscripts; i++)
162 free (cell->subscripts[i]);
163 free (cell->subscripts);
164 for (size_t i = 0; i < cell->n_footnotes; i++)
165 footnote_destroy (cell->footnotes[i]);
166 free (cell->footnotes);
169 table_area_style_uninit (cell->style);
176 table_cell_format_footnote_markers (const struct table_cell *cell,
179 for (size_t i = 0; i < cell->n_footnotes; i++)
182 ds_put_byte (s, ',');
183 ds_put_cstr (s, cell->footnotes[i]->marker);
187 static struct footnote **
188 add_footnotes (struct footnote **refs, size_t n_refs,
189 struct footnote **footnotes, size_t *allocated, size_t *n)
191 for (size_t i = 0; i < n_refs; i++)
193 struct footnote *f = refs[i];
194 if (f->idx >= *allocated)
196 size_t new_allocated = (f->idx + 1) * 2;
197 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
198 while (*allocated < new_allocated)
199 footnotes[(*allocated)++] = NULL;
201 footnotes[f->idx] = f;
209 table_collect_footnotes (const struct table_item *item,
210 struct footnote ***footnotesp)
212 struct footnote **footnotes = NULL;
213 size_t allocated = 0;
216 struct table *t = item->table;
217 for (int y = 0; y < t->n[V]; y++)
219 struct table_cell cell;
220 for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1])
222 table_get_cell (t, x, y, &cell);
224 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
225 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
226 footnotes, &allocated, &n);
230 const struct table_cell *title = table_item_get_title (item);
232 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
233 footnotes, &allocated, &n);
235 const struct table_item_layers *layers = table_item_get_layers (item);
238 for (size_t i = 0; i < layers->n_layers; i++)
239 footnotes = add_footnotes (layers->layers[i].footnotes,
240 layers->layers[i].n_footnotes,
241 footnotes, &allocated, &n);
244 const struct table_cell *caption = table_item_get_caption (item);
246 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
247 footnotes, &allocated, &n);
249 size_t n_nonnull = 0;
250 for (size_t i = 0; i < n; i++)
252 footnotes[n_nonnull++] = footnotes[i];
254 *footnotesp = footnotes;
259 table_halign_to_string (enum table_halign halign)
263 case TABLE_HALIGN_LEFT: return "left";
264 case TABLE_HALIGN_CENTER: return "center";
265 case TABLE_HALIGN_RIGHT: return "right";
266 case TABLE_HALIGN_DECIMAL: return "decimal";
267 case TABLE_HALIGN_MIXED: return "mixed";
268 default: return "**error**";
273 table_valign_to_string (enum table_valign valign)
277 case TABLE_VALIGN_TOP: return "top";
278 case TABLE_VALIGN_CENTER: return "center";
279 case TABLE_VALIGN_BOTTOM: return "bottom";
280 default: return "**error**";
285 table_halign_interpret (enum table_halign halign, bool numeric)
289 case TABLE_HALIGN_LEFT:
290 case TABLE_HALIGN_CENTER:
291 case TABLE_HALIGN_RIGHT:
294 case TABLE_HALIGN_MIXED:
295 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
297 case TABLE_HALIGN_DECIMAL:
298 return TABLE_HALIGN_DECIMAL;
306 font_style_copy (struct pool *container,
307 struct font_style *dst, const struct font_style *src)
311 dst->typeface = pool_strdup (container, dst->typeface);
315 font_style_uninit (struct font_style *font)
318 free (font->typeface);
322 table_area_style_copy (struct pool *container, struct table_area_style *dst,
323 const struct table_area_style *src)
325 font_style_copy (container, &dst->font_style, &src->font_style);
326 dst->cell_style = src->cell_style;
330 table_area_style_uninit (struct table_area_style *area)
333 font_style_uninit (&area->font_style);
337 table_stroke_to_string (enum table_stroke stroke)
341 case TABLE_STROKE_NONE: return "none";
342 case TABLE_STROKE_SOLID: return "solid";
343 case TABLE_STROKE_DASHED: return "dashed";
344 case TABLE_STROKE_THICK: return "thick";
345 case TABLE_STROKE_THIN: return "thin";
346 case TABLE_STROKE_DOUBLE: return "double";
353 cell_color_dump (const struct cell_color *c)
356 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
358 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
362 font_style_dump (const struct font_style *f)
364 printf ("%s %dpx ", f->typeface, f->size);
365 cell_color_dump (&f->fg[0]);
367 cell_color_dump (&f->bg[0]);
368 if (!cell_color_equal (&f->fg[0], &f->fg[1])
369 || !cell_color_equal (&f->bg[0], &f->bg[1]))
372 cell_color_dump (&f->fg[1]);
374 cell_color_dump (&f->bg[1]);
377 fputs (" bold", stdout);
379 fputs (" italic", stdout);
381 fputs (" underline", stdout);
385 font_style_equal (const struct font_style *a, const struct font_style *b)
387 return (a->bold == b->bold
388 && a->italic == b->italic
389 && a->underline == b->underline
390 && a->markup == b->markup
391 && cell_color_equal (&a->fg[0], &b->fg[0])
392 && cell_color_equal (&a->fg[1], &b->fg[1])
393 && cell_color_equal (&a->bg[0], &b->bg[0])
394 && cell_color_equal (&a->bg[1], &b->bg[1])
395 && !strcmp (a->typeface ? a->typeface : "",
396 b->typeface ? b->typeface : "")
397 && a->size == b->size);
401 cell_style_dump (const struct cell_style *c)
403 fputs (table_halign_to_string (c->halign), stdout);
404 if (c->halign == TABLE_HALIGN_DECIMAL)
405 printf ("(%.2gpx)", c->decimal_offset);
406 printf (" %s", table_valign_to_string (c->valign));
407 printf (" %d,%d,%d,%dpx",
408 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
409 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
413 static const bool debugging = true;
415 /* Creates and returns a new table with NC columns and NR rows and initially no
416 header rows or columns.
418 Sets the number of header rows on each side of TABLE to HL on the
419 left, HR on the right, HT on the top, HB on the bottom. Header rows
420 are repeated when a table is broken across multiple columns or
423 The table's cells are initially empty. */
425 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
429 t = pool_create_container (struct table, container);
430 t->n[TABLE_HORZ] = nc;
431 t->n[TABLE_VERT] = nr;
432 t->h[TABLE_HORZ][0] = hl;
433 t->h[TABLE_HORZ][1] = hr;
434 t->h[TABLE_VERT][0] = ht;
435 t->h[TABLE_VERT][1] = hb;
438 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
439 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
441 t->rh = pool_nmalloc (t->container, nc, nr + 1);
442 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
444 t->rv = pool_nmalloc (t->container, nr, nc + 1);
445 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
447 memset (t->styles, 0, sizeof t->styles);
448 memset (t->rule_colors, 0, sizeof t->rule_colors);
455 /* Draws a vertical line to the left of cells at horizontal position X
456 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
458 table_vline (struct table *t, int style, int x, int y1, int y2)
462 if (x < 0 || x > t->n[H]
463 || y1 < 0 || y1 >= t->n[V]
464 || y2 < 0 || y2 >= t->n[V])
466 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
467 x, y1, y2, t->n[H], t->n[V]);
473 assert (x <= t->n[H]);
476 assert (y2 <= t->n[V]);
481 for (y = y1; y <= y2; y++)
482 t->rv[x + (t->n[H] + 1) * y] = style;
486 /* Draws a horizontal line above cells at vertical position Y from X1
487 to X2 inclusive in style STYLE, if style is not -1. */
489 table_hline (struct table *t, int style, int x1, int x2, int y)
493 if (y < 0 || y > t->n[V]
494 || x1 < 0 || x1 >= t->n[H]
495 || x2 < 0 || x2 >= t->n[H])
497 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
498 x1, x2, y, t->n[H], t->n[V]);
504 assert (y <= t->n[V]);
507 assert (x2 < t->n[H]);
512 for (x = x1; x <= x2; x++)
513 t->rh[x + t->n[H] * y] = style;
517 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
518 lines of style F_H and vertical lines of style F_V. Fills the
519 interior of the box with horizontal lines of style I_H and vertical
520 lines of style I_V. Any of the line styles may be -1 to avoid
521 drawing those lines. This is distinct from 0, which draws a null
524 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
525 int x1, int y1, int x2, int y2)
529 if (x1 < 0 || x1 >= t->n[H]
530 || x2 < 0 || x2 >= t->n[H]
531 || y1 < 0 || y1 >= t->n[V]
532 || y2 < 0 || y2 >= t->n[V])
534 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
535 x1, y1, x2, y2, t->n[H], t->n[V]);
544 assert (x2 < t->n[H]);
545 assert (y2 < t->n[V]);
550 for (x = x1; x <= x2; x++)
552 t->rh[x + t->n[H] * y1] = f_h;
553 t->rh[x + t->n[H] * (y2 + 1)] = f_h;
559 for (y = y1; y <= y2; y++)
561 t->rv[x1 + (t->n[H] + 1) * y] = f_v;
562 t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
570 for (y = y1 + 1; y <= y2; y++)
574 for (x = x1; x <= x2; x++)
575 t->rh[x + t->n[H] * y] = i_h;
582 for (x = x1 + 1; x <= x2; x++)
586 for (y = y1; y <= y2; y++)
587 t->rv[x + (t->n[H] + 1) * y] = i_v;
595 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
599 assert (c < table->n[H]);
600 assert (r < table->n[V]);
604 if (c < 0 || r < 0 || c >= table->n[H] || r >= table->n[V])
606 printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
607 c, r, table->n[H], table->n[V]);
612 table->cc[c + r * table->n[H]] = text;
613 table->ct[c + r * table->n[H]] = opt;
616 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
619 table_text (struct table *table, int c, int r, unsigned opt,
622 do_table_text (table, c, r, opt, pool_strdup (table->container, text));
625 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
626 FORMAT, which is formatted as if passed to printf. */
628 table_text_format (struct table *table, int c, int r, unsigned opt,
629 const char *format, ...)
633 va_start (args, format);
634 do_table_text (table, c, r, opt,
635 pool_vasprintf (table->container, format, args));
639 static struct table_cell *
640 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
647 assert (y2 < table->n[V]);
648 assert (x2 < table->n[H]);
652 if (x1 < 0 || x1 >= table->n[H]
653 || y1 < 0 || y1 >= table->n[V]
654 || x2 < x1 || x2 >= table->n[H]
655 || y2 < y1 || y2 >= table->n[V])
657 printf ("table_joint_text(): bad cell "
658 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
659 x1, y1, x2, y2, table->n[H], table->n[V]);
664 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
667 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
668 *cell = (struct table_cell) {
669 .d = { [TABLE_HORZ] = { x1, ++x2 },
670 [TABLE_VERT] = { y1, ++y2 } },
674 void **cc = &table->cc[x1 + y1 * table->n[H]];
675 unsigned short *ct = &table->ct[x1 + y1 * table->n[H]];
676 const int ofs = table->n[H] - (x2 - x1);
677 for (int y = y1; y < y2; y++)
679 for (int x = x1; x < x2; x++)
682 *ct++ = opt | TAB_JOIN;
692 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
693 options OPT to have text value TEXT. */
695 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
696 unsigned opt, const char *text)
698 char *s = pool_strdup (table->container, text);
699 if (x1 == x2 && y1 == y2)
700 do_table_text (table, x1, y1, opt, s);
702 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
705 static struct table_cell *
706 get_joined_cell (struct table *table, int x, int y)
708 int index = x + y * table->n[H];
709 unsigned short opt = table->ct[index];
710 struct table_cell *cell;
713 cell = table->cc[index];
716 char *text = table->cc[index];
718 cell = add_joined_cell (table, x, y, x, y, table->ct[index]);
719 cell->text = text ? text : pool_strdup (table->container, "");
724 /* Sets the subscripts for column X, row Y in TABLE. */
726 table_add_subscripts (struct table *table, int x, int y,
727 char **subscripts, size_t n_subscripts)
729 struct table_cell *cell = get_joined_cell (table, x, y);
731 cell->n_subscripts = n_subscripts;
732 cell->subscripts = pool_nalloc (table->container, n_subscripts,
733 sizeof *cell->subscripts);
734 for (size_t i = 0; i < n_subscripts; i++)
735 cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
738 /* Create a footnote in TABLE with MARKER (e.g. "a") as its marker and CONTENT
739 as its content. The footnote will be styled as STYLE, which is mandatory.
740 IDX must uniquely identify the footnote within TABLE.
742 Returns the new footnote. The return value is the only way to get to the
743 footnote later, so it is important for the caller to remember it. */
745 table_create_footnote (struct table *table, size_t idx, const char *content,
746 const char *marker, struct table_area_style *style)
750 struct footnote *f = pool_alloc (table->container, sizeof *f);
752 f->content = pool_strdup (table->container, content);
753 f->marker = pool_strdup (table->container, marker);
758 /* Attaches a reference to footnote F to the cell at column X, row Y in
761 table_add_footnote (struct table *table, int x, int y, struct footnote *f)
765 struct table_cell *cell = get_joined_cell (table, x, y);
767 cell->footnotes = pool_realloc (
768 table->container, cell->footnotes,
769 (cell->n_footnotes + 1) * sizeof *cell->footnotes);
771 cell->footnotes[cell->n_footnotes++] = f;
774 /* Overrides the style for column X, row Y in TABLE with STYLE.
775 Does not make a copy of STYLE, so it should either be allocated from
776 TABLE->container or have a lifetime that will outlive TABLE. */
778 table_add_style (struct table *table, int x, int y,
779 struct table_area_style *style)
781 get_joined_cell (table, x, y)->style = style;
784 /* Returns true if column C, row R has no contents, otherwise false. */
786 table_cell_is_empty (const struct table *table, int c, int r)
788 return table->cc[c + r * table->n[H]] == NULL;
791 /* Initializes CELL with the contents of the table cell at column X and row Y
794 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
796 assert (x >= 0 && x < t->n[TABLE_HORZ]);
797 assert (y >= 0 && y < t->n[TABLE_VERT]);
799 int index = x + y * t->n[H];
800 unsigned short opt = t->ct[index];
801 const void *cc = t->cc[index];
803 struct table_area_style *style
804 = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
807 const struct table_cell *jc = cc;
813 *cell = (struct table_cell) {
814 .d = { [TABLE_HORZ] = { x, x + 1 },
815 [TABLE_VERT] = { y, y + 1 } },
817 .text = CONST_CAST (char *, cc ? cc : ""),
821 assert (cell->style);
824 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
825 representing a rule running alongside one of the cells in TABLE.
827 Suppose NC is the number of columns in TABLE and NR is the number of rows.
828 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
829 (0,0), the return value is the rule that runs vertically on the left side of
830 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
831 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
834 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
835 within a 7x7 table. The '|' characters at the intersection of the X labels
836 and Y labels show the rule whose style would be returned by calling
837 table_get_rule with those X and Y values:
840 +--+--+--+--+--+--+--+
842 +--+--+--+--+--+--+--+
844 +--+--+--+--+--+--+--+
846 +--+--+--+--+--+--+--+
848 +--+--+--+--+--+--+--+
850 +--+--+--+--+--+--+--+
852 +--+--+--+--+--+--+--+
854 +--+--+--+--+--+--+--+
856 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
857 (X,Y) = (0,0), the return value is the rule that runs horizontally above
858 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
859 between that cell and cell (0,1); and so on, up to (0,NR), which runs
860 horizontally below cell (0,NR-1). */
862 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
863 struct cell_color *color)
865 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
866 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
868 uint8_t raw = (axis == TABLE_VERT
869 ? table->rh[x + table->n[H] * y]
870 : table->rv[x + (table->n[H] + 1) * y]);
871 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
872 >> TAB_RULE_STYLE_SHIFT];
873 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
874 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;