source: trunk/third/libgnomeprintui/libgnomeprintui/gnome-print-preview.c @ 21504

Revision 21504, 13.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21503, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 *  gnome-print-preview.c: print preview driver
4 *
5 *  This program is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Library General Public License
7 *  as published by the Free Software Foundation; either version 2 of
8 *  the License, or (at your option) any later version.
9 *
10 *  This program 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
13 *  GNU Library General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Library General Public
16 *  License along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *  Authors:
20 *    Miguel de Icaza <miguel@ximian.com>
21 *    Lauris Kaplinski <lauris@ximian.com>
22 *
23 *  Copyright (C) 1999-2002 Ximian Inc. and authors
24 *
25 */
26
27#include <config.h>
28
29#include <string.h>
30#include <math.h>
31#include <gdk-pixbuf/gdk-pixbuf.h>
32
33#include <libgnomecanvas/gnome-canvas-clipgroup.h>
34#include <libgnomeprint/private/gp-gc-private.h>
35#include <libgnomeprint/private/gnome-glyphlist-private.h>
36
37#include "gnome-canvas-hacktext.h"
38#include "gnome-print-preview-private.h"
39
40struct _GnomePrintPreviewPrivate {
41        GPGC * gc;
42
43        /* Current page displayed */
44        int top_page;
45        int current_page;
46
47        /* The root group, with a translation setup */
48        GnomeCanvasItem *root;
49
50        /* The current page */
51        GnomeCanvasItem *page;
52
53        /* Strict theme compliance [#96802] */
54        gboolean theme_compliance;
55};
56
57static GnomePrintContextClass *parent_class;
58static gboolean use_theme;
59
60static void
61outline_set_style_cb (GtkWidget *canvas, GnomeCanvasItem *item)
62{
63        gint32 color;
64        GtkStyle *style;
65
66        style = gtk_widget_get_style (GTK_WIDGET (canvas));
67        color = GPP_COLOR_RGBA (style->text [GTK_STATE_NORMAL], 0xff);
68       
69        gnome_canvas_item_set (item, "outline_color_rgba", color, NULL);
70}
71       
72
73static int
74gpp_stroke (GnomePrintContext *pc, const ArtBpath *bpath)
75{
76        GnomePrintPreview *pp = GNOME_PRINT_PREVIEW (pc);
77        GnomePrintPreviewPrivate *priv = pp->priv;
78        GnomeCanvasGroup *group;
79        GnomeCanvasItem *item;
80        GnomeCanvasPathDef *path;
81
82        /* fixme: currentpath invariants */
83
84        group = (GnomeCanvasGroup *) gp_gc_get_data (priv->gc);
85        g_assert (group != NULL);
86        g_assert (GNOME_IS_CANVAS_GROUP (group));
87
88        path = gnome_canvas_path_def_new_from_foreign_bpath ((ArtBpath *) bpath);
89
90        /* Fixme: Can we assume that linewidth == width_units? */
91        /* Probably yes, as object->page ctm == identity */
92
93        item = gnome_canvas_item_new (group,
94                gnome_canvas_bpath_get_type (),
95                "bpath",        path,
96                "width_units",  gp_gc_get_linewidth (pc->gc),
97                "cap_style",    gp_gc_get_linecap (pc->gc) + 1 /* See #104932 */,
98                "join_style",   gp_gc_get_linejoin (pc->gc),
99                "outline_color_rgba", gp_gc_get_rgba (pc->gc),
100                "miterlimit",   gp_gc_get_miterlimit (pc->gc),
101                "dash",         gp_gc_get_dash (pc->gc),
102                NULL);
103
104        gnome_canvas_path_def_unref (path);
105
106        if (use_theme)
107                outline_set_style_cb (GTK_WIDGET (item->canvas), item);
108        return 1;
109}
110
111static void
112fill_set_style_cb (GtkWidget *canvas, GnomeCanvasItem *item)
113{
114        gint32 color;
115        GtkStyle *style;
116
117        style = gtk_widget_get_style (GTK_WIDGET (canvas));
118        color = GPP_COLOR_RGBA (style->bg [GTK_STATE_NORMAL], 0xff);
119       
120        gnome_canvas_item_set (item, "fill_color_rgba", color, NULL);
121}
122       
123static int
124gpp_fill (GnomePrintContext *pc, const ArtBpath *bpath, ArtWindRule rule)
125{
126        GnomePrintPreview *pp;
127        GnomePrintPreviewPrivate * priv;
128        GnomeCanvasGroup *group;
129        GnomeCanvasItem *item;
130        GnomeCanvasPathDef *path;
131       
132        pp = GNOME_PRINT_PREVIEW (pc);
133        priv = pp->priv;
134
135        group = (GnomeCanvasGroup *) gp_gc_get_data (priv->gc);
136        g_assert (group != NULL);
137        g_assert (GNOME_IS_CANVAS_GROUP (group));
138
139        path = gnome_canvas_path_def_new_from_foreign_bpath ((ArtBpath *) bpath);
140
141        item = gnome_canvas_item_new (group,
142                gnome_canvas_bpath_get_type (),
143                "bpath", path,
144                "outline_color", NULL,
145                "fill_color_rgba", gp_gc_get_rgba (pc->gc),
146                "wind", rule,
147                NULL);
148        gnome_canvas_path_def_unref (path);
149
150        if (use_theme)
151                fill_set_style_cb (GTK_WIDGET (item->canvas), item);
152        return 1;
153}
154
155static int
156gpp_clip (GnomePrintContext *pc, const ArtBpath *bpath, ArtWindRule rule)
157{
158        GnomePrintPreview *pp;
159        GnomePrintPreviewPrivate * priv;
160        GnomeCanvasGroup * group;
161        GnomeCanvasItem * clip;
162        GnomeCanvasPathDef *path;
163
164        pp = GNOME_PRINT_PREVIEW (pc);
165        priv = pp->priv;
166
167        group = (GnomeCanvasGroup *) gp_gc_get_data (priv->gc);
168
169        path = gnome_canvas_path_def_new_from_foreign_bpath ((ArtBpath *) bpath);
170
171        clip = gnome_canvas_item_new (group,
172                gnome_canvas_clipgroup_get_type (),
173                "path", path,
174                "wind", rule,
175                NULL);
176
177        gp_gc_set_data (priv->gc, clip);
178
179        gnome_canvas_path_def_unref (path);
180
181        return 1;
182}
183
184static void
185gpp_image_free_pix (guchar *pixels, gpointer data)
186{
187        g_free (pixels);
188
189}
190
191static int
192gpp_image (GnomePrintContext *pc, const gdouble *affine, const guchar *px, gint w, gint h, gint rowstride, gint ch)
193{
194        GnomePrintPreview *pp = GNOME_PRINT_PREVIEW (pc);
195        GnomeCanvasGroup * group;
196        GnomeCanvasItem *item;
197        GdkPixbuf *pixbuf;
198        int size, bpp;
199        void *dup;
200       
201        /*
202         * We do convert gray scale images to RGB
203         */
204
205        if (ch == 1) {
206                bpp = 3;
207        } else {
208                bpp = ch;
209        }
210       
211        size = w * h * bpp;
212        dup = g_malloc (size);
213        if (!dup) return -1;
214
215        if (ch == 3) {
216                memcpy (dup, px, size);
217                pixbuf = gdk_pixbuf_new_from_data (dup, GDK_COLORSPACE_RGB,
218                                                   FALSE, 8, w, h, rowstride,
219                                                   gpp_image_free_pix, NULL);
220        } else if (ch == 4) {
221                memcpy (dup, px, size);
222                pixbuf = gdk_pixbuf_new_from_data (dup, GDK_COLORSPACE_RGB,
223                                                   TRUE, 8, w, h, rowstride,
224                                                   gpp_image_free_pix, NULL);
225        } else if (ch == 1) {
226                const char *source;
227                char *target;
228                int  ix, iy;
229
230                source = px;
231                target = dup;
232
233                for (iy = 0; iy < h; iy++){
234                        for (ix = 0; ix < w; ix++){
235                                *target++ = *source;
236                                *target++ = *source;
237                                *target++ = *source;
238                                source++;
239                        }
240                }
241                pixbuf = gdk_pixbuf_new_from_data (dup, GDK_COLORSPACE_RGB,
242                                                   FALSE, 8, w, h, rowstride * 3,
243                                                   gpp_image_free_pix, NULL);
244        } else
245                return -1;
246
247        group = (GnomeCanvasGroup *) gp_gc_get_data (pp->priv->gc);
248
249        item = gnome_canvas_item_new (group,
250                                      GNOME_TYPE_CANVAS_PIXBUF,
251                                      "pixbuf", pixbuf,
252                                      "x",      0.0,
253                                      "y",      0.0,
254                                      "width",  (gdouble) w,
255                                      "height", (gdouble) h,
256                                      "anchor", GTK_ANCHOR_NW,
257                                      NULL);
258        g_object_unref (G_OBJECT (pixbuf));
259
260        /* Apply the transformation for the image */
261        {
262                double transform[6];
263                double flip[6];
264                flip[0] = 1.0 / w;
265                flip[1] = 0.0;
266                flip[2] = 0.0;
267                flip[3] = -1.0 / h;
268                flip[4] = 0.0;
269                flip[5] = 1.0;
270
271                art_affine_multiply (transform, flip, affine);
272                gnome_canvas_item_affine_absolute (item, transform);
273        }
274       
275        return 1;
276}
277
278static int
279gpp_showpage (GnomePrintContext *pc)
280{
281        return GNOME_PRINT_OK;
282}
283
284static int
285gpp_beginpage (GnomePrintContext *pc, const guchar *name)
286{
287        return GNOME_PRINT_OK;
288}
289
290static void
291glyphlist_set_style_cb (GtkWidget *canvas, GnomeCanvasItem *item)
292{
293        GnomeGlyphList *gl, *new;
294        gint32 color;
295        GtkStyle *style;
296        gint i;
297
298        style = gtk_widget_get_style (GTK_WIDGET (canvas));
299        color = GPP_COLOR_RGBA (style->text [GTK_STATE_NORMAL], 0xff);
300
301        g_object_get (G_OBJECT (item), "glyphlist", &gl, NULL);
302        new = gnome_glyphlist_duplicate (gl);
303        for (i = 0; i < new->r_length; i++) {
304                if (new->rules[i].code ==  GGL_COLOR) {
305                        new->rules[i].value.ival = color;
306                }
307        }
308        gnome_canvas_item_set (item, "glyphlist", new, NULL);
309}
310
311static int
312gpp_glyphlist (GnomePrintContext *pc, const gdouble *affine, GnomeGlyphList * glyphlist)
313{
314        GnomePrintPreview *pp = GNOME_PRINT_PREVIEW (pc);
315        GnomeCanvasGroup *group;
316        GnomeCanvasItem *item;
317        double transform[6], a[6];
318
319        /*
320         * The X and Y positions were computed to be the base
321         * with the translation already done for the new
322         * Postscript->Canvas translation
323         */
324        memcpy (transform, gp_gc_get_ctm (pc->gc), sizeof (transform));
325        art_affine_scale (a, 1.0, -1.0);
326        art_affine_multiply (transform, a, affine);
327
328        group = (GnomeCanvasGroup *) gp_gc_get_data (pp->priv->gc);
329        item = gnome_canvas_item_new (group,
330                                      gnome_canvas_hacktext_get_type (),
331                                      "x", 0.0,
332                                      "y", 0.0,
333                                      "glyphlist", glyphlist,
334                                      NULL);
335
336        gnome_canvas_item_affine_absolute (item, transform);
337
338        if (use_theme)
339                glyphlist_set_style_cb (GTK_WIDGET (item->canvas), item);       
340        return 0;
341}
342
343static int
344gpp_gsave (GnomePrintContext *ctx)
345{
346        GnomePrintPreview *pp;
347
348        pp = GNOME_PRINT_PREVIEW (ctx);
349
350        gp_gc_gsave (pp->priv->gc);
351
352        return GNOME_PRINT_OK;
353}
354
355static int
356gpp_grestore (GnomePrintContext *ctx)
357{
358        GnomePrintPreview *pp;
359
360        pp = GNOME_PRINT_PREVIEW (ctx);
361
362        gp_gc_grestore (pp->priv->gc);
363
364        return GNOME_PRINT_OK;
365}
366
367static int
368gpp_close (GnomePrintContext *pc)
369{
370        return 0;
371}
372
373static void
374gpp_finalize (GObject *object)
375{
376        GnomePrintPreview *pp = GNOME_PRINT_PREVIEW (object);
377        GnomePrintPreviewPrivate *priv = pp->priv;
378
379        gp_gc_unref (priv->gc);
380
381        if (pp->canvas)
382                g_object_unref (G_OBJECT (pp->canvas));
383
384        if (priv->page)
385                gtk_object_destroy (GTK_OBJECT (priv->page));
386
387        if (priv->root)
388                gtk_object_destroy (GTK_OBJECT (priv->root));
389       
390        g_free (priv);
391
392        G_OBJECT_CLASS (parent_class)->finalize (object);
393}
394
395static void
396class_init (GnomePrintPreviewClass *klass)
397{
398        GObjectClass *object_class = (GObjectClass *) klass;
399        GnomePrintContextClass *pc_class = (GnomePrintContextClass *) klass;
400
401        parent_class = g_type_class_peek_parent (klass);
402
403        object_class->finalize = gpp_finalize;
404       
405        pc_class->beginpage = gpp_beginpage;
406        pc_class->showpage  = gpp_showpage;
407        pc_class->clip      = gpp_clip;
408        pc_class->fill      = gpp_fill;
409        pc_class->stroke    = gpp_stroke;
410        pc_class->image     = gpp_image;
411        pc_class->glyphlist = gpp_glyphlist;
412        pc_class->gsave     = gpp_gsave;
413        pc_class->grestore  = gpp_grestore;
414        pc_class->close     = gpp_close;
415}
416
417static void
418instance_init (GnomePrintPreview *preview)
419{
420        preview->priv = g_new0 (GnomePrintPreviewPrivate, 1);
421
422        preview->priv->gc = gp_gc_new ();
423}
424
425static void
426clear_val (GtkObject *object, void **val)
427{
428        *val = NULL;
429}
430
431void
432gnome_print_preview_set_use_theme (gboolean theme)
433{
434        use_theme = theme;
435}
436gboolean
437gnome_print_preview_get_use_theme ()
438{
439        return use_theme;
440}
441
442/**
443 * gnome_print_preview_theme_compliance:
444 * @pp:
445 * @compliance:
446 *
447 * This has to go away for GNOME 2.4. Make compliance an argument of
448 * gnome_print_preview_new_full
449 **/
450void
451gnome_print_preview_theme_compliance (GnomePrintPreview *pp,
452                                      gboolean compliance)
453{
454        pp->priv->theme_compliance = compliance;
455}
456
457GnomePrintContext *
458gnome_print_preview_new_full (GnomePrintConfig *config, GnomeCanvas *canvas,
459                              const gdouble *transform, const ArtDRect *region)
460{
461        GnomePrintPreview *preview;
462        GnomePrintContext *ctx;
463        GnomeCanvasGroup *group;
464        gint ret;
465       
466        g_return_val_if_fail (config != NULL, NULL);
467        g_return_val_if_fail (canvas != NULL, NULL);
468        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
469        g_return_val_if_fail (transform != NULL, NULL);
470        g_return_val_if_fail (region != NULL, NULL);
471
472        ctx = g_object_new (GNOME_TYPE_PRINT_PREVIEW, NULL);
473        ret = gnome_print_context_construct (ctx, config);
474        if (ret != GNOME_PRINT_OK) {
475                g_object_unref (ctx);
476                g_warning ("Could not construct the GnomePrintPreview context\n");
477                return NULL;
478        }
479        preview = GNOME_PRINT_PREVIEW (ctx);
480
481        g_object_ref (G_OBJECT (canvas));
482        preview->canvas = canvas;
483
484        gnome_canvas_set_scroll_region (canvas, region->x0, region->y0, region->x1, region->y1);
485
486        preview->priv->root = gnome_canvas_item_new (gnome_canvas_root (preview->canvas),
487                                                     GNOME_TYPE_CANVAS_GROUP,
488                                                     "x", 0.0, "y", 0.0, NULL);
489
490        preview->priv->page = gnome_canvas_item_new (gnome_canvas_root (preview->canvas),
491                                                     GNOME_TYPE_CANVAS_GROUP,
492                                                     "x", 0.0, "y", 0.0, NULL);
493
494        g_signal_connect (G_OBJECT (preview->priv->page), "destroy",
495                          (GCallback) clear_val, &preview->priv->page);
496        g_signal_connect (G_OBJECT (preview->priv->root), "destroy",
497                          (GCallback) clear_val, &preview->priv->root);
498
499        /* Setup base group */
500        group = GNOME_CANVAS_GROUP (preview->priv->page);
501        gp_gc_set_data (preview->priv->gc, group);
502
503        gnome_canvas_item_affine_absolute (preview->priv->page, transform);
504
505        return ctx;
506}
507
508/**
509 * gnome_print_preview_new:
510 * @config:
511 * @canvas: Canvas on which we display the print preview
512 *
513 * Creates a new PrintPreview object that use the @canvas GnomeCanvas
514 * as its rendering backend.
515 *
516 * Returns: A GnomePrintContext suitable for using with the GNOME print API.
517 */
518GnomePrintContext *
519gnome_print_preview_new (GnomePrintConfig *config, GnomeCanvas *canvas)
520{
521        ArtDRect bbox;
522        gdouble page2root[6];
523        const GnomePrintUnit *unit;
524       
525        g_return_val_if_fail (config != NULL, NULL);
526        g_return_val_if_fail (canvas != NULL, NULL);
527        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
528
529        if (getenv ("GNOME_PRINT_DEBUG_WIDE")) {
530                bbox.x0 = bbox.y0 = -900.0;
531                bbox.x1 = bbox.y1 = 900.0;
532        } else {
533                bbox.x0 = 0.0;
534                bbox.y0 = 0.0;
535                bbox.x1 = 21.0 * (72.0 / 2.54);
536                bbox.y1 = 29.7 * (72.0 / 2.54);
537                if (gnome_print_config_get_length (config, GNOME_PRINT_KEY_PAPER_WIDTH, &bbox.x1, &unit)) {
538                        gnome_print_convert_distance (&bbox.x1, unit, GNOME_PRINT_PS_UNIT);
539                }
540                if (gnome_print_config_get_length (config, GNOME_PRINT_KEY_PAPER_HEIGHT, &bbox.y1, &unit)) {
541                        gnome_print_convert_distance (&bbox.y1, unit, GNOME_PRINT_PS_UNIT);
542                }
543        }
544
545        art_affine_scale (page2root, 1.0, -1.0);
546        page2root[5] = bbox.y1;
547
548        return gnome_print_preview_new_full (config, canvas, page2root, &bbox);
549}
550
551/**
552 * gnome_print_preview_get_type:
553 *
554 * GType identification routine for #GnomePrintPreview
555 *
556 * Returns: The GType for the #GnomePrintPreview object
557 */
558
559GType
560gnome_print_preview_get_type (void)
561{
562        static GType preview_type = 0;
563       
564        if (!preview_type) {
565                static const GTypeInfo preview_info = {
566                        sizeof (GnomePrintPreviewClass),
567                        NULL, NULL,
568                        (GClassInitFunc) class_init,
569                        NULL, NULL,
570                        sizeof (GnomePrintPreview),
571                        0,
572                        (GInstanceInitFunc) instance_init
573                };
574                preview_type = g_type_register_static (GNOME_TYPE_PRINT_CONTEXT, "GnomePrintPreview", &preview_info, 0);
575        }
576
577        return preview_type;
578}
Note: See TracBrowser for help on using the repository browser.