+ struct css_style style;
+ style_start (&style, html->file);
+ enum table_halign halign = table_halign_interpret (
+ cell->style->cell_style.halign, cell->options & TAB_NUMERIC);
+
+ switch (halign)
+ {
+ case TABLE_HALIGN_RIGHT:
+ put_style (&style, "text-align", "right");
+ break;
+ case TABLE_HALIGN_CENTER:
+ put_style (&style, "text-align", "center");
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ if (cell->options & TAB_ROTATE)
+ put_style (&style, "writing-mode", "sideways-lr");
+
+ if (cell->style->cell_style.valign != TABLE_VALIGN_TOP)
+ {
+ put_style (&style, "vertical-align",
+ (cell->style->cell_style.valign == TABLE_VALIGN_BOTTOM
+ ? "bottom" : "middle"));
+ }
+
+ const struct font_style *fs = &cell->style->font_style;
+ char bgcolor[32];
+ if (format_color (fs->bg[cell->d[V][0] % 2],
+ (struct cell_color) CELL_COLOR_WHITE,
+ bgcolor, sizeof bgcolor))
+ put_style (&style, "background", bgcolor);
+
+ char fgcolor[32];
+ if (format_color (fs->fg[cell->d[V][0] % 2],
+ (struct cell_color) CELL_COLOR_BLACK,
+ fgcolor, sizeof fgcolor))
+ put_style (&style, "color", fgcolor);
+
+ if (fs->typeface)
+ {
+ put_style (&style, "font-family", "\"");
+ escape_string (html->file, fs->typeface, " ", "\n");
+ putc ('"', html->file);
+ }
+ if (fs->bold)
+ put_style (&style, "font-weight", "bold");
+ if (fs->italic)
+ put_style (&style, "font-style", "italic");
+ if (fs->underline)
+ put_style (&style, "text-decoration", "underline");
+ if (fs->size)
+ {
+ char buf[32];
+ snprintf (buf, sizeof buf, "%dpt", fs->size);
+ put_style (&style, "font-size", buf);
+ }
+
+ if (border)
+ {
+ put_border (t, cell, &style, V, 0, 0, "top");
+ put_border (t, cell, &style, H, 0, 0, "left");
+
+ if (cell->d[V][1] == t->n[V])
+ put_border (t, cell, &style, V, 0, 1, "bottom");
+ if (cell->d[H][1] == t->n[H])
+ put_border (t, cell, &style, H, 1, 0, "right");
+ }
+ style_end (&style);
+
+ int colspan = table_cell_colspan (cell);
+ if (colspan > 1)
+ fprintf (html->file, " colspan=\"%d\"", colspan);
+
+ int rowspan = table_cell_rowspan (cell);
+ if (rowspan > 1)
+ fprintf (html->file, " rowspan=\"%d\"", rowspan);
+
+ putc ('>', html->file);
+
+ html_put_table_cell_text (html, cell);
+
+ /* output </th> or </td>. */
+ fprintf (html->file, "</%s>\n", tag);
+}
+
+static void
+html_output_table (struct html_driver *html, const struct table_item *item)
+{
+ const struct table *t = table_item_get_table (item);
+ bool tfoot = false;
+
+ fputs ("<table", html->file);
+ if (item->notes)
+ {
+ fputs (" title=\"", html->file);
+ escape_string (html->file, item->notes, " ", "\n");
+ putc ('"', html->file);
+ }
+ fputs (">\n", html->file);
+
+ const struct table_cell *caption = table_item_get_caption (item);
+ if (caption)
+ {
+ put_tfoot (html, t, &tfoot);
+ html_put_table_cell (html, t, caption, "span", false);
+ }
+ struct footnote **f;
+ size_t n_footnotes = table_collect_footnotes (item, &f);
+
+ for (size_t i = 0; i < n_footnotes; i++)
+ {
+ put_tfoot (html, t, &tfoot);
+ escape_tag (html->file, "sup", f[i]->marker, " ", "<br>");
+ escape_string (html->file, f[i]->content, " ", "<br>");
+ }
+ free (f);
+ if (tfoot)
+ {
+ fputs ("</td>\n", html->file);
+ fputs ("</tr>\n", html->file);
+ fputs ("</tfoot>\n", html->file);
+ }
+
+ const struct table_cell *title = table_item_get_title (item);
+ const struct table_item_layers *layers = table_item_get_layers (item);
+ if (title || layers)
+ {
+ fputs ("<caption>", html->file);
+ if (title)
+ html_put_table_cell (html, t, title, "span", false);
+ if (title && layers)
+ fputs ("<br>\n", html->file);
+ if (layers)
+ html_put_table_item_layers (html, layers);
+ fputs ("</caption>\n", html->file);
+ }
+
+ fputs ("<tbody>\n", html->file);
+
+ for (int y = 0; y < t->n[V]; y++)
+ {
+ fputs ("<tr>\n", html->file);
+ for (int x = 0; x < t->n[H]; )
+ {
+ struct table_cell cell;
+ table_get_cell (t, x, y, &cell);
+ if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])