cairo: Use pango_cairo_context_set_resolution() to get font sizes correct.
[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/cairo-fsm.h"
33 #include "output/chart-item-provider.h"
34 #include "output/driver-provider.h"
35 #include "output/group-item.h"
36 #include "output/message-item.h"
37 #include "output/options.h"
38 #include "output/page-eject-item.h"
39 #include "output/page-setup-item.h"
40 #include "output/render.h"
41 #include "output/table-item.h"
42 #include "output/table.h"
43 #include "output/text-item.h"
44
45 #include <cairo/cairo-pdf.h>
46 #include <cairo/cairo-ps.h>
47 #include <cairo/cairo-svg.h>
48
49 #include <cairo/cairo.h>
50 #include <inttypes.h>
51 #include <math.h>
52 #include <pango/pango-font.h>
53 #include <pango/pango-layout.h>
54 #include <pango/pango.h>
55 #include <pango/pangocairo.h>
56 #include <stdlib.h>
57
58 #include "gl/c-ctype.h"
59 #include "gl/c-strcase.h"
60 #include "gl/intprops.h"
61 #include "gl/minmax.h"
62 #include "gl/xalloc.h"
63
64 #include "gettext.h"
65 #define _(msgid) gettext (msgid)
66
67 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
68 #define H TABLE_HORZ
69 #define V TABLE_VERT
70
71 /* The unit used for internal measurements is inch/(72 * XR_POINT).
72    (Thus, XR_POINT units represent one point.) */
73 #define XR_POINT PANGO_SCALE
74
75 /* Conversions to and from points. */
76 static double
77 xr_to_pt (int x)
78 {
79   return x / (double) XR_POINT;
80 }
81
82 /* Dimensions for drawing lines in tables. */
83 #define XR_LINE_WIDTH (XR_POINT / 2) /* Width of an ordinary line. */
84 #define XR_LINE_SPACE XR_POINT       /* Space between double lines. */
85
86 /* Output types. */
87 enum xr_output_type
88   {
89     XR_PDF,
90     XR_PS,
91     XR_SVG
92   };
93
94 /* Cairo output driver. */
95 struct xr_driver
96   {
97     struct output_driver driver;
98
99     /* User parameters. */
100     PangoFontDescription *fonts[XR_N_FONTS];
101
102     /* Measurements all in inch/(72 * XR_POINT). */
103     int size[TABLE_N_AXES];     /* Page size with margins subtracted. */
104     int margins[TABLE_N_AXES][2]; /* Margins. */
105     int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */
106     int object_spacing;         /* Space between output objects. */
107
108     struct cell_color bg;       /* Background color */
109     struct cell_color fg;       /* Foreground color */
110     bool transparent;           /* true -> do not render background */
111     bool systemcolors;          /* true -> do not change colors     */
112
113     int initial_page_number;
114
115     struct page_heading headings[2]; /* Top and bottom headings. */
116     int headings_height[2];
117
118     /* Internal state. */
119     struct xr_fsm_style *style;
120     int char_width, char_height;
121     cairo_t *cairo;
122     cairo_surface_t *surface;
123     int page_number;            /* Current page number. */
124     int y;
125     struct xr_fsm *fsm;
126   };
127
128 static const struct output_driver_class cairo_driver_class;
129
130 static void xr_driver_destroy_fsm (struct xr_driver *);
131 static void xr_driver_run_fsm (struct xr_driver *);
132 \f
133 /* Output driver basics. */
134
135 static struct xr_driver *
136 xr_driver_cast (struct output_driver *driver)
137 {
138   assert (driver->class == &cairo_driver_class);
139   return UP_CAST (driver, struct xr_driver, driver);
140 }
141
142 static struct driver_option *
143 opt (struct output_driver *d, struct string_map *options, const char *key,
144      const char *default_value)
145 {
146   return driver_option_get (d, options, key, default_value);
147 }
148
149 static PangoFontDescription *
150 parse_font (const char *font, int default_size, bool bold, bool italic)
151 {
152   if (!c_strcasecmp (font, "Monospaced"))
153     font = "Monospace";
154
155   PangoFontDescription *desc = pango_font_description_from_string (font);
156   if (desc == NULL)
157     return NULL;
158
159   /* If the font description didn't include an explicit font size, then set it
160      to DEFAULT_SIZE, which is in inch/72000 units. */
161   if (!(pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_SIZE))
162     pango_font_description_set_size (desc,
163                                      (default_size / 1000.0) * PANGO_SCALE);
164
165   pango_font_description_set_weight (desc, (bold
166                                             ? PANGO_WEIGHT_BOLD
167                                             : PANGO_WEIGHT_NORMAL));
168   pango_font_description_set_style (desc, (italic
169                                            ? PANGO_STYLE_ITALIC
170                                            : PANGO_STYLE_NORMAL));
171
172   return desc;
173 }
174
175 static PangoFontDescription *
176 parse_font_option (struct output_driver *d, struct string_map *options,
177                    const char *key, const char *default_value,
178                    int default_size, bool bold, bool italic)
179 {
180   char *string = parse_string (opt (d, options, key, default_value));
181   PangoFontDescription *desc = parse_font (string, default_size, bold, italic);
182   if (!desc)
183     {
184       msg (MW, _("`%s': bad font specification"), string);
185
186       /* Fall back to DEFAULT_VALUE, which had better be a valid font
187          description. */
188       desc = parse_font (default_value, default_size, bold, italic);
189       assert (desc != NULL);
190     }
191   free (string);
192
193   return desc;
194 }
195
196 static void
197 apply_options (struct xr_driver *xr, struct string_map *o)
198 {
199   struct output_driver *d = &xr->driver;
200
201   /* In inch/72000 units used by parse_paper_size() and parse_dimension(). */
202
203   /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
204   const double scale = XR_POINT / 1000.;
205
206   for (int i = 0; i < XR_N_FONTS; i++)
207     if (xr->fonts[i] != NULL)
208       pango_font_description_free (xr->fonts[i]);
209
210   int font_size = parse_int (opt (d, o, "font-size", "10000"), 1000, 1000000);
211   xr->fonts[XR_FONT_FIXED] = parse_font_option
212     (d, o, "fixed-font", "monospace", font_size, false, false);
213   xr->fonts[XR_FONT_PROPORTIONAL] = parse_font_option (
214     d, o, "prop-font", "sans serif", font_size, false, false);
215
216   xr->fg = parse_color (opt (d, o, "foreground-color", "#000000000000"));
217   xr->bg = parse_color (opt (d, o, "background-color", "#FFFFFFFFFFFF"));
218
219   xr->transparent = parse_boolean (opt (d, o, "transparent", "false"));
220   xr->systemcolors = parse_boolean (opt (d, o, "systemcolors", "false"));
221
222   /* Get dimensions.  */
223   int paper[TABLE_N_AXES];
224   parse_paper_size (opt (d, o, "paper-size", ""), &paper[H], &paper[V]);
225
226   int margins[TABLE_N_AXES][2];
227   margins[H][0] = parse_dimension (opt (d, o, "left-margin", ".5in"));
228   margins[H][1] = parse_dimension (opt (d, o, "right-margin", ".5in"));
229   margins[V][0] = parse_dimension (opt (d, o, "top-margin", ".5in"));
230   margins[V][1] = parse_dimension (opt (d, o, "bottom-margin", ".5in"));
231
232   int min_break[TABLE_N_AXES];
233   min_break[H] = parse_dimension (opt (d, o, "min-hbreak", NULL)) * scale;
234   min_break[V] = parse_dimension (opt (d, o, "min-vbreak", NULL)) * scale;
235
236   int object_spacing = (parse_dimension (opt (d, o, "object-spacing", NULL))
237                         * scale);
238
239   /* Convert to inch/(XR_POINT * 72). */
240   for (int a = 0; a < TABLE_N_AXES; a++)
241     {
242       for (int i = 0; i < 2; i++)
243         xr->margins[a][i] = margins[a][i] * scale;
244       xr->size[a] = (paper[a] - margins[a][0] - margins[a][1]) * scale;
245       xr->min_break[a] = min_break[a] >= 0 ? min_break[a] : xr->size[a] / 2;
246     }
247   xr->object_spacing = object_spacing >= 0 ? object_spacing : XR_POINT * 12;
248
249   /* There are no headings so headings_height can stay 0. */
250 }
251
252 static struct xr_driver *
253 xr_allocate (const char *name, int device_type, struct string_map *o)
254 {
255   struct xr_driver *xr = xzalloc (sizeof *xr);
256   struct output_driver *d = &xr->driver;
257
258   output_driver_init (d, &cairo_driver_class, name, device_type);
259
260   apply_options (xr, o);
261
262   return xr;
263 }
264
265 static int
266 pango_to_xr (int pango)
267 {
268   return (XR_POINT != PANGO_SCALE
269           ? ceil (pango * (1. * XR_POINT / PANGO_SCALE))
270           : pango);
271 }
272
273 static int
274 xr_to_pango (int xr)
275 {
276   return (XR_POINT != PANGO_SCALE
277           ? ceil (xr * (1. / XR_POINT * PANGO_SCALE))
278           : xr);
279 }
280
281 static void
282 xr_measure_fonts (cairo_t *cairo, PangoFontDescription *fonts[XR_N_FONTS],
283                   int *char_width, int *char_height)
284 {
285   *char_width = 0;
286   *char_height = 0;
287   for (int i = 0; i < XR_N_FONTS; i++)
288     {
289       PangoContext *context = pango_cairo_create_context (cairo);
290       pango_cairo_context_set_resolution (context, 72.0);
291       PangoLayout *layout = pango_layout_new (context);
292       g_object_unref (context);
293       pango_layout_set_font_description (layout, fonts[i]);
294
295       pango_layout_set_text (layout, "0", 1);
296
297       int cw, ch;
298       pango_layout_get_size (layout, &cw, &ch);
299       *char_width = MAX (*char_width, pango_to_xr (cw));
300       *char_height = MAX (*char_height, pango_to_xr (ch));
301
302       g_object_unref (G_OBJECT (layout));
303     }
304 }
305
306 static int
307 get_layout_height (PangoLayout *layout)
308 {
309   int w, h;
310   pango_layout_get_size (layout, &w, &h);
311   return h;
312 }
313
314 static int
315 xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
316                         const struct page_heading *ph, int page_number,
317                         int width, bool draw, int base_y)
318 {
319   PangoContext *context = pango_cairo_create_context (cairo);
320   pango_cairo_context_set_resolution (context, 72.0);
321   PangoLayout *layout = pango_layout_new (context);
322   g_object_unref (context);
323
324   pango_layout_set_font_description (layout, font);
325
326   int y = 0;
327   for (size_t i = 0; i < ph->n; i++)
328     {
329       const struct page_paragraph *pp = &ph->paragraphs[i];
330
331       char *markup = output_driver_substitute_heading_vars (pp->markup,
332                                                             page_number);
333       pango_layout_set_markup (layout, markup, -1);
334       free (markup);
335
336       pango_layout_set_alignment (
337         layout,
338         (pp->halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
339          : pp->halign == TABLE_HALIGN_CENTER ? PANGO_ALIGN_CENTER
340          : pp->halign == TABLE_HALIGN_MIXED ? PANGO_ALIGN_LEFT
341          : PANGO_ALIGN_RIGHT));
342       pango_layout_set_width (layout, xr_to_pango (width));
343       if (draw)
344         {
345           cairo_save (cairo);
346           cairo_translate (cairo, 0, xr_to_pt (y + base_y));
347           pango_cairo_show_layout (cairo, layout);
348           cairo_restore (cairo);
349         }
350
351       y += pango_to_xr (get_layout_height (layout));
352     }
353
354   g_object_unref (G_OBJECT (layout));
355
356   return y;
357 }
358
359 static int
360 xr_measure_headings (cairo_surface_t *surface,
361                      const PangoFontDescription *font,
362                      const struct page_heading headings[2],
363                      int width, int object_spacing, int height[2])
364 {
365   cairo_t *cairo = cairo_create (surface);
366   int total = 0;
367   for (int i = 0; i < 2; i++)
368     {
369       int h = xr_render_page_heading (cairo, font, &headings[i], -1,
370                                       width, false, 0);
371
372       /* If the top heading is nonempty, add some space below it. */
373       if (h && i == 0)
374         h += object_spacing;
375
376       if (height)
377         height[i] = h;
378       total += h;
379     }
380   cairo_destroy (cairo);
381   return total;
382 }
383
384 static bool
385 xr_check_fonts (cairo_surface_t *surface,
386                 PangoFontDescription *fonts[XR_N_FONTS],
387                 int usable_width, int usable_length)
388 {
389   cairo_t *cairo = cairo_create (surface);
390   int char_width, char_height;
391   xr_measure_fonts (cairo, fonts, &char_width, &char_height);
392   cairo_destroy (cairo);
393
394   bool ok = true;
395   enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
396   if (usable_width / char_width < MIN_WIDTH)
397     {
398       msg (ME, _("The defined page is not wide enough to hold at least %d "
399                  "characters in the default font.  In fact, there's only "
400                  "room for %d characters."),
401            MIN_WIDTH, usable_width / char_width);
402       ok = false;
403     }
404   if (usable_length / char_height < MIN_LENGTH)
405     {
406       msg (ME, _("The defined page is not long enough to hold at least %d "
407                  "lines in the default font.  In fact, there's only "
408                  "room for %d lines."),
409            MIN_LENGTH, usable_length / char_height);
410       ok = false;
411     }
412   return ok;
413 }
414
415 static void
416 xr_set_cairo (struct xr_driver *xr, cairo_t *cairo)
417 {
418   xr->cairo = cairo;
419
420   cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
421
422   xr_measure_fonts (xr->cairo, xr->fonts, &xr->char_width, &xr->char_height);
423
424   if (xr->style == NULL)
425     {
426       xr->style = xmalloc (sizeof *xr->style);
427       *xr->style = (struct xr_fsm_style) {
428         .ref_cnt = 1,
429         .size = { [H] = xr->size[H], [V] = xr->size[V] },
430         .min_break = { [H] = xr->min_break[H], [V] = xr->min_break[V] },
431         .use_system_colors = xr->systemcolors,
432         .transparent = xr->transparent,
433         .font_resolution = 72.0,
434       };
435
436       for (size_t i = 0; i < XR_N_FONTS; i++)
437         xr->style->fonts[i] = pango_font_description_copy (xr->fonts[i]);
438     }
439
440   if (!xr->systemcolors)
441     cairo_set_source_rgb (xr->cairo,
442                           xr->fg.r / 255.0, xr->fg.g / 255.0, xr->fg.b / 255.0);
443 }
444
445 static struct output_driver *
446 xr_create (struct file_handle *fh, enum settings_output_devices device_type,
447            struct string_map *o, enum xr_output_type file_type)
448 {
449   const char *file_name = fh_get_file_name (fh);
450   struct xr_driver *xr = xr_allocate (file_name, device_type, o);
451
452   double paper_pt[TABLE_N_AXES];
453   for (int a = 0; a < TABLE_N_AXES; a++)
454     paper_pt[a] = xr_to_pt (xr->size[a]
455                             + xr->margins[a][0] + xr->margins[a][1]);
456   if (file_type == XR_PDF)
457     xr->surface = cairo_pdf_surface_create (file_name,
458                                             paper_pt[H], paper_pt[V]);
459   else if (file_type == XR_PS)
460     xr->surface = cairo_ps_surface_create (file_name, paper_pt[H], paper_pt[V]);
461   else if (file_type == XR_SVG)
462     xr->surface = cairo_svg_surface_create (file_name,
463                                             paper_pt[H], paper_pt[V]);
464   else
465     NOT_REACHED ();
466
467   cairo_status_t status = cairo_surface_status (xr->surface);
468   if (status != CAIRO_STATUS_SUCCESS)
469     {
470       msg (ME, _("error opening output file `%s': %s"),
471            file_name, cairo_status_to_string (status));
472       goto error;
473     }
474
475   if (!xr_check_fonts (xr->surface, xr->fonts, xr->size[H], xr->size[V]))
476     goto error;
477
478   fh_unref (fh);
479   return &xr->driver;
480
481  error:
482   fh_unref (fh);
483   output_driver_destroy (&xr->driver);
484   return NULL;
485 }
486
487 static struct output_driver *
488 xr_pdf_create (struct  file_handle *fh, enum settings_output_devices device_type,
489                struct string_map *o)
490 {
491   return xr_create (fh, device_type, o, XR_PDF);
492 }
493
494 static struct output_driver *
495 xr_ps_create (struct  file_handle *fh, enum settings_output_devices device_type,
496                struct string_map *o)
497 {
498   return xr_create (fh, device_type, o, XR_PS);
499 }
500
501 static struct output_driver *
502 xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
503                struct string_map *o)
504 {
505   return xr_create (fh, device_type, o, XR_SVG);
506 }
507
508 static void
509 xr_destroy (struct output_driver *driver)
510 {
511   struct xr_driver *xr = xr_driver_cast (driver);
512   size_t i;
513
514   xr_driver_destroy_fsm (xr);
515
516   if (xr->cairo != NULL)
517     {
518       cairo_surface_finish (xr->surface);
519       cairo_status_t status = cairo_status (xr->cairo);
520       if (status != CAIRO_STATUS_SUCCESS)
521         fprintf (stderr,  _("error drawing output for %s driver: %s"),
522                  output_driver_get_name (driver),
523                  cairo_status_to_string (status));
524       cairo_surface_destroy (xr->surface);
525
526       cairo_destroy (xr->cairo);
527     }
528
529   for (i = 0; i < XR_N_FONTS; i++)
530     if (xr->fonts[i] != NULL)
531       pango_font_description_free (xr->fonts[i]);
532
533   xr_fsm_style_unref (xr->style);
534   free (xr);
535 }
536
537 static void
538 xr_flush (struct output_driver *driver)
539 {
540   struct xr_driver *xr = xr_driver_cast (driver);
541
542   cairo_surface_flush (cairo_get_target (xr->cairo));
543 }
544
545 static void
546 xr_update_page_setup (struct output_driver *driver,
547                       const struct page_setup *ps)
548 {
549   struct xr_driver *xr = xr_driver_cast (driver);
550
551   xr->initial_page_number = ps->initial_page_number;
552   xr->object_spacing = ps->object_spacing * 72 * XR_POINT;
553
554   if (xr->cairo)
555     return;
556
557   int size[TABLE_N_AXES];
558   for (int a = 0; a < TABLE_N_AXES; a++)
559     {
560       double total_margin = ps->margins[a][0] + ps->margins[a][1];
561       size[a] = (ps->paper[a] - total_margin) * 72 * XR_POINT;
562     }
563
564   int headings_height[2];
565   size[V] -= xr_measure_headings (
566     xr->surface, xr->fonts[XR_FONT_PROPORTIONAL], ps->headings,
567     size[H], xr->object_spacing, headings_height);
568
569   int swap = ps->orientation == PAGE_LANDSCAPE;
570   enum table_axis h = H ^ swap;
571   enum table_axis v = V ^ swap;
572   if (!xr_check_fonts (xr->surface, xr->fonts, size[h], size[v]))
573     return;
574
575   for (int i = 0; i < 2; i++)
576     {
577       page_heading_uninit (&xr->headings[i]);
578       page_heading_copy (&xr->headings[i], &ps->headings[i]);
579       xr->headings_height[i] = headings_height[i];
580     }
581
582   for (int a = 0; a < TABLE_N_AXES; a++)
583     {
584       xr->size[a] = size[a ^ swap];
585       for (int i = 0; i < 2; i++)
586         xr->margins[a][i] = ps->margins[a ^ swap][i] * 72 * XR_POINT;
587     }
588   cairo_pdf_surface_set_size (xr->surface,
589                               ps->paper[h] * 72.0, ps->paper[v] * 72.0);
590 }
591
592 static void
593 xr_submit (struct output_driver *driver, const struct output_item *output_item)
594 {
595   struct xr_driver *xr = xr_driver_cast (driver);
596
597   if (is_page_setup_item (output_item))
598     {
599       xr_update_page_setup (driver,
600                             to_page_setup_item (output_item)->page_setup);
601       return;
602     }
603
604   if (!xr->cairo)
605     {
606       xr->page_number = xr->initial_page_number - 1;
607       xr_set_cairo (xr, cairo_create (xr->surface));
608       cairo_save (xr->cairo);
609       xr_driver_next_page (xr, xr->cairo);
610     }
611
612   xr_driver_output_item (xr, output_item);
613   while (xr_driver_need_new_page (xr))
614     {
615       cairo_restore (xr->cairo);
616       cairo_show_page (xr->cairo);
617       cairo_save (xr->cairo);
618       xr_driver_next_page (xr, xr->cairo);
619     }
620 }
621 \f
622 /* Functions for rendering a series of output items to a series of Cairo
623    contexts, with pagination.
624
625    Used by PSPPIRE for printing, and by the basic Cairo output driver above as
626    its underlying implementation.
627
628    See the big comment in cairo.h for intended usage. */
629
630 /* Gives new page CAIRO to XR for output. */
631 void
632 xr_driver_next_page (struct xr_driver *xr, cairo_t *cairo)
633 {
634   if (!xr->transparent)
635     {
636       cairo_save (cairo);
637       cairo_set_source_rgb (cairo,
638                             xr->bg.r / 255.0, xr->bg.g / 255.0, xr->bg.b / 255.0);
639       cairo_rectangle (cairo, 0, 0, xr->size[H], xr->size[V]);
640       cairo_fill (cairo);
641       cairo_restore (cairo);
642     }
643   cairo_translate (cairo,
644                    xr_to_pt (xr->margins[H][0]),
645                    xr_to_pt (xr->margins[V][0] + xr->headings_height[0]));
646
647   xr->page_number++;
648   xr->cairo = cairo;
649   xr->y = 0;
650
651   xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL],
652                           &xr->headings[0], xr->page_number, xr->size[H], true,
653                           -xr->headings_height[0]);
654   xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL],
655                           &xr->headings[1], xr->page_number, xr->size[H], true,
656                           xr->size[V]);
657
658   xr_driver_run_fsm (xr);
659 }
660
661 /* Start rendering OUTPUT_ITEM to XR.  Only valid if XR is not in the middle of
662    rendering a previous output item, that is, only if xr_driver_need_new_page()
663    returns false. */
664 void
665 xr_driver_output_item (struct xr_driver *xr,
666                        const struct output_item *output_item)
667 {
668   assert (xr->fsm == NULL);
669   xr->fsm = xr_fsm_create (output_item, xr->style, xr->cairo);
670   xr_driver_run_fsm (xr);
671 }
672
673 /* Returns true if XR is in the middle of rendering an output item and needs a
674    new page to be appended using xr_driver_next_page() to make progress,
675    otherwise false. */
676 bool
677 xr_driver_need_new_page (const struct xr_driver *xr)
678 {
679   return xr->fsm != NULL;
680 }
681
682 /* Returns true if the current page doesn't have any content yet. */
683 bool
684 xr_driver_is_page_blank (const struct xr_driver *xr)
685 {
686   return xr->y == 0;
687 }
688
689 static void
690 xr_driver_destroy_fsm (struct xr_driver *xr)
691 {
692   xr_fsm_destroy (xr->fsm);
693   xr->fsm = NULL;
694 }
695
696 static void
697 xr_driver_run_fsm (struct xr_driver *xr)
698 {
699   if (xr->fsm != NULL)
700     {
701       cairo_save (xr->cairo);
702       cairo_translate (xr->cairo, 0, xr_to_pt (xr->y));
703       int used = xr_fsm_draw_slice (xr->fsm, xr->cairo, xr->size[V] - xr->y);
704       xr->y += used;
705       cairo_restore (xr->cairo);
706
707       if (xr_fsm_is_empty (xr->fsm))
708         xr_driver_destroy_fsm (xr);
709     }
710 }
711 \f
712 struct output_driver_factory pdf_driver_factory =
713   { "pdf", "pspp.pdf", xr_pdf_create };
714 struct output_driver_factory ps_driver_factory =
715   { "ps", "pspp.ps", xr_ps_create };
716 struct output_driver_factory svg_driver_factory =
717   { "svg", "pspp.svg", xr_svg_create };
718
719 static const struct output_driver_class cairo_driver_class =
720 {
721   "cairo",
722   xr_destroy,
723   xr_submit,
724   xr_flush,
725 };
726 \f
727 struct xr_driver *
728 xr_driver_create (cairo_t *cairo, struct string_map *options)
729 {
730   struct xr_driver *xr = xr_allocate ("cairo", 0, options);
731   xr_set_cairo (xr, cairo);
732   return xr;
733 }
734
735 /* Destroy XR, which should have been created with xr_driver_create().  Any
736    cairo_t added to XR is not destroyed, because it is owned by the client. */
737 void
738 xr_driver_destroy (struct xr_driver *xr)
739 {
740   if (xr != NULL)
741     {
742       xr->cairo = NULL;
743       output_driver_destroy (&xr->driver);
744     }
745 }