bd017f6b4f16ac518ad7ba826234c72b2ea2668c
[pspp] / src / output / table.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2011, 2014, 2016 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "output/table.h"
20 #include "output/table-provider.h"
21
22 #include <assert.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25
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"
35
36 #include "gl/xalloc.h"
37
38 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
39 #define H TABLE_HORZ
40 #define V TABLE_VERT
41
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
44    modified. */
45 struct table *
46 table_ref (const struct table *table_)
47 {
48   struct table *table = CONST_CAST (struct table *, table_);
49   table->ref_cnt++;
50   return table;
51 }
52
53 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
54    If TABLE no longer has any owners, it is freed. */
55 void
56 table_unref (struct table *table)
57 {
58   if (table != NULL)
59     {
60       assert (table->ref_cnt > 0);
61       if (--table->ref_cnt == 0)
62         pool_destroy (table->container);
63     }
64 }
65
66 /* Returns true if TABLE has more than one owner.  A table item that is shared
67    among multiple owners must not be modified. */
68 bool
69 table_is_shared (const struct table *table)
70 {
71   return table->ref_cnt > 1;
72 }
73 \f
74 struct table_area_style *
75 table_area_style_clone (struct pool *pool, const struct table_area_style *old)
76 {
77   struct table_area_style *new = pool_malloc (pool, sizeof *new);
78   *new = *old;
79   if (new->font_style.typeface)
80     new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
81   return new;
82 }
83
84 void
85 table_area_style_free (struct table_area_style *style)
86 {
87   if (style)
88     {
89       free (style->font_style.typeface);
90       free (style);
91     }
92 }
93
94 struct footnote *
95 footnote_clone (const struct footnote *old)
96 {
97   struct footnote *new = xmalloc (sizeof *new);
98   *new = (struct footnote) {
99     .idx = old->idx,
100     .content = old->content ? xstrdup (old->content) : NULL,
101     .marker = old->marker ? xstrdup (old->marker) : NULL,
102     .style = old->style ? table_area_style_clone (NULL, old->style) : NULL,
103   };
104   return new;
105 }
106
107 void
108 footnote_destroy (struct footnote *f)
109 {
110   if (f)
111     {
112       free (f->content);
113       free (f->marker);
114       if (f->style)
115         {
116           table_area_style_uninit (f->style);
117           free (f->style);
118         }
119       free (f);
120     }
121 }
122
123 struct table_cell *
124 table_cell_clone (const struct table_cell *old)
125 {
126   struct table_cell *new = xmalloc (sizeof *new);
127   *new = *old;
128   new->text = xstrdup (new->text);
129
130   if (old->n_subscripts)
131     {
132       new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
133       for (size_t i = 0; i < old->n_subscripts; i++)
134         new->subscripts[i] = xstrdup (old->subscripts[i]);
135     }
136   else
137     new->subscripts = NULL;
138
139   if (old->n_footnotes)
140     {
141       new->footnotes = xnmalloc (old->n_footnotes, sizeof *new->footnotes);
142       for (size_t i = 0; i < old->n_footnotes; i++)
143         new->footnotes[i] = footnote_clone (old->footnotes[i]);
144     }
145   else
146     new->footnotes = NULL;
147
148   if (old->style)
149     new->style = table_area_style_clone (NULL, old->style);
150
151   return new;
152 }
153
154 void
155 table_cell_destroy (struct table_cell *cell)
156 {
157   if (!cell)
158     return;
159
160   free (cell->text);
161   for (size_t i = 0; i < cell->n_subscripts; i++)
162     free (cell->subscripts[i]);
163   free (cell->subscripts);
164   for (size_t i = 0; i < cell->n_footnotes; i++)
165     footnote_destroy (cell->footnotes[i]);
166   free (cell->footnotes);
167   if (cell->style)
168     {
169       table_area_style_uninit (cell->style);
170       free (cell->style);
171     }
172   free (cell);
173 }
174
175 void
176 table_cell_format_footnote_markers (const struct table_cell *cell,
177                                     struct string *s)
178 {
179   for (size_t i = 0; i < cell->n_footnotes; i++)
180     {
181       if (i)
182         ds_put_byte (s, ',');
183       ds_put_cstr (s, cell->footnotes[i]->marker);
184     }
185 }
186
187 static struct footnote **
188 add_footnotes (struct footnote **refs, size_t n_refs,
189                struct footnote **footnotes, size_t *allocated, size_t *n)
190 {
191   for (size_t i = 0; i < n_refs; i++)
192     {
193       struct footnote *f = refs[i];
194       if (f->idx >= *allocated)
195         {
196           size_t new_allocated = (f->idx + 1) * 2;
197           footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
198           while (*allocated < new_allocated)
199             footnotes[(*allocated)++] = NULL;
200         }
201       footnotes[f->idx] = f;
202       if (f->idx >= *n)
203         *n = f->idx + 1;
204     }
205   return footnotes;
206 }
207
208 size_t
209 table_collect_footnotes (const struct table_item *item,
210                          struct footnote ***footnotesp)
211 {
212   struct footnote **footnotes = NULL;
213   size_t allocated = 0;
214   size_t n = 0;
215
216   struct table *t = item->table;
217   for (int y = 0; y < t->n[V]; y++)
218     {
219       struct table_cell cell;
220       for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1])
221         {
222           table_get_cell (t, x, y, &cell);
223
224           if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
225             footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
226                                        footnotes, &allocated, &n);
227         }
228     }
229
230   const struct table_cell *title = table_item_get_title (item);
231   if (title)
232     footnotes = add_footnotes (title->footnotes, title->n_footnotes,
233                                footnotes, &allocated, &n);
234
235   const struct table_item_layers *layers = table_item_get_layers (item);
236   if (layers)
237     {
238       for (size_t i = 0; i < layers->n_layers; i++)
239         footnotes = add_footnotes (layers->layers[i].footnotes,
240                                    layers->layers[i].n_footnotes,
241                                    footnotes, &allocated, &n);
242     }
243
244   const struct table_cell *caption = table_item_get_caption (item);
245   if (caption)
246     footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
247                                footnotes, &allocated, &n);
248
249   size_t n_nonnull = 0;
250   for (size_t i = 0; i < n; i++)
251     if (footnotes[i])
252       footnotes[n_nonnull++] = footnotes[i];
253
254   *footnotesp = footnotes;
255   return n_nonnull;
256 }
257 \f
258 const char *
259 table_halign_to_string (enum table_halign halign)
260 {
261   switch (halign)
262     {
263     case TABLE_HALIGN_LEFT: return "left";
264     case TABLE_HALIGN_CENTER: return "center";
265     case TABLE_HALIGN_RIGHT: return "right";
266     case TABLE_HALIGN_DECIMAL: return "decimal";
267     case TABLE_HALIGN_MIXED: return "mixed";
268     default: return "**error**";
269     }
270 }
271
272 const char *
273 table_valign_to_string (enum table_valign valign)
274 {
275   switch (valign)
276     {
277     case TABLE_VALIGN_TOP: return "top";
278     case TABLE_VALIGN_CENTER: return "center";
279     case TABLE_VALIGN_BOTTOM: return "bottom";
280     default: return "**error**";
281     }
282 }
283
284 enum table_halign
285 table_halign_interpret (enum table_halign halign, bool numeric)
286 {
287   switch (halign)
288     {
289     case TABLE_HALIGN_LEFT:
290     case TABLE_HALIGN_CENTER:
291     case TABLE_HALIGN_RIGHT:
292       return halign;
293
294     case TABLE_HALIGN_MIXED:
295       return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
296
297     case TABLE_HALIGN_DECIMAL:
298       return TABLE_HALIGN_DECIMAL;
299
300     default:
301       NOT_REACHED ();
302     }
303 }
304
305 void
306 font_style_copy (struct pool *container,
307                  struct font_style *dst, const struct font_style *src)
308 {
309   *dst = *src;
310   if (dst->typeface)
311     dst->typeface = pool_strdup (container, dst->typeface);
312 }
313
314 void
315 font_style_uninit (struct font_style *font)
316 {
317   if (font)
318     free (font->typeface);
319 }
320
321 void
322 table_area_style_copy (struct pool *container, struct table_area_style *dst,
323                        const struct table_area_style *src)
324 {
325   font_style_copy (container, &dst->font_style, &src->font_style);
326   dst->cell_style = src->cell_style;
327 }
328
329 void
330 table_area_style_uninit (struct table_area_style *area)
331 {
332   if (area)
333     font_style_uninit (&area->font_style);
334 }
335
336 const char *
337 table_stroke_to_string (enum table_stroke stroke)
338 {
339   switch (stroke)
340     {
341     case TABLE_STROKE_NONE: return "none";
342     case TABLE_STROKE_SOLID: return "solid";
343     case TABLE_STROKE_DASHED: return "dashed";
344     case TABLE_STROKE_THICK: return "thick";
345     case TABLE_STROKE_THIN: return "thin";
346     case TABLE_STROKE_DOUBLE: return "double";
347     default:
348       return "**error**";
349     }
350 }
351
352 void
353 cell_color_dump (const struct cell_color *c)
354 {
355   if (c->alpha != 255)
356     printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
357   else
358     printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
359 }
360
361 void
362 font_style_dump (const struct font_style *f)
363 {
364   printf ("%s %dpx ", f->typeface, f->size);
365   cell_color_dump (&f->fg[0]);
366   putchar ('/');
367   cell_color_dump (&f->bg[0]);
368   if (!cell_color_equal (&f->fg[0], &f->fg[1])
369       || !cell_color_equal (&f->bg[0], &f->bg[1]))
370     {
371       printf (" alt=");
372       cell_color_dump (&f->fg[1]);
373       putchar ('/');
374       cell_color_dump (&f->bg[1]);
375     }
376   if (f->bold)
377     fputs (" bold", stdout);
378   if (f->italic)
379     fputs (" italic", stdout);
380   if (f->underline)
381     fputs (" underline", stdout);
382 }
383
384 bool
385 font_style_equal (const struct font_style *a, const struct font_style *b)
386 {
387   return (a->bold == b->bold
388           && a->italic == b->italic
389           && a->underline == b->underline
390           && a->markup == b->markup
391           && cell_color_equal (&a->fg[0], &b->fg[0])
392           && cell_color_equal (&a->fg[1], &b->fg[1])
393           && cell_color_equal (&a->bg[0], &b->bg[0])
394           && cell_color_equal (&a->bg[1], &b->bg[1])
395           && !strcmp (a->typeface ? a->typeface : "",
396                       b->typeface ? b->typeface : "")
397           && a->size == b->size);
398 }
399
400 void
401 cell_style_dump (const struct cell_style *c)
402 {
403   fputs (table_halign_to_string (c->halign), stdout);
404   if (c->halign == TABLE_HALIGN_DECIMAL)
405     printf ("(%.2gpx)", c->decimal_offset);
406   printf (" %s", table_valign_to_string (c->valign));
407   printf (" %d,%d,%d,%dpx",
408           c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
409           c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
410 }
411 \f
412
413 static const bool debugging = true;
414
415 /* Creates and returns a new table with NC columns and NR rows and initially no
416    header rows or columns.
417
418    Sets the number of header rows on each side of TABLE to HL on the
419    left, HR on the right, HT on the top, HB on the bottom.  Header rows
420    are repeated when a table is broken across multiple columns or
421    multiple pages.
422
423    The table's cells are initially empty. */
424 struct table *
425 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
426 {
427   struct table *t;
428
429   t = pool_create_container (struct table, container);
430   t->n[TABLE_HORZ] = nc;
431   t->n[TABLE_VERT] = nr;
432   t->h[TABLE_HORZ][0] = hl;
433   t->h[TABLE_HORZ][1] = hr;
434   t->h[TABLE_VERT][0] = ht;
435   t->h[TABLE_VERT][1] = hb;
436   t->ref_cnt = 1;
437
438   t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
439   t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
440
441   t->rh = pool_nmalloc (t->container, nc, nr + 1);
442   memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
443
444   t->rv = pool_nmalloc (t->container, nr, nc + 1);
445   memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
446
447   memset (t->styles, 0, sizeof t->styles);
448   memset (t->rule_colors, 0, sizeof t->rule_colors);
449
450   return t;
451 }
452 \f
453 /* Rules. */
454
455 /* Draws a vertical line to the left of cells at horizontal position X
456    from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
457 void
458 table_vline (struct table *t, int style, int x, int y1, int y2)
459 {
460   if (debugging)
461     {
462       if (x < 0 || x > t->n[H]
463           || y1 < 0 || y1 >= t->n[V]
464           || y2 < 0 || y2 >= t->n[V])
465         {
466           printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
467                   x, y1, y2, t->n[H], t->n[V]);
468           return;
469         }
470     }
471
472   assert (x >= 0);
473   assert (x <= t->n[H]);
474   assert (y1 >= 0);
475   assert (y2 >= y1);
476   assert (y2 <= t->n[V]);
477
478   if (style != -1)
479     {
480       int y;
481       for (y = y1; y <= y2; y++)
482         t->rv[x + (t->n[H] + 1) * y] = style;
483     }
484 }
485
486 /* Draws a horizontal line above cells at vertical position Y from X1
487    to X2 inclusive in style STYLE, if style is not -1. */
488 void
489 table_hline (struct table *t, int style, int x1, int x2, int y)
490 {
491   if (debugging)
492     {
493       if (y < 0 || y > t->n[V]
494           || x1 < 0 || x1 >= t->n[H]
495           || x2 < 0 || x2 >= t->n[H])
496         {
497           printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
498                   x1, x2, y, t->n[H], t->n[V]);
499           return;
500         }
501     }
502
503   assert (y >= 0);
504   assert (y <= t->n[V]);
505   assert (x2 >= x1);
506   assert (x1 >= 0);
507   assert (x2 < t->n[H]);
508
509   if (style != -1)
510     {
511       int x;
512       for (x = x1; x <= x2; x++)
513         t->rh[x + t->n[H] * y] = style;
514     }
515 }
516
517 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
518    lines of style F_H and vertical lines of style F_V.  Fills the
519    interior of the box with horizontal lines of style I_H and vertical
520    lines of style I_V.  Any of the line styles may be -1 to avoid
521    drawing those lines.  This is distinct from 0, which draws a null
522    line. */
523 void
524 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
525            int x1, int y1, int x2, int y2)
526 {
527   if (debugging)
528     {
529       if (x1 < 0 || x1 >= t->n[H]
530           || x2 < 0 || x2 >= t->n[H]
531           || y1 < 0 || y1 >= t->n[V]
532           || y2 < 0 || y2 >= t->n[V])
533         {
534           printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
535                   x1, y1, x2, y2, t->n[H], t->n[V]);
536           NOT_REACHED ();
537         }
538     }
539
540   assert (x2 >= x1);
541   assert (y2 >= y1);
542   assert (x1 >= 0);
543   assert (y1 >= 0);
544   assert (x2 < t->n[H]);
545   assert (y2 < t->n[V]);
546
547   if (f_h != -1)
548     {
549       int x;
550       for (x = x1; x <= x2; x++)
551         {
552           t->rh[x + t->n[H] * y1] = f_h;
553           t->rh[x + t->n[H] * (y2 + 1)] = f_h;
554         }
555     }
556   if (f_v != -1)
557     {
558       int y;
559       for (y = y1; y <= y2; y++)
560         {
561           t->rv[x1 + (t->n[H] + 1) * y] = f_v;
562           t->rv[(x2 + 1) + (t->n[H] + 1) * y] = f_v;
563         }
564     }
565
566   if (i_h != -1)
567     {
568       int y;
569
570       for (y = y1 + 1; y <= y2; y++)
571         {
572           int x;
573
574           for (x = x1; x <= x2; x++)
575             t->rh[x + t->n[H] * y] = i_h;
576         }
577     }
578   if (i_v != -1)
579     {
580       int x;
581
582       for (x = x1 + 1; x <= x2; x++)
583         {
584           int y;
585
586           for (y = y1; y <= y2; y++)
587             t->rv[x + (t->n[H] + 1) * y] = i_v;
588         }
589     }
590 }
591 \f
592 /* Cells. */
593
594 static void
595 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
596 {
597   assert (c >= 0);
598   assert (r >= 0);
599   assert (c < table->n[H]);
600   assert (r < table->n[V]);
601
602   if (debugging)
603     {
604       if (c < 0 || r < 0 || c >= table->n[H] || r >= table->n[V])
605         {
606           printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
607                   c, r, table->n[H], table->n[V]);
608           return;
609         }
610     }
611
612   table->cc[c + r * table->n[H]] = text;
613   table->ct[c + r * table->n[H]] = opt;
614 }
615
616 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
617    TEXT. */
618 void
619 table_text (struct table *table, int c, int r, unsigned opt,
620           const char *text)
621 {
622   do_table_text (table, c, r, opt, pool_strdup (table->container, text));
623 }
624
625 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
626    FORMAT, which is formatted as if passed to printf. */
627 void
628 table_text_format (struct table *table, int c, int r, unsigned opt,
629                    const char *format, ...)
630 {
631   va_list args;
632
633   va_start (args, format);
634   do_table_text (table, c, r, opt,
635                  pool_vasprintf (table->container, format, args));
636   va_end (args);
637 }
638
639 static struct table_cell *
640 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
641                  unsigned opt)
642 {
643   assert (x1 >= 0);
644   assert (y1 >= 0);
645   assert (y2 >= y1);
646   assert (x2 >= x1);
647   assert (y2 < table->n[V]);
648   assert (x2 < table->n[H]);
649
650   if (debugging)
651     {
652       if (x1 < 0 || x1 >= table->n[H]
653           || y1 < 0 || y1 >= table->n[V]
654           || x2 < x1 || x2 >= table->n[H]
655           || y2 < y1 || y2 >= table->n[V])
656         {
657           printf ("table_joint_text(): bad cell "
658                   "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
659                   x1, y1, x2, y2, table->n[H], table->n[V]);
660           return NULL;
661         }
662     }
663
664   table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
665              x1, y1, x2, y2);
666
667   struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
668   *cell = (struct table_cell) {
669     .d = { [TABLE_HORZ] = { x1, ++x2 },
670            [TABLE_VERT] = { y1, ++y2 } },
671     .options = opt,
672   };
673
674   void **cc = &table->cc[x1 + y1 * table->n[H]];
675   unsigned short *ct = &table->ct[x1 + y1 * table->n[H]];
676   const int ofs = table->n[H] - (x2 - x1);
677   for (int y = y1; y < y2; y++)
678     {
679       for (int x = x1; x < x2; x++)
680         {
681           *cc++ = cell;
682           *ct++ = opt | TAB_JOIN;
683         }
684
685       cc += ofs;
686       ct += ofs;
687     }
688
689   return cell;
690 }
691
692 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
693    options OPT to have text value TEXT. */
694 void
695 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
696                   unsigned opt, const char *text)
697 {
698   char *s = pool_strdup (table->container, text);
699   if (x1 == x2 && y1 == y2)
700     do_table_text (table, x1, y1, opt, s);
701   else
702     add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
703 }
704
705 static struct table_cell *
706 get_joined_cell (struct table *table, int x, int y)
707 {
708   int index = x + y * table->n[H];
709   unsigned short opt = table->ct[index];
710   struct table_cell *cell;
711
712   if (opt & TAB_JOIN)
713     cell = table->cc[index];
714   else
715     {
716       char *text = table->cc[index];
717
718       cell = add_joined_cell (table, x, y, x, y, table->ct[index]);
719       cell->text = text ? text : pool_strdup (table->container, "");
720     }
721   return cell;
722 }
723
724 /* Sets the subscripts for column X, row Y in TABLE. */
725 void
726 table_add_subscripts (struct table *table, int x, int y,
727                       char **subscripts, size_t n_subscripts)
728 {
729   struct table_cell *cell = get_joined_cell (table, x, y);
730
731   cell->n_subscripts = n_subscripts;
732   cell->subscripts = pool_nalloc (table->container, n_subscripts,
733                                   sizeof *cell->subscripts);
734   for (size_t i = 0; i < n_subscripts; i++)
735     cell->subscripts[i] = pool_strdup (table->container, subscripts[i]);
736 }
737
738 /* Create a footnote in TABLE with MARKER (e.g. "a") as its marker and CONTENT
739    as its content.  The footnote will be styled as STYLE, which is mandatory.
740    IDX must uniquely identify the footnote within TABLE.
741
742    Returns the new footnote.  The return value is the only way to get to the
743    footnote later, so it is important for the caller to remember it. */
744 struct footnote *
745 table_create_footnote (struct table *table, size_t idx, const char *content,
746                        const char *marker, struct table_area_style *style)
747 {
748   assert (style);
749
750   struct footnote *f = pool_alloc (table->container, sizeof *f);
751   f->idx = idx;
752   f->content = pool_strdup (table->container, content);
753   f->marker = pool_strdup (table->container, marker);
754   f->style = style;
755   return f;
756 }
757
758 /* Attaches a reference to footnote F to the cell at column X, row Y in
759    TABLE. */
760 void
761 table_add_footnote (struct table *table, int x, int y, struct footnote *f)
762 {
763   assert (f->style);
764
765   struct table_cell *cell = get_joined_cell (table, x, y);
766
767   cell->footnotes = pool_realloc (
768     table->container, cell->footnotes,
769     (cell->n_footnotes + 1) * sizeof *cell->footnotes);
770
771   cell->footnotes[cell->n_footnotes++] = f;
772 }
773
774 /* Overrides the style for column X, row Y in TABLE with STYLE.
775    Does not make a copy of STYLE, so it should either be allocated from
776    TABLE->container or have a lifetime that will outlive TABLE. */
777 void
778 table_add_style (struct table *table, int x, int y,
779                  struct table_area_style *style)
780 {
781   get_joined_cell (table, x, y)->style = style;
782 }
783
784 /* Returns true if column C, row R has no contents, otherwise false. */
785 bool
786 table_cell_is_empty (const struct table *table, int c, int r)
787 {
788   return table->cc[c + r * table->n[H]] == NULL;
789 }
790 \f
791 /* Initializes CELL with the contents of the table cell at column X and row Y
792    within TABLE.  When CELL is no longer needed, the caller is responsible for
793    freeing it by calling table_cell_free(CELL).
794
795    The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
796 void
797 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
798 {
799   assert (x >= 0 && x < t->n[TABLE_HORZ]);
800   assert (y >= 0 && y < t->n[TABLE_VERT]);
801
802   int index = x + y * t->n[H];
803   unsigned short opt = t->ct[index];
804   const void *cc = t->cc[index];
805
806   struct table_area_style *style
807     = t->styles[(opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT];
808   if (opt & TAB_JOIN)
809     {
810       const struct table_cell *jc = cc;
811       *cell = *jc;
812       if (!cell->style)
813         cell->style = style;
814     }
815   else
816     *cell = (struct table_cell) {
817       .d = { [TABLE_HORZ] = { x, x + 1 },
818              [TABLE_VERT] = { y, y + 1 } },
819       .options = opt,
820       .text = CONST_CAST (char *, cc ? cc : ""),
821       .style = style,
822     };
823
824   assert (cell->style);
825 }
826
827 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
828    representing a rule running alongside one of the cells in TABLE.
829
830    Suppose NC is the number of columns in TABLE and NR is the number of rows.
831    Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR.  If (X,Y) =
832    (0,0), the return value is the rule that runs vertically on the left side of
833    cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
834    cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
835    cell (NC-1,0).
836
837    The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
838    within a 7x7 table.  The '|' characters at the intersection of the X labels
839    and Y labels show the rule whose style would be returned by calling
840    table_get_rule with those X and Y values:
841
842                            0  1  2  3  4  5  6  7
843                            +--+--+--+--+--+--+--+
844                          0 |  |  |  |  |  |  |  |
845                            +--+--+--+--+--+--+--+
846                          1 |  |  |  |  |  |  |  |
847                            +--+--+--+--+--+--+--+
848                          2 |  |  |  |  |  |  |  |
849                            +--+--+--+--+--+--+--+
850                          3 |  |  |  |  |  |  |  |
851                            +--+--+--+--+--+--+--+
852                          4 |  |  |  |  |  |  |  |
853                            +--+--+--+--+--+--+--+
854                          5 |  |  |  |  |  |  |  |
855                            +--+--+--+--+--+--+--+
856                          6 |  |  |  |  |  |  |  |
857                            +--+--+--+--+--+--+--+
858
859    Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR.  If
860    (X,Y) = (0,0), the return value is the rule that runs horizontally above
861    the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
862    between that cell and cell (0,1); and so on, up to (0,NR), which runs
863    horizontally below cell (0,NR-1). */
864 int
865 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
866                 struct cell_color *color)
867 {
868   assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
869   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
870
871   uint8_t raw = (axis == TABLE_VERT
872                  ? table->rh[x + table->n[H] * y]
873                  : table->rv[x + (table->n[H] + 1) * y]);
874   struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
875                                             >> TAB_RULE_STYLE_SHIFT];
876   *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
877   return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;
878 }