}
static void
-fill_cell (struct table *t, int x1, int y1, int x2, int y2,
+fill_cell (struct table *t, int x, int y,
int style_idx, const struct pivot_value *value,
bool rotate_label)
{
if (rotate_label)
options |= TABLE_CELL_ROTATE;
+ table_put (t, x, y, x, y, options, value);
+}
+
+static void
+fill_cell_spanned (struct table *t, int x1, int y1, int x2, int y2,
+ int style_idx, const struct pivot_value *value,
+ bool rotate_label, int options)
+{
+ options |= style_idx << TABLE_CELL_STYLE_SHIFT;
+ if (rotate_label)
+ options |= TABLE_CELL_ROTATE;
+
table_put (t, x1, y1, x2, y2, options, value);
}
enum pivot_border cat_col_vert,
const size_t *column_enumeration, size_t n_columns,
int label_style_idx,
- bool rotate_inner_labels, bool rotate_outer_labels)
+ bool rotate_inner_labels, bool rotate_outer_labels,
+ int area[TABLE_N_AXES][2])
{
const enum table_axis v = !h;
const int v_size = h_axis->label_depth;
- const int h_ofs = v_axis->label_depth;
+ const int h_ofs = v_axis->label_depth + area[h][0];
if (!h_axis->n_dimensions || !n_columns || !v_size)
return;
/* Below, we're going to iterate through the dimensions. Each dimension
occupies one or more rows in the heading. 'top_row' is the top row of
these (and 'top_row + d->label_depth - 1' is the bottom row). */
- int top_row = 0;
+ int top_row = area[v][0];
+
+ const int h_max = area[h][1];
+ const int v_max = area[v][1];
/* We're going to iterate through dimensions and the rows that label them
from top to bottom (from outer to inner dimensions). As we move downward,
int y1 = top_row + row_ofs;
int y2 = top_row + row_ofs + c->extra_depth + 1;
- bool is_outer_row = y1 == 0;
- bool is_inner_row = y2 == v_size;
if (pivot_category_is_leaf (c) || c->show_label)
{
int bb[TABLE_N_AXES][2];
bb[h][1] = x2 + h_ofs - 1;
bb[v][0] = y1;
bb[v][1] = y2 - 1;
+ bool is_outer_row = y1 == area[v][0];
+ bool is_inner_row = y2 == v_size + area[v][0];
bool rotate = ((rotate_inner_labels && is_inner_row)
|| (rotate_outer_labels && is_outer_row));
- fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
- label_style_idx, c->name, rotate);
+ fill_cell_spanned (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
+ label_style_idx, c->name, rotate, 0);
/* Draw all the vertical lines in our running example, other
than the far left and far right ones. Only the ones that
= (y1 == v_size - 1 ? cat_col_vert : dim_col_vert);
if (!vrules[x2])
{
- draw_line (t, style, v, x2 + h_ofs, y1, t->n[v] - 1);
+ draw_line (t, style, v, x2 + h_ofs, y1, v_max);
vrules[x2] = true;
}
if (!vrules[x1])
{
- draw_line (t, style, v, x1 + h_ofs, y1, t->n[v] - 1);
+ draw_line (t, style, v, x1 + h_ofs, y1, v_max);
vrules[x1] = true;
}
}
}
}
- if (d->root->show_label_in_corner && h_ofs > 0)
+ if (d->root->show_label_in_corner && h_ofs > area[h][0])
{
int bb[TABLE_N_AXES][2];
bb[h][0] = 0;
bb[h][1] = h_ofs - 1;
bb[v][0] = top_row;
bb[v][1] = top_row + d->label_depth - 1;
- fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
- PIVOT_AREA_CORNER, d->root->name, false);
+ fill_cell_spanned (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
+ PIVOT_AREA_CORNER, d->root->name, false, 0);
}
/* Draw the horizontal line between dimensions, e.g. the ===== line here:
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
*/
if (dim_index != h_axis->n_dimensions - 1)
- draw_line (t, dim_col_horz, h, top_row, h_ofs, t->n[h] - 1);
+ draw_line (t, dim_col_horz, h, top_row, h_ofs, h_max);
top_row += d->label_depth;
}
free (vrules);
return footnotes;
}
+static struct table *
+pivot_output_title (const struct pivot_table *pt)
+{
+ if (!pt->title || !pt->show_title)
+ return NULL;
+ struct table *title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
+ fill_cell (title, 0, 0, PIVOT_AREA_TITLE, pt->title, false);
+ return title;
+}
+
+static int
+pivot_count_layers (const struct pivot_table *pt)
+{
+ const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
+ int n_layers = 0;
+ for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+ {
+ const struct pivot_dimension *d = layer_axis->dimensions[i];
+ if (d->n_leaves)
+ n_layers++;
+ }
+ return n_layers;
+}
+
+static void
+put_layers (struct table *t, const struct pivot_table *pt,
+ const size_t *layer_indexes, int x1, int y1 UNUSED, int x2, int y2)
+{
+ assert (y1 + pivot_count_layers (pt) - 1 == y2);
+ const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
+ for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+ {
+ const struct pivot_dimension *d = layer_axis->dimensions[i];
+ if (!d->n_leaves)
+ continue;
+
+ struct string s = DS_EMPTY_INITIALIZER;
+ pivot_value_format (d->data_leaves[layer_indexes[i]]->name, pt, &s);
+ int y = y2 - i;
+ fill_cell_owned (t, x1, y, x2, y, PIVOT_AREA_LAYERS, &s, false);
+ }
+}
+
+static struct table *
+pivot_output_layers (const struct pivot_table *pt, const size_t *layer_indexes)
+{
+ int n_layers = pivot_count_layers (pt);
+ if (!n_layers)
+ return NULL;
+
+ struct table *layers = create_aux_table (pt, 1, n_layers, PIVOT_AREA_LAYERS);
+ put_layers (layers, pt, layer_indexes, 0, 0, 0, n_layers - 1);
+ return layers;
+}
+
+static struct table *
+pivot_output_caption (const struct pivot_table *pt)
+{
+ if (!pt->caption || !pt->show_caption)
+ return NULL;
+
+ struct table *caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
+ fill_cell (caption, 0, 0, PIVOT_AREA_CAPTION, pt->caption, false);
+ return caption;
+}
+
+static void
+put_footnotes (struct table *t, const struct pivot_table *pt,
+ struct pivot_footnote **f, size_t nf,
+ int x1, int x2, int y1)
+{
+ for (size_t i = 0; i < nf; i++)
+ {
+ struct string s = DS_EMPTY_INITIALIZER;
+ pivot_footnote_format_marker (f[i], pt, &s);
+ ds_put_cstr (&s, ". ");
+ pivot_value_format (f[i]->content, pt, &s);
+ int y = y1 + i;
+ fill_cell_owned (t, x1, y, x2, y, PIVOT_AREA_FOOTER, &s, false);
+ }
+}
+
+static struct table *
+pivot_output_footnotes (const struct pivot_table *pt,
+ struct pivot_footnote **f, size_t nf)
+{
+ if (!nf)
+ return NULL;
+
+ struct table *footnotes = create_aux_table (pt, 1, nf, PIVOT_AREA_FOOTER);
+ put_footnotes (footnotes, pt, f, nf, 0, 0, 0);
+ return footnotes;
+}
+
void
pivot_output (const struct pivot_table *pt,
const size_t *layer_indexes,
- bool printing UNUSED,
+ bool printing,
struct table **titlep,
struct table **layersp,
struct table **bodyp,
[H] = pt->axes[PIVOT_AXIS_ROW].label_depth,
[V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth,
};
- struct table *body = table_create (data[H] + stub[H],
- data[V] + stub[V],
+
+ struct table *body = table_create (stub[H] + data[H], stub[V] + data[V],
stub[H], stub[V]);
for (size_t i = 0; i < PIVOT_N_AREAS; i++)
body->styles[i] = table_area_style_override (
: *src);
}
+ int body_area[TABLE_N_AXES][2] = {
+ [H] = { 0, body->n[H] - 1 },
+ [V] = { 0, body->n[V] - 1 },
+ };
compose_headings (body,
&pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
PIVOT_BORDER_DIM_COL_HORZ,
PIVOT_BORDER_CAT_COL_VERT,
column_enumeration, data[H],
PIVOT_AREA_COLUMN_LABELS,
- pt->rotate_outer_row_labels, false);
+ pt->rotate_outer_row_labels, false, body_area);
compose_headings (body,
&pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
PIVOT_BORDER_CAT_ROW_HORZ,
row_enumeration, data[V],
PIVOT_AREA_ROW_LABELS,
- false, pt->rotate_inner_column_labels);
+ false, pt->rotate_inner_column_labels, body_area);
size_t *dindexes = XCALLOC (pt->n_dimensions, size_t);
size_t y = 0;
{
pivot_table_convert_indexes_ptod (pt, pindexes, dindexes);
const struct pivot_value *value = pivot_table_get (pt, dindexes);
- fill_cell (body, x + stub[H], y + stub[V], x + stub[H], y + stub[V],
+ fill_cell (body, x + stub[H], y + stub[V],
PIVOT_AREA_DATA, value, false);
x++;
if ((pt->corner_text || !pt->look->row_labels_in_corner)
&& stub[H] && stub[V])
- fill_cell (body, 0, 0, stub[H] - 1, stub[V] - 1,
- PIVOT_AREA_CORNER, pt->corner_text, false);
+ fill_cell_spanned (body, 0, 0, stub[H] - 1, stub[V] - 1,
+ PIVOT_AREA_CORNER, pt->corner_text, false,
+ TABLE_CELL_FULL_WIDTH);
if (body->n[H] && body->n[V])
{
- table_hline (body, PIVOT_BORDER_INNER_TOP, 0, body->n[H] - 1, 0);
- table_hline (body, PIVOT_BORDER_INNER_BOTTOM, 0, body->n[H] - 1,
- body->n[V]);
- table_vline (body, PIVOT_BORDER_INNER_LEFT, 0, 0, body->n[V] - 1);
- table_vline (body, PIVOT_BORDER_INNER_RIGHT, body->n[H], 0,
- body->n[V] - 1);
+ int inner[TABLE_N_AXES][2] = {
+ [H] = { 0, body->n[H] },
+ [V] = { 0, body->n[V] },
+ };
+ table_hline (body, PIVOT_BORDER_INNER_TOP,
+ inner[H][0], inner[H][1] - 1, inner[V][0]);
+ table_hline (body, PIVOT_BORDER_INNER_BOTTOM,
+ inner[H][0], inner[H][1] - 1, inner[V][1]);
+ table_vline (body, PIVOT_BORDER_INNER_LEFT,
+ inner[H][0], inner[V][0], inner[V][1] - 1);
+ table_vline (body, PIVOT_BORDER_INNER_LEFT,
+ inner[H][1], inner[V][0], inner[V][1] - 1);
if (stub[V])
- table_hline (body, PIVOT_BORDER_DATA_TOP, 0, body->n[H] - 1, stub[V]);
+ table_hline (body, PIVOT_BORDER_DATA_TOP,
+ inner[H][0], inner[H][1] - 1, stub[V]);
if (stub[H])
- table_vline (body, PIVOT_BORDER_DATA_LEFT, stub[H], 0, body->n[V] - 1);
-
+ table_vline (body, PIVOT_BORDER_DATA_LEFT,
+ stub[H], inner[V][0], inner[V][1] - 1);
}
+
free (column_enumeration);
free (row_enumeration);
- /* Title. */
- struct table *title;
- if (pt->title && pt->show_title && titlep)
- {
- title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
- fill_cell (title, 0, 0, 0, 0, PIVOT_AREA_TITLE, pt->title, false);
- }
- else
- title = NULL;
-
- /* Layers. */
- const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
- int n_layers = 0;
+ *bodyp = body;
+ if (titlep)
+ *titlep = pivot_output_title (pt);
if (layersp)
- for (size_t i = 0; i < layer_axis->n_dimensions; i++)
- {
- const struct pivot_dimension *d = layer_axis->dimensions[i];
- if (d->n_leaves)
- n_layers++;
- }
+ *layersp = pivot_output_layers (pt, layer_indexes);
+ if (captionp)
+ *captionp = pivot_output_caption (pt);
- struct table *layers;
- if (n_layers > 0)
+ if (fp || footnotesp)
{
- layers = create_aux_table (pt, 1, n_layers, PIVOT_AREA_LAYERS);
- size_t y = n_layers - 1;
- for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+ size_t nf;
+ struct pivot_footnote **f = collect_footnotes (
+ pt, titlep ? *titlep : NULL, layersp ? *layersp : NULL, body,
+ captionp ? *captionp : NULL, &nf);
+
+ if (footnotesp)
+ *footnotesp = pivot_output_footnotes (pt, f, nf);
+
+ if (fp)
{
- const struct pivot_dimension *d = layer_axis->dimensions[i];
- if (!d->n_leaves)
- continue;
-
- struct string s = DS_EMPTY_INITIALIZER;
- pivot_value_format (d->data_leaves[layer_indexes[i]]->name, pt, &s);
- fill_cell_owned (layers, 0, y, 0, y, PIVOT_AREA_LAYERS, &s, false);
- y--;
+ *fp = f;
+ *nfp = nf;
}
+ else
+ free (f);
}
- else
- layers = NULL;
+}
+
+struct table *
+pivot_output_monolithic (const struct pivot_table *pt,
+ const size_t *layer_indexes,
+ bool printing)
+{
+ /* Table structure:
+
+ #============ 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]);
- /* Caption. */
- struct table *caption;
- if (pt->caption && pt->show_caption && captionp)
+ /* 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,
+ };
+
+ 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] = MAX (min_body_width, stub[H] + data[H]),
+ [V] = n_title + n_layers + stub[V] + data[V] + n_caption + max_footnotes,
+ };
+
+ struct table *t = table_create (n[H], n[V],
+ stub[H], n_title + n_layers + stub[V]);
+ 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++)
{
- caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
- fill_cell (caption, 0, 0, 0, 0, PIVOT_AREA_CAPTION, pt->caption, false);
+ 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);
}
- else
- caption = NULL;
- /* Footnotes. */
- size_t nf;
- struct pivot_footnote **f = collect_footnotes (pt, title, layers, body,
- caption, &nf);
- struct table *footnotes;
- if (nf && footnotesp)
- {
- footnotes = create_aux_table (pt, 1, nf, PIVOT_AREA_FOOTER);
+ int body[TABLE_N_AXES][2] = {
+ [H] = { 0, n[H] - 1 },
+ [V] = {
+ n_title + n_layers,
+ n_title + n_layers + stub[V] + data[V] - 1
+ },
+ };
+
+ if (n_layers)
+ put_layers (t, pt, layer_indexes,
+ body[H][0], n_title,
+ body[H][1], 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);
- for (size_t i = 0; i < nf; i++)
+ 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])
+ {
+ int x = data_ofs[H];
+ PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
+ column_enumeration,
+ &pt->axes[PIVOT_AXIS_COLUMN])
{
- struct string s = DS_EMPTY_INITIALIZER;
- pivot_footnote_format_marker (f[i], pt, &s);
- ds_put_cstr (&s, ". ");
- pivot_value_format (f[i]->content, pt, &s);
- fill_cell_owned (footnotes, 0, i, 0, i, PIVOT_AREA_FOOTER, &s,
- false);
+ pivot_table_convert_indexes_ptod (pt, pindexes, dindexes);
+ const struct pivot_value *value = pivot_table_get (pt, dindexes);
+ fill_cell (t, x, y, PIVOT_AREA_DATA, value, false);
+ x++;
}
+
+ y++;
}
- else
- footnotes = NULL;
+ free (dindexes);
- *titlep = title;
- if (layersp)
- *layersp = layers;
- *bodyp = body;
- if (captionp)
- *captionp = caption;
- if (footnotesp)
- *footnotesp = footnotes;
- if (fp)
+ if ((pt->corner_text || !pt->look->row_labels_in_corner)
+ && stub[H] && stub[V])
+ fill_cell_spanned (t, body[H][0], body[V][0],
+ body[H][0] + stub[H] - 1, body[V][0] + stub[V] - 1,
+ PIVOT_AREA_CORNER, pt->corner_text, false,
+ TABLE_CELL_FULL_WIDTH);
+
+ if (body[H][1] >= body[H][0] && body[V][1] >= body[V][0])
{
- *fp = f;
- *nfp = nf;
+ table_hline (t, PIVOT_BORDER_INNER_TOP,
+ body[H][0], body[H][1], body[V][0]);
+ table_hline (t, PIVOT_BORDER_INNER_BOTTOM,
+ body[H][0], body[H][1], body[V][1] + 1);
+ table_vline (t, PIVOT_BORDER_INNER_LEFT,
+ body[H][0], body[V][0], body[V][1]);
+ table_vline (t, PIVOT_BORDER_INNER_RIGHT,
+ body[H][1] + 1, body[V][0], body[V][1]);
+
+ if (stub[V])
+ table_hline (t, PIVOT_BORDER_DATA_TOP,
+ body[H][0], body[H][1], data_ofs[V]);
+ if (stub[H])
+ table_vline (t, PIVOT_BORDER_DATA_LEFT,
+ data_ofs[H], body[V][0], body[V][1]);
}
- else
- free (f);
+
+ if (n_caption)
+ fill_cell_spanned (t,
+ body[H][0], body[V][1] + 1,
+ body[H][1], body[V][1] + 1,
+ PIVOT_AREA_CAPTION, pt->caption, false,
+ TABLE_CELL_FULL_WIDTH);
+
+ size_t nf;
+ struct pivot_footnote **f = collect_footnotes (pt, t, NULL, NULL, NULL, &nf);
+ assert (nf <= max_footnotes);
+ put_footnotes (t, pt, f, nf, body[H][0], body[H][1],
+ body[V][1] + 1 + n_caption);
+ t->n[V] = body[V][1] + 1 + n_caption + nf;
+ free (f);
+
+ if (n_title)
+ {
+#if 0
+ printf ("%d,%d - %d,%d\n",
+ body[H][0], 0,
+ body[H][1], 0);
+#endif
+ fill_cell_spanned (t,
+ body[H][0], 0,
+ body[H][1], 0,
+ PIVOT_AREA_TITLE, pt->title, false,
+ TABLE_CELL_FULL_WIDTH);
+ }
+
+ free (column_enumeration);
+ free (row_enumeration);
+
+#if 0
+ printf ("output page:\n");
+ for (int y = 0; y < t->n[V]; y++)
+ for (int x = 0; x < t->n[H]; x++)
+ {
+ struct table_cell cell;
+
+ table_get_cell (t, x, y, &cell);
+ char *s = pivot_value_to_string (cell.value, NULL);
+ printf ("%d,%d - %d,%d: %s\n",
+ cell.d[H][0], cell.d[V][0],
+ cell.d[H][1], cell.d[V][1],
+ s);
+ free (s);
+ }
+#endif
+
+ return t;
}
void
}
/* Allocates and returns a new render_page using PARAMS and TABLE. Allocates
- space for rendering a table with dimensions given in N. The caller must
- initialize most of the members itself. */
+ space for rendering a table with dimensions given in N, headers in H, and
+ content in R. The caller must initialize most of the members itself. */
static struct render_page *
render_page_allocate__ (const struct render_params *params,
- struct table *table, int n[TABLE_N_AXES])
+ struct table *table,
+ const int n[TABLE_N_AXES],
+ const int h[TABLE_N_AXES],
+ const int r[TABLE_N_AXES][2])
{
struct render_page *page = xmalloc (sizeof *page);
- page->params = params;
- page->table = table;
- page->ref_cnt = 1;
- page->n[H] = n[H];
- page->n[V] = n[V];
-
- for (int i = 0; i < TABLE_N_AXES; i++)
- page->cp[i] = xcalloc ((2 * n[i] + 2) , sizeof *page->cp[i]);
-
- hmap_init (&page->overflows);
- memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff);
-
+ *page = (struct render_page) {
+ .params = params,
+ .table = table,
+ .ref_cnt = 1,
+ .n = { [H] = n[H], [V] = n[V] },
+ .h = { [H] = h[H], [V] = h[V] },
+ .r = { [H] = { r[H][0], r[H][1] }, [V] = { r[V][0], r[V][1] } },
+ .cp = { [H] = xcalloc (2 * n[H] + 2, sizeof *page->cp[H]),
+ [V] = xcalloc (2 * n[V] + 2, sizeof *page->cp[V]) },
+ .overflows = HMAP_INITIALIZER (page->overflows),
+ };
return page;
}
static struct render_page *
render_page_allocate (const struct render_params *params, struct table *table)
{
- struct render_page *page = render_page_allocate__ (params, table, table->n);
+ int h[TABLE_N_AXES];
+ int r[TABLE_N_AXES][2];
for (enum table_axis a = 0; a < TABLE_N_AXES; a++)
{
- page->h[a] = table->h[a];
- page->r[a][0] = table->h[a];
- page->r[a][1] = table->n[a];
+ h[a] = table->h[a];
+ r[a][0] = table->h[a];
+ r[a][1] = table->n[a];
}
- return page;
+ return render_page_allocate__ (params, table, table->n, h, r);
}
/* Allocates and returns a new render_page for PARAMS and TABLE, initializing
cell->d[a][0] = MAX (cell->d[a][0], m->p0);
cell->d[a][1] = MIN (cell->d[a][1], m->p0 + m->n);
}
+
+ if (cell->options & TABLE_CELL_FULL_WIDTH)
+ {
+ cell->d[H][0] = 0;
+ cell->d[H][1] = page->n[H];
+ }
}
/* Creates and returns a new render_page for rendering TABLE on a device
const struct render_params *params;
double scale;
- /* An array of "render_page"s to be rendered, in order, vertically. There
- may be up to 5 pages, for the pivot table's title, layers, body,
- captions, and footnotes. */
- struct render_page *pages[5];
- size_t n_pages;
+ struct render_page *page;
- size_t cur_page;
struct render_break x_break;
struct render_break y_break;
};
-static void
-render_pager_add_table (struct render_pager *p, struct table *table,
- int min_width)
-{
- if (table)
- p->pages[p->n_pages++] = render_page_create (p->params, table, min_width);
-}
-
static void
render_pager_start_page (struct render_pager *p)
{
- render_break_init (&p->x_break, render_page_ref (p->pages[p->cur_page++]),
- H);
+ render_break_init (&p->x_break, render_page_ref (p->page), H);
render_break_init_empty (&p->y_break);
}
if (!layer_indexes)
layer_indexes = pt->current_layer;
- struct table *title, *layers, *body, *caption, *footnotes;
- pivot_output (pt, layer_indexes, params->printing,
- &title, &layers, &body, &caption, &footnotes, NULL, NULL);
+ struct table *table = pivot_output_monolithic (pt, layer_indexes,
+ params->printing);
- /* Figure out the width of the body of the table. Use this to determine the
- base scale. */
- struct render_page *body_page = render_page_create (params, body, 0);
- int body_width = table_width (body_page, H);
+ /* Measure the table width and use it to determine the base scale. */
+ struct render_page *page = render_page_create (params, table, 0);
+ int width = table_width (page, H);
double scale = 1.0;
- if (body_width > params->size[H])
+ if (width > params->size[H])
{
if (pt->look->shrink_to_fit[H] && params->ops->scale)
- scale = params->size[H] / (double) body_width;
+ scale = params->size[H] / (double) width;
else
{
struct render_break b;
- render_break_init (&b, render_page_ref (body_page), H);
+ render_break_init (&b, render_page_ref (page), H);
struct render_page *subpage
= render_break_next (&b, params->size[H]);
- body_width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
+ width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
render_page_unref (subpage);
render_break_destroy (&b);
}
/* Create the pager. */
struct render_pager *p = xmalloc (sizeof *p);
- *p = (struct render_pager) { .params = params, .scale = scale };
- render_pager_add_table (p, title, body_width);
- render_pager_add_table (p, layers, body_width);
- p->pages[p->n_pages++] = body_page;
- render_pager_add_table (p, caption, 0);
- render_pager_add_table (p, footnotes, 0);
- assert (p->n_pages <= sizeof p->pages / sizeof *p->pages);
+ *p = (struct render_pager) { .params = params, .scale = scale, .page = page };
/* If we're shrinking tables to fit the page length, then adjust the scale
factor.
necessary would require an iterative search. */
if (pt->look->shrink_to_fit[V] && params->ops->scale)
{
- int total_height = 0;
- for (size_t i = 0; i < p->n_pages; i++)
- total_height += table_width (p->pages[i], V);
- if (total_height * p->scale >= params->size[V])
- p->scale *= params->size[V] / (double) total_height;
+ double height = table_width (p->page, V);
+ if (height * p->scale >= params->size[V])
+ p->scale *= params->size[V] / height;
}
render_pager_start_page (p);
{
render_break_destroy (&p->x_break);
render_break_destroy (&p->y_break);
- for (size_t i = 0; i < p->n_pages; i++)
- render_page_unref (p->pages[i]);
+ render_page_unref (p->page);
free (p);
}
}
if (!render_break_has_next (&p->x_break))
{
render_break_destroy (&p->x_break);
- if (p->cur_page >= p->n_pages)
- {
- render_break_init_empty (&p->x_break);
- render_break_init_empty (&p->y_break);
- return false;
- }
- render_pager_start_page (p);
+ render_break_init_empty (&p->x_break);
+ render_break_init_empty (&p->y_break);
+ return false;
}
else
render_break_init (
}
int ofs[TABLE_N_AXES] = { 0, 0 };
- size_t start_page = SIZE_MAX;
- while (render_pager_has_next (p))
+ if (render_pager_has_next (p))
{
- if (start_page == p->cur_page)
- break;
- start_page = p->cur_page;
-
struct render_page *page
= render_break_next (&p->y_break, space - ofs[V]);
- if (!page)
- break;
-
- render_page_draw (page, ofs);
- ofs[V] += render_page_get_size (page, V);
- render_page_unref (page);
+ if (page)
+ {
+ render_page_draw (page, ofs);
+ ofs[V] += render_page_get_size (page, V);
+ render_page_unref (page);
+ }
}
if (p->scale != 1.0)
clip[H][0] = x;
clip[H][1] = x + w;
- for (size_t i = 0; i < p->n_pages; i++)
- {
- const struct render_page *page = p->pages[i];
- int size = render_page_get_size (page, V);
+ int size = render_page_get_size (p->page, V);
- clip[V][0] = MAX (y, ofs[V]) - ofs[V];
- clip[V][1] = MIN (y + h, ofs[V] + size) - ofs[V];
- if (clip[V][1] > clip[V][0])
- render_page_draw_region (page, ofs, clip);
+ clip[V][0] = MAX (y, ofs[V]) - ofs[V];
+ clip[V][1] = MIN (y + h, ofs[V] + size) - ofs[V];
+ if (clip[V][1] > clip[V][0])
+ render_page_draw_region (p->page, ofs, clip);
- ofs[V] += size;
- }
+ ofs[V] += size;
}
/* Returns the size of P's content along AXIS; i.e. the content's width if AXIS
int
render_pager_get_size (const struct render_pager *p, enum table_axis axis)
{
- int size = 0;
-
- for (size_t i = 0; i < p->n_pages; i++)
- {
- int subsize = render_page_get_size (p->pages[i], axis);
- size = axis == H ? MAX (size, subsize) : size + subsize;
- }
-
- return size;
+ return render_page_get_size (p->page, axis);
}
int
render_pager_get_best_breakpoint (const struct render_pager *p, int height)
{
- int y = 0;
- size_t i;
-
- for (i = 0; i < p->n_pages; i++)
- {
- int size = render_page_get_size (p->pages[i], V);
- if (y + size >= height)
- return render_page_get_best_breakpoint (p->pages[i], height - y) + y;
- y += size;
- }
-
- return height;
+ int size = render_page_get_size (p->page, V);
+ return (size < height
+ ? height
+ : render_page_get_best_breakpoint (p->page, height));
}
\f
/* render_page_select() and helpers. */
/* Allocate subpage. */
int trim[2] = { z0 - page->h[a], page->n[a] - z1 };
+
int n[TABLE_N_AXES] = { [H] = page->n[H], [V] = page->n[V] };
n[a] -= trim[0] + trim[1];
- struct render_page *subpage = render_page_allocate__ (
- page->params, table_ref (page->table), n);
+
+ int r[TABLE_N_AXES][2];
for (enum table_axis k = 0; k < TABLE_N_AXES; k++)
{
- subpage->h[k] = page->h[k];
- subpage->r[k][0] = page->r[k][0];
- subpage->r[k][1] = page->r[k][1];
+ r[k][0] = page->r[k][0];
+ r[k][1] = page->r[k][1];
}
- subpage->r[a][0] += trim[0];
- subpage->r[a][1] -= trim[1];
+ r[a][0] += trim[0];
+ r[a][1] -= trim[1];
+
+ struct render_page *subpage = render_page_allocate__ (
+ page->params, table_ref (page->table), n, page->h, r);
/* An edge is cut off if it was cut off in PAGE or if we're trimming pixels
off that side of the page and there are no headers. */