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 table_cell_format_footnote_markers (const struct table_cell *cell,
98 for (size_t i = 0; i < cell->n_footnotes; i++)
101 ds_put_byte (s, ',');
102 ds_put_cstr (s, cell->footnotes[i]->marker);
106 static const struct footnote **
107 add_footnotes (const struct footnote **refs, size_t n_refs,
108 const struct footnote **footnotes, size_t *allocated, size_t *n)
110 for (size_t i = 0; i < n_refs; i++)
112 const struct footnote *f = refs[i];
113 if (f->idx >= *allocated)
115 size_t new_allocated = (f->idx + 1) * 2;
116 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
117 while (*allocated < new_allocated)
118 footnotes[(*allocated)++] = NULL;
120 footnotes[f->idx] = f;
128 table_collect_footnotes (const struct table_item *item,
129 const struct footnote ***footnotesp)
131 const struct footnote **footnotes = NULL;
132 size_t allocated = 0;
135 struct table *t = item->table;
136 for (int y = 0; y < t->n[V]; y++)
138 struct table_cell cell;
139 for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1])
141 table_get_cell (t, x, y, &cell);
143 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
144 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
145 footnotes, &allocated, &n);
149 const struct table_item_text *title = table_item_get_title (item);
151 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
152 footnotes, &allocated, &n);
154 const struct table_item_layers *layers = table_item_get_layers (item);
157 for (size_t i = 0; i < layers->n_layers; i++)
158 footnotes = add_footnotes (layers->layers[i].footnotes,
159 layers->layers[i].n_footnotes,
160 footnotes, &allocated, &n);
163 const struct table_item_text *caption = table_item_get_caption (item);
165 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
166 footnotes, &allocated, &n);
168 size_t n_nonnull = 0;
169 for (size_t i = 0; i < n; i++)
171 footnotes[n_nonnull++] = footnotes[i];
173 *footnotesp = footnotes;
178 table_halign_to_string (enum table_halign halign)
182 case TABLE_HALIGN_LEFT: return "left";
183 case TABLE_HALIGN_CENTER: return "center";
184 case TABLE_HALIGN_RIGHT: return "right";
185 case TABLE_HALIGN_DECIMAL: return "decimal";
186 case TABLE_HALIGN_MIXED: return "mixed";
187 default: return "**error**";
192 table_valign_to_string (enum table_valign valign)
196 case TABLE_VALIGN_TOP: return "top";
197 case TABLE_VALIGN_CENTER: return "center";
198 case TABLE_VALIGN_BOTTOM: return "bottom";
199 default: return "**error**";
204 table_halign_interpret (enum table_halign halign, bool numeric)
208 case TABLE_HALIGN_LEFT:
209 case TABLE_HALIGN_CENTER:
210 case TABLE_HALIGN_RIGHT:
213 case TABLE_HALIGN_MIXED:
214 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
216 case TABLE_HALIGN_DECIMAL:
217 return TABLE_HALIGN_DECIMAL;
225 font_style_copy (struct pool *container,
226 struct font_style *dst, const struct font_style *src)
230 dst->typeface = pool_strdup (container, dst->typeface);
234 font_style_uninit (struct font_style *font)
237 free (font->typeface);
241 table_area_style_copy (struct pool *container, struct table_area_style *dst,
242 const struct table_area_style *src)
244 font_style_copy (container, &dst->font_style, &src->font_style);
245 dst->cell_style = src->cell_style;
249 table_area_style_uninit (struct table_area_style *area)
252 font_style_uninit (&area->font_style);
256 table_stroke_to_string (enum table_stroke stroke)
260 case TABLE_STROKE_NONE: return "none";
261 case TABLE_STROKE_SOLID: return "solid";
262 case TABLE_STROKE_DASHED: return "dashed";
263 case TABLE_STROKE_THICK: return "thick";
264 case TABLE_STROKE_THIN: return "thin";
265 case TABLE_STROKE_DOUBLE: return "double";
272 cell_color_dump (const struct cell_color *c)
275 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
277 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
281 font_style_dump (const struct font_style *f)
283 printf ("%s %dpx ", f->typeface, f->size);
284 cell_color_dump (&f->fg[0]);
286 cell_color_dump (&f->bg[0]);
287 if (!cell_color_equal (&f->fg[0], &f->fg[1])
288 || !cell_color_equal (&f->bg[0], &f->bg[1]))
291 cell_color_dump (&f->fg[1]);
293 cell_color_dump (&f->bg[1]);
296 fputs (" bold", stdout);
298 fputs (" italic", stdout);
300 fputs (" underline", stdout);
304 cell_style_dump (const struct cell_style *c)
306 fputs (table_halign_to_string (c->halign), stdout);
307 if (c->halign == TABLE_HALIGN_DECIMAL)
308 printf ("(%.2gpx)", c->decimal_offset);
309 printf (" %s", table_valign_to_string (c->valign));
310 printf (" %d,%d,%d,%dpx",
311 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
312 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
316 static const bool debugging = true;
318 /* Creates and returns a new table with NC columns and NR rows and initially no
319 header rows or columns.
321 Sets the number of header rows on each side of TABLE to HL on the
322 left, HR on the right, HT on the top, HB on the bottom. Header rows
323 are repeated when a table is broken across multiple columns or
326 The table's cells are initially empty. */
328 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
332 t = pool_create_container (struct table, container);
333 t->n[TABLE_HORZ] = nc;
334 t->n[TABLE_VERT] = nr;
335 t->h[TABLE_HORZ][0] = hl;
336 t->h[TABLE_HORZ][1] = hr;
337 t->h[TABLE_VERT][0] = ht;
338 t->h[TABLE_VERT][1] = hb;
341 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
342 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
344 t->rh = pool_nmalloc (t->container, nc, nr + 1);
345 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
347 t->rv = pool_nmalloc (t->container, nr, nc + 1);
348 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
350 memset (t->styles, 0, sizeof t->styles);
351 memset (t->rule_colors, 0, sizeof t->rule_colors);
358 /* Draws a vertical line to the left of cells at horizontal position X
359 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
361 table_vline (struct table *t, int style, int x, int y1, int y2)
365 if (x < 0 || x > t->n[H]
366 || y1 < 0 || y1 >= t->n[V]
367 || y2 < 0 || y2 >= t->n[V])
369 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
370 x, y1, y2, t->n[H], t->n[V]);
376 assert (x <= t->n[H]);
379 assert (y2 <= t->n[V]);
384 for (y = y1; y <= y2; y++)
385 t->rv[x + (t->n[H] + 1) * y] = style;
389 /* Draws a horizontal line above cells at vertical position Y from X1
390 to X2 inclusive in style STYLE, if style is not -1. */
392 table_hline (struct table *t, int style, int x1, int x2, int y)
396 if (y < 0 || y > t->n[V]
397 || x1 < 0 || x1 >= t->n[H]
398 || x2 < 0 || x2 >= t->n[H])
400 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
401 x1, x2, y, t->n[H], t->n[V]);
407 assert (y <= t->n[V]);
410 assert (x2 < t->n[H]);
415 for (x = x1; x <= x2; x++)
416 t->rh[x + t->n[H] * y] = style;
420 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
421 lines of style F_H and vertical lines of style F_V. Fills the
422 interior of the box with horizontal lines of style I_H and vertical
423 lines of style I_V. Any of the line styles may be -1 to avoid
424 drawing those lines. This is distinct from 0, which draws a null
427 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
428 int x1, int y1, int x2, int y2)
432 if (x1 < 0 || x1 >= t->n[H]
433 || x2 < 0 || x2 >= t->n[H]
434 || y1 < 0 || y1 >= t->n[V]
435 || y2 < 0 || y2 >= t->n[V])
437 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
438 x1, y1, x2, y2, t->n[H], t->n[V]);
447 assert (x2 < t->n[H]);
448 assert (y2 < t->n[V]);
453 for (x = x1; x <= x2; x++)
455 t->rh[x + t->n[H] * y1] = f_h;
456 t->rh[x + t->n[H] * (y2 + 1)] = f_h;
462 for (y = y1; y <= y2; y++)
464 t->rv[x1 + (t->n[H] + 1) * y] = f_v;
465 t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
473 for (y = y1 + 1; y <= y2; y++)
477 for (x = x1; x <= x2; x++)
478 t->rh[x + t->n[H] * y] = i_h;
485 for (x = x1 + 1; x <= x2; x++)
489 for (y = y1; y <= y2; y++)
490 t->rv[x + (t->n[H] + 1) * y] = i_v;
498 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
502 assert (c < table->n[H]);
503 assert (r < table->n[V]);
507 if (c < 0 || r < 0 || c >= table->n[H] || r >= table->n[V])
509 printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
510 c, r, table->n[H], table->n[V]);
515 table->cc[c + r * table->n[H]] = text;
516 table->ct[c + r * table->n[H]] = opt;
519 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
522 table_text (struct table *table, int c, int r, unsigned opt,
525 do_table_text (table, c, r, opt, pool_strdup (table->container, text));
528 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
529 FORMAT, which is formatted as if passed to printf. */
531 table_text_format (struct table *table, int c, int r, unsigned opt,
532 const char *format, ...)
536 va_start (args, format);
537 do_table_text (table, c, r, opt,
538 pool_vasprintf (table->container, format, args));
542 static struct table_cell *
543 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
550 assert (y2 < table->n[V]);
551 assert (x2 < table->n[H]);
555 if (x1 < 0 || x1 >= table->n[H]
556 || y1 < 0 || y1 >= table->n[V]
557 || x2 < x1 || x2 >= table->n[H]
558 || y2 < y1 || y2 >= table->n[V])
560 printf ("table_joint_text(): bad cell "
561 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
562 x1, y1, x2, y2, table->n[H], table->n[V]);
567 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
570 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
571 *cell = (struct table_cell) {
572 .d = { [TABLE_HORZ] = { x1, ++x2 },
573 [TABLE_VERT] = { y1, ++y2 } },
577 void **cc = &table->cc[x1 + y1 * table->n[H]];
578 unsigned short *ct = &table->ct[x1 + y1 * table->n[H]];
579 const int ofs = table->n[H] - (x2 - x1);
580 for (int y = y1; y < y2; y++)
582 for (int x = x1; x < x2; x++)
585 *ct++ = opt | TAB_JOIN;
595 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
596 options OPT to have text value TEXT. */
598 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
599 unsigned opt, const char *text)
601 char *s = pool_strdup (table->container, text);
602 if (x1 == x2 && y1 == y2)
603 do_table_text (table, x1, y1, opt, s);
605 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
608 static struct table_cell *
609 get_joined_cell (struct table *table, int x, int y)
611 int index = x + y * table->n[H];
612 unsigned short opt = table->ct[index];
613 struct table_cell *cell;
616 cell = table->cc[index];
619 char *text = table->cc[index];
621 cell = add_joined_cell (table, x, y, x, y, table->ct[index]);
622 cell->text = text ? text : pool_strdup (table->container, "");
627 /* Sets the subscripts for column X, row Y in TABLE. */
629 table_add_subscripts (struct table *table, int x, int y,
630 char **subscripts, size_t n_subscripts)
632 struct table_cell *cell = get_joined_cell (table, x, y);
634 cell->n_subscripts = n_subscripts;
635 cell->subscripts = pool_nalloc (table->container, n_subscripts,
636 sizeof *cell->subscripts);
637 for (size_t i = 0; i < n_subscripts; i++)
638 cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
641 /* Create a footnote in TABLE with MARKER (e.g. "a") as its marker and CONTENT
642 as its content. The footnote will be styled as STYLE, which is mandatory.
643 IDX must uniquely identify the footnote within TABLE.
645 Returns the new footnote. The return value is the only way to get to the
646 footnote later, so it is important for the caller to remember it. */
648 table_create_footnote (struct table *table, size_t idx, const char *content,
649 const char *marker, struct table_area_style *style)
653 struct footnote *f = pool_alloc (table->container, sizeof *f);
655 f->content = pool_strdup (table->container, content);
656 f->marker = pool_strdup (table->container, marker);
661 /* Attaches a reference to footnote F to the cell at column X, row Y in
664 table_add_footnote (struct table *table, int x, int y,
665 const struct footnote *f)
669 struct table_cell *cell = get_joined_cell (table, x, y);
671 cell->footnotes = pool_realloc (
672 table->container, cell->footnotes,
673 (cell->n_footnotes + 1) * sizeof *cell->footnotes);
675 cell->footnotes[cell->n_footnotes++] = f;
678 /* Overrides the style for column X, row Y in TABLE with STYLE.
679 Does not make a copy of STYLE, so it should either be allocated from
680 TABLE->container or have a lifetime that will outlive TABLE. */
682 table_add_style (struct table *table, int x, int y,
683 const struct table_area_style *style)
685 get_joined_cell (table, x, y)->style = style;
688 /* Returns true if column C, row R has no contents, otherwise false. */
690 table_cell_is_empty (const struct table *table, int c, int r)
692 return table->cc[c + r * table->n[H]] == NULL;
695 /* Initializes CELL with the contents of the table cell at column X and row Y
696 within TABLE. When CELL is no longer needed, the caller is responsible for
697 freeing it by calling table_cell_free(CELL).
699 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
701 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
703 assert (x >= 0 && x < t->n[TABLE_HORZ]);
704 assert (y >= 0 && y < t->n[TABLE_VERT]);
706 int index = x + y * t->n[H];
707 unsigned short opt = t->ct[index];
708 const void *cc = t->cc[index];
710 const struct table_area_style *style
711 = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
714 const struct table_cell *jc = cc;
720 *cell = (struct table_cell) {
721 .d = { [TABLE_HORZ] = { x, x + 1 },
722 [TABLE_VERT] = { y, y + 1 } },
724 .text = CONST_CAST (char *, cc ? cc : ""),
728 assert (cell->style);
731 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
732 representing a rule running alongside one of the cells in TABLE.
734 Suppose NC is the number of columns in TABLE and NR is the number of rows.
735 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
736 (0,0), the return value is the rule that runs vertically on the left side of
737 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
738 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
741 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
742 within a 7x7 table. The '|' characters at the intersection of the X labels
743 and Y labels show the rule whose style would be returned by calling
744 table_get_rule with those X and Y values:
747 +--+--+--+--+--+--+--+
749 +--+--+--+--+--+--+--+
751 +--+--+--+--+--+--+--+
753 +--+--+--+--+--+--+--+
755 +--+--+--+--+--+--+--+
757 +--+--+--+--+--+--+--+
759 +--+--+--+--+--+--+--+
761 +--+--+--+--+--+--+--+
763 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
764 (X,Y) = (0,0), the return value is the rule that runs horizontally above
765 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
766 between that cell and cell (0,1); and so on, up to (0,NR), which runs
767 horizontally below cell (0,NR-1). */
769 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
770 struct cell_color *color)
772 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
773 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
775 uint8_t raw = (axis == TABLE_VERT
776 ? table->rh[x + table->n[H] * y]
777 : table->rv[x + (table->n[H] + 1) * y]);
778 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
779 >> TAB_RULE_STYLE_SHIFT];
780 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
781 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;