1 /* GTK - The GIMP Toolkit
2 * gtkprintcontext.c: Print Context
3 * Copyright (C) 2006, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 #include "gtkprintoperation-private.h"
24 * SECTION:gtkprintcontext
25 * @Short_description: Encapsulates context for drawing pages
26 * @Title: GtkPrintContext
28 * A GtkPrintContext encapsulates context information that is required when
29 * drawing pages for printing, such as the cairo context and important
30 * parameters like page size and resolution. It also lets you easily
31 * create #PangoLayout and #PangoContext objects that match the font metrics
32 * of the cairo surface.
34 * GtkPrintContext objects gets passed to the #GtkPrintOperation::begin-print,
35 * #GtkPrintOperation::end-print, #GtkPrintOperation::request-page-setup and
36 * #GtkPrintOperation::draw-page signals on the #GtkPrintOperation.
39 * <title>Using GtkPrintContext in a #GtkPrintOperation::draw-page callback</title>
42 * draw_page (GtkPrintOperation *operation,
43 * GtkPrintContext *context,
47 * PangoLayout *layout;
48 * PangoFontDescription *desc;
50 * cr = gtk_print_context_get_cairo_context (context);
52 * // Draw a red rectangle, as wide as the paper (inside the margins)
53 * cairo_set_source_rgb (cr, 1.0, 0, 0);
54 * cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), 50);
59 * cairo_move_to (cr, 20, 10);
60 * cairo_line_to (cr, 40, 20);
61 * cairo_arc (cr, 60, 60, 20, 0, M_PI);
62 * cairo_line_to (cr, 80, 20);
64 * cairo_set_source_rgb (cr, 0, 0, 0);
65 * cairo_set_line_width (cr, 5);
66 * cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
67 * cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
72 * layout = gtk_print_context_create_layout (context);
73 * pango_layout_set_text (layout, "Hello World! Printing is easy", -1);
74 * desc = pango_font_description_from_string ("sans 28");
75 * pango_layout_set_font_description (layout, desc);
76 * pango_font_description_free (desc);
78 * cairo_move_to (cr, 30, 20);
79 * pango_cairo_layout_path (cr, layout);
82 * cairo_set_source_rgb (cr, 0.93, 1.0, 0.47);
83 * cairo_set_line_width (cr, 0.5);
84 * cairo_stroke_preserve (cr);
87 * cairo_set_source_rgb (cr, 0, 0.0, 1.0);
90 * g_object_unref (layout);
95 * Printing support was added in GTK+ 2.10.
99 typedef struct _GtkPrintContextClass GtkPrintContextClass;
101 #define GTK_IS_PRINT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_CONTEXT))
102 #define GTK_PRINT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
103 #define GTK_PRINT_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
105 #define MM_PER_INCH 25.4
106 #define POINTS_PER_INCH 72
108 struct _GtkPrintContext
110 GObject parent_instance;
112 GtkPrintOperation *op;
114 GtkPageSetup *page_setup;
116 gdouble surface_dpi_x;
117 gdouble surface_dpi_y;
119 gdouble pixels_per_unit_x;
120 gdouble pixels_per_unit_y;
122 gboolean has_hard_margins;
123 gdouble hard_margin_top;
124 gdouble hard_margin_bottom;
125 gdouble hard_margin_left;
126 gdouble hard_margin_right;
130 struct _GtkPrintContextClass
132 GObjectClass parent_class;
135 G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
138 gtk_print_context_finalize (GObject *object)
140 GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
142 if (context->page_setup)
143 g_object_unref (context->page_setup);
146 cairo_destroy (context->cr);
148 G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
152 gtk_print_context_init (GtkPrintContext *context)
157 gtk_print_context_class_init (GtkPrintContextClass *class)
159 GObjectClass *gobject_class = (GObjectClass *)class;
161 gobject_class->finalize = gtk_print_context_finalize;
166 _gtk_print_context_new (GtkPrintOperation *op)
168 GtkPrintContext *context;
170 context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
174 context->has_hard_margins = FALSE;
179 static PangoFontMap *
180 _gtk_print_context_get_fontmap (GtkPrintContext *context)
182 return pango_cairo_font_map_get_default ();
186 * gtk_print_context_set_cairo_context:
187 * @context: a #GtkPrintContext
188 * @cr: the cairo context
189 * @dpi_x: the horizontal resolution to use with @cr
190 * @dpi_y: the vertical resolution to use with @cr
192 * Sets a new cairo context on a print context.
194 * This function is intended to be used when implementing
195 * an internal print preview, it is not needed for printing,
196 * since GTK+ itself creates a suitable cairo context in that
202 gtk_print_context_set_cairo_context (GtkPrintContext *context,
208 cairo_destroy (context->cr);
210 context->cr = cairo_reference (cr);
211 context->surface_dpi_x = dpi_x;
212 context->surface_dpi_y = dpi_y;
214 switch (context->op->priv->unit)
218 /* Do nothing, this is the cairo default unit */
219 context->pixels_per_unit_x = 1.0;
220 context->pixels_per_unit_y = 1.0;
222 case GTK_UNIT_POINTS:
223 context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
224 context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
227 context->pixels_per_unit_x = dpi_x;
228 context->pixels_per_unit_y = dpi_y;
231 context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
232 context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
235 cairo_scale (context->cr,
236 context->pixels_per_unit_x,
237 context->pixels_per_unit_y);
242 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
244 cairo_t *cr = context->cr;
245 cairo_matrix_t matrix;
246 GtkPaperSize *paper_size;
247 gdouble width, height;
249 paper_size = gtk_page_setup_get_paper_size (context->page_setup);
251 width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
252 width = width * context->surface_dpi_x / context->pixels_per_unit_x;
253 height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
254 height = height * context->surface_dpi_y / context->pixels_per_unit_y;
256 switch (gtk_page_setup_get_orientation (context->page_setup))
259 case GTK_PAGE_ORIENTATION_PORTRAIT:
261 case GTK_PAGE_ORIENTATION_LANDSCAPE:
262 cairo_translate (cr, 0, height);
263 cairo_matrix_init (&matrix,
267 cairo_transform (cr, &matrix);
269 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
270 cairo_translate (cr, width, height);
271 cairo_matrix_init (&matrix,
275 cairo_transform (cr, &matrix);
277 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
278 cairo_translate (cr, width, 0);
279 cairo_matrix_init (&matrix,
283 cairo_transform (cr, &matrix);
289 _gtk_print_context_reverse_according_to_orientation (GtkPrintContext *context)
291 cairo_t *cr = context->cr;
292 cairo_matrix_t matrix;
293 gdouble width, height;
295 width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
296 width = width * context->surface_dpi_x / context->pixels_per_unit_x;
297 height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
298 height = height * context->surface_dpi_y / context->pixels_per_unit_y;
300 switch (gtk_page_setup_get_orientation (context->page_setup))
303 case GTK_PAGE_ORIENTATION_PORTRAIT:
304 case GTK_PAGE_ORIENTATION_LANDSCAPE:
306 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
307 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
308 cairo_translate (cr, width, height);
309 cairo_matrix_init (&matrix,
313 cairo_transform (cr, &matrix);
319 _gtk_print_context_translate_into_margin (GtkPrintContext *context)
323 g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
325 /* We do it this way to also handle GTK_UNIT_NONE */
326 left = gtk_page_setup_get_left_margin (context->page_setup, GTK_UNIT_INCH);
327 top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
329 cairo_translate (context->cr,
330 left * context->surface_dpi_x / context->pixels_per_unit_x,
331 top * context->surface_dpi_y / context->pixels_per_unit_y);
335 _gtk_print_context_set_page_setup (GtkPrintContext *context,
336 GtkPageSetup *page_setup)
338 g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
339 g_return_if_fail (page_setup == NULL ||
340 GTK_IS_PAGE_SETUP (page_setup));
342 g_object_ref (page_setup);
344 if (context->page_setup != NULL)
345 g_object_unref (context->page_setup);
347 context->page_setup = page_setup;
351 * gtk_print_context_get_cairo_context:
352 * @context: a #GtkPrintContext
354 * Obtains the cairo context that is associated with the
357 * Return value: (transfer none): the cairo context of @context
362 gtk_print_context_get_cairo_context (GtkPrintContext *context)
364 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
370 * gtk_print_context_get_page_setup:
371 * @context: a #GtkPrintContext
373 * Obtains the #GtkPageSetup that determines the page
374 * dimensions of the #GtkPrintContext.
376 * Return value: (transfer none): the page setup of @context
381 gtk_print_context_get_page_setup (GtkPrintContext *context)
383 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
385 return context->page_setup;
389 * gtk_print_context_get_width:
390 * @context: a #GtkPrintContext
392 * Obtains the width of the #GtkPrintContext, in pixels.
394 * Return value: the width of @context
399 gtk_print_context_get_width (GtkPrintContext *context)
401 GtkPrintOperationPrivate *priv;
404 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
406 priv = context->op->priv;
408 if (priv->use_full_page)
409 width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
411 width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
413 /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
414 return width * context->surface_dpi_x / context->pixels_per_unit_x;
418 * gtk_print_context_get_height:
419 * @context: a #GtkPrintContext
421 * Obtains the height of the #GtkPrintContext, in pixels.
423 * Return value: the height of @context
428 gtk_print_context_get_height (GtkPrintContext *context)
430 GtkPrintOperationPrivate *priv;
433 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
435 priv = context->op->priv;
437 if (priv->use_full_page)
438 height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
440 height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
442 /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
443 return height * context->surface_dpi_y / context->pixels_per_unit_y;
447 * gtk_print_context_get_dpi_x:
448 * @context: a #GtkPrintContext
450 * Obtains the horizontal resolution of the #GtkPrintContext,
453 * Return value: the horizontal resolution of @context
458 gtk_print_context_get_dpi_x (GtkPrintContext *context)
460 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
462 return context->surface_dpi_x;
466 * gtk_print_context_get_dpi_y:
467 * @context: a #GtkPrintContext
469 * Obtains the vertical resolution of the #GtkPrintContext,
472 * Return value: the vertical resolution of @context
477 gtk_print_context_get_dpi_y (GtkPrintContext *context)
479 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
481 return context->surface_dpi_y;
485 * gtk_print_context_get_hard_margins:
486 * @context: a #GtkPrintContext
487 * @top: (out): top hardware printer margin
488 * @bottom: (out): bottom hardware printer margin
489 * @left: (out): left hardware printer margin
490 * @right: (out): right hardware printer margin
492 * Obtains the hardware printer margins of the #GtkPrintContext, in units.
494 * Return value: %TRUE if the hard margins were retrieved
499 gtk_print_context_get_hard_margins (GtkPrintContext *context,
505 if (context->has_hard_margins)
507 *top = context->hard_margin_top / context->pixels_per_unit_y;
508 *bottom = context->hard_margin_bottom / context->pixels_per_unit_y;
509 *left = context->hard_margin_left / context->pixels_per_unit_x;
510 *right = context->hard_margin_right / context->pixels_per_unit_x;
513 return context->has_hard_margins;
517 * gtk_print_context_set_hard_margins:
518 * @context: a #GtkPrintContext
519 * @top: top hardware printer margin
520 * @bottom: bottom hardware printer margin
521 * @left: left hardware printer margin
522 * @right: right hardware printer margin
524 * set the hard margins in pixel coordinates
527 _gtk_print_context_set_hard_margins (GtkPrintContext *context,
533 context->hard_margin_top = top;
534 context->hard_margin_bottom = bottom;
535 context->hard_margin_left = left;
536 context->hard_margin_right = right;
537 context->has_hard_margins = TRUE;
541 * gtk_print_context_get_pango_fontmap:
542 * @context: a #GtkPrintContext
544 * Returns a #PangoFontMap that is suitable for use
545 * with the #GtkPrintContext.
547 * Return value: (transfer none): the font map of @context
552 gtk_print_context_get_pango_fontmap (GtkPrintContext *context)
554 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
556 return _gtk_print_context_get_fontmap (context);
560 * gtk_print_context_create_pango_context:
561 * @context: a #GtkPrintContext
563 * Creates a new #PangoContext that can be used with the
566 * Return value: (transfer full): a new Pango context for @context
571 gtk_print_context_create_pango_context (GtkPrintContext *context)
573 PangoContext *pango_context;
574 cairo_font_options_t *options;
576 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
578 pango_context = pango_font_map_create_context (_gtk_print_context_get_fontmap (context));
580 options = cairo_font_options_create ();
581 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
582 pango_cairo_context_set_font_options (pango_context, options);
583 cairo_font_options_destroy (options);
585 /* We use the unit-scaled resolution, as we still want
586 * fonts given in points to work
588 pango_cairo_context_set_resolution (pango_context,
589 context->surface_dpi_y / context->pixels_per_unit_y);
590 return pango_context;
594 * gtk_print_context_create_pango_layout:
595 * @context: a #GtkPrintContext
597 * Creates a new #PangoLayout that is suitable for use
598 * with the #GtkPrintContext.
600 * Return value: (transfer full): a new Pango layout for @context
605 gtk_print_context_create_pango_layout (GtkPrintContext *context)
607 PangoContext *pango_context;
610 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
612 pango_context = gtk_print_context_create_pango_context (context);
613 layout = pango_layout_new (pango_context);
615 pango_cairo_update_context (context->cr, pango_context);
616 g_object_unref (pango_context);