X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcairo.c;h=b8fc486e89e66e1fe218e9543e31eb43b4afe3d9;hb=e30e79108bdfe24672d6d365881d61b87631579d;hp=a60b5ebd04aeddfefbf8b892f761ed889790fd09;hpb=cd39e3af11eb9537e6e6ac2db2ee90fd3c01cb08;p=pspp-builds.git diff --git a/src/output/cairo.c b/src/output/cairo.c index a60b5ebd..b8fc486e 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -16,11 +16,13 @@ #include +#include + #include #include #include #include -#include +#include #include #include @@ -55,9 +57,9 @@ top-margin=0.5in bottom-margin=0.5in - prop-font=Times-Roman - emph-font=Times-Italic - fixed-font=Courier + prop-font=serif + emph-font=serif italic + fixed-font=monospace font-size=10000 line-gutter=1pt @@ -65,10 +67,23 @@ line-width=0.5pt */ -/* Measurements. We use the same scale as Pango, for simplicity. */ +/* Measurements as we present to the rest of PSPP. */ #define XR_POINT PANGO_SCALE #define XR_INCH (XR_POINT * 72) +/* Conversions to and from points. */ +static double +xr_to_pt (int x) +{ + return x / (double) XR_POINT; +} + +static int +pt_to_xr (double x) +{ + return x * XR_POINT + 0.5; +} + /* Output types. */ enum xr_output_type { @@ -89,29 +104,36 @@ struct xr_font /* Cairo output driver extension record. */ struct xr_driver_ext { - char *file_name; /* Output file name. */ - enum xr_output_type file_type; /* Type of output file. */ cairo_t *cairo; + struct xr_font fonts[OUTP_FONT_CNT]; bool draw_headers; /* Draw headers at top of page? */ int page_number; /* Current page number. */ + int line_gutter; /* Space around lines. */ + int line_space; /* Space between lines. */ + int line_width; /* Width of lines. */ + }; + +struct xr_driver_options + { + struct outp_driver *driver; + + char *file_name; /* Output file name. */ + enum xr_output_type file_type; /* Type of output file. */ + + bool portrait; /* Portrait mode? */ + int paper_width; /* Width of paper before dropping margins. */ int paper_length; /* Length of paper before dropping margins. */ int left_margin; /* Left margin in XR units. */ int right_margin; /* Right margin in XR units. */ int top_margin; /* Top margin in XR units. */ int bottom_margin; /* Bottom margin in XR units. */ - - int line_gutter; /* Space around lines. */ - int line_space; /* Space between lines. */ - int line_width; /* Width of lines. */ - - struct xr_font fonts[OUTP_FONT_CNT]; }; -static bool handle_option (struct outp_driver *this, const char *key, +static bool handle_option (void *options, const char *key, const struct string *val); static void draw_headers (struct outp_driver *this); @@ -121,32 +143,18 @@ static int text_width (struct outp_driver *, const char *, enum outp_font); /* Driver initialization. */ -static bool -xr_open_driver (struct outp_driver *this, struct substring options) +static struct outp_driver * +xr_allocate (const char *name, int types) { - cairo_surface_t *surface; - cairo_status_t status; + struct outp_driver *this; struct xr_driver_ext *x; - double width_pt, length_pt; size_t i; + this = outp_allocate_driver (&cairo_class, name, types); this->width = this->length = 0; this->font_height = XR_POINT * 10; - - this->ext = x = xmalloc (sizeof *x); - x->file_name = xstrdup ("pspp.pdf"); - x->file_type = XR_PDF; - x->draw_headers = true; - x->page_number = 0; - x->portrait = true; - outp_get_paper_size ("", &x->paper_width, &x->paper_length); - x->left_margin = XR_INCH / 2; - x->right_margin = XR_INCH / 2; - x->top_margin = XR_INCH / 2; - x->bottom_margin = XR_INCH / 2; - x->line_gutter = XR_POINT; - x->line_space = XR_POINT; - x->line_width = XR_POINT / 2; + this->ext = x = xzalloc (sizeof *x); + x->cairo = NULL; x->fonts[OUTP_FIXED].string = xstrdup ("monospace"); x->fonts[OUTP_PROPORTIONAL].string = xstrdup ("serif"); x->fonts[OUTP_EMPHASIS].string = xstrdup ("serif italic"); @@ -157,32 +165,109 @@ xr_open_driver (struct outp_driver *this, struct substring options) font->metrics = NULL; font->layout = NULL; } + x->draw_headers = true; + x->page_number = 0; + x->line_gutter = XR_POINT; + x->line_space = XR_POINT; + x->line_width = XR_POINT / 2; - outp_parse_options (options, handle_option, this); + return this; +} - if (x->portrait) +static bool +xr_set_cairo (struct outp_driver *this, cairo_t *cairo) +{ + struct xr_driver_ext *x = this->ext; + int i; + + x->cairo = cairo; + + cairo_set_line_width (x->cairo, xr_to_pt (x->line_width)); + + for (i = 0; i < OUTP_FONT_CNT; i++) + if (!load_font (this, &x->fonts[i])) + return false; + + this->fixed_width = text_width (this, "0", OUTP_FIXED); + this->prop_em_width = text_width (this, "0", OUTP_PROPORTIONAL); + + this->horiz_line_width[OUTP_L_NONE] = 0; + this->horiz_line_width[OUTP_L_SINGLE] = 2 * x->line_gutter + x->line_width; + this->horiz_line_width[OUTP_L_DOUBLE] = (2 * x->line_gutter + x->line_space + + 2 * x->line_width); + memcpy (this->vert_line_width, this->horiz_line_width, + sizeof this->vert_line_width); + + return true; +} + +struct outp_driver * +xr_create_driver (cairo_t *cairo) +{ + struct outp_driver *this; + + this = xr_allocate ("cairo", 0); + this->width = INT_MAX / 8; + this->length = INT_MAX / 8; + if (!xr_set_cairo (this, cairo)) { - this->width = x->paper_width; - this->length = x->paper_length; + this->class->close_driver (this); + outp_free_driver (this); + return NULL; + } + return this; +} + +static bool +xr_open_driver (const char *name, int types, struct substring option_string) +{ + struct outp_driver *this; + struct xr_driver_ext *x; + struct xr_driver_options options; + cairo_surface_t *surface; + cairo_status_t status; + double width_pt, length_pt; + + this = xr_allocate (name, types); + x = this->ext; + + options.driver = this; + options.file_name = xstrdup ("pspp.pdf"); + options.file_type = XR_PDF; + options.portrait = true; + outp_get_paper_size ("", &options.paper_width, &options.paper_length); + options.left_margin = XR_INCH / 2; + options.right_margin = XR_INCH / 2; + options.top_margin = XR_INCH / 2; + options.bottom_margin = XR_INCH / 2; + + outp_parse_options (this->name, option_string, handle_option, &options); + + width_pt = options.paper_width / 1000.0; + length_pt = options.paper_length / 1000.0; + if (options.portrait) + { + this->width = pt_to_xr (width_pt); + this->length = pt_to_xr (length_pt); } else { - this->width = x->paper_length; - this->length = x->paper_width; + this->width = pt_to_xr (width_pt); + this->length = pt_to_xr (length_pt); } if (x->draw_headers) - x->top_margin += 3 * this->font_height; - this->width -= x->left_margin + x->right_margin; - this->length -= x->top_margin + x->bottom_margin; - - width_pt = x->paper_width / (double) XR_POINT; - length_pt = x->paper_length / (double) XR_POINT; - if (x->file_type == XR_PDF) - surface = cairo_pdf_surface_create (x->file_name, width_pt, length_pt); - else if (x->file_type == XR_PS) - surface = cairo_ps_surface_create (x->file_name, width_pt, length_pt); - else if (x->file_type == XR_SVG) - surface = cairo_svg_surface_create (x->file_name, width_pt, length_pt); + options.top_margin += 3 * this->font_height; + this->width -= options.left_margin + options.right_margin; + this->length -= options.top_margin + options.bottom_margin; + + if (options.file_type == XR_PDF) + surface = cairo_pdf_surface_create (options.file_name, + width_pt, length_pt); + else if (options.file_type == XR_PS) + surface = cairo_ps_surface_create (options.file_name, width_pt, length_pt); + else if (options.file_type == XR_SVG) + surface = cairo_svg_surface_create (options.file_name, + width_pt, length_pt); else NOT_REACHED (); @@ -190,7 +275,7 @@ xr_open_driver (struct outp_driver *this, struct substring options) if (status != CAIRO_STATUS_SUCCESS) { error (0, 0, _("opening output file \"%s\": %s"), - x->file_name, cairo_status_to_string (status)); + options.file_name, cairo_status_to_string (status)); cairo_surface_destroy (surface); goto error; } @@ -198,13 +283,9 @@ xr_open_driver (struct outp_driver *this, struct substring options) x->cairo = cairo_create (surface); cairo_surface_destroy (surface); - cairo_scale (x->cairo, 1.0 / PANGO_SCALE, 1.0 / PANGO_SCALE); - cairo_translate (x->cairo, x->left_margin, x->top_margin); - cairo_set_line_width (x->cairo, x->line_width); - - for (i = 0; i < OUTP_FONT_CNT; i++) - if (!load_font (this, &x->fonts[i])) - goto error; + cairo_translate (x->cairo, + xr_to_pt (options.left_margin), + xr_to_pt (options.top_margin)); if (this->length / this->font_height < 15) { @@ -216,20 +297,17 @@ xr_open_driver (struct outp_driver *this, struct substring options) goto error; } - this->fixed_width = text_width (this, "0", OUTP_FIXED); - this->prop_em_width = text_width (this, "0", OUTP_PROPORTIONAL); - - this->horiz_line_width[OUTP_L_NONE] = 0; - this->horiz_line_width[OUTP_L_SINGLE] = 2 * x->line_gutter + x->line_width; - this->horiz_line_width[OUTP_L_DOUBLE] = (2 * x->line_gutter + x->line_space - + 2 * x->line_width); - memcpy (this->vert_line_width, this->horiz_line_width, - sizeof this->vert_line_width); + if (!xr_set_cairo (this, x->cairo)) + goto error; + outp_register_driver (this); + free (options.file_name); return true; error: this->class->close_driver (this); + outp_free_driver (this); + free (options.file_name); return false; } @@ -247,12 +325,11 @@ xr_close_driver (struct outp_driver *this) cairo_surface_finish (cairo_get_target (x->cairo)); status = cairo_status (x->cairo); if (status != CAIRO_STATUS_SUCCESS) - error (0, 0, _("writing output file \"%s\": %s"), - x->file_name, cairo_status_to_string (status)); + error (0, 0, _("error writing output file for %s driver: %s"), + this->name, cairo_status_to_string (status)); cairo_destroy (x->cairo); } - free (x->file_name); for (i = 0; i < OUTP_FONT_CNT; i++) free_font (&x->fonts[i]); free (x); @@ -300,9 +377,10 @@ static const struct outp_option option_tab[] = }; static bool -handle_option (struct outp_driver *this, const char *key, - const struct string *val) +handle_option (void *options_, const char *key, const struct string *val) { + struct xr_driver_options *options = options_; + struct outp_driver *this = options->driver; struct xr_driver_ext *x = this->ext; int subcat; char *value = ds_cstr (val); @@ -315,16 +393,16 @@ handle_option (struct outp_driver *this, const char *key, "driver"), key); break; case output_file_arg: - free (x->file_name); - x->file_name = xstrdup (value); + free (options->file_name); + options->file_name = xstrdup (value); break; case output_type_arg: if (!strcmp (value, "pdf")) - x->file_type = XR_PDF; + options->file_type = XR_PDF; else if (!strcmp (value, "ps")) - x->file_type = XR_PS; + options->file_type = XR_PS; else if (!strcmp (value, "svg")) - x->file_type = XR_SVG; + options->file_type = XR_SVG; else { error (0, 0, _("unknown Cairo output type \"%s\""), value); @@ -332,13 +410,14 @@ handle_option (struct outp_driver *this, const char *key, } break; case paper_size_arg: - outp_get_paper_size (value, &x->paper_width, &x->paper_length); + outp_get_paper_size (value, + &options->paper_width, &options->paper_length); break; case orientation_arg: if (!strcmp (value, "portrait")) - x->portrait = true; + options->portrait = true; else if (!strcmp (value, "landscape")) - x->portrait = false; + options->portrait = false; else error (0, 0, _("unknown orientation `%s' (valid orientations are " "`portrait' and `landscape')"), value); @@ -365,16 +444,16 @@ handle_option (struct outp_driver *this, const char *key, switch (subcat) { case 0: - x->left_margin = dimension; + options->left_margin = dimension; break; case 1: - x->right_margin = dimension; + options->right_margin = dimension; break; case 2: - x->top_margin = dimension; + options->top_margin = dimension; break; case 3: - x->bottom_margin = dimension; + options->bottom_margin = dimension; break; case 4: this->font_height = dimension; @@ -425,15 +504,24 @@ xr_close_page (struct outp_driver *this) } static void -xr_submit (struct outp_driver *this UNUSED, struct som_entity *s) +xr_output_chart (struct outp_driver *this, const struct chart *chart) { - switch (s->type) - { - case SOM_CHART: - break; - default: - NOT_REACHED (); - } + struct xr_driver_ext *x = this->ext; + struct chart_geometry geom; + + outp_eject_page (this); + outp_open_page (this); + + cairo_save (x->cairo); + cairo_translate (x->cairo, 0.0, xr_to_pt (this->length)); + cairo_scale (x->cairo, 1.0, -1.0); + chart_geometry_init (x->cairo, &geom, + xr_to_pt (this->width), xr_to_pt (this->length)); + chart_draw (chart, x->cairo, &geom); + chart_geometry_free (x->cairo); + cairo_restore (x->cairo); + + outp_close_page (this); } /* Draws a line from (x0,y0) to (x1,y1). */ @@ -442,8 +530,8 @@ dump_line (struct outp_driver *this, int x0, int y0, int x1, int y1) { struct xr_driver_ext *x = this->ext; cairo_new_path (x->cairo); - cairo_move_to (x->cairo, x0, y0); - cairo_line_to (x->cairo, x1, y1); + cairo_move_to (x->cairo, xr_to_pt (x0), xr_to_pt (y0)); + cairo_line_to (x->cairo, xr_to_pt (x1), xr_to_pt (y1)); cairo_stroke (x->cairo); } @@ -668,9 +756,9 @@ draw_headers (struct outp_driver *this) x1 = this->width - this->prop_em_width; /* Draw box. */ - cairo_rectangle (ext->cairo, 0, y, this->width, - 2 * (this->font_height - + ext->line_width + ext->line_gutter)); + cairo_rectangle (ext->cairo, 0, xr_to_pt (y), xr_to_pt (this->width), + xr_to_pt (2 * (this->font_height + + ext->line_width + ext->line_gutter))); cairo_save (ext->cairo); cairo_set_source_rgb (ext->cairo, 0.9, 0.9, 0.9); cairo_fill_preserve (ext->cairo); @@ -732,11 +820,9 @@ text (struct outp_driver *this, const struct outp_text *text, bool draw, } } cairo_save (ext->cairo); - cairo_translate (ext->cairo, text->x, text->y); - cairo_scale (ext->cairo, PANGO_SCALE, PANGO_SCALE); + cairo_translate (ext->cairo, xr_to_pt (text->x), xr_to_pt (text->y)); pango_cairo_show_layout (ext->cairo, font->layout); cairo_restore (ext->cairo); - pango_cairo_update_layout (ext->cairo, font->layout); } if (width != NULL || height != NULL) @@ -760,28 +846,9 @@ xr_text_metrics (struct outp_driver *this, const struct outp_text *t, static void xr_text_draw (struct outp_driver *this, const struct outp_text *t) { - assert (this->page_open); text (this, t, true, NULL, NULL); } -static void -xr_chart_initialise (struct outp_driver *this UNUSED, struct chart *ch UNUSED) -{ -#ifdef NO_CHARTS - ch->lp = NULL; -#else - /* XXX libplot doesn't support Cairo yet. */ -#endif -} - -static void -xr_chart_finalise (struct outp_driver *this UNUSED, struct chart *ch UNUSED) -{ -#ifndef NO_CHARTS - /* XXX libplot doesn't support Cairo yet. */ -#endif -} - /* Attempts to load FONT, initializing its other members based on its 'string' member and the information in THIS. Returns true if successful, otherwise false. */ @@ -801,7 +868,6 @@ load_font (struct outp_driver *this, struct xr_font *font) pango_font_description_set_absolute_size (font->desc, this->font_height); font->layout = pango_cairo_create_layout (x->cairo); - pango_cairo_update_layout (x->cairo, font->layout); pango_layout_set_font_description (font->layout, font->desc); language = pango_language_get_default (); @@ -835,12 +901,11 @@ const struct outp_class cairo_class = xr_close_page, NULL, - xr_submit, + xr_output_chart, + + NULL, xr_line, xr_text_metrics, xr_text_draw, - - xr_chart_initialise, - xr_chart_finalise };