/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2011, 2013 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
May represent the layout of an entire table presented to
render_page_create(), or a rectangular subregion of a table broken out using
- render_page_next() to allow a table to be broken across multiple pages. */
+ render_break_next() to allow a table to be broken across multiple pages. */
struct render_page
{
const struct render_params *params; /* Parameters of the target device. */
w1 by the common denominator of all three calculations (d), dividing that
out in the column width calculation, and then keeping the remainder for
the next iteration.
+
+ (We actually compute the unspanned width of a column as twice the
+ unspanned width, plus the width of the rule on the left, plus the width of
+ the rule on the right. That way each rule contributes to both the cell on
+ its left and on its right.)
*/
d0 = n;
- d1 = total_unspanned * 2.0;
+ d1 = 2.0 * (total_unspanned > 0 ? total_unspanned : 1.0);
d = d0 * d1;
if (total_unspanned > 0)
d *= 2.0;
w += width * unspanned * d0;
}
- rows[x].width = w / d;
+ rows[x].width = MAX (rows[x].width, w / d);
w -= rows[x].width * d;
}
}
enum table_axis b = !a;
unsigned int rules;
int d[TABLE_N_AXES];
- int width, i;
+ 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. */
/* Calculate maximum width of the rules that are present. */
width = 0;
- for (i = 0; i < N_LINES; i++)
- if (rules & (1u << i))
- width = MAX (width, params->line_widths[a][rule_to_render_type (i)]);
-
+ 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]);
return width;
}
{
if (page != NULL && --page->ref_cnt == 0)
{
+ int i;
struct render_overflow *overflow, *next;
HMAP_FOR_EACH_SAFE (overflow, next, struct render_overflow, node,
hmap_destroy (&page->overflows);
table_unref (page->table);
- free (page->cp[H]);
- free (page->cp[V]);
+
+ for (i = 0; i < TABLE_N_AXES; ++i)
+ {
+ free (page->join_crossing[i]);
+ free (page->cp[i]);
+ }
+
free (page);
}
}
\f
/* Drawing render_pages. */
-static enum render_line_style
+static inline enum render_line_style
get_rule (const struct render_page *page, enum table_axis axis,
const int d[TABLE_N_AXES])
{
page->params->draw_cell (page->params->aux, cell, bb, clip);
}
-/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
- render_params provided to render_page_create(). */
-void
-render_page_draw (const struct render_page *page)
+/* Draws the cells of PAGE indicated in BB. */
+static void
+render_page_draw_cells (const struct render_page *page,
+ int bb[TABLE_N_AXES][2])
{
int x, y;
- for (y = 0; y <= page->n[V] * 2; y++)
- for (x = 0; x <= page->n[H] * 2; )
+ 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];
struct table_cell cell;
table_get_cell (page->table, x / 2, y / 2, &cell);
- if (y / 2 == cell.d[V][0])
+ if (y == bb[V][0] || y / 2 == cell.d[V][0])
render_cell (page, &cell);
x = rule_ofs (cell.d[H][1]);
table_cell_free (&cell);
}
}
+
+/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
+ render_params provided to render_page_create(). */
+void
+render_page_draw (const struct render_page *page)
+{
+ int bb[TABLE_N_AXES][2];
+
+ bb[H][0] = 0;
+ bb[H][1] = page->n[H] * 2 + 1;
+ bb[V][0] = 0;
+ bb[V][1] = page->n[V] * 2 + 1;
+
+ render_page_draw_cells (page, bb);
+}
+
+/* Returns the greatest value i, 0 <= i < n, such that cp[i] <= x0. */
+static int
+get_clip_min_extent (int x0, const int cp[], int n)
+{
+ int low, high, best;
+
+ low = 0;
+ high = n;
+ best = 0;
+ while (low < high)
+ {
+ int middle = low + (high - low) / 2;
+
+ if (cp[middle] <= x0)
+ {
+ best = middle;
+ low = middle + 1;
+ }
+ else
+ high = middle;
+ }
+
+ return best;
+}
+
+/* Returns the least value i, 0 <= i < n, such that cp[i + 1] >= x1. */
+static int
+get_clip_max_extent (int x1, const int cp[], int n)
+{
+ int low, high, best;
+
+ low = 0;
+ high = n;
+ best = n;
+ while (low < high)
+ {
+ int middle = low + (high - low) / 2;
+
+ if (cp[middle] >= x1)
+ best = high = middle;
+ else
+ low = middle + 1;
+ }
+
+ return best;
+}
+
+/* Renders the cells of PAGE that intersect (X,Y)-(X+W,Y+H), by calling the
+ 'draw_line' and 'draw_cell' functions from the render_params provided to
+ render_page_create(). */
+void
+render_page_draw_region (const struct render_page *page,
+ int x, int y, int w, int h)
+{
+ int bb[TABLE_N_AXES][2];
+
+ bb[H][0] = get_clip_min_extent (x, page->cp[H], page->n[H] * 2 + 1);
+ bb[H][1] = get_clip_max_extent (x + w, page->cp[H], page->n[H] * 2 + 1);
+ bb[V][0] = get_clip_min_extent (y, page->cp[V], page->n[V] * 2 + 1);
+ bb[V][1] = get_clip_max_extent (y + h, page->cp[V], page->n[V] * 2 + 1);
+
+ render_page_draw_cells (page, bb);
+}
\f
/* Breaking up tables to fit on a page. */
render_break_destroy (struct render_break *b)
{
if (b != NULL)
- render_page_unref (b->page);
+ {
+ render_page_unref (b->page);
+ b->page = NULL;
+ }
}
/* Returns true if B still has cells that are yet to be returned,
if (z0 == page->h[a][0] && p0 == 0
&& z1 == page->n[a] - page->h[a][1] && p1 == 0)
{
- struct render_page *page_rw = (struct render_page *) page;
+ struct render_page *page_rw = CONST_CAST (struct render_page *, page);
page_rw->ref_cnt++;
return page_rw;
}
s.p1 = p1;
s.subpage = subpage;
- for (z = 0; z < page->n[b]; z++)
- {
- struct table_cell cell;
- int d[TABLE_N_AXES];
+ if (!page->h[a][0] || z0 > page->h[a][0] || p0)
+ for (z = 0; z < page->n[b]; z++)
+ {
+ struct table_cell cell;
+ int d[TABLE_N_AXES];
- d[a] = z0;
- d[b] = z;
- table_get_cell (page->table, d[H], d[V], &cell);
- if ((z == cell.d[b][0] && (p0 || cell.d[a][0] < z0))
- || (z == cell.d[b][1] - 1 && p1))
- {
- ro = insert_overflow (&s, &cell);
- ro->overflow[a][0] += p0 + axis_width (page, a,
- cell_ofs (cell.d[a][0]),
- cell_ofs (z0));
- if (z1 == z0 + 1)
- ro->overflow[a][1] += p1;
- if (page->h[a][0] && page->h[a][1])
- ro->overflow[a][0] -= page->join_crossing[a][cell.d[a][0] + 1];
- if (cell.d[a][1] > z1)
+ d[a] = z0;
+ d[b] = z;
+ table_get_cell (page->table, d[H], d[V], &cell);
+ if ((z == cell.d[b][0] && (p0 || cell.d[a][0] < z0))
+ || (z == cell.d[b][1] - 1 && p1))
+ {
+ ro = insert_overflow (&s, &cell);
+ ro->overflow[a][0] += p0 + axis_width (page, a,
+ cell_ofs (cell.d[a][0]),
+ cell_ofs (z0));
+ if (z1 == z0 + 1)
+ ro->overflow[a][1] += p1;
+ if (page->h[a][0] && page->h[a][1])
+ ro->overflow[a][0] -= page->join_crossing[a][cell.d[a][0] + 1];
+ if (cell.d[a][1] > z1)
+ ro->overflow[a][1] += axis_width (page, a, cell_ofs (z1),
+ cell_ofs (cell.d[a][1]));
+ }
+ table_cell_free (&cell);
+ }
+
+ if (!page->h[a][1] || z1 < page->n[a] - page->h[a][1] || p1)
+ for (z = 0; z < page->n[b]; z++)
+ {
+ struct table_cell cell;
+ int d[TABLE_N_AXES];
+
+ /* XXX need to handle p1 below */
+ d[a] = z1 - 1;
+ d[b] = z;
+ table_get_cell (page->table, d[H], d[V], &cell);
+ if (z == cell.d[b][0] && cell.d[a][1] > z1
+ && find_overflow_for_cell (&s, &cell) == NULL)
+ {
+ ro = insert_overflow (&s, &cell);
ro->overflow[a][1] += axis_width (page, a, cell_ofs (z1),
cell_ofs (cell.d[a][1]));
- }
- table_cell_free (&cell);
- }
-
- for (z = 0; z < page->n[b]; z++)
- {
- struct table_cell cell;
- int d[TABLE_N_AXES];
-
- /* XXX need to handle p1 below */
- d[a] = z1 - 1;
- d[b] = z;
- table_get_cell (page->table, d[H], d[V], &cell);
- if (z == cell.d[b][0] && cell.d[a][1] > z1
- && find_overflow_for_cell (&s, &cell) == NULL)
- {
- ro = insert_overflow (&s, &cell);
- ro->overflow[a][1] += axis_width (page, a, cell_ofs (z1),
- cell_ofs (cell.d[a][1]));
- }
- table_cell_free (&cell);
- }
+ }
+ table_cell_free (&cell);
+ }
/* Copy overflows from PAGE into subpage. */
HMAP_FOR_EACH (ro, struct render_overflow, node, &page->overflows)
return of;
}
-