/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
#define H TABLE_HORZ
#define V TABLE_VERT
-
+\f
struct xr_fsm_style *
xr_fsm_style_ref (const struct xr_fsm_style *style_)
{
return style;
}
+struct xr_fsm_style *
+xr_fsm_style_unshare (struct xr_fsm_style *old)
+{
+ assert (old->ref_cnt > 0);
+ if (old->ref_cnt == 1)
+ return old;
+
+ xr_fsm_style_unref (old);
+
+ struct xr_fsm_style *new = xmemdup (old, sizeof *old);
+ new->ref_cnt = 1;
+ for (int i = 0; i < XR_N_FONTS; i++)
+ if (old->fonts[i])
+ new->fonts[i] = pango_font_description_copy (old->fonts[i]);
+
+ return new;
+}
+
void
xr_fsm_style_unref (struct xr_fsm_style *style)
{
if (font_style->typeface)
desc = parse_font (
font_style->typeface,
- font_style->size ? font_style->size * 1000 * xr->style->font_scale : 10000,
+ (font_style->size ? font_style->size * 1000 : 10000) * xr->style->font_scale,
font_style->bold, font_style->italic);
if (!desc)
desc = xr->style->fonts[font_type];
.ops = &xrr_render_ops,
.aux = fsm,
.size = { [H] = style->size[H], [V] = style->size[V] },
- /* XXX font_size */
.line_widths = xr_line_widths,
.min_break = { [H] = style->min_break[H], [V] = style->min_break[V] },
.supports_margins = true,
{
int ref_cnt;
- int size[TABLE_N_AXES]; /* Page size. */
+ int size[TABLE_N_AXES]; /* Page size. */
int min_break[TABLE_N_AXES]; /* Minimum cell size to allow breaking. */
PangoFontDescription *fonts[XR_N_FONTS];
struct cell_color fg;
double font_scale;
};
struct xr_fsm_style *xr_fsm_style_ref (const struct xr_fsm_style *);
+struct xr_fsm_style *xr_fsm_style_unshare (struct xr_fsm_style *);
void xr_fsm_style_unref (struct xr_fsm_style *);
bool xr_fsm_style_equals (const struct xr_fsm_style *,
const struct xr_fsm_style *);
new->ref_cnt = 1;
for (int i = 0; i < 2; i++)
page_heading_copy (&new->headings[i], &old->headings[i]);
- if (old->font)
- new->font = pango_font_description_copy (old->font);
return new;
}
{
for (int i = 0; i < 2; i++)
page_heading_uninit (&ps->headings[i]);
- if (ps->font)
- pango_font_description_free (ps->font);
free (ps);
}
}
}
-static bool
-pfd_equals (const PangoFontDescription *a,
- const PangoFontDescription *b)
-{
- return a && b ? pango_font_description_equal (a, b) : !a && !b;
-}
-
bool
xr_page_style_equals (const struct xr_page_style *a,
const struct xr_page_style *b)
{
for (int i = 0; i < TABLE_N_AXES; i++)
- {
- if (a->size[i] != b->size[i])
+ for (int j = 0; j < 2; j++)
+ if (a->margins[i][j] != b->margins[i][j])
return false;
- for (int j = 0; j < 2; j++)
- if (a->margins[i][j] != b->margins[i][j])
- return false;
- }
-
for (int i = 0; i < 2; i++)
if (!page_heading_equals (&a->headings[i], &b->headings[i]))
return false;
- return (pfd_equals (a->font, b->font)
- && a->font_scale == b->font_scale
- && a->initial_page_number == b->initial_page_number
+ return (a->initial_page_number == b->initial_page_number
&& a->object_spacing == b->object_spacing);
}
\f
struct xr_pager
{
struct xr_page_style *page_style;
+ struct xr_fsm_style *fsm_style;
int page_index;
int heading_heights[2];
/* Current output item. */
struct xr_fsm *fsm;
- struct xr_fsm_style *fsm_style;
struct output_item *item;
/* Current output page. */
}
static void
-xr_measure_headings (const struct xr_page_style *ps, int heading_heights[2])
+xr_measure_headings (const struct xr_page_style *ps,
+ const struct xr_fsm_style *fs,
+ int heading_heights[2])
{
cairo_surface_t *surface = cairo_recording_surface_create (
CAIRO_CONTENT_COLOR, NULL);
for (int i = 0; i < 2; i++)
{
int *h = &heading_heights[i];
- *h = xr_render_page_heading (cairo, ps->font, &ps->headings[i], -1,
- ps->size[H], false, 0);
+ *h = xr_render_page_heading (cairo, fs->fonts[XR_FONT_PROPORTIONAL],
+ &ps->headings[i], -1, fs->size[H], false,
+ 0);
if (*h)
*h += ps->object_spacing;
}
}
struct xr_pager *
-xr_pager_create (const struct xr_page_style *ps_)
+xr_pager_create (const struct xr_page_style *ps_,
+ const struct xr_fsm_style *fs_)
{
+ printf ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
struct xr_page_style *ps = xr_page_style_ref (ps_);
+ struct xr_fsm_style *fs = xr_fsm_style_ref (fs_);
int heading_heights[2];
- xr_measure_headings (ps, heading_heights);
+ xr_measure_headings (ps, fs, heading_heights);
int total = heading_heights[0] + heading_heights[1];
- if (total > 0 && total < ps->size[V])
+ if (total > 0 && total < fs->size[V])
{
+ fs = xr_fsm_style_unshare (fs);
ps = xr_page_style_unshare (ps);
for (int i = 0; i < 2; i++)
ps->margins[V][i] += heading_heights[i];
- ps->size[V] -= total;
+ fs->size[V] -= total;
}
struct xr_pager *p = xmalloc (sizeof *p);
- *p = (struct xr_pager) { .page_style = ps };
+ *p = (struct xr_pager) { .page_style = ps, .fsm_style = fs };
return p;
}
{
if (p)
{
- xr_fsm_destroy (p->fsm);
+ printf (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ xr_page_style_unref (p->page_style);
xr_fsm_style_unref (p->fsm_style);
+
+ xr_fsm_destroy (p->fsm);
output_item_unref (p->item);
- xr_page_style_unref (p->page_style);
if (p->cr)
- cairo_destroy (p->cr);
+ {
+ cairo_restore (p->cr);
+ cairo_destroy (p->cr);
+ }
free (p);
}
}
}
void
-xr_pager_add_item (struct xr_pager *p, const struct xr_fsm_style *fsm_style,
- const struct output_item *item)
+xr_pager_add_item (struct xr_pager *p, const struct output_item *item)
{
+ printf ("add_item\n");
assert (!p->item);
p->item = output_item_ref (item);
- p->fsm_style = xr_fsm_style_ref (fsm_style);
xr_pager_run (p);
}
void
xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
{
+ printf ("add_page\n");
assert (!p->cr);
+ cairo_save (cr);
p->cr = cr;
p->y = 0;
+ const struct xr_fsm_style *fs = p->fsm_style;
const struct xr_page_style *ps = p->page_style;
const struct cell_color *bg = &ps->bg;
if (bg->alpha)
cairo_save (cr);
cairo_set_source_rgba (cr, bg->r / 255.0, bg->g / 255.0,
bg->b / 255.0, bg->alpha / 255.0);
- cairo_rectangle (cr, 0, 0, ps->size[H], ps->size[V]);
+ cairo_rectangle (cr, 0, 0, fs->size[H], fs->size[V]);
cairo_fill (cr);
cairo_restore (cr);
}
xr_to_pt (ps->margins[H][0]),
xr_to_pt (ps->margins[V][0]));
+ const PangoFontDescription *font = fs->fonts[XR_FONT_PROPORTIONAL];
int page_number = p->page_index++ + ps->initial_page_number;
if (p->heading_heights[0])
- xr_render_page_heading (cr, ps->font, &ps->headings[0], page_number,
- ps->size[H], true, -p->heading_heights[0]);
+ xr_render_page_heading (cr, font, &ps->headings[0], page_number,
+ fs->size[H], true, -p->heading_heights[0]);
if (p->heading_heights[1])
- xr_render_page_heading (cr, ps->font, &ps->headings[1], page_number,
- ps->size[H], true,
- ps->size[V] + ps->object_spacing);
+ xr_render_page_heading (cr, font, &ps->headings[1], page_number,
+ fs->size[H], true,
+ fs->size[V] + ps->object_spacing);
xr_pager_run (p);
}
bool
xr_pager_needs_new_page (struct xr_pager *p)
{
- if (p->item && p->y >= p->page_style->size[V])
+ if (p->item && (!p->cr || p->y >= p->fsm_style->size[V]))
{
- cairo_destroy (p->cr);
- p->cr = NULL;
+ if (p->cr)
+ {
+ cairo_restore (p->cr);
+ cairo_destroy (p->cr);
+ p->cr = NULL;
+ }
return true;
}
else
static void
xr_pager_run (struct xr_pager *p)
{
- if (p->item && p->cr && p->y < p->page_style->size[V])
+ printf ("run:\n");
+ if (p->item && p->cr && p->y < p->fsm_style->size[V])
{
if (!p->fsm)
{
- /* XXX fsm_style needs to account for heading_heights */
+ printf ("\tcreate fsm\n");
p->fsm = xr_fsm_create (p->item, p->fsm_style, p->cr);
if (!p->fsm)
{
- xr_fsm_style_unref (p->fsm_style);
- p->fsm_style = NULL;
+ printf ("\t(was null)\n");
output_item_unref (p->item);
p->item = NULL;
for (;;)
{
+ printf ("\tdraw slice\n");
int spacing = p->page_style->object_spacing;
int chunk = xr_fsm_draw_slice (p->fsm, p->cr,
- p->page_style->size[V] - p->y);
+ p->fsm_style->size[V] - p->y);
p->y += chunk + spacing;
cairo_translate (p->cr, 0, xr_to_pt (chunk + spacing));
if (xr_fsm_is_empty (p->fsm))
{
+ printf ("\tfinished object\n");
xr_fsm_destroy (p->fsm);
p->fsm = NULL;
- xr_fsm_style_unref (p->fsm_style);
- p->fsm_style = NULL;
output_item_unref (p->item);
p->item = NULL;
return;
}
else if (!chunk)
{
+ printf ("\tobject doesn't fit on page\n");
assert (p->y > 0);
p->y = INT_MAX;
return;
}
+ printf ("\tneed to draw another slice\n");
}
}
+ if (!p->item)
+ printf ("\tno item\n");
+ if (!p->cr)
+ printf ("\tno page\n");
}
{
int ref_cnt;
- int size[TABLE_N_AXES]; /* Page size minus margins. */
int margins[TABLE_N_AXES][2]; /* Margins. */
struct page_heading headings[2]; /* Top and bottom headings. */
- PangoFontDescription *font;
struct cell_color bg; /* Background color. */
- double font_scale;
int initial_page_number;
int object_spacing;
};
struct xr_page_style *xr_page_style_default (void);
static inline int
-xr_page_style_paper_size (const struct xr_page_style *ps, enum table_axis a)
+xr_page_style_paper_size (const struct xr_page_style *ps,
+ const struct xr_fsm_style *fs, enum table_axis a)
{
- return ps->size[a] + ps->margins[a][0] + ps->margins[a][1];
+ return fs->size[a] + ps->margins[a][0] + ps->margins[a][1];
}
struct xr_pager *xr_pager_create (const struct xr_page_style *,
void xr_pager_destroy (struct xr_pager *);
bool xr_pager_has_item (const struct xr_pager *);
-void xr_pager_add_item (struct xr_pager *, const struct xr_fsm_style *,
- const struct output_item *);
+void xr_pager_add_item (struct xr_pager *, const struct output_item *);
bool xr_pager_has_page (const struct xr_pager *);
void xr_pager_add_page (struct xr_pager *, cairo_t *);
*xr->page_style = (struct xr_page_style) {
.ref_cnt = 1,
- .size = { [H] = size[H], [V] = size[V] },
.margins = {
[H] = { margins[H][0], margins[H][1], },
[V] = { margins[V][0], margins[V][1], },
},
- .font = pango_font_description_copy (proportional_font),
-
.bg = bg,
- .font_scale = font_scale,
.initial_page_number = 1,
.object_spacing = object_spacing,
};
double paper[TABLE_N_AXES];
for (int a = 0; a < TABLE_N_AXES; a++)
- paper[a] = xr_to_pt (xr_page_style_paper_size (xr->page_style, a));
+ paper[a] = xr_to_pt (xr_page_style_paper_size (xr->page_style,
+ xr->fsm_style, a));
if (file_type == XR_PDF)
xr->surface = cairo_pdf_surface_create (file_name, paper[H], paper[V]);
else if (file_type == XR_PS)
*page_style = (struct xr_page_style) {
.ref_cnt = 1,
- .size = {
- [H] = (ps->paper[h] - ps->margins[h][0] - ps->margins[h][1]) * scale,
- [V] = (ps->paper[v] - ps->margins[v][0] - ps->margins[v][1]) * scale,
- },
.margins = {
[H] = { ps->margins[h][0] * scale, ps->margins[h][1] * scale },
[V] = { ps->margins[v][0] * scale, ps->margins[v][1] * scale },
},
- .font = pango_font_description_copy (xr->page_style->font),
-
.bg = xr->page_style->bg,
- .font_scale = xr->page_style->font_scale,
.initial_page_number = ps->initial_page_number,
.object_spacing = ps->object_spacing * 72 * XR_POINT,
};
if (!xr->pager)
{
- xr->pager = xr_pager_create (xr->page_style);
+ xr->pager = xr_pager_create (xr->page_style, xr->fsm_style);
xr_pager_add_page (xr->pager, cairo_create (xr->surface));
}
- xr_pager_add_item (xr->pager, xr->fsm_style, output_item);
+ xr_pager_add_item (xr->pager, output_item);
while (xr_pager_needs_new_page (xr->pager))
{
cairo_surface_show_page (xr->surface);
get_cairo_context_from_print_context (GtkPrintContext *context)
{
cairo_t *cr = gtk_print_context_get_cairo_context (context);
-
- /*
- For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
- Windows returns 600.
- */
- double xres = gtk_print_context_get_dpi_x (context);
- double yres = gtk_print_context_get_dpi_y (context);
-
- /* This means that the cairo context now has its dimensions in Points */
- cairo_scale (cr, xres / 72.0, yres / 72.0);
-
- return cr;
+ return cairo_reference (cr);
}
-
static void
create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
{
[V] = gtk_page_setup_get_paper_height (ps, GTK_UNIT_POINTS) * XR_POINT,
};
+ /* These are all 1/2 inch. The "margins" that GTK+ gives us are useless:
+ they are the printer's imagable area. */
int margins[TABLE_N_AXES][2] = {
- [H][0] = gtk_page_setup_get_left_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
- [H][1] = gtk_page_setup_get_right_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
- [V][0] = gtk_page_setup_get_top_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
- [V][1] = gtk_page_setup_get_bottom_margin (ps, GTK_UNIT_POINTS) * XR_POINT,
+ [H][0] = XR_POINT * 36,
+ [H][1] = XR_POINT * 36,
+ [V][0] = XR_POINT * 36,
+ [V][1] = XR_POINT * 36,
};
double size[TABLE_N_AXES];
*view->page_style = (struct xr_page_style) {
.ref_cnt = 1,
- .size = { [H] = size[H], [V] = size[V] },
.margins = {
[H] = { margins[H][0], margins[H][1] },
[V] = { margins[V][0], margins[V][1] },
},
- .font = pango_font_description_copy (proportional_font),
.bg = { .alpha = 0 },
- .font_scale = 72.0 / 128.0,
.initial_page_number = 1,
.object_spacing = 12 * XR_POINT,
};
.ref_cnt = 1,
.size = { [H] = size[H], [V] = size[V] },
+ .min_break = { [H] = size[H] / 2, [V] = size[V] / 2 },
.fonts = {
[XR_FONT_PROPORTIONAL] = proportional_font,
[XR_FONT_FIXED] = fixed_font,
.font_scale = 72.0 / 128.0
};
- view->pager = xr_pager_create (view->page_style);
+ view->pager = xr_pager_create (view->page_style, view->fsm_style);
}
static gboolean
}
else if (view->print_item < view->n_items)
{
- xr_pager_add_item (view->pager, view->fsm_style,
- view->items[view->print_item++].item);
+ xr_pager_add_item (view->pager, view->items[view->print_item++].item);
while (xr_pager_needs_new_page (view->pager))
{
xr_pager_add_page (view->pager,
}
else
{
- gtk_print_operation_set_n_pages (operation, view->print_n_pages);
+ gtk_print_operation_set_n_pages (operation, MAX (1, view->print_n_pages));
/* Re-create the driver to do the real printing. */
xr_pager_destroy (view->pager);
- view->pager = xr_pager_create (view->page_style);
+ view->pager = xr_pager_create (view->page_style, view->fsm_style);
view->print_item = 0;
view->paginated = TRUE;
create_xr_print_driver (context, view);
view->print_item = 0;
- view->print_n_pages = 1;
+ view->print_n_pages = 0;
view->paginated = FALSE;
}
struct psppire_output_view *view)
{
xr_pager_destroy (view->pager);
+ view->pager = NULL;
}
get_cairo_context_from_print_context (context));
while (!xr_pager_needs_new_page (view->pager)
&& view->print_item < view->n_items)
- xr_pager_add_item (view->pager, view->fsm_style,
- view->items [view->print_item++].item);
+ xr_pager_add_item (view->pager, view->items [view->print_item++].item);
}
if (view->print_settings != NULL)
gtk_print_operation_set_print_settings (print, view->print_settings);
+ gtk_print_operation_set_use_full_page (print, TRUE);
+ gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
+
g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
g_signal_connect (print, "end_print", G_CALLBACK (end_print), view);
g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);