+
+
+char *
+xr_draw_eps_chart (const struct chart_item *item,
+ const char *file_name_template, int number,
+ const struct cell_color *fg,
+ const struct cell_color *bg)
+{
+ const int width = 640;
+ const int length = 480;
+
+ cairo_surface_t *surface;
+ const char *number_pos;
+ char *file_name;
+ cairo_t *cr;
+
+ number_pos = strchr (file_name_template, '#');
+ if (number_pos != NULL)
+ file_name = xasprintf ("%.*s%d%s.eps", (int) (number_pos - file_name_template),
+ file_name_template, number, number_pos + 1);
+ else
+ file_name = xasprintf ("%s.eps", file_name_template);
+
+ surface = cairo_ps_surface_create (file_name, width, length);
+ cairo_ps_surface_set_eps (surface, true);
+ cr = cairo_create (surface);
+
+ cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
+
+ xr_draw_chart (item, cr, 0.0, 0.0, width, length);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return file_name;
+}
+
+\f
+
+struct xr_table_state
+ {
+ struct xr_render_fsm fsm;
+ struct render_pager *p;
+ };
+
+static bool
+xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr)
+{
+ struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm);
+
+ while (render_pager_has_next (ts->p))
+ {
+ int used;
+
+ used = render_pager_draw_next (ts->p, xr->length - xr->y);
+ if (!used)
+ {
+ assert (xr->y > 0);
+ return true;
+ }
+ else
+ xr->y += used;
+ }
+ return false;
+}
+
+static void
+xr_table_destroy (struct xr_render_fsm *fsm)
+{
+ struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm);
+
+ render_pager_destroy (ts->p);
+ free (ts);
+}
+
+static struct xr_render_fsm *
+xr_render_table (struct xr_driver *xr, struct table_item *table_item)
+{
+ struct xr_table_state *ts;
+
+ ts = xmalloc (sizeof *ts);
+ ts->fsm.render = xr_table_render;
+ ts->fsm.destroy = xr_table_destroy;
+
+ if (xr->y > 0)
+ xr->y += xr->char_height;
+
+ ts->p = render_pager_create (xr->params, table_item);
+ table_item_unref (table_item);
+
+ return &ts->fsm;
+}
+\f
+struct xr_chart_state
+ {
+ struct xr_render_fsm fsm;
+ struct chart_item *chart_item;
+ };
+
+static bool
+xr_chart_render (struct xr_render_fsm *fsm, struct xr_driver *xr)
+{
+ struct xr_chart_state *cs = UP_CAST (fsm, struct xr_chart_state, fsm);
+
+ const int chart_height = 0.8 * (xr->length < xr->width ? xr->length : xr->width);
+
+ if (xr->y > xr->length - chart_height)
+ return true;
+
+ if (xr->cairo != NULL)
+ {
+ xr_draw_chart (cs->chart_item, xr->cairo,
+ 0.0,
+ xr_to_pt (xr->y),
+ xr_to_pt (xr->width),
+ xr_to_pt (chart_height));
+ }
+ xr->y += chart_height;
+
+ return false;
+}
+
+static void
+xr_chart_destroy (struct xr_render_fsm *fsm)
+{
+ struct xr_chart_state *cs = UP_CAST (fsm, struct xr_chart_state, fsm);
+
+ chart_item_unref (cs->chart_item);
+ free (cs);
+}
+
+static struct xr_render_fsm *
+xr_render_chart (const struct chart_item *chart_item)
+{
+ struct xr_chart_state *cs;
+
+ cs = xmalloc (sizeof *cs);
+ cs->fsm.render = xr_chart_render;
+ cs->fsm.destroy = xr_chart_destroy;
+ cs->chart_item = chart_item_ref (chart_item);
+
+ return &cs->fsm;
+}
+\f
+static bool
+xr_eject_render (struct xr_render_fsm *fsm UNUSED, struct xr_driver *xr)
+{
+ return xr->y > 0;
+}
+
+static void
+xr_eject_destroy (struct xr_render_fsm *fsm UNUSED)
+{
+ /* Nothing to do. */
+}
+
+static struct xr_render_fsm *
+xr_render_eject (void)
+{
+ static struct xr_render_fsm eject_renderer =
+ {
+ xr_eject_render,
+ xr_eject_destroy
+ };
+
+ return &eject_renderer;
+}
+\f
+static struct xr_render_fsm *
+xr_render_text (struct xr_driver *xr, const struct text_item *text_item)
+{
+ enum text_item_type type = text_item_get_type (text_item);
+
+ switch (type)
+ {
+ case TEXT_ITEM_PAGE_TITLE:
+ break;
+
+ default:
+ return xr_render_table (
+ xr, text_item_to_table_item (text_item_ref (text_item)));
+ }
+
+ return NULL;
+}
+
+static struct xr_render_fsm *
+xr_render_message (struct xr_driver *xr,
+ const struct message_item *message_item)
+{
+ char *s = msg_to_string (message_item_get_msg (message_item));
+ struct text_item *item = text_item_create (TEXT_ITEM_LOG, s);
+ free (s);
+ return xr_render_table (xr, text_item_to_table_item (item));
+}
+
+static struct xr_render_fsm *
+xr_render_output_item (struct xr_driver *xr,
+ const struct output_item *output_item)
+{
+ if (is_table_item (output_item))
+ return xr_render_table (xr, table_item_ref (to_table_item (output_item)));
+ else if (is_chart_item (output_item))
+ return xr_render_chart (to_chart_item (output_item));
+ else if (is_text_item (output_item))
+ return xr_render_text (xr, to_text_item (output_item));
+ else if (is_page_eject_item (output_item))
+ return xr->y > 0 ? xr_render_eject () : NULL;
+ else if (is_message_item (output_item))
+ return xr_render_message (xr, to_message_item (output_item));
+ else
+ return NULL;
+}
+
+bool
+xr_draw_svg_file (struct xr_rendering *r,
+ const char *filename)
+{
+ int width, height;
+ g_assert (r);
+ xr_rendering_measure (r, &width, &height);
+ cairo_surface_t *surface = cairo_svg_surface_create (filename, width, height);
+ if (!surface)
+ {
+ g_error ("Could not create cairo svg surface with file %s", filename);
+ return FALSE;
+ }
+ cairo_t *cr = cairo_create (surface);
+ xr_rendering_draw (r, cr, 0, 0, width, height);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ return TRUE;
+}