]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintcontext.c
Move documentation to inline comments: GtkPrintContext
[~andy/gtk] / gtk / gtkprintcontext.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintcontext.c: Print Context
3  * Copyright (C) 2006, Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #include "config.h"
22 #include "gtkprintoperation-private.h"
23
24
25 /**
26  * SECTION:gtkprintcontext
27  * @Short_description: Encapsulates context for drawing pages
28  * @Title: GtkPrintContext
29  *
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.
35  *
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.
39  *
40  * <example>
41  * <title>Using GtkPrintContext in a #GtkPrintOperation::draw-page callback</title>
42  * <programlisting>
43  * static void
44  * draw_page (GtkPrintOperation *operation,
45  *         GtkPrintContext   *context,
46  *         int                page_nr)
47  * {
48  *   cairo_t *cr;
49  *   PangoLayout *layout;
50  *   PangoFontDescription *desc;
51  *
52  *   cr = gtk_print_context_get_cairo_context (context);
53  *
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);
57  *
58  *   cairo_fill (cr);
59  *
60  *   // Draw some lines
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);
65  *
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);
70  *
71  *   cairo_stroke (cr);
72  *
73  *   // Draw some text
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);
79  *
80  *   cairo_move_to (cr, 30, 20);
81  *   pango_cairo_layout_path (cr, layout);
82  *
83  *   // Font Outline
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);
87  *
88  *   // Font Fill
89  *   cairo_set_source_rgb (cr, 0, 0.0, 1.0);
90  *   cairo_fill (cr);
91  *
92  *   g_object_unref (layout);
93  * }
94  * </programlisting>
95  * </example>
96  *
97  * Printing support was added in GTK+ 2.10.
98  */
99
100
101 typedef struct _GtkPrintContextClass GtkPrintContextClass;
102
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))
106
107 #define MM_PER_INCH 25.4
108 #define POINTS_PER_INCH 72
109
110 struct _GtkPrintContext
111 {
112   GObject parent_instance;
113
114   GtkPrintOperation *op;
115   cairo_t *cr;
116   GtkPageSetup *page_setup;
117
118   gdouble surface_dpi_x;
119   gdouble surface_dpi_y;
120   
121   gdouble pixels_per_unit_x;
122   gdouble pixels_per_unit_y;
123
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;
129
130 };
131
132 struct _GtkPrintContextClass
133 {
134   GObjectClass parent_class;
135 };
136
137 G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
138
139 static void
140 gtk_print_context_finalize (GObject *object)
141 {
142   GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
143
144   if (context->page_setup)
145     g_object_unref (context->page_setup);
146
147   if (context->cr)
148     cairo_destroy (context->cr);
149   
150   G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
151 }
152
153 static void
154 gtk_print_context_init (GtkPrintContext *context)
155 {
156 }
157
158 static void
159 gtk_print_context_class_init (GtkPrintContextClass *class)
160 {
161   GObjectClass *gobject_class = (GObjectClass *)class;
162
163   gobject_class->finalize = gtk_print_context_finalize;
164 }
165
166
167 GtkPrintContext *
168 _gtk_print_context_new (GtkPrintOperation *op)
169 {
170   GtkPrintContext *context;
171
172   context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
173
174   context->op = op;
175   context->cr = NULL;
176   context->has_hard_margins = FALSE;
177   
178   return context;
179 }
180
181 static PangoFontMap *
182 _gtk_print_context_get_fontmap (GtkPrintContext *context)
183 {
184   return pango_cairo_font_map_get_default ();
185 }
186
187 /**
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
193  *
194  * Sets a new cairo context on a print context. 
195  * 
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
199  * case.
200  *
201  * Since: 2.10 
202  */
203 void
204 gtk_print_context_set_cairo_context (GtkPrintContext *context,
205                                      cairo_t         *cr,
206                                      double           dpi_x,
207                                      double           dpi_y)
208 {
209   if (context->cr)
210     cairo_destroy (context->cr);
211
212   context->cr = cairo_reference (cr);
213   context->surface_dpi_x = dpi_x;
214   context->surface_dpi_y = dpi_y;
215
216   switch (context->op->priv->unit)
217     {
218     default:
219     case GTK_UNIT_PIXEL:
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;
223       break;
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;
227       break;
228     case GTK_UNIT_INCH:
229       context->pixels_per_unit_x = dpi_x;
230       context->pixels_per_unit_y = dpi_y;
231       break;
232     case GTK_UNIT_MM:
233       context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
234       context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
235       break;
236     }
237   cairo_scale (context->cr,
238                context->pixels_per_unit_x,
239                context->pixels_per_unit_y);
240 }
241
242
243 void
244 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
245 {
246   cairo_t *cr = context->cr;
247   cairo_matrix_t matrix;
248   GtkPaperSize *paper_size;
249   gdouble width, height;
250
251   paper_size = gtk_page_setup_get_paper_size (context->page_setup);
252
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;
257   
258   switch (gtk_page_setup_get_orientation (context->page_setup))
259     {
260     default:
261     case GTK_PAGE_ORIENTATION_PORTRAIT:
262       break;
263     case GTK_PAGE_ORIENTATION_LANDSCAPE:
264       cairo_translate (cr, 0, height);
265       cairo_matrix_init (&matrix,
266                          0, -1,
267                          1,  0,
268                          0,  0);
269       cairo_transform (cr, &matrix);
270       break;
271     case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
272       cairo_translate (cr, width, height);
273       cairo_matrix_init (&matrix,
274                          -1,  0,
275                           0, -1,
276                           0,  0);
277       cairo_transform (cr, &matrix);
278       break;
279     case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
280       cairo_translate (cr, width, 0);
281       cairo_matrix_init (&matrix,
282                           0,  1,
283                          -1,  0,
284                           0,  0);
285       cairo_transform (cr, &matrix);
286       break;
287     }
288 }
289
290 void
291 _gtk_print_context_translate_into_margin (GtkPrintContext *context)
292 {
293   gdouble left, top;
294
295   g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
296
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);
300
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);
304 }
305
306 void
307 _gtk_print_context_set_page_setup (GtkPrintContext *context,
308                                    GtkPageSetup    *page_setup)
309 {
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));
313   
314   g_object_ref (page_setup);
315
316   if (context->page_setup != NULL)
317     g_object_unref (context->page_setup);
318
319   context->page_setup = page_setup;
320 }
321
322 /**
323  * gtk_print_context_get_cairo_context:
324  * @context: a #GtkPrintContext
325  *
326  * Obtains the cairo context that is associated with the
327  * #GtkPrintContext.
328  *
329  * Return value: (transfer none): the cairo context of @context
330  *
331  * Since: 2.10
332  */
333 cairo_t *
334 gtk_print_context_get_cairo_context (GtkPrintContext *context)
335 {
336   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
337
338   return context->cr;
339 }
340
341 /**
342  * gtk_print_context_get_page_setup:
343  * @context: a #GtkPrintContext
344  *
345  * Obtains the #GtkPageSetup that determines the page
346  * dimensions of the #GtkPrintContext.
347  *
348  * Return value: (transfer none): the page setup of @context
349  *
350  * Since: 2.10
351  */
352 GtkPageSetup *
353 gtk_print_context_get_page_setup (GtkPrintContext *context)
354 {
355   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
356
357   return context->page_setup;
358 }
359
360 /**
361  * gtk_print_context_get_width:
362  * @context: a #GtkPrintContext
363  *
364  * Obtains the width of the #GtkPrintContext, in pixels.
365  *
366  * Return value: the width of @context
367  *
368  * Since: 2.10 
369  */
370 gdouble
371 gtk_print_context_get_width (GtkPrintContext *context)
372 {
373   GtkPrintOperationPrivate *priv;
374   gdouble width;
375
376   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
377
378   priv = context->op->priv;
379
380   if (priv->use_full_page)
381     width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
382   else
383     width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
384
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;
387 }
388
389 /**
390  * gtk_print_context_get_height:
391  * @context: a #GtkPrintContext
392  * 
393  * Obtains the height of the #GtkPrintContext, in pixels.
394  *
395  * Return value: the height of @context
396  *
397  * Since: 2.10
398  */
399 gdouble
400 gtk_print_context_get_height (GtkPrintContext *context)
401 {
402   GtkPrintOperationPrivate *priv;
403   gdouble height;
404
405   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
406
407   priv = context->op->priv;
408
409   if (priv->use_full_page)
410     height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
411   else
412     height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
413
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;
416 }
417
418 /**
419  * gtk_print_context_get_dpi_x:
420  * @context: a #GtkPrintContext
421  * 
422  * Obtains the horizontal resolution of the #GtkPrintContext,
423  * in dots per inch.
424  *
425  * Return value: the horizontal resolution of @context
426  *
427  * Since: 2.10
428  */
429 gdouble
430 gtk_print_context_get_dpi_x (GtkPrintContext *context)
431 {
432   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
433
434   return context->surface_dpi_x;
435 }
436
437 /**
438  * gtk_print_context_get_dpi_y:
439  * @context: a #GtkPrintContext
440  * 
441  * Obtains the vertical resolution of the #GtkPrintContext,
442  * in dots per inch.
443  *
444  * Return value: the vertical resolution of @context
445  *
446  * Since: 2.10
447  */
448 gdouble
449 gtk_print_context_get_dpi_y (GtkPrintContext *context)
450 {
451   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
452
453   return context->surface_dpi_y;
454 }
455
456 /**
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
463  *
464  * Obtains the hardware printer margins of the #GtkPrintContext, in units.
465  *
466  * Return value: %TRUE if the hard margins were retrieved
467  *
468  * Since: 2.20
469  */
470 gboolean
471 gtk_print_context_get_hard_margins (GtkPrintContext *context,
472                                     gdouble         *top,
473                                     gdouble         *bottom,
474                                     gdouble         *left,
475                                     gdouble         *right)
476 {
477   if (context->has_hard_margins)
478     {
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;
483     }
484
485   return context->has_hard_margins;
486 }
487
488 /**
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
495  *
496  * set the hard margins in pixel coordinates
497  */
498 void
499 _gtk_print_context_set_hard_margins (GtkPrintContext *context,
500                                      gdouble          top,
501                                      gdouble          bottom,
502                                      gdouble          left,
503                                      gdouble          right)
504 {
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;
510 }
511
512 /**
513  * gtk_print_context_get_pango_fontmap:
514  * @context: a #GtkPrintContext
515  *
516  * Returns a #PangoFontMap that is suitable for use
517  * with the #GtkPrintContext.
518  *
519  * Return value: (transfer none): the font map of @context
520  *
521  * Since: 2.10
522  */
523 PangoFontMap *
524 gtk_print_context_get_pango_fontmap (GtkPrintContext *context)
525 {
526   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
527
528   return _gtk_print_context_get_fontmap (context);
529 }
530
531 /**
532  * gtk_print_context_create_pango_context:
533  * @context: a #GtkPrintContext
534  *
535  * Creates a new #PangoContext that can be used with the
536  * #GtkPrintContext.
537  *
538  * Return value: (transfer full): a new Pango context for @context
539  * 
540  * Since: 2.10
541  */
542 PangoContext *
543 gtk_print_context_create_pango_context (GtkPrintContext *context)
544 {
545   PangoContext *pango_context;
546   cairo_font_options_t *options;
547
548   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
549   
550   pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (_gtk_print_context_get_fontmap (context)));
551
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);
556   
557   /* We use the unit-scaled resolution, as we still want 
558    * fonts given in points to work 
559    */
560   pango_cairo_context_set_resolution (pango_context,
561                                       context->surface_dpi_y / context->pixels_per_unit_y);
562   return pango_context;
563 }
564
565 /**
566  * gtk_print_context_create_pango_layout:
567  * @context: a #GtkPrintContext
568  *
569  * Creates a new #PangoLayout that is suitable for use
570  * with the #GtkPrintContext.
571  * 
572  * Return value: (transfer full): a new Pango layout for @context
573  *
574  * Since: 2.10
575  */
576 PangoLayout *
577 gtk_print_context_create_pango_layout (GtkPrintContext *context)
578 {
579   PangoContext *pango_context;
580   PangoLayout *layout;
581
582   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
583
584   pango_context = gtk_print_context_create_pango_context (context);
585   layout = pango_layout_new (pango_context);
586
587   pango_cairo_update_context (context->cr, pango_context);
588   g_object_unref (pango_context);
589
590   return layout;
591 }