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_halign_to_string (enum table_halign halign)
99 case TABLE_HALIGN_LEFT: return "left";
100 case TABLE_HALIGN_CENTER: return "center";
101 case TABLE_HALIGN_RIGHT: return "right";
102 case TABLE_HALIGN_DECIMAL: return "decimal";
103 case TABLE_HALIGN_MIXED: return "mixed";
104 default: return "**error**";
109 table_valign_to_string (enum table_valign valign)
113 case TABLE_VALIGN_TOP: return "top";
114 case TABLE_VALIGN_CENTER: return "center";
115 case TABLE_VALIGN_BOTTOM: return "bottom";
116 default: return "**error**";
121 table_halign_interpret (enum table_halign halign, bool numeric)
125 case TABLE_HALIGN_LEFT:
126 case TABLE_HALIGN_CENTER:
127 case TABLE_HALIGN_RIGHT:
130 case TABLE_HALIGN_MIXED:
131 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
133 case TABLE_HALIGN_DECIMAL:
134 return TABLE_HALIGN_DECIMAL;
142 font_style_copy (struct pool *container,
143 struct font_style *dst, const struct font_style *src)
147 dst->typeface = pool_strdup (container, dst->typeface);
151 font_style_uninit (struct font_style *font)
154 free (font->typeface);
158 table_area_style_copy (struct pool *container, struct table_area_style *dst,
159 const struct table_area_style *src)
161 font_style_copy (container, &dst->font_style, &src->font_style);
162 dst->cell_style = src->cell_style;
166 table_area_style_uninit (struct table_area_style *area)
169 font_style_uninit (&area->font_style);
173 table_stroke_to_string (enum table_stroke stroke)
177 case TABLE_STROKE_NONE: return "none";
178 case TABLE_STROKE_SOLID: return "solid";
179 case TABLE_STROKE_DASHED: return "dashed";
180 case TABLE_STROKE_THICK: return "thick";
181 case TABLE_STROKE_THIN: return "thin";
182 case TABLE_STROKE_DOUBLE: return "double";
189 cell_color_dump (const struct cell_color *c)
192 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
194 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
198 font_style_dump (const struct font_style *f)
200 printf ("%s %dpx ", f->typeface, f->size);
201 cell_color_dump (&f->fg[0]);
203 cell_color_dump (&f->bg[0]);
204 if (!cell_color_equal (&f->fg[0], &f->fg[1])
205 || !cell_color_equal (&f->bg[0], &f->bg[1]))
208 cell_color_dump (&f->fg[1]);
210 cell_color_dump (&f->bg[1]);
213 fputs (" bold", stdout);
215 fputs (" italic", stdout);
217 fputs (" underline", stdout);
221 font_style_equal (const struct font_style *a, const struct font_style *b)
223 return (a->bold == b->bold
224 && a->italic == b->italic
225 && a->underline == b->underline
226 && a->markup == b->markup
227 && cell_color_equal (&a->fg[0], &b->fg[0])
228 && cell_color_equal (&a->fg[1], &b->fg[1])
229 && cell_color_equal (&a->bg[0], &b->bg[0])
230 && cell_color_equal (&a->bg[1], &b->bg[1])
231 && !strcmp (a->typeface ? a->typeface : "",
232 b->typeface ? b->typeface : "")
233 && a->size == b->size);
237 cell_style_dump (const struct cell_style *c)
239 fputs (table_halign_to_string (c->halign), stdout);
240 if (c->halign == TABLE_HALIGN_DECIMAL)
241 printf ("(%.2gpx)", c->decimal_offset);
242 printf (" %s", table_valign_to_string (c->valign));
243 printf (" %d,%d,%d,%dpx",
244 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
245 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
249 static const bool debugging = true;
251 /* Creates and returns a new table with NC columns and NR rows and initially no
252 header rows or columns.
254 Sets the number of header rows on each side of TABLE to HL on the
255 left, HR on the right, HT on the top, HB on the bottom. Header rows
256 are repeated when a table is broken across multiple columns or
259 The table's cells are initially empty. */
261 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
265 t = pool_create_container (struct table, container);
266 t->n[TABLE_HORZ] = nc;
267 t->n[TABLE_VERT] = nr;
268 t->h[TABLE_HORZ][0] = hl;
269 t->h[TABLE_HORZ][1] = hr;
270 t->h[TABLE_VERT][0] = ht;
271 t->h[TABLE_VERT][1] = hb;
274 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
275 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
277 t->rh = pool_nmalloc (t->container, nc, nr + 1);
278 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
280 t->rv = pool_nmalloc (t->container, nr, nc + 1);
281 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
283 memset (t->styles, 0, sizeof t->styles);
284 memset (t->rule_colors, 0, sizeof t->rule_colors);
291 /* Draws a vertical line to the left of cells at horizontal position X
292 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
294 table_vline (struct table *t, int style, int x, int y1, int y2)
298 if (x < 0 || x > t->n[H]
299 || y1 < 0 || y1 >= t->n[V]
300 || y2 < 0 || y2 >= t->n[V])
302 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
303 x, y1, y2, t->n[H], t->n[V]);
309 assert (x <= t->n[H]);
312 assert (y2 <= t->n[V]);
317 for (y = y1; y <= y2; y++)
318 t->rv[x + (t->n[H] + 1) * y] = style;
322 /* Draws a horizontal line above cells at vertical position Y from X1
323 to X2 inclusive in style STYLE, if style is not -1. */
325 table_hline (struct table *t, int style, int x1, int x2, int y)
329 if (y < 0 || y > t->n[V]
330 || x1 < 0 || x1 >= t->n[H]
331 || x2 < 0 || x2 >= t->n[H])
333 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
334 x1, x2, y, t->n[H], t->n[V]);
340 assert (y <= t->n[V]);
343 assert (x2 < t->n[H]);
348 for (x = x1; x <= x2; x++)
349 t->rh[x + t->n[H] * y] = style;
353 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
354 lines of style F_H and vertical lines of style F_V. Fills the
355 interior of the box with horizontal lines of style I_H and vertical
356 lines of style I_V. Any of the line styles may be -1 to avoid
357 drawing those lines. This is distinct from 0, which draws a null
360 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
361 int x1, int y1, int x2, int y2)
365 if (x1 < 0 || x1 >= t->n[H]
366 || x2 < 0 || x2 >= t->n[H]
367 || y1 < 0 || y1 >= t->n[V]
368 || y2 < 0 || y2 >= t->n[V])
370 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
371 x1, y1, x2, y2, t->n[H], t->n[V]);
380 assert (x2 < t->n[H]);
381 assert (y2 < t->n[V]);
386 for (x = x1; x <= x2; x++)
388 t->rh[x + t->n[H] * y1] = f_h;
389 t->rh[x + t->n[H] * (y2 + 1)] = f_h;
395 for (y = y1; y <= y2; y++)
397 t->rv[x1 + (t->n[H] + 1) * y] = f_v;
398 t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
406 for (y = y1 + 1; y <= y2; y++)
410 for (x = x1; x <= x2; x++)
411 t->rh[x + t->n[H] * y] = i_h;
418 for (x = x1 + 1; x <= x2; x++)
422 for (y = y1; y <= y2; y++)
423 t->rv[x + (t->n[H] + 1) * y] = i_v;
431 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
435 assert (c < table->n[H]);
436 assert (r < table->n[V]);
440 if (c < 0 || r < 0 || c >= table->n[H] || r >= table->n[V])
442 printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
443 c, r, table->n[H], table->n[V]);
448 table->cc[c + r * table->n[H]] = text;
449 table->ct[c + r * table->n[H]] = opt;
452 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
455 table_text (struct table *table, int c, int r, unsigned opt,
458 do_table_text (table, c, r, opt, pool_strdup (table->container, text));
461 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
462 FORMAT, which is formatted as if passed to printf. */
464 table_text_format (struct table *table, int c, int r, unsigned opt,
465 const char *format, ...)
469 va_start (args, format);
470 do_table_text (table, c, r, opt,
471 pool_vasprintf (table->container, format, args));
475 static struct table_cell *
476 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
483 assert (y2 < table->n[V]);
484 assert (x2 < table->n[H]);
488 if (x1 < 0 || x1 >= table->n[H]
489 || y1 < 0 || y1 >= table->n[V]
490 || x2 < x1 || x2 >= table->n[H]
491 || y2 < y1 || y2 >= table->n[V])
493 printf ("table_joint_text(): bad cell "
494 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
495 x1, y1, x2, y2, table->n[H], table->n[V]);
500 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
503 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
504 *cell = (struct table_cell) {
505 .d = { [TABLE_HORZ] = { x1, ++x2 },
506 [TABLE_VERT] = { y1, ++y2 } },
510 void **cc = &table->cc[x1 + y1 * table->n[H]];
511 unsigned short *ct = &table->ct[x1 + y1 * table->n[H]];
512 const int ofs = table->n[H] - (x2 - x1);
513 for (int y = y1; y < y2; y++)
515 for (int x = x1; x < x2; x++)
518 *ct++ = opt | TAB_JOIN;
528 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
529 options OPT to have text value TEXT. */
531 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
532 unsigned opt, const char *text)
534 char *s = pool_strdup (table->container, text);
535 if (x1 == x2 && y1 == y2)
536 do_table_text (table, x1, y1, opt, s);
538 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
541 static struct table_cell *
542 get_joined_cell (struct table *table, int x, int y)
544 int index = x + y * table->n[H];
545 unsigned short opt = table->ct[index];
546 struct table_cell *cell;
549 cell = table->cc[index];
552 char *text = table->cc[index];
554 cell = add_joined_cell (table, x, y, x, y, table->ct[index]);
555 cell->text = text ? text : pool_strdup (table->container, "");
560 /* Sets the subscripts for column X, row Y in TABLE. */
562 table_add_subscripts (struct table *table, int x, int y,
563 char **subscripts, size_t n_subscripts)
565 struct table_cell *cell = get_joined_cell (table, x, y);
567 cell->n_subscripts = n_subscripts;
568 cell->subscripts = pool_nalloc (table->container, n_subscripts,
569 sizeof *cell->subscripts);
570 for (size_t i = 0; i < n_subscripts; i++)
571 cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
574 /* Attaches a reference to the NF footnotes at F to the cell at column X, row Y
577 table_add_footnotes (struct table *table, int x, int y,
578 struct pivot_footnote **f, size_t nf)
580 struct table_cell *cell = get_joined_cell (table, x, y);
582 cell->footnotes = pool_realloc (
583 table->container, cell->footnotes,
584 (cell->n_footnotes + nf) * sizeof *cell->footnotes);
586 for (size_t i = 0; i < nf; i++)
587 cell->footnotes[cell->n_footnotes++] = f[i];
590 /* Overrides the style for column X, row Y in TABLE with STYLE.
591 Does not make a copy of STYLE, so it should either be allocated from
592 TABLE->container or have a lifetime that will outlive TABLE. */
594 table_add_style (struct table *table, int x, int y,
595 struct table_area_style *style)
597 get_joined_cell (table, x, y)->style = style;
600 /* Returns true if column C, row R has no contents, otherwise false. */
602 table_cell_is_empty (const struct table *table, int c, int r)
604 return table->cc[c + r * table->n[H]] == NULL;
607 /* Initializes CELL with the contents of the table cell at column X and row Y
610 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
612 assert (x >= 0 && x < t->n[TABLE_HORZ]);
613 assert (y >= 0 && y < t->n[TABLE_VERT]);
615 int index = x + y * t->n[H];
616 unsigned short opt = t->ct[index];
617 const void *cc = t->cc[index];
619 struct table_area_style *style
620 = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
623 const struct table_cell *jc = cc;
629 *cell = (struct table_cell) {
630 .d = { [TABLE_HORZ] = { x, x + 1 },
631 [TABLE_VERT] = { y, y + 1 } },
633 .text = CONST_CAST (char *, cc ? cc : ""),
637 assert (cell->style);
640 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
641 representing a rule running alongside one of the cells in TABLE.
643 Suppose NC is the number of columns in TABLE and NR is the number of rows.
644 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
645 (0,0), the return value is the rule that runs vertically on the left side of
646 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
647 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
650 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
651 within a 7x7 table. The '|' characters at the intersection of the X labels
652 and Y labels show the rule whose style would be returned by calling
653 table_get_rule with those X and Y values:
656 +--+--+--+--+--+--+--+
658 +--+--+--+--+--+--+--+
660 +--+--+--+--+--+--+--+
662 +--+--+--+--+--+--+--+
664 +--+--+--+--+--+--+--+
666 +--+--+--+--+--+--+--+
668 +--+--+--+--+--+--+--+
670 +--+--+--+--+--+--+--+
672 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
673 (X,Y) = (0,0), the return value is the rule that runs horizontally above
674 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
675 between that cell and cell (0,1); and so on, up to (0,NR), which runs
676 horizontally below cell (0,NR-1). */
678 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
679 struct cell_color *color)
681 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
682 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
684 uint8_t raw = (axis == TABLE_VERT
685 ? table->rh[x + table->n[H] * y]
686 : table->rv[x + (table->n[H] + 1) * y]);
687 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
688 >> TAB_RULE_STYLE_SHIFT];
689 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
690 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;