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 /* Increases TABLE's reference count, indicating that it has an additional
39 owner. An table that is shared among multiple owners must not be
42 table_ref (const struct table *table_)
44 struct table *table = CONST_CAST (struct table *, table_);
49 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
50 If TABLE no longer has any owners, it is freed. */
52 table_unref (struct table *table)
56 assert (table->ref_cnt > 0);
57 if (--table->ref_cnt == 0)
58 pool_destroy (table->container);
62 /* Returns true if TABLE has more than one owner. A table item that is shared
63 among multiple owners must not be modified. */
65 table_is_shared (const struct table *table)
67 return table->ref_cnt > 1;
70 struct table_area_style *
71 table_area_style_clone (struct pool *pool, const struct table_area_style *old)
73 struct table_area_style *new = pool_malloc (pool, sizeof *new);
75 if (new->font_style.typeface)
76 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
81 table_area_style_free (struct table_area_style *style)
85 free (style->font_style.typeface);
91 table_cell_format_footnote_markers (const struct table_cell *cell,
94 for (size_t i = 0; i < cell->n_footnotes; i++)
98 ds_put_cstr (s, cell->footnotes[i]->marker);
102 static const struct footnote **
103 add_footnotes (const struct footnote **refs, size_t n_refs,
104 const struct footnote **footnotes, size_t *allocated, size_t *n)
106 for (size_t i = 0; i < n_refs; i++)
108 const struct footnote *f = refs[i];
109 if (f->idx >= *allocated)
111 size_t new_allocated = (f->idx + 1) * 2;
112 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
113 while (*allocated < new_allocated)
114 footnotes[(*allocated)++] = NULL;
116 footnotes[f->idx] = f;
124 table_collect_footnotes (const struct table_item *item,
125 const struct footnote ***footnotesp)
127 const struct footnote **footnotes = NULL;
128 size_t allocated = 0;
131 struct table *t = item->table;
132 for (int y = 0; y < table_nr (t); y++)
134 struct table_cell cell;
135 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
137 table_get_cell (t, x, y, &cell);
139 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
140 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
141 footnotes, &allocated, &n);
145 const struct table_item_text *title = table_item_get_title (item);
147 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
148 footnotes, &allocated, &n);
150 const struct table_item_layers *layers = table_item_get_layers (item);
153 for (size_t i = 0; i < layers->n_layers; i++)
154 footnotes = add_footnotes (layers->layers[i].footnotes,
155 layers->layers[i].n_footnotes,
156 footnotes, &allocated, &n);
159 const struct table_item_text *caption = table_item_get_caption (item);
161 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
162 footnotes, &allocated, &n);
164 size_t n_nonnull = 0;
165 for (size_t i = 0; i < n; i++)
167 footnotes[n_nonnull++] = footnotes[i];
169 *footnotesp = footnotes;
174 table_halign_to_string (enum table_halign halign)
178 case TABLE_HALIGN_LEFT: return "left";
179 case TABLE_HALIGN_CENTER: return "center";
180 case TABLE_HALIGN_RIGHT: return "right";
181 case TABLE_HALIGN_DECIMAL: return "decimal";
182 case TABLE_HALIGN_MIXED: return "mixed";
183 default: return "**error**";
188 table_valign_to_string (enum table_valign valign)
192 case TABLE_VALIGN_TOP: return "top";
193 case TABLE_VALIGN_CENTER: return "center";
194 case TABLE_VALIGN_BOTTOM: return "bottom";
195 default: return "**error**";
200 table_halign_interpret (enum table_halign halign, bool numeric)
204 case TABLE_HALIGN_LEFT:
205 case TABLE_HALIGN_CENTER:
206 case TABLE_HALIGN_RIGHT:
209 case TABLE_HALIGN_MIXED:
210 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
212 case TABLE_HALIGN_DECIMAL:
213 return TABLE_HALIGN_DECIMAL;
221 font_style_copy (struct pool *container,
222 struct font_style *dst, const struct font_style *src)
226 dst->typeface = pool_strdup (container, dst->typeface);
230 font_style_uninit (struct font_style *font)
233 free (font->typeface);
237 table_area_style_copy (struct pool *container, struct table_area_style *dst,
238 const struct table_area_style *src)
240 font_style_copy (container, &dst->font_style, &src->font_style);
241 dst->cell_style = src->cell_style;
245 table_area_style_uninit (struct table_area_style *area)
248 font_style_uninit (&area->font_style);
252 table_stroke_to_string (enum table_stroke stroke)
256 case TABLE_STROKE_NONE: return "none";
257 case TABLE_STROKE_SOLID: return "solid";
258 case TABLE_STROKE_DASHED: return "dashed";
259 case TABLE_STROKE_THICK: return "thick";
260 case TABLE_STROKE_THIN: return "thin";
261 case TABLE_STROKE_DOUBLE: return "double";
268 cell_color_dump (const struct cell_color *c)
271 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
273 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
277 font_style_dump (const struct font_style *f)
279 printf ("%s %dpx ", f->typeface, f->size);
280 cell_color_dump (&f->fg[0]);
282 cell_color_dump (&f->bg[0]);
283 if (!cell_color_equal (&f->fg[0], &f->fg[1])
284 || !cell_color_equal (&f->bg[0], &f->bg[1]))
287 cell_color_dump (&f->fg[1]);
289 cell_color_dump (&f->bg[1]);
292 fputs (" bold", stdout);
294 fputs (" italic", stdout);
296 fputs (" underline", stdout);
300 cell_style_dump (const struct cell_style *c)
302 fputs (table_halign_to_string (c->halign), stdout);
303 if (c->halign == TABLE_HALIGN_DECIMAL)
304 printf ("(%.2gpx)", c->decimal_offset);
305 printf (" %s", table_valign_to_string (c->valign));
306 printf (" %d,%d,%d,%dpx",
307 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
308 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
312 static const bool debugging = true;
314 /* Creates and returns a new table with NC columns and NR rows and initially no
315 header rows or columns.
317 Sets the number of header rows on each side of TABLE to HL on the
318 left, HR on the right, HT on the top, HB on the bottom. Header rows
319 are repeated when a table is broken across multiple columns or
322 The table's cells are initially empty. */
324 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
328 t = pool_create_container (struct table, container);
329 t->n[TABLE_HORZ] = nc;
330 t->n[TABLE_VERT] = nr;
331 t->h[TABLE_HORZ][0] = hl;
332 t->h[TABLE_HORZ][1] = hr;
333 t->h[TABLE_VERT][0] = ht;
334 t->h[TABLE_VERT][1] = hb;
337 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
338 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
340 t->rh = pool_nmalloc (t->container, nc, nr + 1);
341 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
343 t->rv = pool_nmalloc (t->container, nr, nc + 1);
344 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
346 memset (t->styles, 0, sizeof t->styles);
347 memset (t->rule_colors, 0, sizeof t->rule_colors);
354 /* Draws a vertical line to the left of cells at horizontal position X
355 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
357 table_vline (struct table *t, int style, int x, int y1, int y2)
361 if (x < 0 || x > table_nc (t)
362 || y1 < 0 || y1 >= table_nr (t)
363 || y2 < 0 || y2 >= table_nr (t))
365 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
366 x, y1, y2, table_nc (t), table_nr (t));
372 assert (x <= table_nc (t));
375 assert (y2 <= table_nr (t));
380 for (y = y1; y <= y2; y++)
381 t->rv[x + (table_nc (t) + 1) * y] = style;
385 /* Draws a horizontal line above cells at vertical position Y from X1
386 to X2 inclusive in style STYLE, if style is not -1. */
388 table_hline (struct table *t, int style, int x1, int x2, int y)
392 if (y < 0 || y > table_nr (t)
393 || x1 < 0 || x1 >= table_nc (t)
394 || x2 < 0 || x2 >= table_nc (t))
396 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
397 x1, x2, y, table_nc (t), table_nr (t));
403 assert (y <= table_nr (t));
406 assert (x2 < table_nc (t));
411 for (x = x1; x <= x2; x++)
412 t->rh[x + table_nc (t) * y] = style;
416 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
417 lines of style F_H and vertical lines of style F_V. Fills the
418 interior of the box with horizontal lines of style I_H and vertical
419 lines of style I_V. Any of the line styles may be -1 to avoid
420 drawing those lines. This is distinct from 0, which draws a null
423 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
424 int x1, int y1, int x2, int y2)
428 if (x1 < 0 || x1 >= table_nc (t)
429 || x2 < 0 || x2 >= table_nc (t)
430 || y1 < 0 || y1 >= table_nr (t)
431 || y2 < 0 || y2 >= table_nr (t))
433 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
434 x1, y1, x2, y2, table_nc (t), table_nr (t));
443 assert (x2 < table_nc (t));
444 assert (y2 < table_nr (t));
449 for (x = x1; x <= x2; x++)
451 t->rh[x + table_nc (t) * y1] = f_h;
452 t->rh[x + table_nc (t) * (y2 + 1)] = f_h;
458 for (y = y1; y <= y2; y++)
460 t->rv[x1 + (table_nc (t) + 1) * y] = f_v;
461 t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v;
469 for (y = y1 + 1; y <= y2; y++)
473 for (x = x1; x <= x2; x++)
474 t->rh[x + table_nc (t) * y] = i_h;
481 for (x = x1 + 1; x <= x2; x++)
485 for (y = y1; y <= y2; y++)
486 t->rv[x + (table_nc (t) + 1) * y] = i_v;
494 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
498 assert (c < table_nc (table));
499 assert (r < table_nr (table));
503 if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table))
505 printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
506 c, r, table_nc (table), table_nr (table));
511 table->cc[c + r * table_nc (table)] = text;
512 table->ct[c + r * table_nc (table)] = opt;
515 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
518 table_text (struct table *table, int c, int r, unsigned opt,
521 do_table_text (table, c, r, opt, pool_strdup (table->container, text));
524 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
525 FORMAT, which is formatted as if passed to printf. */
527 table_text_format (struct table *table, int c, int r, unsigned opt,
528 const char *format, ...)
532 va_start (args, format);
533 do_table_text (table, c, r, opt,
534 pool_vasprintf (table->container, format, args));
538 static struct table_cell *
539 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
546 assert (y2 < table_nr (table));
547 assert (x2 < table_nc (table));
551 if (x1 < 0 || x1 >= table_nc (table)
552 || y1 < 0 || y1 >= table_nr (table)
553 || x2 < x1 || x2 >= table_nc (table)
554 || y2 < y1 || y2 >= table_nr (table))
556 printf ("table_joint_text(): bad cell "
557 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
558 x1, y1, x2, y2, table_nc (table), table_nr (table));
563 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
566 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
567 *cell = (struct table_cell) {
568 .d = { [TABLE_HORZ] = { x1, ++x2 },
569 [TABLE_VERT] = { y1, ++y2 } },
573 void **cc = &table->cc[x1 + y1 * table_nc (table)];
574 unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)];
575 const int ofs = table_nc (table) - (x2 - x1);
576 for (int y = y1; y < y2; y++)
578 for (int x = x1; x < x2; x++)
581 *ct++ = opt | TAB_JOIN;
591 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
592 options OPT to have text value TEXT. */
594 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
595 unsigned opt, const char *text)
597 char *s = pool_strdup (table->container, text);
598 if (x1 == x2 && y1 == y2)
599 do_table_text (table, x1, y1, opt, s);
601 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
604 static struct table_cell *
605 get_joined_cell (struct table *table, int x, int y)
607 int index = x + y * table_nc (table);
608 unsigned short opt = table->ct[index];
609 struct table_cell *cell;
612 cell = table->cc[index];
615 char *text = table->cc[index];
617 cell = add_joined_cell (table, x, y, x, y, table->ct[index]);
618 cell->text = text ? text : pool_strdup (table->container, "");
623 /* Sets the subscripts for column X, row Y in TABLE. */
625 table_add_subscripts (struct table *table, int x, int y,
626 char **subscripts, size_t n_subscripts)
628 struct table_cell *cell = get_joined_cell (table, x, y);
630 cell->n_subscripts = n_subscripts;
631 cell->subscripts = pool_nalloc (table->container, n_subscripts,
632 sizeof *cell->subscripts);
633 for (size_t i = 0; i < n_subscripts; i++)
634 cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
637 /* Sets the superscript for column X, row Y in TABLE. */
639 table_add_superscript (struct table *table, int x, int y,
640 const char *superscript)
642 get_joined_cell (table, x, y)->superscript
643 = pool_strdup (table->container, superscript);
646 /* Create a footnote in TABLE with MARKER (e.g. "a") as its marker and CONTENT
647 as its content. The footnote will be styled as STYLE, which is mandatory.
648 IDX must uniquely identify the footnote within TABLE.
650 Returns the new footnote. The return value is the only way to get to the
651 footnote later, so it is important for the caller to remember it. */
653 table_create_footnote (struct table *table, size_t idx, const char *content,
654 const char *marker, struct table_area_style *style)
658 struct footnote *f = pool_alloc (table->container, sizeof *f);
660 f->content = pool_strdup (table->container, content);
661 f->marker = pool_strdup (table->container, marker);
666 /* Attaches a reference to footnote F to the cell at column X, row Y in
669 table_add_footnote (struct table *table, int x, int y,
670 const struct footnote *f)
674 struct table_cell *cell = get_joined_cell (table, x, y);
676 cell->footnotes = pool_realloc (
677 table->container, cell->footnotes,
678 (cell->n_footnotes + 1) * sizeof *cell->footnotes);
680 cell->footnotes[cell->n_footnotes++] = f;
683 /* Overrides the style for column X, row Y in TABLE with STYLE.
684 Does not make a copy of STYLE, so it should either be allocated from
685 TABLE->container or have a lifetime that will outlive TABLE. */
687 table_add_style (struct table *table, int x, int y,
688 const struct table_area_style *style)
690 get_joined_cell (table, x, y)->style = style;
693 /* Returns true if column C, row R has no contents, otherwise false. */
695 table_cell_is_empty (const struct table *table, int c, int r)
697 return table->cc[c + r * table_nc (table)] == NULL;
700 /* Initializes CELL with the contents of the table cell at column X and row Y
701 within TABLE. When CELL is no longer needed, the caller is responsible for
702 freeing it by calling table_cell_free(CELL).
704 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
706 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
708 assert (x >= 0 && x < t->n[TABLE_HORZ]);
709 assert (y >= 0 && y < t->n[TABLE_VERT]);
711 int index = x + y * table_nc (t);
712 unsigned short opt = t->ct[index];
713 const void *cc = t->cc[index];
715 const struct table_area_style *style
716 = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
719 const struct table_cell *jc = cc;
725 *cell = (struct table_cell) {
726 .d = { [TABLE_HORZ] = { x, x + 1 },
727 [TABLE_VERT] = { y, y + 1 } },
729 .text = CONST_CAST (char *, cc ? cc : ""),
733 assert (cell->style);
736 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
737 representing a rule running alongside one of the cells in TABLE.
739 Suppose NC is the number of columns in TABLE and NR is the number of rows.
740 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
741 (0,0), the return value is the rule that runs vertically on the left side of
742 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
743 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
746 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
747 within a 7x7 table. The '|' characters at the intersection of the X labels
748 and Y labels show the rule whose style would be returned by calling
749 table_get_rule with those X and Y values:
752 +--+--+--+--+--+--+--+
754 +--+--+--+--+--+--+--+
756 +--+--+--+--+--+--+--+
758 +--+--+--+--+--+--+--+
760 +--+--+--+--+--+--+--+
762 +--+--+--+--+--+--+--+
764 +--+--+--+--+--+--+--+
766 +--+--+--+--+--+--+--+
768 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
769 (X,Y) = (0,0), the return value is the rule that runs horizontally above
770 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
771 between that cell and cell (0,1); and so on, up to (0,NR), which runs
772 horizontally below cell (0,NR-1). */
774 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
775 struct cell_color *color)
777 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
778 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
780 uint8_t raw = (axis == TABLE_VERT
781 ? table->rh[x + table_nc (table) * y]
782 : table->rv[x + (table_nc (table) + 1) * y]);
783 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
784 >> TAB_RULE_STYLE_SHIFT];
785 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
786 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;