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/pivot-table.h"
33 #include "output/table-item.h"
34 #include "output/table.h"
35 #include "output/text-item.h"
37 #include "gl/xalloc.h"
39 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
43 /* Increases TABLE's reference count, indicating that it has an additional
44 owner. An table that is shared among multiple owners must not be
47 table_ref (const struct table *table_)
49 struct table *table = CONST_CAST (struct table *, table_);
54 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
55 If TABLE no longer has any owners, it is freed. */
57 table_unref (struct table *table)
61 assert (table->ref_cnt > 0);
62 if (--table->ref_cnt == 0)
63 pool_destroy (table->container);
67 /* Returns true if TABLE has more than one owner. A table item that is shared
68 among multiple owners must not be modified. */
70 table_is_shared (const struct table *table)
72 return table->ref_cnt > 1;
75 struct table_area_style *
76 table_area_style_clone (struct pool *pool, const struct table_area_style *old)
78 struct table_area_style *new = pool_malloc (pool, sizeof *new);
80 if (new->font_style.typeface)
81 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
86 table_area_style_free (struct table_area_style *style)
90 free (style->font_style.typeface);
96 table_halign_to_string (enum table_halign halign)
100 case TABLE_HALIGN_LEFT: return "left";
101 case TABLE_HALIGN_CENTER: return "center";
102 case TABLE_HALIGN_RIGHT: return "right";
103 case TABLE_HALIGN_DECIMAL: return "decimal";
104 case TABLE_HALIGN_MIXED: return "mixed";
105 default: return "**error**";
110 table_valign_to_string (enum table_valign valign)
114 case TABLE_VALIGN_TOP: return "top";
115 case TABLE_VALIGN_CENTER: return "center";
116 case TABLE_VALIGN_BOTTOM: return "bottom";
117 default: return "**error**";
122 table_halign_interpret (enum table_halign halign, bool numeric)
126 case TABLE_HALIGN_LEFT:
127 case TABLE_HALIGN_CENTER:
128 case TABLE_HALIGN_RIGHT:
131 case TABLE_HALIGN_MIXED:
132 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
134 case TABLE_HALIGN_DECIMAL:
135 return TABLE_HALIGN_DECIMAL;
143 font_style_copy (struct pool *container,
144 struct font_style *dst, const struct font_style *src)
148 dst->typeface = pool_strdup (container, dst->typeface);
152 font_style_uninit (struct font_style *font)
155 free (font->typeface);
159 table_area_style_copy (struct pool *container, struct table_area_style *dst,
160 const struct table_area_style *src)
162 font_style_copy (container, &dst->font_style, &src->font_style);
163 dst->cell_style = src->cell_style;
167 table_area_style_uninit (struct table_area_style *area)
170 font_style_uninit (&area->font_style);
174 table_stroke_to_string (enum table_stroke stroke)
178 case TABLE_STROKE_NONE: return "none";
179 case TABLE_STROKE_SOLID: return "solid";
180 case TABLE_STROKE_DASHED: return "dashed";
181 case TABLE_STROKE_THICK: return "thick";
182 case TABLE_STROKE_THIN: return "thin";
183 case TABLE_STROKE_DOUBLE: return "double";
190 cell_color_dump (const struct cell_color *c)
193 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
195 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
199 font_style_dump (const struct font_style *f)
201 printf ("%s %dpx ", f->typeface, f->size);
202 cell_color_dump (&f->fg[0]);
204 cell_color_dump (&f->bg[0]);
205 if (!cell_color_equal (&f->fg[0], &f->fg[1])
206 || !cell_color_equal (&f->bg[0], &f->bg[1]))
209 cell_color_dump (&f->fg[1]);
211 cell_color_dump (&f->bg[1]);
214 fputs (" bold", stdout);
216 fputs (" italic", stdout);
218 fputs (" underline", stdout);
222 font_style_equal (const struct font_style *a, const struct font_style *b)
224 return (a->bold == b->bold
225 && a->italic == b->italic
226 && a->underline == b->underline
227 && a->markup == b->markup
228 && cell_color_equal (&a->fg[0], &b->fg[0])
229 && cell_color_equal (&a->fg[1], &b->fg[1])
230 && cell_color_equal (&a->bg[0], &b->bg[0])
231 && cell_color_equal (&a->bg[1], &b->bg[1])
232 && !strcmp (a->typeface ? a->typeface : "",
233 b->typeface ? b->typeface : "")
234 && a->size == b->size);
238 cell_style_dump (const struct cell_style *c)
240 fputs (table_halign_to_string (c->halign), stdout);
241 if (c->halign == TABLE_HALIGN_DECIMAL)
242 printf ("(%.2gpx)", c->decimal_offset);
243 printf (" %s", table_valign_to_string (c->valign));
244 printf (" %d,%d,%d,%dpx",
245 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
246 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
250 static const bool debugging = true;
252 /* Creates and returns a new table with NC columns and NR rows and initially no
253 header rows or columns.
255 Sets the number of header rows on each side of TABLE to HL on the
256 left, HR on the right, HT on the top, HB on the bottom. Header rows
257 are repeated when a table is broken across multiple columns or
260 The table's cells are initially empty. */
262 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
266 t = pool_create_container (struct table, container);
267 t->n[TABLE_HORZ] = nc;
268 t->n[TABLE_VERT] = nr;
269 t->h[TABLE_HORZ][0] = hl;
270 t->h[TABLE_HORZ][1] = hr;
271 t->h[TABLE_VERT][0] = ht;
272 t->h[TABLE_VERT][1] = hb;
275 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
276 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
278 t->rh = pool_nmalloc (t->container, nc, nr + 1);
279 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
281 t->rv = pool_nmalloc (t->container, nr, nc + 1);
282 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
284 memset (t->styles, 0, sizeof t->styles);
285 memset (t->rule_colors, 0, sizeof t->rule_colors);
292 /* Draws a vertical line to the left of cells at horizontal position X
293 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
295 table_vline (struct table *t, int style, int x, int y1, int y2)
299 if (x < 0 || x > t->n[H]
300 || y1 < 0 || y1 >= t->n[V]
301 || y2 < 0 || y2 >= t->n[V])
303 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
304 x, y1, y2, t->n[H], t->n[V]);
310 assert (x <= t->n[H]);
313 assert (y2 <= t->n[V]);
318 for (y = y1; y <= y2; y++)
319 t->rv[x + (t->n[H] + 1) * y] = style;
323 /* Draws a horizontal line above cells at vertical position Y from X1
324 to X2 inclusive in style STYLE, if style is not -1. */
326 table_hline (struct table *t, int style, int x1, int x2, int y)
330 if (y < 0 || y > t->n[V]
331 || x1 < 0 || x1 >= t->n[H]
332 || x2 < 0 || x2 >= t->n[H])
334 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
335 x1, x2, y, t->n[H], t->n[V]);
341 assert (y <= t->n[V]);
344 assert (x2 < t->n[H]);
349 for (x = x1; x <= x2; x++)
350 t->rh[x + t->n[H] * y] = style;
354 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
355 lines of style F_H and vertical lines of style F_V. Fills the
356 interior of the box with horizontal lines of style I_H and vertical
357 lines of style I_V. Any of the line styles may be -1 to avoid
358 drawing those lines. This is distinct from 0, which draws a null
361 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
362 int x1, int y1, int x2, int y2)
366 if (x1 < 0 || x1 >= t->n[H]
367 || x2 < 0 || x2 >= t->n[H]
368 || y1 < 0 || y1 >= t->n[V]
369 || y2 < 0 || y2 >= t->n[V])
371 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
372 x1, y1, x2, y2, t->n[H], t->n[V]);
381 assert (x2 < t->n[H]);
382 assert (y2 < t->n[V]);
387 for (x = x1; x <= x2; x++)
389 t->rh[x + t->n[H] * y1] = f_h;
390 t->rh[x + t->n[H] * (y2 + 1)] = f_h;
396 for (y = y1; y <= y2; y++)
398 t->rv[x1 + (t->n[H] + 1) * y] = f_v;
399 t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
407 for (y = y1 + 1; y <= y2; y++)
411 for (x = x1; x <= x2; x++)
412 t->rh[x + t->n[H] * y] = i_h;
419 for (x = x1 + 1; x <= x2; x++)
423 for (y = y1; y <= y2; y++)
424 t->rv[x + (t->n[H] + 1) * y] = i_v;
431 /* Fill TABLE cells (X1,X2)-(Y1,Y2), inclusive, with VALUE and OPT. */
433 table_put (struct table *table, int x1, int y1, int x2, int y2,
434 unsigned opt, const struct pivot_value *value)
436 assert (0 <= x1 && x1 <= x2 && x2 < table->n[H]);
437 assert (0 <= y1 && y1 <= y2 && y2 < table->n[V]);
439 if (x1 == x2 && y1 == y2)
441 table->cc[x1 + y1 * table->n[H]] = CONST_CAST (struct pivot_value *, value);
442 table->ct[x1 + y1 * table->n[H]] = opt;
446 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
449 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
450 *cell = (struct table_cell) {
451 .d = { [H] = { x1, x2 + 1 }, [V] = { y1, y2 + 1 } },
456 for (int y = y1; y <= y2; y++)
458 size_t ofs = x1 + y * table->n[H];
459 void **cc = &table->cc[ofs];
460 unsigned short *ct = &table->ct[ofs];
461 for (int x = x1; x <= x2; x++)
464 *ct++ = opt | TAB_JOIN;
471 free_value (void *value_)
473 struct pivot_value *value = value_;
474 pivot_value_destroy (value);
478 table_put_owned (struct table *table, int x1, int y1, int x2, int y2,
479 unsigned opt, struct pivot_value *value)
481 table_put (table, x1, y1, x2, y2, opt, value);
482 pool_register (table->container, free_value, value);
485 /* Returns true if column C, row R has no contents, otherwise false. */
487 table_cell_is_empty (const struct table *table, int c, int r)
489 return table->cc[c + r * table->n[H]] == NULL;
492 /* Initializes CELL with the contents of the table cell at column X and row Y
495 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
497 assert (x >= 0 && x < t->n[TABLE_HORZ]);
498 assert (y >= 0 && y < t->n[TABLE_VERT]);
500 int index = x + y * t->n[H];
501 unsigned short opt = t->ct[index];
502 const void *cc = t->cc[index];
504 struct table_area_style *style
505 = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
507 static const struct pivot_value empty_value = {
508 .type = PIVOT_VALUE_TEXT,
510 .local = (char *) "",
513 .user_provided = true,
519 const struct table_cell *jc = cc;
522 cell->value = &empty_value;
523 if (!cell->font_style)
524 cell->font_style = &style->font_style;
525 if (!cell->cell_style)
526 cell->cell_style = &style->cell_style;
530 const struct pivot_value *v = cc ? cc : &empty_value;
531 *cell = (struct table_cell) {
532 .d = { [H] = { x, x + 1 }, [V] = { y, y + 1 } },
535 .font_style = v->font_style ? v->font_style : &style->font_style,
536 .cell_style = v->cell_style ? v->cell_style : &style->cell_style,
540 assert (cell->font_style);
541 assert (cell->cell_style);
544 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
545 representing a rule running alongside one of the cells in TABLE.
547 Suppose NC is the number of columns in TABLE and NR is the number of rows.
548 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
549 (0,0), the return value is the rule that runs vertically on the left side of
550 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
551 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
554 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
555 within a 7x7 table. The '|' characters at the intersection of the X labels
556 and Y labels show the rule whose style would be returned by calling
557 table_get_rule with those X and Y values:
560 +--+--+--+--+--+--+--+
562 +--+--+--+--+--+--+--+
564 +--+--+--+--+--+--+--+
566 +--+--+--+--+--+--+--+
568 +--+--+--+--+--+--+--+
570 +--+--+--+--+--+--+--+
572 +--+--+--+--+--+--+--+
574 +--+--+--+--+--+--+--+
576 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
577 (X,Y) = (0,0), the return value is the rule that runs horizontally above
578 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
579 between that cell and cell (0,1); and so on, up to (0,NR), which runs
580 horizontally below cell (0,NR-1). */
582 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
583 struct cell_color *color)
585 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
586 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
588 uint8_t raw = (axis == TABLE_VERT
589 ? table->rh[x + table->n[H] * y]
590 : table->rv[x + (table->n[H] + 1) * y]);
591 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
592 >> TAB_RULE_STYLE_SHIFT];
593 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
594 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;