+ #============ Frame ============#
+ # Title #
+ # Layers #
+ # +--- Body ------------------+ #
+ # | Stub | #
+ # | +--------------------+ #
+ # | | Data | #
+ # | | | #
+ # | | | #
+ # | | | #
+ # +------+--------------------+ #
+ # Caption #
+ # Footnotes #
+ #===============================#
+
+ The regions are the following size:
+
+ - Frame: Either 0 or 1 row or column wide, depending on whether the table
+ style has an outer border on each side. The frame cells are always
+ empty and marked as TABLE_CELL_PADDING.
+
+ - Title: Either 0 or 1 row high.
+
+ - Layers: Usually, one row for each layer dimension, but less if a layer
+ dimension is empty (has no value).
+
+ - Body and data: Variable (and can be empty).
+
+ - Caption: Either 0 or 1 row high.
+
+ - Footnotes: From zero rows up to the number of footnotes in PT (only
+ footnotes referenced in the other regions are shown).
+
+ The title, layers, caption, and footnote Region join all the body's
+ columns into single cells.
+ */
+
+ /* Size of data region. */
+ size_t data[TABLE_N_AXES];
+ size_t *column_enumeration = pivot_table_enumerate_axis (
+ pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &data[H]);
+ size_t *row_enumeration = pivot_table_enumerate_axis (
+ pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &data[V]);
+
+ /* Size of stub region. */
+ int stub[TABLE_N_AXES] = {
+ [H] = pt->axes[PIVOT_AXIS_ROW].label_depth,
+ [V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth,
+ };
+
+ /* Width of each side of the frame. */
+ int frame[TABLE_N_AXES][2] = {
+ [H] = {
+ pt->look->borders[PIVOT_BORDER_OUTER_LEFT].stroke != TABLE_STROKE_NONE,
+ pt->look->borders[PIVOT_BORDER_OUTER_RIGHT].stroke != TABLE_STROKE_NONE,
+ },
+ [V] = {
+ pt->look->borders[PIVOT_BORDER_OUTER_TOP].stroke != TABLE_STROKE_NONE,
+ pt->look->borders[PIVOT_BORDER_OUTER_BOTTOM].stroke != TABLE_STROKE_NONE,
+ },
+ };
+
+ int n_title = pt->title && pt->show_title;
+ int n_layers = pivot_count_layers (pt);
+ int n_caption = pt->caption && pt->show_caption;
+ int max_footnotes = pt->n_footnotes;
+
+ int min_body_width = n_title || n_layers || n_caption;
+ int n[TABLE_N_AXES] = {
+ [H] = frame[H][0] + MAX (min_body_width, stub[H] + data[H]) + frame[H][1],
+ [V] = frame[V][0] + n_title + n_layers + stub[V] + data[V] + n_caption + max_footnotes + frame[V][1],
+ };
+
+ struct table *t = table_create (
+ n[H],
+ n[V],
+#if 1
+ frame[H][0] + stub[H], frame[H][1],
+ frame[V][0] + n_title + n_layers + stub[V], frame[V][1]
+#else
+ 0, 0, 0, 0
+#endif
+ );
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ t->styles[i] = table_area_style_override (
+ t->container, &pt->look->areas[i], NULL, NULL, false);
+
+ t->n_borders = PIVOT_N_BORDERS;
+ t->borders = pool_nmalloc (t->container, PIVOT_N_BORDERS, sizeof *t->borders);
+ for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
+ {
+ const struct table_border_style *src = &pt->look->borders[i];
+ struct table_border_style *dst = &t->borders[i];
+ *dst = (!printing && pt->show_grid_lines && src->stroke == TABLE_STROKE_NONE
+ ? (struct table_border_style) { .stroke = TABLE_STROKE_DASHED,
+ .color = CELL_COLOR_BLACK }
+ : *src);
+ }
+
+ int body[TABLE_N_AXES][2] = {
+ [H] = { frame[H][0], n[H] - frame[H][1] - 1 },
+ [V] = {
+ frame[V][0] + n_title + n_layers,
+ frame[V][0] + n_title + n_layers + stub[V] + data[V] - 1
+ },
+ };
+
+ if (n_layers)
+ put_layers (t, pt, layer_indexes,
+ body[H][0], frame[V][0] + n_title,
+ body[H][1], frame[V][0] + n_title + n_layers - 1);
+
+ compose_headings (t,
+ &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
+ PIVOT_BORDER_DIM_COL_HORZ,
+ PIVOT_BORDER_DIM_COL_VERT,
+ PIVOT_BORDER_CAT_COL_HORZ,
+ PIVOT_BORDER_CAT_COL_VERT,
+ column_enumeration, data[H],
+ PIVOT_AREA_COLUMN_LABELS,
+ pt->rotate_outer_row_labels, false, body);
+
+ compose_headings (t,
+ &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
+ PIVOT_BORDER_DIM_ROW_VERT,
+ PIVOT_BORDER_DIM_ROW_HORZ,
+ PIVOT_BORDER_CAT_ROW_VERT,
+ PIVOT_BORDER_CAT_ROW_HORZ,
+ row_enumeration, data[V],
+ PIVOT_AREA_ROW_LABELS,
+ false, pt->rotate_inner_column_labels, body);
+
+ int data_ofs[TABLE_N_AXES] = {
+ [H] = body[H][0] + stub[H],
+ [V] = body[V][0] + stub[V],
+ };
+
+ const size_t *pindexes[PIVOT_N_AXES] = { [PIVOT_AXIS_LAYER] = layer_indexes };
+ size_t *dindexes = XCALLOC (pt->n_dimensions, size_t);
+ int y = data_ofs[V];
+ PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
+ &pt->axes[PIVOT_AXIS_ROW])