/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2011, 2013, 2014, 2016 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/assertion.h"
#include "libpspp/hash-functions.h"
#include "libpspp/hmap.h"
+#include "libpspp/pool.h"
#include "output/render.h"
#include "output/tab.h"
#include "output/table-item.h"
int n[TABLE_N_AXES];
int h[TABLE_N_AXES][2];
- /* cp[H] represents x positions within the table.
+ /* "Cell positions".
+
+ cp[H] represents x positions within the table.
cp[H][0] = 0.
cp[H][1] = the width of the leftmost vertical rule.
cp[H][2] = cp[H][1] + the width of the leftmost column.
entire page can overflow on all four sides!) */
struct hmap overflows;
- /* Contains "struct render_footnote"s, one for each cell with one or more
- footnotes.
-
- 'n_footnotes' is the number of footnotes in the table. There might be
- more than hmap_count(&page->footnotes) because there can be more than
- one footnote in a cell. */
- struct hmap footnotes;
- size_t n_footnotes;
-
/* If a single column (or row) is too wide (or tall) to fit on a page
reasonably, then render_break_next() will split a single row or column
across multiple render_pages. This member indicates when this has
};
static struct render_page *render_page_create (const struct render_params *,
- const struct table *);
+ struct table *, int min_width);
struct render_page *render_page_ref (const struct render_page *page_);
static void render_page_unref (struct render_page *);
return NULL;
}
\f
-/* A footnote. */
-struct render_footnote
- {
- struct hmap_node node;
-
- /* The area of the table covered by the cell that has the footnote.
-
- d[H][0] is the leftmost column.
- d[H][1] is the rightmost column, plus 1.
- d[V][0] is the top row.
- d[V][1] is the bottom row, plus 1.
-
- The cell in its original table might occupy a larger region. This
- member reflects the size of the cell in the current render_page, after
- trimming off any rows or columns due to page-breaking. */
- int d[TABLE_N_AXES][2];
-
- /* The index of the first footnote in the cell. */
- int idx;
- };
-
-static int
-count_footnotes (const struct table_cell *cell)
-{
- size_t i;
- int n;
-
- n = 0;
- for (i = 0; i < cell->n_contents; i++)
- n += cell->contents[i].n_footnotes;
- return n;
-}
-
-static int
-find_footnote_idx (const struct table_cell *cell, const struct hmap *footnotes)
-{
- const struct render_footnote *f;
-
- if (!count_footnotes (cell))
- return 0;
-
- HMAP_FOR_EACH_WITH_HASH (f, struct render_footnote, node,
- hash_cell (cell->d[H][0], cell->d[V][0]), footnotes)
- if (f->d[H][0] == cell->d[H][0] && f->d[V][0] == cell->d[V][0])
- return f->idx;
-
- NOT_REACHED ();
-}
-\f
/* Row or column dimensions. Used to figure the size of a table in
render_page_create() and discarded after that. */
struct render_row
distribute_spanned_width (int width,
struct render_row *rows, const int *rules, int n)
{
- int total_unspanned;
- double w, d0, d1, d;
- int x;
-
/* Sum up the unspanned widths of the N rows for use as weights. */
- total_unspanned = 0;
- for (x = 0; x < n; x++)
+ int total_unspanned = 0;
+ for (int x = 0; x < n; x++)
total_unspanned += rows[x].unspanned;
- for (x = 0; x < n - 1; x++)
+ for (int x = 0; x < n - 1; x++)
total_unspanned += rules[x + 1];
if (total_unspanned >= width)
return;
unspanned weights when 'total_unspanned' is 0 (because that would cause a
division by zero).
- This implementation uses floating-point types and operators, but all the
- values involved are integers. For integers smaller than 53 bits, this
- should not lose any precision, and it should degrade gracefully for larger
- values.
-
The calculation we want to do is this:
w0 = width / n
the rule on the right. That way each rule contributes to both the cell on
its left and on its right.)
*/
- d0 = n;
- d1 = 2.0 * (total_unspanned > 0 ? total_unspanned : 1.0);
- d = d0 * d1;
+ long long int d0 = n;
+ long long int d1 = 2LL * MAX (total_unspanned, 1);
+ long long int d = d0 * d1;
if (total_unspanned > 0)
- d *= 2.0;
- w = floor (d / 2.0);
- for (x = 0; x < n; x++)
+ d *= 2;
+ long long int w = d / 2;
+ for (int x = 0; x < n; x++)
{
w += width * d1;
if (total_unspanned > 0)
{
- double unspanned = rows[x].unspanned * 2.0;
+ long long int unspanned = rows[x].unspanned * 2LL;
if (x < n - 1)
unspanned += rules[x + 1];
if (x > 0)
{
switch (type)
{
- case TAL_0:
- case TAL_GAP:
+ case TAL_NONE:
return RENDER_LINE_NONE;
- case TAL_1:
+ case TAL_SOLID:
return RENDER_LINE_SINGLE;
- case TAL_2:
+ case TAL_DASHED:
+ return RENDER_LINE_DASHED;
+ case TAL_THICK:
+ return RENDER_LINE_THICK;
+ case TAL_THIN:
+ return RENDER_LINE_THIN;
+ case TAL_DOUBLE:
return RENDER_LINE_DOUBLE;
default:
NOT_REACHED ();
enum table_axis b = !a;
unsigned int rules;
int d[TABLE_N_AXES];
- int width;
/* Determine all types of rules that are present, as a bitmap in 'rules'
where rule type 't' is present if bit 2**t is set. */
+ struct cell_color color;
rules = 0;
d[a] = z;
for (d[b] = 0; d[b] < table->n[b]; d[b]++)
- rules |= 1u << table_get_rule (table, a, d[H], d[V]);
+ rules |= 1u << table_get_rule (table, a, d[H], d[V], &color);
+
+ /* Turn off TAL_NONE because it has width 0 and we needn't bother. However,
+ if the device doesn't support margins, make sure that there is at least a
+ small gap between cells (but we don't need any at the left or right edge
+ of the table). */
+ if (rules & (1u << TAL_NONE))
+ {
+ rules &= ~(1u << TAL_NONE);
+ if (z > 0 && z < table->n[a] && !params->supports_margins && a == H)
+ rules |= 1u << TAL_SOLID;
+ }
/* Calculate maximum width of the rules that are present. */
- width = 0;
- if (rules & (1u << TAL_1)
- || (z > 0 && z < table->n[a] && rules & (1u << TAL_GAP)))
- width = params->line_widths[a][RENDER_LINE_SINGLE];
- if (rules & (1u << TAL_2))
- width = MAX (width, params->line_widths[a][RENDER_LINE_DOUBLE]);
+ int width = 0;
+ for (size_t i = 0; i < TABLE_N_STROKES; i++)
+ if (rules & (1u << i))
+ width = MAX (width, params->line_widths[a][rule_to_render_type (i)]);
return width;
}
}
hmap_init (&page->overflows);
- hmap_init (&page->footnotes);
- page->n_footnotes = 0;
memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff);
return page;
const struct render_row *rows_max,
int w_min, int w_max, const int *rules)
{
- /* This implementation uses floating-point types and operators, but all the
- values involved are integers. For integers smaller than 53 bits, this
- should not lose any precision, and it should degrade gracefully for larger
- values. */
const int n = table->n[H];
- const double avail = params->size[H] - w_min;
- const double wanted = w_max - w_min;
- struct render_page *page;
- double w;
- int *cph;
- int x;
+ const long long int avail = params->size[H] - w_min;
+ const long long int wanted = w_max - w_min;
assert (wanted > 0);
- page = render_page_allocate (params, table);
+ struct render_page *page = render_page_allocate (params, table);
- cph = page->cp[H];
+ int *cph = page->cp[H];
*cph = 0;
- w = (int) wanted / 2;
- for (x = 0; x < n; x++)
+ long long int w = wanted / 2;
+ for (int x = 0; x < n; x++)
{
- int extra;
-
w += avail * (rows_max[x].width - rows_min[x].width);
- extra = w / wanted;
+ int extra = w / wanted;
w -= extra * wanted;
cph[1] = cph[0] + rules[x];
size is PARAMS->size, but the caller is responsible for actually breaking it
up to fit on such a device, using the render_break abstraction. */
static struct render_page *
-render_page_create (const struct render_params *params,
- const struct table *table_)
+render_page_create (const struct render_params *params, struct table *table,
+ int min_width)
{
struct render_page *page;
- struct table *table;
enum { MIN, MAX };
struct render_row *columns[2];
struct render_row *rows;
int table_widths[2];
int *rules[TABLE_N_AXES];
- struct hmap footnotes;
- int footnote_idx;
int nr, nc;
int x, y;
int i;
enum table_axis axis;
- table = table_ref (table_);
nc = table_nc (table);
nr = table_nr (table);
}
/* Calculate minimum and maximum widths of cells that do not
- span multiple columns. Assign footnote markers. */
- hmap_init (&footnotes);
- footnote_idx = 0;
+ span multiple columns. */
for (i = 0; i < 2; i++)
columns[i] = xzalloc (nc * sizeof *columns[i]);
for (y = 0; y < nr; y++)
table_get_cell (table, x, y, &cell);
if (y == cell.d[V][0])
{
- int n;
-
if (table_cell_colspan (&cell) == 1)
{
int w[2];
int i;
- params->measure_cell_width (params->aux, &cell, footnote_idx,
+ params->measure_cell_width (params->aux, &cell,
&w[MIN], &w[MAX]);
for (i = 0; i < 2; i++)
if (columns[i][x].unspanned < w[i])
columns[i][x].unspanned = w[i];
}
-
- n = count_footnotes (&cell);
- if (n > 0)
- {
- struct render_footnote *f = xmalloc (sizeof *f);
- f->d[H][0] = cell.d[H][0];
- f->d[H][1] = cell.d[H][1];
- f->d[V][0] = cell.d[V][0];
- f->d[V][1] = cell.d[V][1];
- f->idx = footnote_idx;
- hmap_insert (&footnotes, &f->node, hash_cell (x, y));
-
- footnote_idx += n;
- }
}
x = cell.d[H][1];
table_cell_free (&cell);
{
int w[2];
- params->measure_cell_width (params->aux, &cell,
- find_footnote_idx (&cell, &footnotes),
- &w[MIN], &w[MAX]);
+ params->measure_cell_width (params->aux, &cell, &w[MIN], &w[MAX]);
for (i = 0; i < 2; i++)
distribute_spanned_width (w[i], &columns[i][cell.d[H][0]],
rules[H], table_cell_colspan (&cell));
x = cell.d[H][1];
table_cell_free (&cell);
}
+ if (min_width > 0)
+ for (i = 0; i < 2; i++)
+ distribute_spanned_width (min_width, &columns[i][0], rules[H], nc);
+
+ /* In pathological cases, spans can cause the minimum width of a column to
+ exceed the maximum width. This bollixes our interpolation algorithm
+ later, so fix it up. */
+ for (i = 0; i < nc; i++)
+ if (columns[MIN][i].width > columns[MAX][i].width)
+ columns[MAX][i].width = columns[MIN][i].width;
/* Decide final column widths. */
for (i = 0; i < 2; i++)
if (table_cell_rowspan (&cell) == 1)
{
int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
- int h = params->measure_cell_height (
- params->aux, &cell, find_footnote_idx (&cell, &footnotes), w);
+ int h = params->measure_cell_height (params->aux, &cell, w);
if (h > r->unspanned)
r->unspanned = r->width = h;
}
if (y == cell.d[V][0] && table_cell_rowspan (&cell) > 1)
{
int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
- int h = params->measure_cell_height (
- params->aux, &cell, find_footnote_idx (&cell, &footnotes), w);
+ int h = params->measure_cell_height (params->aux, &cell, w);
distribute_spanned_width (h, &rows[cell.d[V][0]], rules[V],
table_cell_rowspan (&cell));
}
}
}
- hmap_swap (&page->footnotes, &footnotes);
- hmap_destroy (&footnotes);
- page->n_footnotes = footnote_idx;
-
free (rules[H]);
free (rules[V]);
hmap_destroy (&page->overflows);
table_unref (page->table);
-
+
for (i = 0; i < TABLE_N_AXES; ++i)
{
free (page->join_crossing[i]);
static inline enum render_line_style
get_rule (const struct render_page *page, enum table_axis axis,
- const int d[TABLE_N_AXES])
+ const int d[TABLE_N_AXES], struct cell_color *color)
{
return rule_to_render_type (table_get_rule (page->table,
- axis, d[H] / 2, d[V] / 2));
+ axis, d[H] / 2, d[V] / 2,
+ color));
}
static bool
bool
render_direction_rtl (void)
{
- /* TRANSLATORS: Do not translate this string. If the script of your language
- reads from right to left (eg Persian, Arabic, Hebrew etc), then replace
- this string with "output-direction-rtl". Otherwise either leave it
+ /* TRANSLATORS: Do not translate this string. If the script of your language
+ reads from right to left (eg Persian, Arabic, Hebrew etc), then replace
+ this string with "output-direction-rtl". Otherwise either leave it
untranslated or copy it verbatim. */
const char *dir = _("output-direction-ltr");
if ( 0 == strcmp ("output-direction-rtl", dir))
const int d[TABLE_N_AXES])
{
enum render_line_style styles[TABLE_N_AXES][2];
+ struct cell_color colors[TABLE_N_AXES][2];
enum table_axis a;
for (a = 0; a < TABLE_N_AXES; a++)
e[H] = d[H];
e[V] = d[V];
e[b]--;
- styles[a][0] = get_rule (page, a, e);
+ styles[a][0] = get_rule (page, a, e, &colors[a][0]);
}
if (d[b] / 2 < page->table->n[b])
- styles[a][1] = get_rule (page, a, d);
+ styles[a][1] = get_rule (page, a, d, &colors[a][1]);
}
else
- styles[a][0] = styles[a][1] = get_rule (page, a, d);
+ {
+ styles[a][0] = styles[a][1] = get_rule (page, a, d, &colors[a][0]);
+ colors[a][1] = colors[a][0];
+ }
}
if (styles[H][0] != RENDER_LINE_NONE || styles[H][1] != RENDER_LINE_NONE
bb[H][0] = ofs[H] + page->cp[H][d[H]];
bb[H][1] = ofs[H] + page->cp[H][d[H] + 1];
- if (render_direction_rtl ())
+ if (page->params->rtl)
{
int temp = bb[H][0];
- bb[H][0] = page->params->size[H] - bb[H][1];
- bb[H][1] = page->params->size[H] - temp;
+ bb[H][0] = render_page_get_size (page, H) - bb[H][1];
+ bb[H][1] = render_page_get_size (page, H) - temp;
}
bb[V][0] = ofs[V] + page->cp[V][d[V]];
bb[V][1] = ofs[V] + page->cp[V][d[V] + 1];
- page->params->draw_line (page->params->aux, bb, styles);
+ page->params->draw_line (page->params->aux, bb, styles, colors);
}
}
bb[H][0] = clip[H][0] = ofs[H] + page->cp[H][cell->d[H][0] * 2 + 1];
bb[H][1] = clip[H][1] = ofs[H] + page->cp[H][cell->d[H][1] * 2];
- if (render_direction_rtl ())
+ if (page->params->rtl)
{
int temp = bb[H][0];
- bb[H][0] = clip[H][0] = page->params->size[H] - bb[H][1];
- bb[H][1] = clip[H][1] = page->params->size[H] - temp;
+ bb[H][0] = clip[H][0] = render_page_get_size (page, H) - bb[H][1];
+ bb[H][1] = clip[H][1] = render_page_get_size (page, H) - temp;
}
bb[V][0] = clip[V][0] = ofs[V] + page->cp[V][cell->d[V][0] * 2 + 1];
bb[V][1] = clip[V][1] = ofs[V] + page->cp[V][cell->d[V][1] * 2];
+ enum table_valign valign = cell->style->cell_style.valign;
+ if (valign != TABLE_VALIGN_TOP)
+ {
+ int height = page->params->measure_cell_height (
+ page->params->aux, cell, bb[H][1] - bb[H][0]);
+ int extra = bb[V][1] - bb[V][0] - height;
+ if (extra > 0)
+ {
+ if (valign == TABLE_VALIGN_CENTER)
+ extra /= 2;
+ bb[V][0] += extra;
+ }
+ }
+
of = find_overflow (page, cell->d[H][0], cell->d[V][0]);
if (of)
{
}
}
- page->params->draw_cell (page->params->aux, cell,
- find_footnote_idx (cell, &page->footnotes), bb, clip);
+ int spill[TABLE_N_AXES][2];
+ for (enum table_axis axis = 0; axis < TABLE_N_AXES; axis++)
+ {
+ spill[axis][0] = rule_width (page, axis, cell->d[axis][0]) / 2;
+ spill[axis][1] = rule_width (page, axis, cell->d[axis][1]) / 2;
+ }
+
+ int color_idx = (cell->d[V][0] < page->h[V][0]
+ || page->n[V] - (cell->d[V][0] + 1) < page->h[V][1]
+ ? 0
+ : (cell->d[V][0] - page->h[V][0]) & 1);
+ page->params->draw_cell (page->params->aux, cell, color_idx,
+ bb, spill, clip);
}
/* Draws the cells of PAGE indicated in BB. */
render_page_draw_cells (const struct render_page *page,
int ofs[TABLE_N_AXES], int bb[TABLE_N_AXES][2])
{
- int x, y;
-
- for (y = bb[V][0]; y < bb[V][1]; y++)
- for (x = bb[H][0]; x < bb[H][1]; )
- if (is_rule (x) || is_rule (y))
- {
- int d[TABLE_N_AXES];
- d[H] = x;
- d[V] = y;
- render_rule (page, ofs, d);
- x++;
- }
- else
+ 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;
x = rule_ofs (cell.d[H][1]);
table_cell_free (&cell);
}
+ else
+ x++;
+
+ for (int y = bb[V][0]; y < bb[V][1]; y++)
+ for (int x = bb[H][0]; x < bb[H][1]; x++)
+ if (is_rule (x) || is_rule (y))
+ {
+ int d[TABLE_N_AXES];
+ d[H] = x;
+ d[V] = y;
+ render_rule (page, ofs, d);
+ }
}
/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
int z0, int p0,
int z1, int p1);
-/* Initializes render_break B for breaking PAGE along AXIS. */
+/* Initializes render_break B for breaking PAGE along AXIS.
+ Takes ownership of PAGE. */
static void
-render_break_init (struct render_break *b, const struct render_page *page,
+render_break_init (struct render_break *b, struct render_page *page,
enum table_axis axis)
{
- b->page = render_page_ref (page);
+ b->page = page;
b->axis = axis;
b->z = page->h[axis][0];
b->pixel = 0;
table_get_cell (page->table, x, z, &cell);
w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
better_pixel = page->params->adjust_break (
- page->params->aux, &cell,
- find_footnote_idx (&cell, &page->footnotes), w, pixel);
+ page->params->aux, &cell, w, pixel);
x = cell.d[H][1];
table_cell_free (&cell);
};
static const struct render_page *
-render_pager_add_table (struct render_pager *p, struct table *table)
+render_pager_add_table (struct render_pager *p, struct table *table,
+ int min_width)
{
struct render_page *page;
if (p->n_pages >= p->allocated_pages)
p->pages = x2nrealloc (p->pages, &p->allocated_pages, sizeof *p->pages);
- page = p->pages[p->n_pages++] = render_page_create (p->params, table);
+ page = p->pages[p->n_pages++] = render_page_create (p->params, table,
+ min_width);
return page;
}
static void
render_pager_start_page (struct render_pager *p)
{
- render_break_init (&p->x_break, p->pages[p->cur_page++], H);
+ render_break_init (&p->x_break, render_page_ref (p->pages[p->cur_page++]),
+ H);
render_break_init_empty (&p->y_break);
}
static void
-add_footnote_page (struct render_pager *p, const struct render_page *body)
+add_footnote_page (struct render_pager *p, const struct table_item *item)
{
- const struct table *table = body->table;
- int nc = table_nc (table);
- int nr = table_nr (table);
- int footnote_idx = 0;
- struct tab_table *t;
- int x, y;
-
- if (!body->n_footnotes)
+ const struct footnote **f;
+ size_t n_footnotes = table_collect_footnotes (item, &f);
+ if (!n_footnotes)
return;
- t = tab_create (2, body->n_footnotes);
- for (y = 0; y < nr; y++)
- for (x = 0; x < nc; )
- {
- struct table_cell cell;
+ struct tab_table *t = tab_create (2, n_footnotes);
- table_get_cell (table, x, y, &cell);
- if (y == cell.d[V][0])
+ for (size_t i = 0; i < n_footnotes; i++)
+ if (f[i])
+ {
+ tab_text_format (t, 0, i, TAB_LEFT, "%s.", f[i]->marker);
+ tab_text (t, 1, i, TAB_LEFT, f[i]->content);
+ if (f[i]->style)
{
- size_t i;
-
- for (i = 0; i < cell.n_contents; i++)
- {
- const struct cell_contents *cc = &cell.contents[i];
- size_t j;
-
- for (j = 0; j < cc->n_footnotes; j++)
- {
- const char *f = cc->footnotes[j];
-
- tab_text (t, 0, footnote_idx, TAB_LEFT, "");
- tab_footnote (t, 0, footnote_idx, "(none)");
- tab_text (t, 1, footnote_idx, TAB_LEFT, f);
- footnote_idx++;
- }
- }
+ tab_add_style (t, 0, i, f[i]->style);
+ tab_add_style (t, 1, i, f[i]->style);
}
- x = cell.d[H][1];
- table_cell_free (&cell);
}
- render_pager_add_table (p, &t->table);
+ render_pager_add_table (p, &t->table, 0);
+
+ free (f);
+}
+
+static void
+add_text_page (struct render_pager *p, const struct table_item_text *t,
+ int min_width)
+{
+ if (!t)
+ return;
+
+ struct tab_table *tab = tab_create (1, 1);
+ tab_text (tab, 0, 0, 0, t->content);
+ for (size_t i = 0; i < t->n_footnotes; i++)
+ tab_add_footnote (tab, 0, 0, t->footnotes[i]);
+ if (t->style)
+ tab->styles[0] = area_style_clone (tab->container, t->style);
+ render_pager_add_table (p, &tab->table, min_width);
}
/* Creates and returns a new render_pager for rendering TABLE_ITEM on the
render_pager_create (const struct render_params *params,
const struct table_item *table_item)
{
- const char *caption = table_item_get_caption (table_item);
- const char *title = table_item_get_title (table_item);
- const struct render_page *body_page;
+ const struct table *table = table_item_get_table (table_item);
struct render_pager *p;
p = xzalloc (sizeof *p);
p->params = params;
+ struct render_page *page = render_page_create (params, table_ref (table), 0);
+ struct render_break b;
+ render_break_init (&b, page, H);
+ struct render_page *subpage = render_break_next (&b, p->params->size[H]);
+ int title_width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
+ render_page_unref (subpage);
+ render_break_destroy (&b);
+
/* Title. */
- if (title)
- render_pager_add_table (p, table_from_string (TAB_LEFT, title));
+ add_text_page (p, table_item_get_title (table_item), title_width);
+
+ /* Layers. */
+ add_text_page (p, table_item_get_layers (table_item), title_width);
/* Body. */
- body_page = render_pager_add_table (p, table_ref (table_item_get_table (
- table_item)));
+ render_pager_add_table (p, table_ref (table_item_get_table (table_item)), 0);
/* Caption. */
- if (caption)
- render_pager_add_table (p, table_from_string (TAB_LEFT, caption));
+ add_text_page (p, table_item_get_caption (table_item), 0);
/* Footnotes. */
- add_footnote_page (p, body_page);
+ add_footnote_page (p, table_item);
render_pager_start_page (p);
render_page_select (const struct render_page *page, enum table_axis axis,
int z0, int p0, int z1, int p1)
{
- const struct render_footnote *f;
struct render_page_selection s;
enum table_axis a = axis;
enum table_axis b = !a;
table_cell_free (&cell);
}
- /* Copy footnotes from PAGE into subpage. */
- HMAP_FOR_EACH (f, struct render_footnote, node, &page->footnotes)
- if ((f->d[a][0] >= z0 && f->d[a][0] < z1)
- || (f->d[a][1] - 1 >= z0 && f->d[a][1] - 1 < z1))
- {
- struct render_footnote *nf = xmalloc (sizeof *nf);
- nf->d[a][0] = MAX (z0, f->d[a][0]) - z0 + page->h[a][0];
- nf->d[a][1] = MIN (z1, f->d[a][1]) - z0 + page->h[a][0];
- nf->d[b][0] = f->d[b][0];
- nf->d[b][1] = f->d[b][1];
- nf->idx = f->idx;
- hmap_insert (&subpage->footnotes, &nf->node,
- hash_cell (nf->d[H][0], nf->d[V][0]));
- }
-
return subpage;
}