]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintcontext.c
Merge branch 'master' into native-layout
[~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 #include "gtkalias.h"
24
25 typedef struct _GtkPrintContextClass GtkPrintContextClass;
26
27 #define GTK_IS_PRINT_CONTEXT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_CONTEXT))
28 #define GTK_PRINT_CONTEXT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
29 #define GTK_PRINT_CONTEXT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
30
31 #define MM_PER_INCH 25.4
32 #define POINTS_PER_INCH 72
33
34 struct _GtkPrintContext
35 {
36   GObject parent_instance;
37
38   GtkPrintOperation *op;
39   cairo_t *cr;
40   GtkPageSetup *page_setup;
41
42   gdouble surface_dpi_x;
43   gdouble surface_dpi_y;
44   
45   gdouble pixels_per_unit_x;
46   gdouble pixels_per_unit_y;
47
48   gboolean has_hard_margins;
49   gdouble hard_margin_top;
50   gdouble hard_margin_bottom;
51   gdouble hard_margin_left;
52   gdouble hard_margin_right;
53
54 };
55
56 struct _GtkPrintContextClass
57 {
58   GObjectClass parent_class;
59 };
60
61 G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
62
63 static void
64 gtk_print_context_finalize (GObject *object)
65 {
66   GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
67
68   if (context->page_setup)
69     g_object_unref (context->page_setup);
70
71   if (context->cr)
72     cairo_destroy (context->cr);
73   
74   G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
75 }
76
77 static void
78 gtk_print_context_init (GtkPrintContext *context)
79 {
80 }
81
82 static void
83 gtk_print_context_class_init (GtkPrintContextClass *class)
84 {
85   GObjectClass *gobject_class = (GObjectClass *)class;
86
87   gobject_class->finalize = gtk_print_context_finalize;
88 }
89
90
91 GtkPrintContext *
92 _gtk_print_context_new (GtkPrintOperation *op)
93 {
94   GtkPrintContext *context;
95
96   context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
97
98   context->op = op;
99   context->cr = NULL;
100   context->has_hard_margins = FALSE;
101   
102   return context;
103 }
104
105 static PangoFontMap *
106 _gtk_print_context_get_fontmap (GtkPrintContext *context)
107 {
108   return pango_cairo_font_map_get_default ();
109 }
110
111 /**
112  * gtk_print_context_set_cairo_context:
113  * @context: a #GtkPrintContext
114  * @cr: the cairo context
115  * @dpi_x: the horizontal resolution to use with @cr
116  * @dpi_y: the vertical resolution to use with @cr
117  *
118  * Sets a new cairo context on a print context. 
119  * 
120  * This function is intended to be used when implementing
121  * an internal print preview, it is not needed for printing,
122  * since GTK+ itself creates a suitable cairo context in that
123  * case.
124  *
125  * Since: 2.10 
126  */
127 void
128 gtk_print_context_set_cairo_context (GtkPrintContext *context,
129                                      cairo_t         *cr,
130                                      double           dpi_x,
131                                      double           dpi_y)
132 {
133   if (context->cr)
134     cairo_destroy (context->cr);
135
136   context->cr = cairo_reference (cr);
137   context->surface_dpi_x = dpi_x;
138   context->surface_dpi_y = dpi_y;
139
140   switch (context->op->priv->unit)
141     {
142     default:
143     case GTK_UNIT_PIXEL:
144       /* Do nothing, this is the cairo default unit */
145       context->pixels_per_unit_x = 1.0;
146       context->pixels_per_unit_y = 1.0;
147       break;
148     case GTK_UNIT_POINTS:
149       context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
150       context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
151       break;
152     case GTK_UNIT_INCH:
153       context->pixels_per_unit_x = dpi_x;
154       context->pixels_per_unit_y = dpi_y;
155       break;
156     case GTK_UNIT_MM:
157       context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
158       context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
159       break;
160     }
161   cairo_scale (context->cr,
162                context->pixels_per_unit_x,
163                context->pixels_per_unit_y);
164 }
165
166
167 void
168 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
169 {
170   cairo_t *cr = context->cr;
171   cairo_matrix_t matrix;
172   GtkPaperSize *paper_size;
173   gdouble width, height;
174
175   paper_size = gtk_page_setup_get_paper_size (context->page_setup);
176
177   width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
178   width = width * context->surface_dpi_x / context->pixels_per_unit_x;
179   height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
180   height = height * context->surface_dpi_y / context->pixels_per_unit_y;
181   
182   switch (gtk_page_setup_get_orientation (context->page_setup))
183     {
184     default:
185     case GTK_PAGE_ORIENTATION_PORTRAIT:
186       break;
187     case GTK_PAGE_ORIENTATION_LANDSCAPE:
188       cairo_translate (cr, 0, height);
189       cairo_matrix_init (&matrix,
190                          0, -1,
191                          1,  0,
192                          0,  0);
193       cairo_transform (cr, &matrix);
194       break;
195     case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
196       cairo_translate (cr, width, height);
197       cairo_matrix_init (&matrix,
198                          -1,  0,
199                           0, -1,
200                           0,  0);
201       cairo_transform (cr, &matrix);
202       break;
203     case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
204       cairo_translate (cr, width, 0);
205       cairo_matrix_init (&matrix,
206                           0,  1,
207                          -1,  0,
208                           0,  0);
209       cairo_transform (cr, &matrix);
210       break;
211     }
212 }
213
214 void
215 _gtk_print_context_translate_into_margin (GtkPrintContext *context)
216 {
217   GtkPrintOperationPrivate *priv;
218   gdouble left, top;
219
220   g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
221
222   priv = context->op->priv;
223
224   /* We do it this way to also handle GTK_UNIT_PIXELS */
225   
226   left = gtk_page_setup_get_left_margin (context->page_setup, GTK_UNIT_INCH);
227   top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
228
229   cairo_translate (context->cr,
230                    left * context->surface_dpi_x / context->pixels_per_unit_x,
231                    top * context->surface_dpi_y / context->pixels_per_unit_y);
232 }
233
234 void
235 _gtk_print_context_set_page_setup (GtkPrintContext *context,
236                                    GtkPageSetup    *page_setup)
237 {
238   g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
239   g_return_if_fail (page_setup == NULL ||
240                     GTK_IS_PAGE_SETUP (page_setup));
241   
242   g_object_ref (page_setup);
243
244   if (context->page_setup != NULL)
245     g_object_unref (context->page_setup);
246
247   context->page_setup = page_setup;
248 }
249
250 /**
251  * gtk_print_context_get_cairo_context:
252  * @context: a #GtkPrintContext
253  *
254  * Obtains the cairo context that is associated with the
255  * #GtkPrintContext.
256  *
257  * Return value: the cairo context of @context
258  *
259  * Since: 2.10
260  */
261 cairo_t *
262 gtk_print_context_get_cairo_context (GtkPrintContext *context)
263 {
264   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
265
266   return context->cr;
267 }
268
269 /**
270  * gtk_print_context_get_page_setup:
271  * @context: a #GtkPrintContext
272  *
273  * Obtains the #GtkPageSetup that determines the page
274  * dimensions of the #GtkPrintContext.
275  *
276  * Return value: the page setup of @context
277  *
278  * Since: 2.10
279  */
280 GtkPageSetup *
281 gtk_print_context_get_page_setup (GtkPrintContext *context)
282 {
283   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
284
285   return context->page_setup;
286 }
287
288 /**
289  * gtk_print_context_get_width:
290  * @context: a #GtkPrintContext
291  *
292  * Obtains the width of the #GtkPrintContext, in pixels.
293  *
294  * Return value: the width of @context
295  *
296  * Since: 2.10 
297  */
298 gdouble
299 gtk_print_context_get_width (GtkPrintContext *context)
300 {
301   GtkPrintOperationPrivate *priv;
302   gdouble width;
303
304   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
305
306   priv = context->op->priv;
307
308   if (priv->use_full_page)
309     width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
310   else
311     width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
312
313   /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
314   return width * context->surface_dpi_x / context->pixels_per_unit_x;
315 }
316
317 /**
318  * gtk_print_context_get_height:
319  * @context: a #GtkPrintContext
320  * 
321  * Obtains the height of the #GtkPrintContext, in pixels.
322  *
323  * Return value: the height of @context
324  *
325  * Since: 2.10
326  */
327 gdouble
328 gtk_print_context_get_height (GtkPrintContext *context)
329 {
330   GtkPrintOperationPrivate *priv;
331   gdouble height;
332
333   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
334
335   priv = context->op->priv;
336
337   if (priv->use_full_page)
338     height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
339   else
340     height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
341
342   /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
343   return height * context->surface_dpi_y / context->pixels_per_unit_y;
344 }
345
346 /**
347  * gtk_print_context_get_dpi_x:
348  * @context: a #GtkPrintContext
349  * 
350  * Obtains the horizontal resolution of the #GtkPrintContext,
351  * in dots per inch.
352  *
353  * Return value: the horizontal resolution of @context
354  *
355  * Since: 2.10
356  */
357 gdouble
358 gtk_print_context_get_dpi_x (GtkPrintContext *context)
359 {
360   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
361
362   return context->surface_dpi_x;
363 }
364
365 /**
366  * gtk_print_context_get_dpi_y:
367  * @context: a #GtkPrintContext
368  * 
369  * Obtains the vertical resolution of the #GtkPrintContext,
370  * in dots per inch.
371  *
372  * Return value: the vertical resolution of @context
373  *
374  * Since: 2.10
375  */
376 gdouble
377 gtk_print_context_get_dpi_y (GtkPrintContext *context)
378 {
379   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
380
381   return context->surface_dpi_y;
382 }
383
384 /**
385  * gtk_print_context_get_hard_margins:
386  * @context: a #GtkPrintContext
387  * @top: top hardware printer margin
388  * @bottom: bottom hardware printer margin
389  * @left: left hardware printer margin
390  * @right: right hardware printer margin
391  *
392  * Obtains the hardware printer margins of the #GtkPrintContext, in units.
393  *
394  * Return value: %TRUE if the hard margins were retrieved
395  *
396  * Since: 2.20
397  */
398 gboolean
399 gtk_print_context_get_hard_margins (GtkPrintContext *context,
400                                     gdouble         *top,
401                                     gdouble         *bottom,
402                                     gdouble         *left,
403                                     gdouble         *right)
404 {
405   if (context->has_hard_margins)
406     {
407       *top    = context->hard_margin_top / context->pixels_per_unit_y;
408       *bottom = context->hard_margin_bottom / context->pixels_per_unit_y;
409       *left   = context->hard_margin_left / context->pixels_per_unit_x;
410       *right  = context->hard_margin_right / context->pixels_per_unit_x;
411     }
412
413   return context->has_hard_margins;
414 }
415
416 /**
417  * gtk_print_context_set_hard_margins:
418  * @context: a #GtkPrintContext
419  * @top: top hardware printer margin
420  * @bottom: bottom hardware printer margin
421  * @left: left hardware printer margin
422  * @right: right hardware printer margin
423  *
424  * set the hard margins in pixel coordinates
425  */
426 void
427 _gtk_print_context_set_hard_margins (GtkPrintContext *context,
428                                      gdouble          top,
429                                      gdouble          bottom,
430                                      gdouble          left,
431                                      gdouble          right)
432 {
433   context->hard_margin_top    = top;
434   context->hard_margin_bottom = bottom;
435   context->hard_margin_left   = left;
436   context->hard_margin_right  = right;
437   context->has_hard_margins   = TRUE;
438 }
439
440 /**
441  * gtk_print_context_get_pango_fontmap:
442  * @context: a #GtkPrintContext
443  *
444  * Returns a #PangoFontMap that is suitable for use 
445  * with the #GtkPrintContext.
446  *
447  * Return value: the font map of @context
448  *
449  * Since: 2.10
450  */
451 PangoFontMap *
452 gtk_print_context_get_pango_fontmap (GtkPrintContext *context)
453 {
454   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
455
456   return _gtk_print_context_get_fontmap (context);
457 }
458
459 /**
460  * gtk_print_context_create_pango_context:
461  * @context: a #GtkPrintContext 
462  *
463  * Creates a new #PangoContext that can be used with the
464  * #GtkPrintContext.
465  *
466  * Return value: a new Pango context for @context
467  * 
468  * Since: 2.10
469  */
470 PangoContext *
471 gtk_print_context_create_pango_context (GtkPrintContext *context)
472 {
473   PangoContext *pango_context;
474   cairo_font_options_t *options;
475
476   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
477   
478   pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (_gtk_print_context_get_fontmap (context)));
479
480   options = cairo_font_options_create ();
481   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
482   pango_cairo_context_set_font_options (pango_context, options);
483   cairo_font_options_destroy (options);
484   
485   /* We use the unit-scaled resolution, as we still want 
486    * fonts given in points to work 
487    */
488   pango_cairo_context_set_resolution (pango_context,
489                                       context->surface_dpi_y / context->pixels_per_unit_y);
490   return pango_context;
491 }
492
493 /**
494  * gtk_print_context_create_pango_layout:
495  * @context: a #GtkPrintContext
496  *
497  * Creates a new #PangoLayout that is suitable for use
498  * with the #GtkPrintContext.
499  * 
500  * Return value: a new Pango layout for @context
501  *
502  * Since: 2.10
503  */
504 PangoLayout *
505 gtk_print_context_create_pango_layout (GtkPrintContext *context)
506 {
507   PangoContext *pango_context;
508   PangoLayout *layout;
509
510   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
511
512   pango_context = gtk_print_context_create_pango_context (context);
513   layout = pango_layout_new (pango_context);
514
515   pango_cairo_update_context (context->cr, pango_context);
516   g_object_unref (pango_context);
517
518   return layout;
519 }
520
521
522 #define __GTK_PRINT_CONTEXT_C__
523 #include "gtkaliasdef.c"