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/tab.h"
35 #include "gl/xalloc.h"
37 /* Increases TABLE's reference count, indicating that it has an additional
38 owner. An table that is shared among multiple owners must not be
41 table_ref (const struct table *table_)
43 struct table *table = CONST_CAST (struct table *, table_);
48 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
49 If TABLE no longer has any owners, it is freed. */
51 table_unref (struct table *table)
55 assert (table->ref_cnt > 0);
56 if (--table->ref_cnt == 0)
61 /* Returns true if TABLE has more than one owner. A table item that is shared
62 among multiple owners must not be modified. */
64 table_is_shared (const struct table *table)
66 return table->ref_cnt > 1;
70 area_style_clone (struct pool *pool, const struct area_style *old)
72 struct area_style *new = pool_malloc (pool, sizeof *new);
74 if (new->font_style.typeface)
75 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
80 area_style_free (struct area_style *style)
84 free (style->font_style.typeface);
89 /* Initializes CELL with the contents of the table cell at column X and row Y
90 within TABLE. When CELL is no longer needed, the caller is responsible for
91 freeing it by calling table_cell_free(CELL).
93 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
95 table_get_cell (const struct table *table, int x, int y,
96 struct table_cell *cell)
98 assert (x >= 0 && x < table->n[TABLE_HORZ]);
99 assert (y >= 0 && y < table->n[TABLE_VERT]);
101 static const struct area_style default_style = AREA_STYLE_INITIALIZER;
102 cell->style = &default_style;
104 tab_get_cell (table, x, y, cell);
107 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
108 representing a rule running alongside one of the cells in TABLE.
110 Suppose NC is the number of columns in TABLE and NR is the number of rows.
111 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
112 (0,0), the return value is the rule that runs vertically on the left side of
113 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
114 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
117 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
118 within a 7x7 table. The '|' characters at the intersection of the X labels
119 and Y labels show the rule whose style would be returned by calling
120 table_get_rule with those X and Y values:
123 +--+--+--+--+--+--+--+
125 +--+--+--+--+--+--+--+
127 +--+--+--+--+--+--+--+
129 +--+--+--+--+--+--+--+
131 +--+--+--+--+--+--+--+
133 +--+--+--+--+--+--+--+
135 +--+--+--+--+--+--+--+
137 +--+--+--+--+--+--+--+
139 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
140 (X,Y) = (0,0), the return value is the rule that runs horizontally above
141 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
142 between that cell and cell (0,1); and so on, up to (0,NR), which runs
143 horizontally below cell (0,NR-1). */
145 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
146 struct cell_color *color)
148 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
149 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
150 *color = (struct cell_color) CELL_COLOR_BLACK;
151 return tab_get_rule (table, axis, x, y, color);
155 table_cell_format_footnote_markers (const struct table_cell *cell,
158 for (size_t i = 0; i < cell->n_footnotes; i++)
161 ds_put_byte (s, ',');
162 ds_put_cstr (s, cell->footnotes[i]->marker);
166 static const struct footnote **
167 add_footnotes (const struct footnote **refs, size_t n_refs,
168 const struct footnote **footnotes, size_t *allocated, size_t *n)
170 for (size_t i = 0; i < n_refs; i++)
172 const struct footnote *f = refs[i];
173 if (f->idx >= *allocated)
175 size_t new_allocated = (f->idx + 1) * 2;
176 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
177 while (*allocated < new_allocated)
178 footnotes[(*allocated)++] = NULL;
180 footnotes[f->idx] = f;
188 table_collect_footnotes (const struct table_item *item,
189 const struct footnote ***footnotesp)
191 const struct footnote **footnotes = NULL;
192 size_t allocated = 0;
195 struct table *t = item->table;
196 for (int y = 0; y < table_nr (t); y++)
198 struct table_cell cell;
199 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
201 table_get_cell (t, x, y, &cell);
203 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
204 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
205 footnotes, &allocated, &n);
209 const struct table_item_text *title = table_item_get_title (item);
211 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
212 footnotes, &allocated, &n);
214 const struct table_item_layers *layers = table_item_get_layers (item);
217 for (size_t i = 0; i < layers->n_layers; i++)
218 footnotes = add_footnotes (layers->layers[i].footnotes,
219 layers->layers[i].n_footnotes,
220 footnotes, &allocated, &n);
223 const struct table_item_text *caption = table_item_get_caption (item);
225 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
226 footnotes, &allocated, &n);
228 size_t n_nonnull = 0;
229 for (size_t i = 0; i < n; i++)
231 footnotes[n_nonnull++] = footnotes[i];
233 *footnotesp = footnotes;
237 /* Returns a table that contains a single cell, whose contents are the
238 left-aligned TEXT. */
240 table_from_string (const char *text)
242 struct tab_table *t = tab_create (1, 1, 0, 0, 0, 0);
243 tab_text (t, 0, 0, TAB_LEFT, text);
248 table_halign_to_string (enum table_halign halign)
252 case TABLE_HALIGN_LEFT: return "left";
253 case TABLE_HALIGN_CENTER: return "center";
254 case TABLE_HALIGN_RIGHT: return "right";
255 case TABLE_HALIGN_DECIMAL: return "decimal";
256 case TABLE_HALIGN_MIXED: return "mixed";
257 default: return "**error**";
262 table_valign_to_string (enum table_valign valign)
266 case TABLE_VALIGN_TOP: return "top";
267 case TABLE_VALIGN_CENTER: return "center";
268 case TABLE_VALIGN_BOTTOM: return "bottom";
269 default: return "**error**";
274 table_halign_interpret (enum table_halign halign, bool numeric)
278 case TABLE_HALIGN_LEFT:
279 case TABLE_HALIGN_CENTER:
280 case TABLE_HALIGN_RIGHT:
283 case TABLE_HALIGN_MIXED:
284 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
286 case TABLE_HALIGN_DECIMAL:
287 return TABLE_HALIGN_DECIMAL;
295 font_style_copy (struct font_style *dst, const struct font_style *src)
299 dst->typeface = xstrdup (dst->typeface);
303 font_style_uninit (struct font_style *font)
306 free (font->typeface);
310 area_style_copy (struct area_style *dst, const struct area_style *src)
312 font_style_copy (&dst->font_style, &src->font_style);
313 dst->cell_style = src->cell_style;
317 area_style_uninit (struct area_style *area)
320 font_style_uninit (&area->font_style);
324 table_stroke_to_string (enum table_stroke stroke)
328 case TABLE_STROKE_NONE: return "none";
329 case TABLE_STROKE_SOLID: return "solid";
330 case TABLE_STROKE_DASHED: return "dashed";
331 case TABLE_STROKE_THICK: return "thick";
332 case TABLE_STROKE_THIN: return "thin";
333 case TABLE_STROKE_DOUBLE: return "double";
340 cell_color_dump (const struct cell_color *c)
343 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
345 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
349 font_style_dump (const struct font_style *f)
351 printf ("%s %dpx ", f->typeface, f->size);
352 cell_color_dump (&f->fg[0]);
354 cell_color_dump (&f->bg[0]);
355 if (!cell_color_equal (&f->fg[0], &f->fg[1])
356 || !cell_color_equal (&f->bg[0], &f->bg[1]))
359 cell_color_dump (&f->fg[1]);
361 cell_color_dump (&f->bg[1]);
364 fputs (" bold", stdout);
366 fputs (" italic", stdout);
368 fputs (" underline", stdout);
372 cell_style_dump (const struct cell_style *c)
374 fputs (table_halign_to_string (c->halign), stdout);
375 if (c->halign == TABLE_HALIGN_DECIMAL)
376 printf ("(%.2gpx)", c->decimal_offset);
377 printf (" %s", table_valign_to_string (c->valign));
378 printf (" %d,%d,%d,%dpx",
379 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
380 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);