psppire-output-view: Consistently apply "transparent" and "systemcolors".
[pspp] / src / output / cairo.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "output/cairo.h"
20
21 #include "libpspp/assertion.h"
22 #include "libpspp/cast.h"
23 #include "libpspp/hash-functions.h"
24 #include "libpspp/message.h"
25 #include "libpspp/pool.h"
26 #include "libpspp/start-date.h"
27 #include "libpspp/str.h"
28 #include "libpspp/string-map.h"
29 #include "libpspp/version.h"
30 #include "data/file-handle-def.h"
31 #include "output/cairo-chart.h"
32 #include "output/chart-item-provider.h"
33 #include "output/charts/boxplot.h"
34 #include "output/charts/np-plot.h"
35 #include "output/charts/piechart.h"
36 #include "output/charts/barchart.h"
37 #include "output/charts/plot-hist.h"
38 #include "output/charts/roc-chart.h"
39 #include "output/charts/spreadlevel-plot.h"
40 #include "output/charts/scree.h"
41 #include "output/charts/scatterplot.h"
42 #include "output/driver-provider.h"
43 #include "output/group-item.h"
44 #include "output/message-item.h"
45 #include "output/options.h"
46 #include "output/page-setup-item.h"
47 #include "output/render.h"
48 #include "output/table-item.h"
49 #include "output/table.h"
50 #include "output/text-item.h"
51
52 #include <cairo/cairo-pdf.h>
53 #include <cairo/cairo-ps.h>
54 #include <cairo/cairo-svg.h>
55 #include <cairo/cairo.h>
56 #include <inttypes.h>
57 #include <math.h>
58 #include <pango/pango-font.h>
59 #include <pango/pango-layout.h>
60 #include <pango/pango.h>
61 #include <pango/pangocairo.h>
62 #include <stdlib.h>
63
64 #include "gl/c-ctype.h"
65 #include "gl/c-strcase.h"
66 #include "gl/intprops.h"
67 #include "gl/minmax.h"
68 #include "gl/xalloc.h"
69
70 #include "gettext.h"
71 #define _(msgid) gettext (msgid)
72
73 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
74 #define H TABLE_HORZ
75 #define V TABLE_VERT
76
77 /* The unit used for internal measurements is inch/(72 * XR_POINT).
78    (Thus, XR_POINT units represent one point.) */
79 #define XR_POINT PANGO_SCALE
80
81 /* Conversions to and from points. */
82 static double
83 xr_to_pt (int x)
84 {
85   return x / (double) XR_POINT;
86 }
87
88 /* Conversion from 1/96" units ("pixels") to Cairo/Pango units. */
89 static int
90 px_to_xr (int x)
91 {
92   return x * (PANGO_SCALE * 72 / 96);
93 }
94
95 /* Dimensions for drawing lines in tables. */
96 #define XR_LINE_WIDTH (XR_POINT / 2) /* Width of an ordinary line. */
97 #define XR_LINE_SPACE XR_POINT       /* Space between double lines. */
98
99 /* Output types. */
100 enum xr_output_type
101   {
102     XR_PDF,
103     XR_PS,
104     XR_SVG
105   };
106
107 /* Cairo fonts. */
108 enum xr_font_type
109   {
110     XR_FONT_PROPORTIONAL,
111     XR_FONT_EMPHASIS,
112     XR_FONT_FIXED,
113     XR_N_FONTS
114   };
115
116 /* A font for use with Cairo. */
117 struct xr_font
118   {
119     PangoFontDescription *desc;
120     PangoLayout *layout;
121   };
122
123 /* An output item whose rendering is in progress. */
124 struct xr_render_fsm
125   {
126     /* Renders as much of itself as it can on the current page.  Returns true
127        if rendering is complete, false if the output item needs another
128        page. */
129     bool (*render) (struct xr_render_fsm *, struct xr_driver *);
130
131     /* Destroys the output item. */
132     void (*destroy) (struct xr_render_fsm *);
133   };
134
135 /* Cairo output driver. */
136 struct xr_driver
137   {
138     struct output_driver driver;
139
140     /* User parameters. */
141     struct xr_font fonts[XR_N_FONTS];
142
143     int width;                  /* Page width minus margins. */
144     int length;                 /* Page length minus margins and header. */
145
146     int left_margin;            /* Left margin in inch/(72 * XR_POINT). */
147     int right_margin;           /* Right margin in inch/(72 * XR_POINT). */
148     int top_margin;             /* Top margin in inch/(72 * XR_POINT). */
149     int bottom_margin;          /* Bottom margin in inch/(72 * XR_POINT). */
150
151     int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */
152     int object_spacing;         /* Space between output objects. */
153
154     struct cell_color bg;       /* Background color */
155     struct cell_color fg;       /* Foreground color */
156     bool transparent;           /* true -> do not render background */
157     bool systemcolors;          /* true -> do not change colors     */
158
159     int initial_page_number;
160
161     struct page_heading headings[2]; /* Top and bottom headings. */
162     int headings_height[2];
163
164     /* Internal state. */
165     struct render_params *params;
166     double font_scale;
167     int char_width, char_height;
168     cairo_t *cairo;
169     cairo_surface_t *surface;
170     int page_number;            /* Current page number. */
171     int y;
172     struct xr_render_fsm *fsm;
173   };
174
175 static const struct output_driver_class cairo_driver_class;
176
177 static void xr_driver_destroy_fsm (struct xr_driver *);
178 static void xr_driver_run_fsm (struct xr_driver *);
179
180 static void xr_draw_line (void *, int bb[TABLE_N_AXES][2],
181                           enum render_line_style styles[TABLE_N_AXES][2],
182                           struct cell_color colors[TABLE_N_AXES][2]);
183 static void xr_measure_cell_width (void *, const struct table_cell *,
184                                    int *min, int *max);
185 static int xr_measure_cell_height (void *, const struct table_cell *,
186                                    int width);
187 static void xr_draw_cell (void *, const struct table_cell *, int color_idx,
188                           int bb[TABLE_N_AXES][2], int valign_offset,
189                           int spill[TABLE_N_AXES][2],
190                           int clip[TABLE_N_AXES][2]);
191 static int xr_adjust_break (void *, const struct table_cell *,
192                             int width, int height);
193
194 static struct xr_render_fsm *xr_render_output_item (
195   struct xr_driver *, const struct output_item *);
196 \f
197 /* Output driver basics. */
198
199 static struct xr_driver *
200 xr_driver_cast (struct output_driver *driver)
201 {
202   assert (driver->class == &cairo_driver_class);
203   return UP_CAST (driver, struct xr_driver, driver);
204 }
205
206 static struct driver_option *
207 opt (struct output_driver *d, struct string_map *options, const char *key,
208      const char *default_value)
209 {
210   return driver_option_get (d, options, key, default_value);
211 }
212
213 static PangoFontDescription *
214 parse_font (const char *font, int default_size, bool bold, bool italic)
215 {
216   if (!c_strcasecmp (font, "Monospaced"))
217     font = "Monospace";
218
219   PangoFontDescription *desc = pango_font_description_from_string (font);
220   if (desc == NULL)
221     return NULL;
222
223   /* If the font description didn't include an explicit font size, then set it
224      to DEFAULT_SIZE, which is in inch/72000 units. */
225   if (!(pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_SIZE))
226     pango_font_description_set_size (desc,
227                                      (default_size / 1000.0) * PANGO_SCALE);
228
229   pango_font_description_set_weight (desc, (bold
230                                             ? PANGO_WEIGHT_BOLD
231                                             : PANGO_WEIGHT_NORMAL));
232   pango_font_description_set_style (desc, (italic
233                                            ? PANGO_STYLE_ITALIC
234                                            : PANGO_STYLE_NORMAL));
235
236   return desc;
237 }
238
239 static PangoFontDescription *
240 parse_font_option (struct output_driver *d, struct string_map *options,
241                    const char *key, const char *default_value,
242                    int default_size, bool bold, bool italic)
243 {
244   char *string = parse_string (opt (d, options, key, default_value));
245   PangoFontDescription *desc = parse_font (string, default_size, bold, italic);
246   if (!desc)
247     {
248       msg (MW, _("`%s': bad font specification"), string);
249
250       /* Fall back to DEFAULT_VALUE, which had better be a valid font
251          description. */
252       desc = parse_font (default_value, default_size, bold, italic);
253       assert (desc != NULL);
254     }
255   free (string);
256
257   return desc;
258 }
259
260 static void
261 apply_options (struct xr_driver *xr, struct string_map *o)
262 {
263   struct output_driver *d = &xr->driver;
264
265   /* In inch/72000 units used by parse_paper_size() and parse_dimension(). */
266   int left_margin, right_margin;
267   int top_margin, bottom_margin;
268   int paper_width, paper_length;
269   int font_size;
270   int min_break[TABLE_N_AXES];
271
272   /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
273   const double scale = XR_POINT / 1000.;
274
275   int i;
276
277   for (i = 0; i < XR_N_FONTS; i++)
278     {
279       struct xr_font *font = &xr->fonts[i];
280
281       if (font->desc != NULL)
282         pango_font_description_free (font->desc);
283     }
284
285   font_size = parse_int (opt (d, o, "font-size", "10000"), 1000, 1000000);
286   xr->fonts[XR_FONT_FIXED].desc = parse_font_option
287     (d, o, "fixed-font", "monospace", font_size, false, false);
288   xr->fonts[XR_FONT_PROPORTIONAL].desc = parse_font_option (
289     d, o, "prop-font", "sans serif", font_size, false, false);
290   xr->fonts[XR_FONT_EMPHASIS].desc = parse_font_option (
291     d, o, "emph-font", "sans serif", font_size, false, true);
292
293   xr->fg = parse_color (opt (d, o, "foreground-color", "#000000000000"));
294   xr->bg = parse_color (opt (d, o, "background-color", "#FFFFFFFFFFFF"));
295
296   xr->transparent = parse_boolean (opt (d, o, "transparent", "false"));
297   xr->systemcolors = parse_boolean (opt (d, o, "systemcolors", "false"));
298
299   /* Get dimensions.  */
300   parse_paper_size (opt (d, o, "paper-size", ""), &paper_width, &paper_length);
301   left_margin = parse_dimension (opt (d, o, "left-margin", ".5in"));
302   right_margin = parse_dimension (opt (d, o, "right-margin", ".5in"));
303   top_margin = parse_dimension (opt (d, o, "top-margin", ".5in"));
304   bottom_margin = parse_dimension (opt (d, o, "bottom-margin", ".5in"));
305
306   min_break[H] = parse_dimension (opt (d, o, "min-hbreak", NULL)) * scale;
307   min_break[V] = parse_dimension (opt (d, o, "min-vbreak", NULL)) * scale;
308
309   int object_spacing = (parse_dimension (opt (d, o, "object-spacing", NULL))
310                         * scale);
311
312   /* Convert to inch/(XR_POINT * 72). */
313   xr->left_margin = left_margin * scale;
314   xr->right_margin = right_margin * scale;
315   xr->top_margin = top_margin * scale;
316   xr->bottom_margin = bottom_margin * scale;
317   xr->width = (paper_width - left_margin - right_margin) * scale;
318   xr->length = (paper_length - top_margin - bottom_margin) * scale;
319   xr->min_break[H] = min_break[H] >= 0 ? min_break[H] : xr->width / 2;
320   xr->min_break[V] = min_break[V] >= 0 ? min_break[V] : xr->length / 2;
321   xr->object_spacing = object_spacing >= 0 ? object_spacing : XR_POINT * 12;
322
323   /* There are no headings so headings_height can stay 0. */
324 }
325
326 static struct xr_driver *
327 xr_allocate (const char *name, int device_type, struct string_map *o,
328              double font_scale)
329 {
330   struct xr_driver *xr = xzalloc (sizeof *xr);
331   struct output_driver *d = &xr->driver;
332
333   output_driver_init (d, &cairo_driver_class, name, device_type);
334
335   /* This is a nasty kluge for an issue that does not make sense.  On any
336      surface other than a screen (e.g. for output to PDF or PS or SVG), the
337      fonts are way too big by default.  A "9-point" font seems to appear about
338      16 points tall.  We use a scale factor for these surfaces to help, but the
339      underlying issue is a mystery. */
340   xr->font_scale = font_scale;
341
342   apply_options (xr, o);
343
344   return xr;
345 }
346
347 static int
348 pango_to_xr (int pango)
349 {
350   return (XR_POINT != PANGO_SCALE
351           ? ceil (pango * (1. * XR_POINT / PANGO_SCALE))
352           : pango);
353 }
354
355 static int
356 xr_to_pango (int xr)
357 {
358   return (XR_POINT != PANGO_SCALE
359           ? ceil (xr * (1. / XR_POINT * PANGO_SCALE))
360           : xr);
361 }
362
363 static void
364 xr_measure_fonts (cairo_t *cairo, const struct xr_font fonts[XR_N_FONTS],
365                   int *char_width, int *char_height)
366 {
367   *char_width = 0;
368   *char_height = 0;
369   for (int i = 0; i < XR_N_FONTS; i++)
370     {
371       PangoLayout *layout = pango_cairo_create_layout (cairo);
372       pango_layout_set_font_description (layout, fonts[i].desc);
373
374       pango_layout_set_text (layout, "0", 1);
375
376       int cw, ch;
377       pango_layout_get_size (layout, &cw, &ch);
378       *char_width = MAX (*char_width, pango_to_xr (cw));
379       *char_height = MAX (*char_height, pango_to_xr (ch));
380
381       g_object_unref (G_OBJECT (layout));
382     }
383 }
384
385 static int
386 get_layout_height (PangoLayout *layout)
387 {
388   int w, h;
389   pango_layout_get_size (layout, &w, &h);
390   return h;
391 }
392
393 static int
394 xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
395                         const struct page_heading *ph, int page_number,
396                         int width, bool draw, int base_y)
397 {
398   PangoLayout *layout = pango_cairo_create_layout (cairo);
399   pango_layout_set_font_description (layout, font);
400
401   int y = 0;
402   for (size_t i = 0; i < ph->n; i++)
403     {
404       const struct page_paragraph *pp = &ph->paragraphs[i];
405
406       char *markup = output_driver_substitute_heading_vars (pp->markup,
407                                                             page_number);
408       pango_layout_set_markup (layout, markup, -1);
409       free (markup);
410
411       pango_layout_set_alignment (
412         layout,
413         (pp->halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
414          : pp->halign == TABLE_HALIGN_CENTER ? PANGO_ALIGN_CENTER
415          : pp->halign == TABLE_HALIGN_MIXED ? PANGO_ALIGN_LEFT
416          : PANGO_ALIGN_RIGHT));
417       pango_layout_set_width (layout, xr_to_pango (width));
418       if (draw)
419         {
420           cairo_save (cairo);
421           cairo_translate (cairo, 0, xr_to_pt (y + base_y));
422           pango_cairo_show_layout (cairo, layout);
423           cairo_restore (cairo);
424         }
425
426       y += pango_to_xr (get_layout_height (layout));
427     }
428
429   g_object_unref (G_OBJECT (layout));
430
431   return y;
432 }
433
434 static int
435 xr_measure_headings (cairo_surface_t *surface,
436                      const PangoFontDescription *font,
437                      const struct page_heading headings[2],
438                      int width, int object_spacing, int height[2])
439 {
440   cairo_t *cairo = cairo_create (surface);
441   int total = 0;
442   for (int i = 0; i < 2; i++)
443     {
444       int h = xr_render_page_heading (cairo, font, &headings[i], -1,
445                                       width, false, 0);
446
447       /* If the top heading is nonempty, add some space below it. */
448       if (h && i == 0)
449         h += object_spacing;
450
451       if (height)
452         height[i] = h;
453       total += h;
454     }
455   cairo_destroy (cairo);
456   return total;
457 }
458
459 static bool
460 xr_check_fonts (cairo_surface_t *surface,
461                 const struct xr_font fonts[XR_N_FONTS],
462                 int usable_width, int usable_length)
463 {
464   cairo_t *cairo = cairo_create (surface);
465   int char_width, char_height;
466   xr_measure_fonts (cairo, fonts, &char_width, &char_height);
467   cairo_destroy (cairo);
468
469   bool ok = true;
470   enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
471   if (usable_width / char_width < MIN_WIDTH)
472     {
473       msg (ME, _("The defined page is not wide enough to hold at least %d "
474                  "characters in the default font.  In fact, there's only "
475                  "room for %d characters."),
476            MIN_WIDTH, usable_width / char_width);
477       ok = false;
478     }
479   if (usable_length / char_height < MIN_LENGTH)
480     {
481       msg (ME, _("The defined page is not long enough to hold at least %d "
482                  "lines in the default font.  In fact, there's only "
483                  "room for %d lines."),
484            MIN_LENGTH, usable_length / char_height);
485       ok = false;
486     }
487   return ok;
488 }
489
490 static void
491 xr_set_cairo (struct xr_driver *xr, cairo_t *cairo)
492 {
493   xr->cairo = cairo;
494
495   cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
496
497   xr_measure_fonts (xr->cairo, xr->fonts, &xr->char_width, &xr->char_height);
498
499   for (int i = 0; i < XR_N_FONTS; i++)
500     {
501       struct xr_font *font = &xr->fonts[i];
502       font->layout = pango_cairo_create_layout (cairo);
503       pango_layout_set_font_description (font->layout, font->desc);
504     }
505
506   if (xr->params == NULL)
507     {
508       xr->params = xmalloc (sizeof *xr->params);
509       xr->params->draw_line = xr_draw_line;
510       xr->params->measure_cell_width = xr_measure_cell_width;
511       xr->params->measure_cell_height = xr_measure_cell_height;
512       xr->params->adjust_break = xr_adjust_break;
513       xr->params->draw_cell = xr_draw_cell;
514       xr->params->aux = xr;
515       xr->params->size[H] = xr->width;
516       xr->params->size[V] = xr->length;
517       xr->params->font_size[H] = xr->char_width;
518       xr->params->font_size[V] = xr->char_height;
519
520       int lw = XR_LINE_WIDTH;
521       int ls = XR_LINE_SPACE;
522       for (int i = 0; i < TABLE_N_AXES; i++)
523         {
524           xr->params->line_widths[i][RENDER_LINE_NONE] = 0;
525           xr->params->line_widths[i][RENDER_LINE_SINGLE] = lw;
526           xr->params->line_widths[i][RENDER_LINE_DASHED] = lw;
527           xr->params->line_widths[i][RENDER_LINE_THICK] = lw * 2;
528           xr->params->line_widths[i][RENDER_LINE_THIN] = lw / 2;
529           xr->params->line_widths[i][RENDER_LINE_DOUBLE] = 2 * lw + ls;
530         }
531
532       for (int i = 0; i < TABLE_N_AXES; i++)
533         xr->params->min_break[i] = xr->min_break[i];
534       xr->params->supports_margins = true;
535       xr->params->rtl = render_direction_rtl ();
536     }
537
538   if (!xr->systemcolors)
539     cairo_set_source_rgb (xr->cairo,
540                           xr->fg.r / 255.0, xr->fg.g / 255.0, xr->fg.b / 255.0);
541 }
542
543 static struct output_driver *
544 xr_create (struct file_handle *fh, enum settings_output_devices device_type,
545            struct string_map *o, enum xr_output_type file_type)
546 {
547   const char *file_name = fh_get_file_name (fh);
548   struct xr_driver *xr = xr_allocate (file_name, device_type, o, 72.0 / 128.0);
549   double width_pt = xr_to_pt (xr->width + xr->left_margin + xr->right_margin);
550   double length_pt = xr_to_pt (xr->length + xr->top_margin + xr->bottom_margin);
551   if (file_type == XR_PDF)
552     xr->surface = cairo_pdf_surface_create (file_name, width_pt, length_pt);
553   else if (file_type == XR_PS)
554     xr->surface = cairo_ps_surface_create (file_name, width_pt, length_pt);
555   else if (file_type == XR_SVG)
556     xr->surface = cairo_svg_surface_create (file_name, width_pt, length_pt);
557   else
558     NOT_REACHED ();
559
560   cairo_status_t status = cairo_surface_status (xr->surface);
561   if (status != CAIRO_STATUS_SUCCESS)
562     {
563       msg (ME, _("error opening output file `%s': %s"),
564            file_name, cairo_status_to_string (status));
565       goto error;
566     }
567
568   if (!xr_check_fonts (xr->surface, xr->fonts, xr->width, xr->length))
569     goto error;
570
571   fh_unref (fh);
572   return &xr->driver;
573
574  error:
575   fh_unref (fh);
576   output_driver_destroy (&xr->driver);
577   return NULL;
578 }
579
580 static struct output_driver *
581 xr_pdf_create (struct  file_handle *fh, enum settings_output_devices device_type,
582                struct string_map *o)
583 {
584   return xr_create (fh, device_type, o, XR_PDF);
585 }
586
587 static struct output_driver *
588 xr_ps_create (struct  file_handle *fh, enum settings_output_devices device_type,
589                struct string_map *o)
590 {
591   return xr_create (fh, device_type, o, XR_PS);
592 }
593
594 static struct output_driver *
595 xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
596                struct string_map *o)
597 {
598   return xr_create (fh, device_type, o, XR_SVG);
599 }
600
601 static void
602 xr_destroy (struct output_driver *driver)
603 {
604   struct xr_driver *xr = xr_driver_cast (driver);
605   size_t i;
606
607   xr_driver_destroy_fsm (xr);
608
609   if (xr->cairo != NULL)
610     {
611       cairo_surface_finish (xr->surface);
612       cairo_status_t status = cairo_status (xr->cairo);
613       if (status != CAIRO_STATUS_SUCCESS)
614         fprintf (stderr,  _("error drawing output for %s driver: %s"),
615                  output_driver_get_name (driver),
616                  cairo_status_to_string (status));
617       cairo_surface_destroy (xr->surface);
618
619       cairo_destroy (xr->cairo);
620     }
621
622   for (i = 0; i < XR_N_FONTS; i++)
623     {
624       struct xr_font *font = &xr->fonts[i];
625
626       if (font->desc != NULL)
627         pango_font_description_free (font->desc);
628       if (font->layout != NULL)
629         g_object_unref (font->layout);
630     }
631
632   free (xr->params);
633   free (xr);
634 }
635
636 static void
637 xr_flush (struct output_driver *driver)
638 {
639   struct xr_driver *xr = xr_driver_cast (driver);
640
641   cairo_surface_flush (cairo_get_target (xr->cairo));
642 }
643
644 static void
645 xr_update_page_setup (struct output_driver *driver,
646                       const struct page_setup *ps)
647 {
648   struct xr_driver *xr = xr_driver_cast (driver);
649
650   xr->initial_page_number = ps->initial_page_number;
651   xr->object_spacing = ps->object_spacing * 72 * XR_POINT;
652
653   if (xr->cairo)
654     return;
655
656   int usable[TABLE_N_AXES];
657   for (int i = 0; i < 2; i++)
658     usable[i] = (ps->paper[i]
659                  - (ps->margins[i][0] + ps->margins[i][1])) * 72 * XR_POINT;
660
661   int headings_height[2];
662   usable[V] -= xr_measure_headings (
663     xr->surface, xr->fonts[XR_FONT_PROPORTIONAL].desc, ps->headings,
664     usable[H], xr->object_spacing, headings_height);
665
666   enum table_axis h = ps->orientation == PAGE_LANDSCAPE;
667   enum table_axis v = !h;
668   if (!xr_check_fonts (xr->surface, xr->fonts, usable[h], usable[v]))
669     return;
670
671   for (int i = 0; i < 2; i++)
672     {
673       page_heading_uninit (&xr->headings[i]);
674       page_heading_copy (&xr->headings[i], &ps->headings[i]);
675       xr->headings_height[i] = headings_height[i];
676     }
677   xr->width = usable[h];
678   xr->length = usable[v];
679   xr->left_margin = ps->margins[h][0] * 72 * XR_POINT;
680   xr->right_margin = ps->margins[h][1] * 72 * XR_POINT;
681   xr->top_margin = ps->margins[v][0] * 72 * XR_POINT;
682   xr->bottom_margin = ps->margins[v][1] * 72 * XR_POINT;
683   cairo_pdf_surface_set_size (xr->surface,
684                               ps->paper[h] * 72.0, ps->paper[v] * 72.0);
685 }
686
687 static void
688 xr_submit (struct output_driver *driver, const struct output_item *output_item)
689 {
690   struct xr_driver *xr = xr_driver_cast (driver);
691
692   if (is_page_setup_item (output_item))
693     {
694       xr_update_page_setup (driver,
695                             to_page_setup_item (output_item)->page_setup);
696       return;
697     }
698
699   if (!xr->cairo)
700     {
701       xr->page_number = xr->initial_page_number - 1;
702       xr_set_cairo (xr, cairo_create (xr->surface));
703       cairo_save (xr->cairo);
704       xr_driver_next_page (xr, xr->cairo);
705     }
706
707   xr_driver_output_item (xr, output_item);
708   while (xr_driver_need_new_page (xr))
709     {
710       cairo_restore (xr->cairo);
711       cairo_show_page (xr->cairo);
712       cairo_save (xr->cairo);
713       xr_driver_next_page (xr, xr->cairo);
714     }
715 }
716 \f
717 /* Functions for rendering a series of output items to a series of Cairo
718    contexts, with pagination.
719
720    Used by PSPPIRE for printing, and by the basic Cairo output driver above as
721    its underlying implementation.
722
723    See the big comment in cairo.h for intended usage. */
724
725 /* Gives new page CAIRO to XR for output. */
726 void
727 xr_driver_next_page (struct xr_driver *xr, cairo_t *cairo)
728 {
729   if (!xr->transparent)
730     {
731       cairo_save (cairo);
732       cairo_set_source_rgb (cairo,
733                             xr->bg.r / 255.0, xr->bg.g / 255.0, xr->bg.b / 255.0);
734       cairo_rectangle (cairo, 0, 0, xr->width, xr->length);
735       cairo_fill (cairo);
736       cairo_restore (cairo);
737     }
738   cairo_translate (cairo,
739                    xr_to_pt (xr->left_margin),
740                    xr_to_pt (xr->top_margin + xr->headings_height[0]));
741
742   xr->page_number++;
743   xr->cairo = cairo;
744   xr->y = 0;
745
746   xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL].desc,
747                           &xr->headings[0], xr->page_number, xr->width, true,
748                           -xr->headings_height[0]);
749   xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL].desc,
750                           &xr->headings[1], xr->page_number, xr->width, true,
751                           xr->length);
752
753   xr_driver_run_fsm (xr);
754 }
755
756 /* Start rendering OUTPUT_ITEM to XR.  Only valid if XR is not in the middle of
757    rendering a previous output item, that is, only if xr_driver_need_new_page()
758    returns false. */
759 void
760 xr_driver_output_item (struct xr_driver *xr,
761                        const struct output_item *output_item)
762 {
763   assert (xr->fsm == NULL);
764   xr->fsm = xr_render_output_item (xr, output_item);
765   xr_driver_run_fsm (xr);
766 }
767
768 /* Returns true if XR is in the middle of rendering an output item and needs a
769    new page to be appended using xr_driver_next_page() to make progress,
770    otherwise false. */
771 bool
772 xr_driver_need_new_page (const struct xr_driver *xr)
773 {
774   return xr->fsm != NULL;
775 }
776
777 /* Returns true if the current page doesn't have any content yet. */
778 bool
779 xr_driver_is_page_blank (const struct xr_driver *xr)
780 {
781   return xr->y == 0;
782 }
783
784 static void
785 xr_driver_destroy_fsm (struct xr_driver *xr)
786 {
787   if (xr->fsm != NULL)
788     {
789       xr->fsm->destroy (xr->fsm);
790       xr->fsm = NULL;
791     }
792 }
793
794 static void
795 xr_driver_run_fsm (struct xr_driver *xr)
796 {
797   if (xr->fsm != NULL && !xr->fsm->render (xr->fsm, xr))
798     xr_driver_destroy_fsm (xr);
799 }
800 \f
801 static void
802 xr_layout_cell (struct xr_driver *, const struct table_cell *,
803                 int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
804                 int *width, int *height, int *brk);
805
806 static void
807 set_source_rgba (cairo_t *cairo, const struct cell_color *color)
808 {
809   cairo_set_source_rgba (cairo,
810                          color->r / 255., color->g / 255., color->b / 255.,
811                          color->alpha / 255.);
812 }
813
814 static void
815 dump_line (struct xr_driver *xr, int x0, int y0, int x1, int y1, int style,
816            const struct cell_color *color)
817 {
818   cairo_new_path (xr->cairo);
819   if (!xr->systemcolors)
820     set_source_rgba (xr->cairo, color);
821   cairo_set_line_width (
822     xr->cairo,
823     xr_to_pt (style == RENDER_LINE_THICK ? XR_LINE_WIDTH * 2
824               : style == RENDER_LINE_THIN ? XR_LINE_WIDTH / 2
825               : XR_LINE_WIDTH));
826   cairo_move_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y0 + xr->y));
827   cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y1 + xr->y));
828   cairo_stroke (xr->cairo);
829 }
830
831 static void UNUSED
832 dump_rectangle (struct xr_driver *xr, int x0, int y0, int x1, int y1)
833 {
834   cairo_new_path (xr->cairo);
835   cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
836   cairo_close_path (xr->cairo);
837   cairo_stroke (xr->cairo);
838   cairo_move_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y0 + xr->y));
839   cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y0 + xr->y));
840   cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y1 + xr->y));
841   cairo_line_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y1 + xr->y));
842 }
843
844 static void
845 fill_rectangle (struct xr_driver *xr, int x0, int y0, int x1, int y1)
846 {
847   cairo_new_path (xr->cairo);
848   cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
849   cairo_rectangle (xr->cairo,
850                    xr_to_pt (x0), xr_to_pt (y0 + xr->y),
851                    xr_to_pt (x1 - x0), xr_to_pt (y1 - y0));
852   cairo_fill (xr->cairo);
853 }
854
855 /* Draws a horizontal line X0...X2 at Y if LEFT says so,
856    shortening it to X0...X1 if SHORTEN is true.
857    Draws a horizontal line X1...X3 at Y if RIGHT says so,
858    shortening it to X2...X3 if SHORTEN is true. */
859 static void
860 horz_line (struct xr_driver *xr, int x0, int x1, int x2, int x3, int y,
861            enum render_line_style left, enum render_line_style right,
862            const struct cell_color *left_color,
863            const struct cell_color *right_color,
864            bool shorten)
865 {
866   if (left != RENDER_LINE_NONE && right != RENDER_LINE_NONE && !shorten
867       && cell_color_equal (left_color, right_color))
868     dump_line (xr, x0, y, x3, y, left, left_color);
869   else
870     {
871       if (left != RENDER_LINE_NONE)
872         dump_line (xr, x0, y, shorten ? x1 : x2, y, left, left_color);
873       if (right != RENDER_LINE_NONE)
874         dump_line (xr, shorten ? x2 : x1, y, x3, y, right, right_color);
875     }
876 }
877
878 /* Draws a vertical line Y0...Y2 at X if TOP says so,
879    shortening it to Y0...Y1 if SHORTEN is true.
880    Draws a vertical line Y1...Y3 at X if BOTTOM says so,
881    shortening it to Y2...Y3 if SHORTEN is true. */
882 static void
883 vert_line (struct xr_driver *xr, int y0, int y1, int y2, int y3, int x,
884            enum render_line_style top, enum render_line_style bottom,
885            const struct cell_color *top_color,
886            const struct cell_color *bottom_color,
887            bool shorten)
888 {
889   if (top != RENDER_LINE_NONE && bottom != RENDER_LINE_NONE && !shorten
890       && cell_color_equal (top_color, bottom_color))
891     dump_line (xr, x, y0, x, y3, top, top_color);
892   else
893     {
894       if (top != RENDER_LINE_NONE)
895         dump_line (xr, x, y0, x, shorten ? y1 : y2, top, top_color);
896       if (bottom != RENDER_LINE_NONE)
897         dump_line (xr, x, shorten ? y2 : y1, x, y3, bottom, bottom_color);
898     }
899 }
900
901 static void
902 xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2],
903               enum render_line_style styles[TABLE_N_AXES][2],
904               struct cell_color colors[TABLE_N_AXES][2])
905 {
906   const int x0 = bb[H][0];
907   const int y0 = bb[V][0];
908   const int x3 = bb[H][1];
909   const int y3 = bb[V][1];
910   const int top = styles[H][0];
911   const int bottom = styles[H][1];
912
913   int start_side = render_direction_rtl();
914   int end_side = !start_side;
915   const int start_of_line = styles[V][start_side];
916   const int end_of_line   = styles[V][end_side];
917   const struct cell_color *top_color = &colors[H][0];
918   const struct cell_color *bottom_color = &colors[H][1];
919   const struct cell_color *start_color = &colors[V][start_side];
920   const struct cell_color *end_color = &colors[V][end_side];
921
922   /* The algorithm here is somewhat subtle, to allow it to handle
923      all the kinds of intersections that we need.
924
925      Three additional ordinates are assigned along the x axis.  The
926      first is xc, midway between x0 and x3.  The others are x1 and
927      x2; for a single vertical line these are equal to xc, and for
928      a double vertical line they are the ordinates of the left and
929      right half of the double line.
930
931      yc, y1, and y2 are assigned similarly along the y axis.
932
933      The following diagram shows the coordinate system and output
934      for double top and bottom lines, single left line, and no
935      right line:
936
937                  x0       x1 xc  x2      x3
938                y0 ________________________
939                   |        #     #       |
940                   |        #     #       |
941                   |        #     #       |
942                   |        #     #       |
943                   |        #     #       |
944      y1 = y2 = yc |#########     #       |
945                   |        #     #       |
946                   |        #     #       |
947                   |        #     #       |
948                   |        #     #       |
949                y3 |________#_____#_______|
950   */
951   struct xr_driver *xr = xr_;
952
953   /* Offset from center of each line in a pair of double lines. */
954   int double_line_ofs = (XR_LINE_SPACE + XR_LINE_WIDTH) / 2;
955
956   /* Are the lines along each axis single or double?
957      (It doesn't make sense to have different kinds of line on the
958      same axis, so we don't try to gracefully handle that case.) */
959   bool double_vert = top == RENDER_LINE_DOUBLE || bottom == RENDER_LINE_DOUBLE;
960   bool double_horz = start_of_line == RENDER_LINE_DOUBLE || end_of_line == RENDER_LINE_DOUBLE;
961
962   /* When horizontal lines are doubled,
963      the left-side line along y1 normally runs from x0 to x2,
964      and the right-side line along y1 from x3 to x1.
965      If the top-side line is also doubled, we shorten the y1 lines,
966      so that the left-side line runs only to x1,
967      and the right-side line only to x2.
968      Otherwise, the horizontal line at y = y1 below would cut off
969      the intersection, which looks ugly:
970                x0       x1     x2      x3
971              y0 ________________________
972                 |        #     #       |
973                 |        #     #       |
974                 |        #     #       |
975                 |        #     #       |
976              y1 |#########     ########|
977                 |                      |
978                 |                      |
979              y2 |######################|
980                 |                      |
981                 |                      |
982              y3 |______________________|
983      It is more of a judgment call when the horizontal line is
984      single.  We actually choose to cut off the line anyhow, as
985      shown in the first diagram above.
986   */
987   bool shorten_y1_lines = top == RENDER_LINE_DOUBLE;
988   bool shorten_y2_lines = bottom == RENDER_LINE_DOUBLE;
989   bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
990   int horz_line_ofs = double_vert ? double_line_ofs : 0;
991   int xc = (x0 + x3) / 2;
992   int x1 = xc - horz_line_ofs;
993   int x2 = xc + horz_line_ofs;
994
995   bool shorten_x1_lines = start_of_line == RENDER_LINE_DOUBLE;
996   bool shorten_x2_lines = end_of_line == RENDER_LINE_DOUBLE;
997   bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
998   int vert_line_ofs = double_horz ? double_line_ofs : 0;
999   int yc = (y0 + y3) / 2;
1000   int y1 = yc - vert_line_ofs;
1001   int y2 = yc + vert_line_ofs;
1002
1003   if (!double_horz)
1004     horz_line (xr, x0, x1, x2, x3, yc, start_of_line, end_of_line,
1005                start_color, end_color, shorten_yc_line);
1006   else
1007     {
1008       horz_line (xr, x0, x1, x2, x3, y1, start_of_line, end_of_line,
1009                  start_color, end_color, shorten_y1_lines);
1010       horz_line (xr, x0, x1, x2, x3, y2, start_of_line, end_of_line,
1011                  start_color, end_color, shorten_y2_lines);
1012     }
1013
1014   if (!double_vert)
1015     vert_line (xr, y0, y1, y2, y3, xc, top, bottom, top_color, bottom_color,
1016                shorten_xc_line);
1017   else
1018     {
1019       vert_line (xr, y0, y1, y2, y3, x1, top, bottom, top_color, bottom_color,
1020                  shorten_x1_lines);
1021       vert_line (xr, y0, y1, y2, y3, x2, top, bottom, top_color, bottom_color,
1022                  shorten_x2_lines);
1023     }
1024 }
1025
1026 static void
1027 xr_measure_cell_width (void *xr_, const struct table_cell *cell,
1028                        int *min_width, int *max_width)
1029 {
1030   struct xr_driver *xr = xr_;
1031   int bb[TABLE_N_AXES][2];
1032   int clip[TABLE_N_AXES][2];
1033   int h;
1034
1035   bb[H][0] = 0;
1036   bb[H][1] = INT_MAX;
1037   bb[V][0] = 0;
1038   bb[V][1] = INT_MAX;
1039   clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
1040   xr_layout_cell (xr, cell, bb, clip, max_width, &h, NULL);
1041
1042   bb[H][1] = 1;
1043   xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL);
1044
1045   if (*min_width > 0)
1046     *min_width += px_to_xr (cell->style->cell_style.margin[H][0]
1047                             + cell->style->cell_style.margin[H][1]);
1048   if (*max_width > 0)
1049     *max_width += px_to_xr (cell->style->cell_style.margin[H][0]
1050                             + cell->style->cell_style.margin[H][1]);
1051 }
1052
1053 static int
1054 xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width)
1055 {
1056   struct xr_driver *xr = xr_;
1057   int bb[TABLE_N_AXES][2];
1058   int clip[TABLE_N_AXES][2];
1059   int w, h;
1060
1061   bb[H][0] = 0;
1062   bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0]
1063                                + cell->style->cell_style.margin[H][1]);
1064   bb[V][0] = 0;
1065   bb[V][1] = INT_MAX;
1066   clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
1067   xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL);
1068   h += px_to_xr (cell->style->cell_style.margin[V][0]
1069                  + cell->style->cell_style.margin[V][1]);
1070   return h;
1071 }
1072
1073 static void xr_clip (struct xr_driver *, int clip[TABLE_N_AXES][2]);
1074
1075 static void
1076 xr_draw_cell (void *xr_, const struct table_cell *cell, int color_idx,
1077               int bb[TABLE_N_AXES][2], int valign_offset,
1078               int spill[TABLE_N_AXES][2],
1079               int clip[TABLE_N_AXES][2])
1080 {
1081   struct xr_driver *xr = xr_;
1082   int w, h, brk;
1083
1084   if (!xr->transparent)
1085     {
1086       cairo_save (xr->cairo);
1087       int bg_clip[TABLE_N_AXES][2];
1088       for (int axis = 0; axis < TABLE_N_AXES; axis++)
1089         {
1090           bg_clip[axis][0] = clip[axis][0];
1091           if (bb[axis][0] == clip[axis][0])
1092             bg_clip[axis][0] -= spill[axis][0];
1093
1094           bg_clip[axis][1] = clip[axis][1];
1095           if (bb[axis][1] == clip[axis][1])
1096             bg_clip[axis][1] += spill[axis][1];
1097         }
1098       xr_clip (xr, bg_clip);
1099       set_source_rgba (xr->cairo, &cell->style->font_style.bg[color_idx]);
1100       fill_rectangle (xr,
1101                       bb[H][0] - spill[H][0],
1102                       bb[V][0] - spill[V][0],
1103                       bb[H][1] + spill[H][1],
1104                       bb[V][1] + spill[V][1]);
1105       cairo_restore (xr->cairo);
1106     }
1107   cairo_save (xr->cairo);
1108   if (!xr->systemcolors)
1109     set_source_rgba (xr->cairo, &cell->style->font_style.fg[color_idx]);
1110
1111   bb[V][0] += valign_offset;
1112
1113   for (int axis = 0; axis < TABLE_N_AXES; axis++)
1114     {
1115       bb[axis][0] += px_to_xr (cell->style->cell_style.margin[axis][0]);
1116       bb[axis][1] -= px_to_xr (cell->style->cell_style.margin[axis][1]);
1117     }
1118   if (bb[H][0] < bb[H][1] && bb[V][0] < bb[V][1])
1119     xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
1120   cairo_restore (xr->cairo);
1121 }
1122
1123 static int
1124 xr_adjust_break (void *xr_, const struct table_cell *cell,
1125                  int width, int height)
1126 {
1127   struct xr_driver *xr = xr_;
1128   int bb[TABLE_N_AXES][2];
1129   int clip[TABLE_N_AXES][2];
1130   int w, h, brk;
1131
1132   if (xr_measure_cell_height (xr_, cell, width) < height)
1133     return -1;
1134
1135   bb[H][0] = 0;
1136   bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0]
1137                                + cell->style->cell_style.margin[H][1]);
1138   if (bb[H][1] <= 0)
1139     return 0;
1140   bb[V][0] = 0;
1141   bb[V][1] = height - px_to_xr (cell->style->cell_style.margin[V][0]
1142                                 + cell->style->cell_style.margin[V][1]);
1143   clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
1144   xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
1145   return brk;
1146 }
1147 \f
1148 static void
1149 xr_clip (struct xr_driver *xr, int clip[TABLE_N_AXES][2])
1150 {
1151   if (clip[H][1] != INT_MAX || clip[V][1] != INT_MAX)
1152     {
1153       double x0 = xr_to_pt (clip[H][0]);
1154       double y0 = xr_to_pt (clip[V][0] + xr->y);
1155       double x1 = xr_to_pt (clip[H][1]);
1156       double y1 = xr_to_pt (clip[V][1] + xr->y);
1157
1158       cairo_rectangle (xr->cairo, x0, y0, x1 - x0, y1 - y0);
1159       cairo_clip (xr->cairo);
1160     }
1161 }
1162
1163 static void
1164 add_attr (PangoAttrList *list, PangoAttribute *attr,
1165           guint start_index, guint end_index)
1166 {
1167   attr->start_index = start_index;
1168   attr->end_index = end_index;
1169   pango_attr_list_insert (list, attr);
1170 }
1171
1172 static void
1173 markup_escape (struct string *out, unsigned int options,
1174                const char *in, size_t len)
1175 {
1176   if (!(options & TAB_MARKUP))
1177     {
1178       ds_put_substring (out, ss_buffer (in, len == -1 ? strlen (in) : len));
1179       return;
1180     }
1181
1182   while (len-- > 0)
1183     {
1184       int c = *in++;
1185       switch (c)
1186         {
1187         case 0:
1188           return;
1189         case '&':
1190           ds_put_cstr (out, "&amp;");
1191           break;
1192         case '<':
1193           ds_put_cstr (out, "&lt;");
1194           break;
1195         case '>':
1196           ds_put_cstr (out, "&gt;");
1197           break;
1198         default:
1199           ds_put_byte (out, c);
1200           break;
1201         }
1202     }
1203 }
1204
1205 static int
1206 get_layout_dimension (PangoLayout *layout, enum table_axis axis)
1207 {
1208   int size[TABLE_N_AXES];
1209   pango_layout_get_size (layout, &size[H], &size[V]);
1210   return size[axis];
1211 }
1212
1213 static int
1214 xr_layout_cell_text (struct xr_driver *xr, const struct table_cell *cell,
1215                      int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
1216                      int *widthp, int *brk)
1217 {
1218   const struct font_style *font_style = &cell->style->font_style;
1219   const struct cell_style *cell_style = &cell->style->cell_style;
1220   unsigned int options = cell->options;
1221
1222   enum table_axis X = options & TAB_ROTATE ? V : H;
1223   enum table_axis Y = !X;
1224   int R = options & TAB_ROTATE ? 0 : 1;
1225
1226   struct xr_font *font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED]
1227                           : &xr->fonts[XR_FONT_PROPORTIONAL]);
1228   struct xr_font local_font;
1229   if (font_style->typeface)
1230     {
1231       PangoFontDescription *desc = parse_font (
1232         font_style->typeface,
1233         font_style->size ? font_style->size * 1000 * xr->font_scale : 10000,
1234         font_style->bold, font_style->italic);
1235       if (desc)
1236         {
1237           PangoLayout *layout = pango_cairo_create_layout (xr->cairo);
1238           pango_layout_set_font_description (layout, desc);
1239
1240           local_font.desc = desc;
1241           local_font.layout = layout;
1242           font = &local_font;
1243         }
1244     }
1245
1246   const char *text = cell->text;
1247   enum table_halign halign = table_halign_interpret (
1248     cell_style->halign, cell->options & TAB_NUMERIC);
1249   if (cell_style->halign == TABLE_HALIGN_DECIMAL && !(options & TAB_ROTATE))
1250     {
1251       int margin_adjustment = -px_to_xr (cell_style->decimal_offset);
1252
1253       const char *decimal = strrchr (text, cell_style->decimal_char);
1254       if (decimal)
1255         {
1256           pango_layout_set_text (font->layout, decimal, strlen (decimal));
1257           pango_layout_set_width (font->layout, -1);
1258           margin_adjustment += get_layout_dimension (font->layout, H);
1259         }
1260
1261       if (margin_adjustment < 0)
1262         bb[H][1] += margin_adjustment;
1263     }
1264
1265   struct string tmp = DS_EMPTY_INITIALIZER;
1266   PangoAttrList *attrs = NULL;
1267
1268   /* Deal with an oddity of the Unicode line-breaking algorithm (or perhaps in
1269      Pango's implementation of it): it will break after a period or a comma
1270      that precedes a digit, e.g. in ".000" it will break after the period.
1271      This code looks for such a situation and inserts a U+2060 WORD JOINER
1272      to prevent the break.
1273
1274      This isn't necessary when the decimal point is between two digits
1275      (e.g. "0.000" won't be broken) or when the display width is not limited so
1276      that word wrapping won't happen.
1277
1278      It isn't necessary to look for more than one period or comma, as would
1279      happen with grouping like 1,234,567.89 or 1.234.567,89 because if groups
1280      are present then there will always be a digit on both sides of every
1281      period and comma. */
1282   if (options & TAB_MARKUP)
1283     {
1284       PangoAttrList *new_attrs;
1285       char *new_text;
1286       if (pango_parse_markup (text, -1, 0, &new_attrs, &new_text, NULL, NULL))
1287         {
1288           attrs = new_attrs;
1289           tmp.ss = ss_cstr (new_text);
1290           tmp.capacity = tmp.ss.length;
1291         }
1292       else
1293         {
1294           /* XXX should we report the error? */
1295           ds_put_cstr (&tmp, text);
1296         }
1297     }
1298   else if (options & TAB_ROTATE || bb[H][1] != INT_MAX)
1299     {
1300       const char *decimal = text + strcspn (text, ".,");
1301       if (decimal[0]
1302           && c_isdigit (decimal[1])
1303           && (decimal == text || !c_isdigit (decimal[-1])))
1304         {
1305           ds_extend (&tmp, strlen (text) + 16);
1306           markup_escape (&tmp, options, text, decimal - text + 1);
1307           ds_put_unichar (&tmp, 0x2060 /* U+2060 WORD JOINER */);
1308           markup_escape (&tmp, options, decimal + 1, -1);
1309         }
1310     }
1311
1312   if (font_style->underline)
1313     {
1314       if (!attrs)
1315         attrs = pango_attr_list_new ();
1316       pango_attr_list_insert (attrs, pango_attr_underline_new (
1317                                 PANGO_UNDERLINE_SINGLE));
1318     }
1319
1320   if (cell->n_footnotes || cell->n_subscripts || cell->superscript)
1321     {
1322       /* If we haven't already put TEXT into tmp, do it now. */
1323       if (ds_is_empty (&tmp))
1324         {
1325           ds_extend (&tmp, strlen (text) + 16);
1326           markup_escape (&tmp, options, text, -1);
1327         }
1328
1329       size_t subscript_ofs = ds_length (&tmp);
1330       for (size_t i = 0; i < cell->n_subscripts; i++)
1331         {
1332           if (i)
1333             ds_put_byte (&tmp, ',');
1334           ds_put_cstr (&tmp, cell->subscripts[i]);
1335         }
1336
1337       size_t superscript_ofs = ds_length (&tmp);
1338       if (cell->superscript)
1339         ds_put_cstr (&tmp, cell->superscript);
1340
1341       size_t footnote_ofs = ds_length (&tmp);
1342       for (size_t i = 0; i < cell->n_footnotes; i++)
1343         {
1344           if (i)
1345             ds_put_byte (&tmp, ',');
1346           ds_put_cstr (&tmp, cell->footnotes[i]->marker);
1347         }
1348
1349       /* Allow footnote markers to occupy the right margin.  That way, numbers
1350          in the column are still aligned. */
1351       if (cell->n_footnotes && halign == TABLE_HALIGN_RIGHT)
1352         {
1353           /* Measure the width of the footnote marker, so we know how much we
1354              need to make room for. */
1355           pango_layout_set_text (font->layout, ds_cstr (&tmp) + footnote_ofs,
1356                                  ds_length (&tmp) - footnote_ofs);
1357
1358           PangoAttrList *fn_attrs = pango_attr_list_new ();
1359           pango_attr_list_insert (
1360             fn_attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
1361           pango_attr_list_insert (fn_attrs, pango_attr_rise_new (3000));
1362           pango_layout_set_attributes (font->layout, fn_attrs);
1363           pango_attr_list_unref (fn_attrs);
1364           int footnote_width = get_layout_dimension (font->layout, X);
1365
1366           /* Bound the adjustment by the width of the right margin. */
1367           int right_margin = px_to_xr (cell_style->margin[X][R]);
1368           int footnote_adjustment = MIN (footnote_width, right_margin);
1369
1370           /* Adjust the bounding box. */
1371           if (options & TAB_ROTATE)
1372             footnote_adjustment = -footnote_adjustment;
1373           bb[X][R] += footnote_adjustment;
1374
1375           /* Clean up. */
1376           pango_layout_set_attributes (font->layout, NULL);
1377         }
1378
1379       /* Set attributes. */
1380       if (!attrs)
1381         attrs = pango_attr_list_new ();
1382       add_attr (attrs, pango_attr_font_desc_new (font->desc), subscript_ofs,
1383                 PANGO_ATTR_INDEX_TO_TEXT_END);
1384       add_attr (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL),
1385                 subscript_ofs, PANGO_ATTR_INDEX_TO_TEXT_END);
1386       if (cell->n_subscripts)
1387         add_attr (attrs, pango_attr_rise_new (-3000), subscript_ofs,
1388                   superscript_ofs - subscript_ofs);
1389       if (cell->superscript || cell->n_footnotes)
1390         add_attr (attrs, pango_attr_rise_new (3000), superscript_ofs,
1391                   PANGO_ATTR_INDEX_TO_TEXT_END);
1392     }
1393
1394   /* Set the attributes, if any. */
1395   if (attrs)
1396     {
1397       pango_layout_set_attributes (font->layout, attrs);
1398       pango_attr_list_unref (attrs);
1399     }
1400
1401   /* Set the text. */
1402   if (ds_is_empty (&tmp))
1403     pango_layout_set_text (font->layout, text, -1);
1404   else
1405     pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
1406   ds_destroy (&tmp);
1407
1408   pango_layout_set_alignment (font->layout,
1409                               (halign == TABLE_HALIGN_RIGHT ? PANGO_ALIGN_RIGHT
1410                                : halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
1411                                : PANGO_ALIGN_CENTER));
1412   pango_layout_set_width (
1413     font->layout,
1414     bb[X][1] == INT_MAX ? -1 : xr_to_pango (bb[X][1] - bb[X][0]));
1415   pango_layout_set_wrap (font->layout, PANGO_WRAP_WORD);
1416
1417   if (clip[H][0] != clip[H][1])
1418     {
1419       cairo_save (xr->cairo);
1420       if (!(options & TAB_ROTATE))
1421         xr_clip (xr, clip);
1422       if (options & TAB_ROTATE)
1423         {
1424           cairo_translate (xr->cairo,
1425                            xr_to_pt (bb[H][0]),
1426                            xr_to_pt (bb[V][1] + xr->y));
1427           cairo_rotate (xr->cairo, -M_PI_2);
1428         }
1429       else
1430         cairo_translate (xr->cairo,
1431                          xr_to_pt (bb[H][0]),
1432                          xr_to_pt (bb[V][0] + xr->y));
1433       pango_cairo_show_layout (xr->cairo, font->layout);
1434
1435       /* If enabled, this draws a blue rectangle around the extents of each
1436          line of text, which can be rather useful for debugging layout
1437          issues. */
1438       if (0)
1439         {
1440           PangoLayoutIter *iter;
1441           iter = pango_layout_get_iter (font->layout);
1442           do
1443             {
1444               PangoRectangle extents;
1445
1446               pango_layout_iter_get_line_extents (iter, &extents, NULL);
1447               cairo_save (xr->cairo);
1448               cairo_set_source_rgb (xr->cairo, 1, 0, 0);
1449               dump_rectangle (xr,
1450                               pango_to_xr (extents.x),
1451                               pango_to_xr (extents.y) - xr->y,
1452                               pango_to_xr (extents.x + extents.width),
1453                               pango_to_xr (extents.y + extents.height) - xr->y);
1454               cairo_restore (xr->cairo);
1455             }
1456           while (pango_layout_iter_next_line (iter));
1457           pango_layout_iter_free (iter);
1458         }
1459
1460       cairo_restore (xr->cairo);
1461     }
1462
1463   int size[TABLE_N_AXES];
1464   pango_layout_get_size (font->layout, &size[H], &size[V]);
1465   int w = pango_to_xr (size[X]);
1466   int h = pango_to_xr (size[Y]);
1467   if (w > *widthp)
1468     *widthp = w;
1469   if (bb[V][0] + h >= bb[V][1] && !(options & TAB_ROTATE))
1470     {
1471       PangoLayoutIter *iter;
1472       int best = 0;
1473
1474       /* Choose a breakpoint between lines instead of in the middle of one. */
1475       iter = pango_layout_get_iter (font->layout);
1476       do
1477         {
1478           PangoRectangle extents;
1479           int y0, y1;
1480           int bottom;
1481
1482           pango_layout_iter_get_line_extents (iter, NULL, &extents);
1483           pango_layout_iter_get_line_yrange (iter, &y0, &y1);
1484           extents.x = pango_to_xr (extents.x);
1485           extents.y = pango_to_xr (y0);
1486           extents.width = pango_to_xr (extents.width);
1487           extents.height = pango_to_xr (y1 - y0);
1488           bottom = bb[V][0] + extents.y + extents.height;
1489           if (bottom < bb[V][1])
1490             {
1491               if (brk && clip[H][0] != clip[H][1])
1492                 best = bottom;
1493               if (brk)
1494                 *brk = bottom;
1495             }
1496           else
1497             break;
1498         }
1499       while (pango_layout_iter_next_line (iter));
1500       pango_layout_iter_free (iter);
1501
1502       /* If enabled, draws a green line across the chosen breakpoint, which can
1503          be useful for debugging issues with breaking.  */
1504       if (0)
1505         {
1506           if (best)
1507             dump_line (xr, -xr->left_margin, best,
1508                        xr->width + xr->right_margin, best,
1509                        RENDER_LINE_SINGLE,
1510                        &(struct cell_color) CELL_COLOR (0, 255, 0));
1511         }
1512     }
1513
1514   pango_layout_set_attributes (font->layout, NULL);
1515
1516   if (font == &local_font)
1517     {
1518       g_object_unref (G_OBJECT (font->layout));
1519       pango_font_description_free (font->desc);
1520     }
1521
1522   return h;
1523 }
1524
1525 static void
1526 xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell,
1527                 int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
1528                 int *width, int *height, int *brk)
1529 {
1530   *width = 0;
1531   *height = 0;
1532
1533   /* If enabled, draws a blue rectangle around the cell extents, which can be
1534      useful for debugging layout. */
1535   if (0)
1536     {
1537       if (clip[H][0] != clip[H][1])
1538         {
1539           cairo_save (xr->cairo);
1540           cairo_set_source_rgb (xr->cairo, 0, 0, 1);
1541           dump_rectangle (xr, bb[H][0], bb[V][0], bb[H][1], bb[V][1]);
1542           cairo_restore (xr->cairo);
1543         }
1544     }
1545
1546   if (brk)
1547     *brk = bb[V][0];
1548   *height = xr_layout_cell_text (xr, cell, bb, clip, width, brk);
1549 }
1550 \f
1551 struct output_driver_factory pdf_driver_factory =
1552   { "pdf", "pspp.pdf", xr_pdf_create };
1553 struct output_driver_factory ps_driver_factory =
1554   { "ps", "pspp.ps", xr_ps_create };
1555 struct output_driver_factory svg_driver_factory =
1556   { "svg", "pspp.svg", xr_svg_create };
1557
1558 static const struct output_driver_class cairo_driver_class =
1559 {
1560   "cairo",
1561   xr_destroy,
1562   xr_submit,
1563   xr_flush,
1564 };
1565 \f
1566 /* GUI rendering helpers. */
1567
1568 struct xr_rendering
1569   {
1570     struct output_item *item;
1571
1572     /* Table items. */
1573     struct render_pager *p;
1574     struct xr_driver *xr;
1575   };
1576
1577 #define CHART_WIDTH 500
1578 #define CHART_HEIGHT 375
1579
1580
1581
1582 struct xr_driver *
1583 xr_driver_create (cairo_t *cairo, struct string_map *options)
1584 {
1585   struct xr_driver *xr = xr_allocate ("cairo", 0, options, 1.0);
1586   xr_set_cairo (xr, cairo);
1587   return xr;
1588 }
1589
1590 /* Destroy XR, which should have been created with xr_driver_create().  Any
1591    cairo_t added to XR is not destroyed, because it is owned by the client. */
1592 void
1593 xr_driver_destroy (struct xr_driver *xr)
1594 {
1595   if (xr != NULL)
1596     {
1597       xr->cairo = NULL;
1598       output_driver_destroy (&xr->driver);
1599     }
1600 }
1601
1602 static struct xr_rendering *
1603 xr_rendering_create_text (struct xr_driver *xr, const char *text, cairo_t *cr)
1604 {
1605   struct table_item *table_item;
1606   struct xr_rendering *r;
1607
1608   table_item = table_item_create (table_from_string (text), NULL, NULL);
1609   r = xr_rendering_create (xr, &table_item->output_item, cr);
1610   table_item_unref (table_item);
1611
1612   return r;
1613 }
1614
1615 struct xr_rendering *
1616 xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
1617                      cairo_t *cr)
1618 {
1619   struct xr_rendering *r = NULL;
1620
1621   if (is_text_item (item))
1622     r = xr_rendering_create_text (xr, text_item_get_text (to_text_item (item)),
1623                                   cr);
1624   else if (is_message_item (item))
1625     {
1626       const struct message_item *message_item = to_message_item (item);
1627       char *s = msg_to_string (message_item_get_msg (message_item));
1628       r = xr_rendering_create_text (xr, s, cr);
1629       free (s);
1630     }
1631   else if (is_table_item (item))
1632     {
1633       r = xzalloc (sizeof *r);
1634       r->item = output_item_ref (item);
1635       r->xr = xr;
1636       xr_set_cairo (xr, cr);
1637       r->p = render_pager_create (xr->params, to_table_item (item));
1638     }
1639   else if (is_chart_item (item))
1640     {
1641       r = xzalloc (sizeof *r);
1642       r->item = output_item_ref (item);
1643     }
1644   else if (is_group_open_item (item))
1645     r = xr_rendering_create_text (xr, to_group_open_item (item)->command_name,
1646                                   cr);
1647
1648   return r;
1649 }
1650
1651 void
1652 xr_rendering_destroy (struct xr_rendering *r)
1653 {
1654   if (r)
1655     {
1656       output_item_unref (r->item);
1657       render_pager_destroy (r->p);
1658       free (r);
1659     }
1660 }
1661
1662 void
1663 xr_rendering_measure (const struct xr_rendering *r, int *wp, int *hp)
1664 {
1665   int w, h;
1666
1667   if (is_table_item (r->item))
1668     {
1669       w = render_pager_get_size (r->p, H) / XR_POINT;
1670       h = render_pager_get_size (r->p, V) / XR_POINT;
1671     }
1672   else
1673     {
1674       w = CHART_WIDTH;
1675       h = CHART_HEIGHT;
1676     }
1677
1678   if (wp)
1679     *wp = w;
1680   if (hp)
1681     *hp = h;
1682 }
1683
1684 static void xr_draw_chart (const struct chart_item *, cairo_t *,
1685                     double x, double y, double width, double height);
1686
1687 /* Draws onto CR */
1688 void
1689 xr_rendering_draw (struct xr_rendering *r, cairo_t *cr,
1690                    int x0, int y0, int x1, int y1)
1691 {
1692   if (is_table_item (r->item))
1693     {
1694       struct xr_driver *xr = r->xr;
1695
1696       xr_set_cairo (xr, cr);
1697
1698       render_pager_draw_region (r->p, x0 * XR_POINT, y0 * XR_POINT,
1699                                 (x1 - x0) * XR_POINT, (y1 - y0) * XR_POINT);
1700     }
1701   else
1702     xr_draw_chart (to_chart_item (r->item), cr,
1703                    0, 0, CHART_WIDTH, CHART_HEIGHT);
1704 }
1705
1706 static void
1707 xr_draw_chart (const struct chart_item *chart_item, cairo_t *cr,
1708                double x, double y, double width, double height)
1709 {
1710   struct xrchart_geometry geom;
1711
1712   cairo_save (cr);
1713   cairo_translate (cr, x, y + height);
1714   cairo_scale (cr, 1.0, -1.0);
1715   xrchart_geometry_init (cr, &geom, width, height);
1716   if (is_boxplot (chart_item))
1717     xrchart_draw_boxplot (chart_item, cr, &geom);
1718   else if (is_histogram_chart (chart_item))
1719     xrchart_draw_histogram (chart_item, cr, &geom);
1720   else if (is_np_plot_chart (chart_item))
1721     xrchart_draw_np_plot (chart_item, cr, &geom);
1722   else if (is_piechart (chart_item))
1723     xrchart_draw_piechart (chart_item, cr, &geom);
1724   else if (is_barchart (chart_item))
1725     xrchart_draw_barchart (chart_item, cr, &geom);
1726   else if (is_roc_chart (chart_item))
1727     xrchart_draw_roc (chart_item, cr, &geom);
1728   else if (is_scree (chart_item))
1729     xrchart_draw_scree (chart_item, cr, &geom);
1730   else if (is_spreadlevel_plot_chart (chart_item))
1731     xrchart_draw_spreadlevel (chart_item, cr, &geom);
1732   else if (is_scatterplot_chart (chart_item))
1733     xrchart_draw_scatterplot (chart_item, cr, &geom);
1734   else
1735     NOT_REACHED ();
1736   xrchart_geometry_free (cr, &geom);
1737
1738   cairo_restore (cr);
1739 }
1740
1741 char *
1742 xr_draw_png_chart (const struct chart_item *item,
1743                    const char *file_name_template, int number,
1744                    const struct cell_color *fg,
1745                    const struct cell_color *bg)
1746 {
1747   const int width = 640;
1748   const int length = 480;
1749
1750   cairo_surface_t *surface;
1751   cairo_status_t status;
1752   const char *number_pos;
1753   char *file_name;
1754   cairo_t *cr;
1755
1756   number_pos = strchr (file_name_template, '#');
1757   if (number_pos != NULL)
1758     file_name = xasprintf ("%.*s%d%s.png", (int) (number_pos - file_name_template),
1759                            file_name_template, number, number_pos + 1);
1760   else
1761     file_name = xasprintf ("%s.png", file_name_template);
1762
1763   surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
1764   cr = cairo_create (surface);
1765
1766   cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
1767   cairo_paint (cr);
1768
1769   cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
1770
1771   xr_draw_chart (item, cr, 0.0, 0.0, width, length);
1772
1773   status = cairo_surface_write_to_png (surface, file_name);
1774   if (status != CAIRO_STATUS_SUCCESS)
1775     msg (ME, _("error writing output file `%s': %s"),
1776            file_name, cairo_status_to_string (status));
1777
1778   cairo_destroy (cr);
1779   cairo_surface_destroy (surface);
1780
1781   return file_name;
1782 }
1783
1784
1785 char *
1786 xr_draw_eps_chart (const struct chart_item *item,
1787                    const char *file_name_template, int number,
1788                    const struct cell_color *fg,
1789                    const struct cell_color *bg)
1790 {
1791   const int width = 640;
1792   const int length = 480;
1793
1794   cairo_surface_t *surface;
1795   const char *number_pos;
1796   char *file_name;
1797   cairo_t *cr;
1798
1799   number_pos = strchr (file_name_template, '#');
1800   if (number_pos != NULL)
1801     file_name = xasprintf ("%.*s%d%s.eps", (int) (number_pos - file_name_template),
1802                            file_name_template, number, number_pos + 1);
1803   else
1804     file_name = xasprintf ("%s.eps", file_name_template);
1805
1806   surface = cairo_ps_surface_create (file_name, width, length);
1807   cairo_ps_surface_set_eps (surface, true);
1808   cr = cairo_create (surface);
1809
1810   cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
1811   cairo_paint (cr);
1812
1813   cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
1814
1815   xr_draw_chart (item, cr, 0.0, 0.0, width, length);
1816
1817   cairo_destroy (cr);
1818   cairo_surface_destroy (surface);
1819
1820   return file_name;
1821 }
1822
1823 \f
1824
1825 struct xr_table_state
1826   {
1827     struct xr_render_fsm fsm;
1828     struct render_pager *p;
1829   };
1830
1831 static bool
1832 xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr)
1833 {
1834   struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm);
1835
1836   while (render_pager_has_next (ts->p))
1837     {
1838       int used;
1839
1840       used = render_pager_draw_next (ts->p, xr->length - xr->y);
1841       if (!used)
1842         {
1843           assert (xr->y > 0);
1844           return true;
1845         }
1846       else
1847         xr->y += used;
1848     }
1849   return false;
1850 }
1851
1852 static void
1853 xr_table_destroy (struct xr_render_fsm *fsm)
1854 {
1855   struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm);
1856
1857   render_pager_destroy (ts->p);
1858   free (ts);
1859 }
1860
1861 static struct xr_render_fsm *
1862 xr_render_table (struct xr_driver *xr, struct table_item *table_item)
1863 {
1864   struct xr_table_state *ts;
1865
1866   ts = xmalloc (sizeof *ts);
1867   ts->fsm.render = xr_table_render;
1868   ts->fsm.destroy = xr_table_destroy;
1869
1870   if (xr->y > 0)
1871     xr->y += xr->char_height;
1872
1873   ts->p = render_pager_create (xr->params, table_item);
1874   table_item_unref (table_item);
1875
1876   return &ts->fsm;
1877 }
1878 \f
1879 struct xr_chart_state
1880   {
1881     struct xr_render_fsm fsm;
1882     struct chart_item *chart_item;
1883   };
1884
1885 static bool
1886 xr_chart_render (struct xr_render_fsm *fsm, struct xr_driver *xr)
1887 {
1888   struct xr_chart_state *cs = UP_CAST (fsm, struct xr_chart_state, fsm);
1889
1890   const int chart_height = 0.8 * (xr->length < xr->width ? xr->length : xr->width);
1891
1892   if (xr->y > xr->length - chart_height)
1893     return true;
1894
1895   if (xr->cairo != NULL)
1896     {
1897       xr_draw_chart (cs->chart_item, xr->cairo,
1898                      0.0,
1899                      xr_to_pt (xr->y),
1900                      xr_to_pt (xr->width),
1901                      xr_to_pt (chart_height));
1902     }
1903   xr->y += chart_height;
1904
1905   return false;
1906 }
1907
1908 static void
1909 xr_chart_destroy (struct xr_render_fsm *fsm)
1910 {
1911   struct xr_chart_state *cs = UP_CAST (fsm, struct xr_chart_state, fsm);
1912
1913   chart_item_unref (cs->chart_item);
1914   free (cs);
1915 }
1916
1917 static struct xr_render_fsm *
1918 xr_render_chart (const struct chart_item *chart_item)
1919 {
1920   struct xr_chart_state *cs;
1921
1922   cs = xmalloc (sizeof *cs);
1923   cs->fsm.render = xr_chart_render;
1924   cs->fsm.destroy = xr_chart_destroy;
1925   cs->chart_item = chart_item_ref (chart_item);
1926
1927   return &cs->fsm;
1928 }
1929 \f
1930 static bool
1931 xr_eject_render (struct xr_render_fsm *fsm UNUSED, struct xr_driver *xr)
1932 {
1933   return xr->y > 0;
1934 }
1935
1936 static void
1937 xr_eject_destroy (struct xr_render_fsm *fsm UNUSED)
1938 {
1939   /* Nothing to do. */
1940 }
1941
1942 static struct xr_render_fsm *
1943 xr_render_eject (void)
1944 {
1945   static struct xr_render_fsm eject_renderer =
1946     {
1947       xr_eject_render,
1948       xr_eject_destroy
1949     };
1950
1951   return &eject_renderer;
1952 }
1953 \f
1954 static struct xr_render_fsm *
1955 xr_render_text (struct xr_driver *xr, const struct text_item *text_item)
1956 {
1957   enum text_item_type type = text_item_get_type (text_item);
1958
1959   switch (type)
1960     {
1961     case TEXT_ITEM_PAGE_TITLE:
1962       break;
1963
1964     case TEXT_ITEM_EJECT_PAGE:
1965       if (xr->y > 0)
1966         return xr_render_eject ();
1967       break;
1968
1969     default:
1970       return xr_render_table (
1971         xr, text_item_to_table_item (text_item_ref (text_item)));
1972     }
1973
1974   return NULL;
1975 }
1976
1977 static struct xr_render_fsm *
1978 xr_render_message (struct xr_driver *xr,
1979                    const struct message_item *message_item)
1980 {
1981   char *s = msg_to_string (message_item_get_msg (message_item));
1982   struct text_item *item = text_item_create (TEXT_ITEM_LOG, s);
1983   free (s);
1984   return xr_render_table (xr, text_item_to_table_item (item));
1985 }
1986
1987 static struct xr_render_fsm *
1988 xr_render_output_item (struct xr_driver *xr,
1989                        const struct output_item *output_item)
1990 {
1991   if (is_table_item (output_item))
1992     return xr_render_table (xr, table_item_ref (to_table_item (output_item)));
1993   else if (is_chart_item (output_item))
1994     return xr_render_chart (to_chart_item (output_item));
1995   else if (is_text_item (output_item))
1996     return xr_render_text (xr, to_text_item (output_item));
1997   else if (is_message_item (output_item))
1998     return xr_render_message (xr, to_message_item (output_item));
1999   else
2000     return NULL;
2001 }
2002
2003 bool
2004 xr_draw_svg_file (struct xr_rendering *r,
2005                   const char *filename)
2006 {
2007   int width, height;
2008   g_assert (r);
2009   xr_rendering_measure (r, &width, &height);
2010   cairo_surface_t *surface = cairo_svg_surface_create (filename, width, height);
2011   if (!surface)
2012     {
2013       g_error ("Could not create cairo svg surface with file %s", filename);
2014       return FALSE;
2015     }
2016   cairo_t *cr = cairo_create (surface);
2017   xr_rendering_draw (r, cr, 0, 0, width, height);
2018   cairo_destroy (cr);
2019   cairo_surface_destroy (surface);
2020   return TRUE;
2021 }