From: Ben Pfaff Date: Mon, 26 Dec 2022 17:04:12 +0000 (-0800) Subject: work on monolithic output and outer borders X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fpivot-titles;p=pspp work on monolithic output and outer borders --- diff --git a/src/output/cairo-fsm.c b/src/output/cairo-fsm.c index 51f48efb75..9f7b71af7e 100644 --- a/src/output/cairo-fsm.c +++ b/src/output/cairo-fsm.c @@ -407,6 +407,12 @@ static void xrr_measure_cell_width (void *xr_, const struct table_cell *cell, int *min_width, int *max_width) { + if (cell->options & TABLE_CELL_PADDING) + { + *min_width = *max_width = XR_LINE_WIDTH; + return; + } + struct xr_fsm *xr = xr_; int bb[TABLE_N_AXES][2]; int clip[TABLE_N_AXES][2]; @@ -432,6 +438,9 @@ xrr_measure_cell_width (void *xr_, const struct table_cell *cell, static int xrr_measure_cell_height (void *xr_, const struct table_cell *cell, int width) { + if (cell->options & TABLE_CELL_PADDING) + return XR_LINE_WIDTH; + struct xr_fsm *xr = xr_; const int (*margin)[2] = cell->cell_style->margin; diff --git a/src/output/pivot-output.c b/src/output/pivot-output.c index 8a6e9c8659..68bc9aa3d9 100644 --- a/src/output/pivot-output.c +++ b/src/output/pivot-output.c @@ -112,7 +112,7 @@ table_area_style_override (struct pool *pool, } 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) { @@ -120,6 +120,18 @@ fill_cell (struct table *t, int x1, int y1, int x2, int y2, 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); } @@ -162,11 +174,12 @@ compose_headings (struct table *t, 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; @@ -176,7 +189,10 @@ compose_headings (struct table *t, /* 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, @@ -258,8 +274,6 @@ compose_headings (struct table *t, 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]; @@ -267,10 +281,12 @@ compose_headings (struct table *t, 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 @@ -292,12 +308,12 @@ compose_headings (struct table *t, = (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; } } @@ -324,15 +340,15 @@ compose_headings (struct table *t, } } - 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: @@ -348,7 +364,7 @@ compose_headings (struct table *t, +-----+-----+-----+-----+-----+-----+-----+-----+-----+ */ 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); @@ -364,7 +380,6 @@ create_aux_table (const struct pivot_table *pt, int nc, int nr, return table; } - static void add_references (const struct pivot_table *pt, const struct table *table, bool *refs, size_t *n_refs) @@ -432,10 +447,104 @@ collect_footnotes (const struct pivot_table *pt, 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, @@ -456,9 +565,26 @@ pivot_output (const struct pivot_table *pt, [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], - stub[H], 0, stub[V], 0); + 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 fs[TABLE_N_AXES] = { + [H] = stub[H] + frame[H][0], + [V] = stub[V] + frame[V][0], + }; + + struct table *body = table_create ( + frame[H][0] + stub[H] + data[H] + frame[H][1], + frame[V][0] + stub[V] + data[V] + frame[V][1], + frame[H][0] + stub[H], frame[H][1], + frame[V][0] + stub[V], frame[V][1]); for (size_t i = 0; i < PIVOT_N_AREAS; i++) body->styles[i] = table_area_style_override ( body->container, &pt->look->areas[i], NULL, NULL, false); @@ -476,6 +602,10 @@ pivot_output (const struct pivot_table *pt, : *src); } + int body_area[TABLE_N_AXES][2] = { + [H] = { frame[H][0], body->n[H] - frame[H][1] - 1 }, + [V] = { frame[V][0], body->n[V] - frame[V][1] - 1 }, + }; compose_headings (body, &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW], PIVOT_BORDER_DIM_COL_HORZ, @@ -484,7 +614,7 @@ pivot_output (const struct pivot_table *pt, 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], @@ -494,7 +624,7 @@ pivot_output (const struct pivot_table *pt, 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; @@ -508,7 +638,7 @@ pivot_output (const struct pivot_table *pt, { 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 + fs[H], y + fs[V], PIVOT_AREA_DATA, value, false); x++; @@ -520,115 +650,357 @@ pivot_output (const struct pivot_table *pt, 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, fs[H] - 1, fs[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] = { frame[H][0], body->n[H] - frame[H][1] }, + [V] = { frame[V][0], body->n[V] - frame[V][1] }, + }; + 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, fs[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, + fs[H], inner[V][0], inner[V][1] - 1); + } + if (frame[H][0]) + { + for (int y = 0; y < body->n[V]; y++) + table_put (body, 0, y, 0, y, TABLE_CELL_PADDING, NULL); + table_vline (body, PIVOT_BORDER_OUTER_LEFT, 0, 0, body->n[V] - 1); } + if (frame[H][1]) + { + int x = body->n[H] - 1; + for (int y = 0; y < body->n[V]; y++) + table_put (body, x, y, x, y, TABLE_CELL_PADDING, NULL); + table_vline (body, PIVOT_BORDER_OUTER_RIGHT, + body->n[H], 0, body->n[V] - 1); + } + if (frame[V][0]) + { + for (int x = 0; x < body->n[H]; x++) + table_put (body, x, 0, x, 0, TABLE_CELL_PADDING, NULL); + table_hline (body, PIVOT_BORDER_OUTER_TOP, 0, body->n[H] - 1, 0); + } + if (frame[V][1]) + { + int y = body->n[V] - 1; + for (int x = 0; x < body->n[H]; x++) + table_put (body, x, y, x, y, TABLE_CELL_PADDING, NULL); + table_hline (body, PIVOT_BORDER_OUTER_BOTTOM, 0, body->n[H] - 1, body->n[V]); + } + free (column_enumeration); free (row_enumeration); - /* Title. */ - struct table *title; - if (pt->title && pt->show_title && titlep) + *bodyp = body; + if (titlep) + *titlep = pivot_output_title (pt); + if (layersp) + *layersp = pivot_output_layers (pt, layer_indexes); + if (captionp) + *captionp = pivot_output_caption (pt); + + if (fp || footnotesp) { - title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE); - fill_cell (title, 0, 0, 0, 0, PIVOT_AREA_TITLE, pt->title, false); + 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) + { + *fp = f; + *nfp = nf; + } + else + free (f); } - else - title = NULL; +} - /* Layers. */ - const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; - int n_layers = 0; - 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++; - } +struct table * +pivot_output_monolithic (const struct pivot_table *pt, + const size_t *layer_indexes, + bool printing) +{ + /* Table structure: - struct table *layers; - if (n_layers > 0) + #============ 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]) { - 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++) + int x = data_ofs[H]; + PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN], + column_enumeration, + &pt->axes[PIVOT_AXIS_COLUMN]) { - 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--; + 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 - layers = NULL; + free (dindexes); + + 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); - /* Caption. */ - struct table *caption; - if (pt->caption && pt->show_caption && captionp) + if (body[H][1] >= body[H][0] && body[V][1] >= body[V][0]) { - caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION); - fill_cell (caption, 0, 0, 0, 0, PIVOT_AREA_CAPTION, pt->caption, false); + 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 - caption = NULL; - /* Footnotes. */ + 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, title, layers, body, - caption, &nf); - struct table *footnotes; - if (nf && footnotesp) + 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 + frame[V][1]; + free (f); + + if (n_title) { - footnotes = create_aux_table (pt, 1, nf, PIVOT_AREA_FOOTER); - - 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); - fill_cell_owned (footnotes, 0, i, 0, i, PIVOT_AREA_FOOTER, &s, - false); - } + printf ("%d,%d - %d,%d\n", + body[H][0], frame[V][0], + body[H][1], frame[V][0]); + fill_cell_spanned (t, + body[H][0], frame[V][0], + body[H][1], frame[V][0], + PIVOT_AREA_TITLE, pt->title, false, + TABLE_CELL_FULL_WIDTH); } - else - footnotes = NULL; - *titlep = title; - if (layersp) - *layersp = layers; - *bodyp = body; - if (captionp) - *captionp = caption; - if (footnotesp) - *footnotesp = footnotes; - if (fp) + if (frame[H][0]) { - *fp = f; - *nfp = nf; + for (int y = 0; y < t->n[V]; y++) + table_put (t, 0, y, 0, y, TABLE_CELL_PADDING, NULL); + table_vline (t, PIVOT_BORDER_OUTER_LEFT, 0, 0, t->n[V] - 1); } - else - free (f); + if (frame[H][1]) + { + int x = t->n[H] - 1; + for (int y = 0; y < t->n[V]; y++) + table_put (t, x, y, x, y, TABLE_CELL_PADDING, NULL); + table_vline (t, PIVOT_BORDER_OUTER_RIGHT, + t->n[H], 0, t->n[V] - 1); + } + if (frame[V][0]) + { + for (int x = 0; x < t->n[H]; x++) + table_put (t, x, 0, x, 0, TABLE_CELL_PADDING, NULL); + table_hline (t, PIVOT_BORDER_OUTER_TOP, 0, t->n[H] - 1, 0); + } + if (frame[V][1]) + { + int y = t->n[V] - 1; + for (int x = 0; x < t->n[H]; x++) + table_put (t, x, y, x, y, TABLE_CELL_PADDING, NULL); + table_hline (t, PIVOT_BORDER_OUTER_TOP, 0, t->n[H] - 1, t->n[V]); + } + + free (column_enumeration); + free (row_enumeration); + + 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); + } + + return t; } void diff --git a/src/output/pivot-output.h b/src/output/pivot-output.h index 4013c1bc45..6620cf7618 100644 --- a/src/output/pivot-output.h +++ b/src/output/pivot-output.h @@ -40,4 +40,8 @@ void pivot_output (const struct pivot_table *, struct table **footnotesp, struct pivot_footnote ***fp, size_t *nfp); +struct table *pivot_output_monolithic (const struct pivot_table *, + const size_t *layer_indexes, + bool printing); + #endif /* output/pivot-output.h */ diff --git a/src/output/render.c b/src/output/render.c index 9e469a5e26..12c8f2c494 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -41,6 +41,16 @@ #define H TABLE_HORZ #define V TABLE_VERT +/* Maps a contiguous range of cells from a page to the underlying table along + the horizontal or vertical dimension. */ +struct map + { + int p[2]; /* Range of ordinates in the page. */ + int t[2]; /* Range of ordinates in the table. */ + int ofs; /* p[0] - t[0]. */ + int n; /* p[1] - p[0] == t[1] - t[0]. */ + }; + /* A layout for rendering a specific table on a specific device. May represent the layout of an entire table presented to @@ -67,9 +77,11 @@ struct render_page n[H] = h[H][0] + (r[H][1] - r[H][0]) + h[H][1] n[V] = h[V][0] + (r[V][1] - r[V][0]) + h[V][1] */ + int n[TABLE_N_AXES]; int h[TABLE_N_AXES][2]; int r[TABLE_N_AXES][2]; - int n[TABLE_N_AXES]; + + struct map maps[TABLE_N_AXES][3]; /* "Cell positions". @@ -499,29 +511,53 @@ measure_rule (const struct render_params *params, const struct table *table, return width; } +static struct map +make_map (int p0, int t0, int n) +{ + return (struct map) { + .p = { p0, p0 + n }, + .t = { t0, t0 + n }, + .ofs = p0 - t0, + .n = n, + }; +} + /* 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][2], + 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]; + *page = (struct render_page) { + .params = params, + .table = table, + .ref_cnt = 1, + .n = { [H] = n[H], [V] = n[V] }, + .h = { [H] = { h[H][0], h[H][1] }, [V] = { h[V][0], h[V][1] } }, + .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]) }, + .join_crossing = { + [H] = xcalloc (n[H] + 1, sizeof *page->join_crossing[H]), + [V] = xcalloc (n[V] + 1, sizeof *page->join_crossing[V]) + }, + .overflows = HMAP_INITIALIZER (page->overflows), + }; - for (int i = 0; i < TABLE_N_AXES; i++) + for (enum table_axis a = 0; a < TABLE_N_AXES; a++) { - page->cp[i] = xcalloc ((2 * n[i] + 2) , sizeof *page->cp[i]); - page->join_crossing[i] = xcalloc ((n[i] + 1) , sizeof *page->join_crossing[i]); + struct map *m = page->maps[a]; + if (h[a][0]) + *m++ = make_map (0, 0, page->h[a][0]); + *m++ = make_map (h[a][0], r[a][0], r[a][1] - r[a][0]); + if (h[a][1]) + *m++ = make_map (n[a] - h[a][1], table->n[a] - table->h[a][1], h[a][1]); } - - hmap_init (&page->overflows); - memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff); - return page; } @@ -531,15 +567,16 @@ render_page_allocate__ (const struct render_params *params, 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][2]; + int r[TABLE_N_AXES][2]; for (enum table_axis a = 0; a < TABLE_N_AXES; a++) { - page->h[a][0] = table->h[a][0]; - page->h[a][1] = table->h[a][1]; - page->r[a][0] = table->h[a][0]; - page->r[a][1] = table->n[a] - table->h[a][1]; + h[a][0] = table->h[a][0]; + h[a][1] = table->h[a][1]; + r[a][0] = table->h[a][0]; + r[a][1] = table->n[a] - table->h[a][1]; } - return page; + return render_page_allocate__ (params, table, table->n, h, r); } /* Allocates and returns a new render_page for PARAMS and TABLE, initializing @@ -608,39 +645,21 @@ set_join_crossings (struct render_page *page, enum table_axis axis, page->join_crossing[axis][z] = rules[z]; } -/* Maps a contiguous range of cells from a page to the underlying table along - the horizpntal or vertical dimension. */ -struct map - { - int p0; /* First ordinate in the page. */ - int t0; /* First ordinate in the table. */ - int n; /* Number of ordinates in page and table. */ - }; - -/* Initializes M to a mapping from PAGE to PAGE->table along axis A. The - mapping includes ordinate Z (in PAGE). */ -static void -get_map (const struct render_page *page, enum table_axis a, int z, - struct map *m) +/* Returns a mapping from page to table ordinates along axis A that includes + ordinate Z (in PAGE). */ +static const struct map * +get_map (const struct render_page *page, enum table_axis a, int z) { - if (z < page->h[a][0]) - { - m->p0 = 0; - m->t0 = 0; - m->n = page->h[a][0]; - } - else if (z < page->n[a] - page->h[a][1]) + for (size_t i = 0; i < 3; i++) { - m->p0 = page->h[a][0]; - m->t0 = page->r[a][0]; - m->n = page->r[a][1] - page->r[a][0]; - } - else - { - m->p0 = page->n[a] - page->h[a][1]; - m->t0 = page->table->n[a] - page->table->h[a][1]; - m->n = page->h[a][1]; + const struct map *m = &page->maps[a][i]; + if (z < m->p[1]) + { + assert (z >= m->p[0]); + return m; + } } + NOT_REACHED (); } /* Initializes CELL with the contents of the table cell at column X and row Y @@ -655,25 +674,35 @@ static void render_get_cell (const struct render_page *page, int x, int y, struct table_cell *cell) { - int d[TABLE_N_AXES] = { [H] = x, [V] = y }; - struct map map[TABLE_N_AXES]; + const struct map *map[TABLE_N_AXES] = { + [H] = get_map (page, H, x), + [V] = get_map (page, V, y), + }; - for (enum table_axis a = 0; a < TABLE_N_AXES; a++) - { - struct map *m = &map[a]; - get_map (page, a, d[a], m); - d[a] += m->t0 - m->p0; - } - table_get_cell (page->table, d[H], d[V], cell); + /* Get CELL, translating X and Y into table coordinates. CELL is also + returned in table coordinates. */ + table_get_cell (page->table, x + map[H]->ofs, y + map[V]->ofs, cell); + /* Translate CELL into page coordinates. */ for (enum table_axis a = 0; a < TABLE_N_AXES; a++) { - struct map *m = &map[a]; + const struct map *m = map[a]; - for (int i = 0; i < 2; i++) - cell->d[a][i] -= m->t0 - m->p0; - 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 0 + if (a == H && cell->options & TABLE_CELL_FULL_WIDTH) + { + printf ("special case\n"); + cell->d[a][0] -= m->ofs; + cell->d[a][1] -= get_map (page, H, cell->d[a][1] - 1)->ofs; + } + else +#endif + { + for (int i = 0; i < 2; i++) + cell->d[a][i] -= m->ofs; + cell->d[a][0] = MAX (cell->d[a][0], m->p[0]); + cell->d[a][1] = MIN (cell->d[a][1], m->p[1]); + } } } @@ -774,6 +803,7 @@ render_page_create (const struct render_params *params, struct table *table, /* Fits even with maximum widths. Use them. */ page = create_page_with_exact_widths (params, table, columns[MAX], rules[H]); + //page->h[H][0] = page->h[H][1] = 0; } else if (table_widths[MIN] <= params->size[H]) { @@ -781,6 +811,7 @@ render_page_create (const struct render_params *params, struct table *table, page = create_page_with_interpolated_widths ( params, table, columns[MIN], columns[MAX], table_widths[MIN], table_widths[MAX], rules[H]); + //page->h[H][0] = page->h[H][1] = 0; } else { @@ -945,9 +976,7 @@ get_rule (const struct render_page *page, enum table_axis axis, - (page->n[a] - page->h[a][1])); enum table_axis b = !axis; - struct map m; - get_map (page, b, d[b], &m); - d[b] += m.t0 - m.p0; + d[b] += get_map (page, b, d[b])->ofs; struct table_border_style border = table_get_rule (page->table, axis, d[H], d[V]); @@ -1117,19 +1146,55 @@ static void render_page_draw_cells (const struct render_page *page, int ofs[TABLE_N_AXES], int bb[TABLE_N_AXES][2]) { + /* OK, the problem is the headers.... the left-side headers shouldn't apply + to the title and caption and so on */ + printf ("render page %d,%d - %d,%d\n", + bb[H][0], bb[V][0], + bb[H][1], bb[V][1]); for (int y = bb[V][0]; y < bb[V][1]; y++) - for (int x = bb[H][0]; x < bb[H][1];) - if (!is_rule (x) && !is_rule (y)) - { - struct table_cell cell; + if (!is_rule (y)) + for (int x = bb[H][0]; x < bb[H][1]; x++) + if (!is_rule (x)) + { + struct table_cell cell; + + render_get_cell (page, x / 2, y / 2, &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); + } - render_get_cell (page, x / 2, y / 2, &cell); - if (y / 2 == bb[V][0] / 2 || y / 2 == cell.d[V][0]) - render_cell (page, ofs, &cell); - x = rule_ofs (cell.d[H][1]); - } - else - x++; + for (int y = bb[V][0]; y < bb[V][1]; y++) + if (!is_rule (y)) + { + for (int x = bb[H][0]; x < bb[H][1];) + if (!is_rule (x)) + { + struct table_cell cell; + + render_get_cell (page, x / 2, y / 2, &cell); + if (y / 2 == bb[V][0] / 2 || y / 2 == cell.d[V][0]) + { + if (cell.d[H][1] - cell.d[H][0] != 1 || + cell.d[V][1] - cell.d[V][0] != 1) + { + char *s = pivot_value_to_string (cell.value, NULL); + printf ("rendering %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); + } + render_cell (page, ofs, &cell); + } + x = rule_ofs (cell.d[H][1]); + } + else + x++; + } for (int y = bb[V][0]; y < bb[V][1]; y++) for (int x = bb[H][0]; x < bb[H][1]; x++) @@ -1456,30 +1521,16 @@ struct render_pager 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); } @@ -1493,26 +1544,24 @@ render_pager_create (const struct render_params *params, 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); } @@ -1520,13 +1569,7 @@ render_pager_create (const struct render_params *params, /* 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. @@ -1538,11 +1581,9 @@ render_pager_create (const struct render_params *params, 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); @@ -1558,8 +1599,7 @@ render_pager_destroy (struct render_pager *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); } } @@ -1577,13 +1617,9 @@ render_pager_has_next (const struct render_pager *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 ( @@ -1609,22 +1645,17 @@ render_pager_draw_next (struct render_pager *p, int space) } 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) @@ -1652,18 +1683,14 @@ render_pager_draw_region (const struct render_pager *p, 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 @@ -1671,32 +1698,16 @@ render_pager_draw_region (const struct render_pager *p, 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)); } /* render_page_select() and helpers. */ @@ -1754,19 +1765,21 @@ render_page_select (const struct render_page *page, enum table_axis axis, /* Allocate subpage. */ int trim[2] = { z0 - page->h[a][0], (page->n[a] - page->h[a][1]) - 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][0] = page->h[k][0]; - subpage->h[k][1] = page->h[k][1]; - 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. */ diff --git a/src/output/table.h b/src/output/table.h index 1fe78d8e76..a5ab5ee8bb 100644 --- a/src/output/table.h +++ b/src/output/table.h @@ -183,7 +183,10 @@ enum { TABLE_CELL_ROTATE = 1 << 0, /* Rotate cell contents 90 degrees. */ TABLE_CELL_JOIN = 1 << 1, /* Joined cell (internal use only). */ - TABLE_CELL_STYLE_SHIFT = 2, + TABLE_CELL_PADDING = 1 << 2, /* Padding cell. */ + TABLE_CELL_FULL_WIDTH = 1 << 3, /* Cell spans full width, + ignoring headers. */ + TABLE_CELL_STYLE_SHIFT = 4, TABLE_CELL_STYLE_MASK = 7 << TABLE_CELL_STYLE_SHIFT, };