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