XR_FONT_PROPORTIONAL,
XR_FONT_EMPHASIS,
XR_FONT_FIXED,
+ XR_FONT_MARKER,
XR_N_FONTS
};
int line_space; /* Space between lines. */
int line_width; /* Width of lines. */
+ int cell_margin;
+
int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */
struct xr_color bg; /* Background color */
static void xr_draw_line (void *, int bb[TABLE_N_AXES][2],
enum render_line_style styles[TABLE_N_AXES][2]);
static void xr_measure_cell_width (void *, const struct table_cell *,
- int *min, int *max);
+ int footnote_idx, int *min, int *max);
static int xr_measure_cell_height (void *, const struct table_cell *,
- int width);
-static void xr_draw_cell (void *, const struct table_cell *,
+ int footnote_idx, int width);
+static void xr_draw_cell (void *, const struct table_cell *, int footnote_idx,
int bb[TABLE_N_AXES][2],
int clip[TABLE_N_AXES][2]);
-static int xr_adjust_break (void *, const struct table_cell *,
+static int xr_adjust_break (void *, const struct table_cell *, int footnote_idx,
int width, int height);
static struct xr_render_fsm *xr_render_output_item (
"serif", font_size);
xr->fonts[XR_FONT_EMPHASIS].desc = parse_font (d, o, "emph-font",
"serif italic", font_size);
+ xr->fonts[XR_FONT_MARKER].desc = parse_font (d, o, "marker-font", "serif",
+ font_size * PANGO_SCALE_X_SMALL);
- xr->line_gutter = parse_dimension (opt (d, o, "gutter", "3pt")) * scale;
+ xr->line_gutter = 0;
xr->line_space = XR_POINT;
xr->line_width = XR_POINT / 2;
xr->page_number = 0;
xr->char_width = MAX (xr->char_width, pango_to_xr (char_width));
xr->char_height = MAX (xr->char_height, pango_to_xr (char_height));
}
+ xr->cell_margin = xr->char_width;
if (xr->params == NULL)
{
cairo_surface_flush (cairo_get_target (xr->cairo));
}
-static void
-xr_init_caption_cell (const char *caption, struct table_cell *cell,
- struct cell_contents *contents)
-{
- contents->options = TAB_LEFT;
- contents->text = CONST_CAST (char *, caption);
- contents->table = NULL;
- cell->contents = contents;
- cell->n_contents = 1;
- cell->destructor = NULL;
-}
-
-static struct render_page *
-xr_render_table_item (struct xr_driver *xr, const struct table_item *item,
- int *caption_widthp, int *caption_heightp)
-{
- const char *caption = table_item_get_caption (item);
-
- if (caption != NULL)
- {
- /* XXX doesn't do well with very large captions */
- struct cell_contents contents;
- int min_width, max_width;
- struct table_cell cell;
-
- xr_init_caption_cell (caption, &cell, &contents);
-
- xr_measure_cell_width (xr, &cell, &min_width, &max_width);
- *caption_widthp = MIN (max_width, xr->width);
- *caption_heightp = xr_measure_cell_height (xr, &cell, *caption_widthp);
- }
- else
- *caption_heightp = 0;
-
- return render_page_create (xr->params, table_item_get_table (item));
-}
-
static void
xr_submit (struct output_driver *driver, const struct output_item *output_item)
{
}
\f
static void
-xr_layout_cell (struct xr_driver *, const struct table_cell *,
+xr_layout_cell (struct xr_driver *, const struct table_cell *, int footnote_idx,
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int *width, int *height, int *brk);
static void
xr_measure_cell_width (void *xr_, const struct table_cell *cell,
- int *min_width, int *max_width)
+ int footnote_idx, int *min_width, int *max_width)
{
struct xr_driver *xr = xr_;
int bb[TABLE_N_AXES][2];
bb[V][0] = 0;
bb[V][1] = INT_MAX;
clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
- xr_layout_cell (xr, cell, bb, clip, max_width, &h, NULL);
+ xr_layout_cell (xr, cell, footnote_idx, bb, clip, max_width, &h, NULL);
bb[H][1] = 1;
- xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL);
+ xr_layout_cell (xr, cell, footnote_idx, bb, clip, min_width, &h, NULL);
+
+ if (*min_width > 0)
+ *min_width += xr->cell_margin * 2;
+ if (*max_width > 0)
+ *max_width += xr->cell_margin * 2;
}
static int
-xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width)
+xr_measure_cell_height (void *xr_, const struct table_cell *cell,
+ int footnote_idx, int width)
{
struct xr_driver *xr = xr_;
int bb[TABLE_N_AXES][2];
int w, h;
bb[H][0] = 0;
- bb[H][1] = width;
+ bb[H][1] = width - xr->cell_margin * 2;
+ if (bb[H][1] <= 0)
+ return 0;
bb[V][0] = 0;
bb[V][1] = INT_MAX;
clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
- xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL);
+ xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, NULL);
return h;
}
static void
-xr_draw_cell (void *xr_, const struct table_cell *cell,
+xr_draw_cell (void *xr_, const struct table_cell *cell, int footnote_idx,
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2])
{
struct xr_driver *xr = xr_;
int w, h, brk;
- xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
+ bb[H][0] += xr->cell_margin;
+ bb[H][1] -= xr->cell_margin;
+ if (bb[H][0] >= bb[H][1])
+ return;
+ xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk);
}
static int
-xr_adjust_break (void *xr_, const struct table_cell *cell,
+xr_adjust_break (void *xr_, const struct table_cell *cell, int footnote_idx,
int width, int height)
{
struct xr_driver *xr = xr_;
int clip[TABLE_N_AXES][2];
int w, h, brk;
- if (xr_measure_cell_height (xr_, cell, width) < height)
+ if (xr_measure_cell_height (xr_, cell, footnote_idx, width) < height)
return -1;
bb[H][0] = 0;
- bb[H][1] = width;
+ bb[H][1] = width - 2 * xr->cell_margin;
+ if (bb[H][1] <= 0)
+ return 0;
bb[V][0] = 0;
bb[V][1] = height;
clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
- xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
+ xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk);
return brk;
}
\f
}
}
+static void
+add_attr_with_start (PangoAttrList *list, PangoAttribute *attr, guint start_index)
+{
+ attr->start_index = start_index;
+ pango_attr_list_insert (list, attr);
+}
+
static int
xr_layout_cell_text (struct xr_driver *xr,
- const struct cell_contents *contents,
+ const struct cell_contents *contents, int footnote_idx,
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int y, int *widthp, int *brk)
{
unsigned int options = contents->options;
struct xr_font *font;
+ bool merge_footnotes;
+ size_t length;
int w, h;
+ if (contents->n_footnotes == 0)
+ merge_footnotes = false;
+ else if (contents->n_footnotes == 1 && (options & TAB_ALIGNMENT) == TAB_RIGHT)
+ {
+ PangoAttrList *attrs;
+ char marker[16];
+
+ font = &xr->fonts[XR_FONT_MARKER];
+
+ str_format_26adic (footnote_idx + 1, false, marker, sizeof marker);
+ pango_layout_set_text (font->layout, marker, strlen (marker));
+
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_rise_new (7000));
+ pango_layout_set_attributes (font->layout, attrs);
+ pango_attr_list_unref (attrs);
+
+ pango_layout_get_size (font->layout, &w, &h);
+ merge_footnotes = w > xr->cell_margin;
+ if (!merge_footnotes && clip[H][0] != clip[H][1])
+ {
+ cairo_save (xr->cairo);
+ xr_clip (xr, clip);
+ cairo_translate (xr->cairo,
+ xr_to_pt (bb[H][1] + xr->x),
+ xr_to_pt (y + xr->y));
+ pango_layout_set_alignment (font->layout, PANGO_ALIGN_LEFT);
+ pango_layout_set_width (font->layout, -1);
+ pango_cairo_show_layout (xr->cairo, font->layout);
+ cairo_restore (xr->cairo);
+ }
+
+ pango_layout_set_attributes (font->layout, NULL);
+ }
+ else
+ merge_footnotes = true;
+
font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED]
: options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS]
: &xr->fonts[XR_FONT_PROPORTIONAL]);
- pango_layout_set_text (font->layout, contents->text, -1);
+ length = strlen (contents->text);
+ if (merge_footnotes)
+ {
+ PangoAttrList *attrs;
+ struct string s;
+ size_t i;
+
+ bb[H][1] += xr->cell_margin;
+
+ ds_init_empty (&s);
+ ds_extend (&s, length + contents->n_footnotes * 10);
+ ds_put_cstr (&s, contents->text);
+ for (i = 0; i < contents->n_footnotes; i++)
+ {
+ char marker[16];
+
+ if (i > 0)
+ ds_put_byte (&s, ',');
+ str_format_26adic (footnote_idx + i + 1, false, marker, sizeof marker);
+ ds_put_cstr (&s, marker);
+ }
+ pango_layout_set_text (font->layout, ds_cstr (&s), ds_length (&s));
+ ds_destroy (&s);
+
+ attrs = pango_attr_list_new ();
+ add_attr_with_start (attrs, pango_attr_rise_new (7000), length);
+ add_attr_with_start (
+ attrs, pango_attr_font_desc_new (xr->fonts[XR_FONT_MARKER].desc), length);
+ pango_layout_set_attributes (font->layout, attrs);
+ pango_attr_list_unref (attrs);
+ }
+ else
+ pango_layout_set_text (font->layout, contents->text, -1);
pango_layout_set_alignment (
font->layout,
}
}
}
+
+ pango_layout_set_attributes (font->layout, NULL);
return y + h;
}
static int
xr_layout_cell_subtable (struct xr_driver *xr,
const struct cell_contents *contents,
+ int footnote_idx UNUSED,
int bb[TABLE_N_AXES][2],
int clip[TABLE_N_AXES][2], int *widthp, int *brk)
{
- const struct table *table = contents->table;
int single_width, double_width;
struct render_params params;
- struct render_page *page;
+ struct render_pager *p;
int r[TABLE_N_AXES][2];
int width, height;
int i;
}
xr->nest++;
- page = render_page_create (¶ms, table);
- width = render_page_get_size (page, H);
- height = render_page_get_size (page, V);
+ p = render_pager_create (¶ms, contents->table);
+ width = render_pager_get_size (p, H);
+ height = render_pager_get_size (p, V);
if (bb[V][0] + height >= bb[V][1])
- *brk = bb[V][0] + render_page_get_best_breakpoint (page, bb[V][1] - bb[V][0]);
+ *brk = bb[V][0] + render_pager_get_best_breakpoint (p, bb[V][1] - bb[V][0]);
/* r = intersect(bb, clip) - bb. */
for (i = 0; i < TABLE_N_AXES; i++)
else if (alignment == TAB_CENTER)
xr->x += (params.size[H] - width) / 2;
xr->y += bb[V][0];
- render_page_draw_region (page, r[H][0], r[V][0],
- r[H][1] - r[H][0], r[V][1] - r[V][0]);
+ render_pager_draw_region (p, r[H][0], r[V][0],
+ r[H][1] - r[H][0], r[V][1] - r[V][0]);
xr->y -= bb[V][0];
xr->x = save_x;
cairo_restore (xr->cairo);
}
- render_page_unref (page);
+ render_pager_destroy (p);
xr->nest--;
if (width > *widthp)
static void
xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell,
+ int footnote_idx,
int bb_[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int *width, int *height, int *brk)
{
}
if (contents->text)
- bb[V][0] = xr_layout_cell_text (xr, contents, bb, clip,
+ bb[V][0] = xr_layout_cell_text (xr, contents, footnote_idx, bb, clip,
bb[V][0], width, brk);
else
- bb[V][0] = xr_layout_cell_subtable (xr, contents, bb, clip, width, brk);
+ bb[V][0] = xr_layout_cell_subtable (xr, contents, footnote_idx,
+ bb, clip, width, brk);
+ footnote_idx += contents->n_footnotes;
}
*height = bb[V][0] - bb_[V][0];
}
-
-static void
-xr_draw_title (struct xr_driver *xr, const char *title,
- int title_width, int title_height)
-{
- struct cell_contents contents;
- struct table_cell cell;
- int bb[TABLE_N_AXES][2];
-
- xr_init_caption_cell (title, &cell, &contents);
- bb[H][0] = 0;
- bb[H][1] = title_width;
- bb[V][0] = 0;
- bb[V][1] = title_height;
- xr_draw_cell (xr, &cell, bb, bb);
-}
\f
struct output_driver_factory pdf_driver_factory =
{ "pdf", "pspp.pdf", xr_pdf_create };
struct output_item *item;
/* Table items. */
- struct render_page *page;
+ struct render_pager *p;
struct xr_driver *xr;
- int title_width;
- int title_height;
};
#define CHART_WIDTH 500
r->item = output_item_ref (item);
r->xr = xr;
xr_set_cairo (xr, cr);
- r->page = xr_render_table_item (xr, to_table_item (item),
- &r->title_width, &r->title_height);
+ r->p = render_pager_create (xr->params, to_table_item (item));
}
else if (is_chart_item (item))
{
if (r)
{
output_item_unref (r->item);
- render_page_unref (r->page);
+ render_pager_destroy (r->p);
free (r);
}
}
{
if (is_table_item (r->item))
{
- int w0 = render_page_get_size (r->page, H);
- int w1 = r->title_width;
- *w = MAX (w0, w1) / XR_POINT;
- *h = (render_page_get_size (r->page, V) + r->title_height) / XR_POINT;
+ *w = render_pager_get_size (r->p, H) / XR_POINT;
+ *h = render_pager_get_size (r->p, V) / XR_POINT;
}
else
{
xr_set_cairo (xr, cr);
- if (r->title_height > 0)
- {
- xr->y = 0;
- xr_draw_title (xr, table_item_get_caption (to_table_item (r->item)),
- r->title_width, r->title_height);
- }
-
- xr->y = r->title_height;
- render_page_draw_region (r->page,
- x * XR_POINT, (y * XR_POINT) - r->title_height,
- w * XR_POINT, h * XR_POINT);
+ xr->y = 0;
+ render_pager_draw_region (r->p,
+ x * XR_POINT, y * XR_POINT,
+ w * XR_POINT, h * XR_POINT);
}
else
xr_draw_chart (to_chart_item (r->item), cr,
struct xr_render_fsm fsm;
struct table_item *table_item;
struct render_pager *p;
- int caption_height;
};
static bool
while (render_pager_has_next (ts->p))
{
- int space = xr->length - xr->y - ts->caption_height;
- struct render_page *slice = render_pager_next (ts->p, space);
+ int used;
- if (!slice)
+ used = render_pager_draw_next (ts->p, xr->length - xr->y);
+ if (!used)
{
assert (xr->y > 0);
return true;
}
-
- if (ts->caption_height)
- {
- if (xr->cairo)
- xr_draw_title (xr, table_item_get_caption (ts->table_item),
- xr->width, ts->caption_height);
-
- xr->y += ts->caption_height;
- ts->caption_height = 0;
- }
-
- if (xr->cairo)
- render_page_draw (slice);
- xr->y += render_page_get_size (slice, V);
- render_page_unref (slice);
+ else
+ xr->y += used;
}
return false;
}
xr_render_table (struct xr_driver *xr, const struct table_item *table_item)
{
struct xr_table_state *ts;
- struct render_page *page;
- int caption_width;
ts = xmalloc (sizeof *ts);
ts->fsm.render = xr_table_render;
if (xr->y > 0)
xr->y += xr->char_height;
- page = xr_render_table_item (xr, table_item,
- &caption_width, &ts->caption_height);
- xr->params->size[V] = xr->length - ts->caption_height;
-
- ts->p = render_pager_create (page);
+ ts->p = render_pager_create (xr->params, table_item);
return &ts->fsm;
}