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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "gtkprintoperation-private.h"
26 * SECTION:gtkprintcontext
27 * @Short_description: Encapsulates context for drawing pages
28 * @Title: GtkPrintContext
30 * A GtkPrintContext encapsulates context information that is required when
31 * drawing pages for printing, such as the cairo context and important
32 * parameters like page size and resolution. It also lets you easily
33 * create #PangoLayout and #PangoContext objects that match the font metrics
34 * of the cairo surface.
36 * GtkPrintContext objects gets passed to the #GtkPrintOperation::begin-print,
37 * #GtkPrintOperation::end-print, #GtkPrintOperation::request-page-setup and
38 * #GtkPrintOperation::draw-page signals on the #GtkPrintOperation.
41 * <title>Using GtkPrintContext in a #GtkPrintOperation::draw-page callback</title>
44 * draw_page (GtkPrintOperation *operation,
45 * GtkPrintContext *context,
49 * PangoLayout *layout;
50 * PangoFontDescription *desc;
52 * cr = gtk_print_context_get_cairo_context (context);
54 * // Draw a red rectangle, as wide as the paper (inside the margins)
55 * cairo_set_source_rgb (cr, 1.0, 0, 0);
56 * cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), 50);
61 * cairo_move_to (cr, 20, 10);
62 * cairo_line_to (cr, 40, 20);
63 * cairo_arc (cr, 60, 60, 20, 0, M_PI);
64 * cairo_line_to (cr, 80, 20);
66 * cairo_set_source_rgb (cr, 0, 0, 0);
67 * cairo_set_line_width (cr, 5);
68 * cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
69 * cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
74 * layout = gtk_print_context_create_layout (context);
75 * pango_layout_set_text (layout, "Hello World! Printing is easy", -1);
76 * desc = pango_font_description_from_string ("sans 28");
77 * pango_layout_set_font_description (layout, desc);
78 * pango_font_description_free (desc);
80 * cairo_move_to (cr, 30, 20);
81 * pango_cairo_layout_path (cr, layout);
84 * cairo_set_source_rgb (cr, 0.93, 1.0, 0.47);
85 * cairo_set_line_width (cr, 0.5);
86 * cairo_stroke_preserve (cr);
89 * cairo_set_source_rgb (cr, 0, 0.0, 1.0);
92 * g_object_unref (layout);
97 * Printing support was added in GTK+ 2.10.
101 typedef struct _GtkPrintContextClass GtkPrintContextClass;
103 #define GTK_IS_PRINT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_CONTEXT))
104 #define GTK_PRINT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
105 #define GTK_PRINT_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
107 #define MM_PER_INCH 25.4
108 #define POINTS_PER_INCH 72
110 struct _GtkPrintContext
112 GObject parent_instance;
114 GtkPrintOperation *op;
116 GtkPageSetup *page_setup;
118 gdouble surface_dpi_x;
119 gdouble surface_dpi_y;
121 gdouble pixels_per_unit_x;
122 gdouble pixels_per_unit_y;
124 gboolean has_hard_margins;
125 gdouble hard_margin_top;
126 gdouble hard_margin_bottom;
127 gdouble hard_margin_left;
128 gdouble hard_margin_right;
132 struct _GtkPrintContextClass
134 GObjectClass parent_class;
137 G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
140 gtk_print_context_finalize (GObject *object)
142 GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
144 if (context->page_setup)
145 g_object_unref (context->page_setup);
148 cairo_destroy (context->cr);
150 G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
154 gtk_print_context_init (GtkPrintContext *context)
159 gtk_print_context_class_init (GtkPrintContextClass *class)
161 GObjectClass *gobject_class = (GObjectClass *)class;
163 gobject_class->finalize = gtk_print_context_finalize;
168 _gtk_print_context_new (GtkPrintOperation *op)
170 GtkPrintContext *context;
172 context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
176 context->has_hard_margins = FALSE;
181 static PangoFontMap *
182 _gtk_print_context_get_fontmap (GtkPrintContext *context)
184 return pango_cairo_font_map_get_default ();
188 * gtk_print_context_set_cairo_context:
189 * @context: a #GtkPrintContext
190 * @cr: the cairo context
191 * @dpi_x: the horizontal resolution to use with @cr
192 * @dpi_y: the vertical resolution to use with @cr
194 * Sets a new cairo context on a print context.
196 * This function is intended to be used when implementing
197 * an internal print preview, it is not needed for printing,
198 * since GTK+ itself creates a suitable cairo context in that
204 gtk_print_context_set_cairo_context (GtkPrintContext *context,
210 cairo_destroy (context->cr);
212 context->cr = cairo_reference (cr);
213 context->surface_dpi_x = dpi_x;
214 context->surface_dpi_y = dpi_y;
216 switch (context->op->priv->unit)
220 /* Do nothing, this is the cairo default unit */
221 context->pixels_per_unit_x = 1.0;
222 context->pixels_per_unit_y = 1.0;
224 case GTK_UNIT_POINTS:
225 context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
226 context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
229 context->pixels_per_unit_x = dpi_x;
230 context->pixels_per_unit_y = dpi_y;
233 context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
234 context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
237 cairo_scale (context->cr,
238 context->pixels_per_unit_x,
239 context->pixels_per_unit_y);
244 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
246 cairo_t *cr = context->cr;
247 cairo_matrix_t matrix;
248 GtkPaperSize *paper_size;
249 gdouble width, height;
251 paper_size = gtk_page_setup_get_paper_size (context->page_setup);
253 width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
254 width = width * context->surface_dpi_x / context->pixels_per_unit_x;
255 height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
256 height = height * context->surface_dpi_y / context->pixels_per_unit_y;
258 switch (gtk_page_setup_get_orientation (context->page_setup))
261 case GTK_PAGE_ORIENTATION_PORTRAIT:
263 case GTK_PAGE_ORIENTATION_LANDSCAPE:
264 cairo_translate (cr, 0, height);
265 cairo_matrix_init (&matrix,
269 cairo_transform (cr, &matrix);
271 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
272 cairo_translate (cr, width, height);
273 cairo_matrix_init (&matrix,
277 cairo_transform (cr, &matrix);
279 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
280 cairo_translate (cr, width, 0);
281 cairo_matrix_init (&matrix,
285 cairo_transform (cr, &matrix);
291 _gtk_print_context_translate_into_margin (GtkPrintContext *context)
295 g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
297 /* We do it this way to also handle GTK_UNIT_PIXELS */
298 left = gtk_page_setup_get_left_margin (context->page_setup, GTK_UNIT_INCH);
299 top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
301 cairo_translate (context->cr,
302 left * context->surface_dpi_x / context->pixels_per_unit_x,
303 top * context->surface_dpi_y / context->pixels_per_unit_y);
307 _gtk_print_context_set_page_setup (GtkPrintContext *context,
308 GtkPageSetup *page_setup)
310 g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
311 g_return_if_fail (page_setup == NULL ||
312 GTK_IS_PAGE_SETUP (page_setup));
314 g_object_ref (page_setup);
316 if (context->page_setup != NULL)
317 g_object_unref (context->page_setup);
319 context->page_setup = page_setup;
323 * gtk_print_context_get_cairo_context:
324 * @context: a #GtkPrintContext
326 * Obtains the cairo context that is associated with the
329 * Return value: (transfer none): the cairo context of @context
334 gtk_print_context_get_cairo_context (GtkPrintContext *context)
336 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
342 * gtk_print_context_get_page_setup:
343 * @context: a #GtkPrintContext
345 * Obtains the #GtkPageSetup that determines the page
346 * dimensions of the #GtkPrintContext.
348 * Return value: (transfer none): the page setup of @context
353 gtk_print_context_get_page_setup (GtkPrintContext *context)
355 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
357 return context->page_setup;
361 * gtk_print_context_get_width:
362 * @context: a #GtkPrintContext
364 * Obtains the width of the #GtkPrintContext, in pixels.
366 * Return value: the width of @context
371 gtk_print_context_get_width (GtkPrintContext *context)
373 GtkPrintOperationPrivate *priv;
376 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
378 priv = context->op->priv;
380 if (priv->use_full_page)
381 width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
383 width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
385 /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
386 return width * context->surface_dpi_x / context->pixels_per_unit_x;
390 * gtk_print_context_get_height:
391 * @context: a #GtkPrintContext
393 * Obtains the height of the #GtkPrintContext, in pixels.
395 * Return value: the height of @context
400 gtk_print_context_get_height (GtkPrintContext *context)
402 GtkPrintOperationPrivate *priv;
405 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
407 priv = context->op->priv;
409 if (priv->use_full_page)
410 height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
412 height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
414 /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
415 return height * context->surface_dpi_y / context->pixels_per_unit_y;
419 * gtk_print_context_get_dpi_x:
420 * @context: a #GtkPrintContext
422 * Obtains the horizontal resolution of the #GtkPrintContext,
425 * Return value: the horizontal resolution of @context
430 gtk_print_context_get_dpi_x (GtkPrintContext *context)
432 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
434 return context->surface_dpi_x;
438 * gtk_print_context_get_dpi_y:
439 * @context: a #GtkPrintContext
441 * Obtains the vertical resolution of the #GtkPrintContext,
444 * Return value: the vertical resolution of @context
449 gtk_print_context_get_dpi_y (GtkPrintContext *context)
451 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
453 return context->surface_dpi_y;
457 * gtk_print_context_get_hard_margins:
458 * @context: a #GtkPrintContext
459 * @top: (out): top hardware printer margin
460 * @bottom: (out): bottom hardware printer margin
461 * @left: (out): left hardware printer margin
462 * @right: (out): right hardware printer margin
464 * Obtains the hardware printer margins of the #GtkPrintContext, in units.
466 * Return value: %TRUE if the hard margins were retrieved
471 gtk_print_context_get_hard_margins (GtkPrintContext *context,
477 if (context->has_hard_margins)
479 *top = context->hard_margin_top / context->pixels_per_unit_y;
480 *bottom = context->hard_margin_bottom / context->pixels_per_unit_y;
481 *left = context->hard_margin_left / context->pixels_per_unit_x;
482 *right = context->hard_margin_right / context->pixels_per_unit_x;
485 return context->has_hard_margins;
489 * gtk_print_context_set_hard_margins:
490 * @context: a #GtkPrintContext
491 * @top: top hardware printer margin
492 * @bottom: bottom hardware printer margin
493 * @left: left hardware printer margin
494 * @right: right hardware printer margin
496 * set the hard margins in pixel coordinates
499 _gtk_print_context_set_hard_margins (GtkPrintContext *context,
505 context->hard_margin_top = top;
506 context->hard_margin_bottom = bottom;
507 context->hard_margin_left = left;
508 context->hard_margin_right = right;
509 context->has_hard_margins = TRUE;
513 * gtk_print_context_get_pango_fontmap:
514 * @context: a #GtkPrintContext
516 * Returns a #PangoFontMap that is suitable for use
517 * with the #GtkPrintContext.
519 * Return value: (transfer none): the font map of @context
524 gtk_print_context_get_pango_fontmap (GtkPrintContext *context)
526 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
528 return _gtk_print_context_get_fontmap (context);
532 * gtk_print_context_create_pango_context:
533 * @context: a #GtkPrintContext
535 * Creates a new #PangoContext that can be used with the
538 * Return value: (transfer full): a new Pango context for @context
543 gtk_print_context_create_pango_context (GtkPrintContext *context)
545 PangoContext *pango_context;
546 cairo_font_options_t *options;
548 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
550 pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (_gtk_print_context_get_fontmap (context)));
552 options = cairo_font_options_create ();
553 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
554 pango_cairo_context_set_font_options (pango_context, options);
555 cairo_font_options_destroy (options);
557 /* We use the unit-scaled resolution, as we still want
558 * fonts given in points to work
560 pango_cairo_context_set_resolution (pango_context,
561 context->surface_dpi_y / context->pixels_per_unit_y);
562 return pango_context;
566 * gtk_print_context_create_pango_layout:
567 * @context: a #GtkPrintContext
569 * Creates a new #PangoLayout that is suitable for use
570 * with the #GtkPrintContext.
572 * Return value: (transfer full): a new Pango layout for @context
577 gtk_print_context_create_pango_layout (GtkPrintContext *context)
579 PangoContext *pango_context;
582 g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
584 pango_context = gtk_print_context_create_pango_context (context);
585 layout = pango_layout_new (pango_context);
587 pango_cairo_update_context (context->cr, pango_context);
588 g_object_unref (pango_context);