1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
3 * Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
4 * Copyright (C) 2005, Bastien Nocera <hadess@hadess.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <glib/gi18n.h>
26 #include "impress-document.h"
27 #include "ev-document-thumbnails.h"
28 #include "ev-document-misc.h"
30 struct _ImpressDocumentClass
32 GObjectClass parent_class;
35 struct _ImpressDocument
37 GObject parent_instance;
45 PangoContext *pango_ctx;
47 /* Only used while rendering inside the mainloop */
53 #define PAGE_WIDTH 1024
54 #define PAGE_HEIGHT 768
56 typedef struct _ImpressDocumentClass ImpressDocumentClass;
58 static void impress_document_document_iface_init (EvDocumentIface *iface);
59 static void impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
61 G_DEFINE_TYPE_WITH_CODE (ImpressDocument, impress_document, G_TYPE_OBJECT,
62 { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
63 impress_document_document_iface_init);
64 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
65 impress_document_document_thumbnails_iface_init);
70 imp_render_draw_bezier_real (GdkDrawable *d, GdkGC *gc, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
73 int ax, bx, cx, ay, by, cy;
80 bx = 3 * (x2 - x1) - cx;
81 ax = x3 - x0 - cx - bx;
83 by = 3 * (y2 - y1) - cy;
84 ay = y3 - y0 - cy - by;
86 for (t = 0; t < 1; t += 0.01) {
89 nx = ax * t3 + bx * t2 + cx * t + x0;
90 ny = ay * t3 + by * t2 + cy * t + y0;
91 gdk_draw_line (d, gc, x, y, nx, ny);
98 imp_render_get_size(void *drw_data, int *w, int *h)
100 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
102 gdk_drawable_get_size(impress_document->pixmap, w, h);
106 imp_render_set_fg_color(void *drw_data, ImpColor *color)
108 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
112 c.green = color->green;
113 c.blue = color->blue;
114 gdk_gc_set_rgb_fg_color(impress_document->gc, &c);
118 imp_render_draw_line(void *drw_data, int x1, int y1, int x2, int y2)
120 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
122 gdk_draw_line(impress_document->pixmap, impress_document->gc, x1, y1, x2, y2);
126 imp_render_draw_rect(void *drw_data, int fill, int x, int y, int w, int h)
128 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
130 gdk_draw_rectangle(impress_document->pixmap, impress_document->gc, fill, x, y, w, h);
134 imp_render_draw_polygon(void *drw_data, int fill, ImpPoint *pts, int nr_pts)
136 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
138 gdk_draw_polygon(impress_document->pixmap, impress_document->gc, fill, (GdkPoint *)pts, nr_pts);
142 imp_render_draw_arc(void *drw_data, int fill, int x, int y, int w, int h, int sa, int ea)
144 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
146 gdk_draw_arc(impress_document->pixmap, impress_document->gc, fill, x, y, w, h, sa * 64, ea * 64);
150 imp_render_draw_bezier(void *drw_data, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
152 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
154 imp_render_draw_bezier_real (impress_document->pixmap, impress_document->gc, x0, y0, x1, y1, x2, y2, x3, y3);
158 imp_render_open_image(void *drw_data, const unsigned char *pix, size_t size)
160 GdkPixbufLoader *gpl;
163 gpl = gdk_pixbuf_loader_new();
164 gdk_pixbuf_loader_write(gpl, pix, size, NULL);
165 gdk_pixbuf_loader_close(gpl, NULL);
166 pb = gdk_pixbuf_loader_get_pixbuf(gpl);
171 imp_render_get_image_size(void *drw_data, void *img_data, int *w, int *h)
173 GdkPixbuf *pb = (GdkPixbuf *) img_data;
175 *w = gdk_pixbuf_get_width(pb);
176 *h = gdk_pixbuf_get_height(pb);
180 imp_render_scale_image(void *drw_data, void *img_data, int w, int h)
182 GdkPixbuf *pb = (GdkPixbuf *) img_data;
184 return gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR);
188 imp_render_draw_image(void *drw_data, void *img_data, int x, int y, int w, int h)
190 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
191 GdkPixbuf *pb = (GdkPixbuf *) img_data;
193 gdk_draw_pixbuf(impress_document->pixmap, impress_document->gc, pb, 0, 0, x, y, w, h, GDK_RGB_DITHER_NONE, 0, 0);
197 imp_render_close_image(void *drw_data, void *img_data)
199 GdkPixbuf *pb = (GdkPixbuf *) img_data;
201 g_object_unref(G_OBJECT(pb));
205 imp_render_markup(const char *text, size_t len, int styles, int size)
207 double scr_mm, scr_px, dpi;
212 scr_mm = gdk_screen_get_height_mm(gdk_screen_get_default());
213 scr_px = gdk_screen_get_height(gdk_screen_get_default());
214 dpi = (scr_px / scr_mm) * 25.4;
215 sz = (int) ((double) size * 72.0 * PANGO_SCALE / dpi);
216 esc = g_markup_escape_text(text, len);
217 ret = g_strdup_printf("<span size ='%d'>%s</span>", sz, esc);
223 imp_render_get_text_size(void *drw_data, const char *text, size_t len, int size, int styles, int *w, int *h)
225 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
230 g_return_if_fail (impress_document->pango_ctx != NULL);
232 lay = pango_layout_new(impress_document->pango_ctx);
233 m = imp_render_markup(text, len, styles, size);
234 pango_layout_set_markup(lay, m, strlen(m));
235 pango_layout_get_size(lay, &pw, &ph);
238 *w = pw / PANGO_SCALE;
239 *h = ph / PANGO_SCALE;
243 imp_render_draw_text(void *drw_data, int x, int y, const char *text, size_t len, int size, int styles)
245 ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
249 g_return_if_fail (impress_document->pango_ctx != NULL);
251 lay = pango_layout_new(impress_document->pango_ctx);
252 m = imp_render_markup(text, len, styles, size);
253 pango_layout_set_markup(lay, m, strlen(m));
254 gdk_draw_layout(impress_document->pixmap, impress_document->gc, x, y, lay);
259 static const ImpDrawer imp_render_functions = {
261 imp_render_set_fg_color,
262 imp_render_draw_line,
263 imp_render_draw_rect,
264 imp_render_draw_polygon,
266 imp_render_draw_bezier,
267 imp_render_open_image,
268 imp_render_get_image_size,
269 imp_render_scale_image,
270 imp_render_draw_image,
271 imp_render_close_image,
272 imp_render_get_text_size,
276 /* Document interface */
278 impress_document_load (EvDocument *document,
282 ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
287 /* FIXME: Could we actually load uris ? */
288 filename = g_filename_from_uri (uri, NULL, error);
293 EV_DOCUMENT_ERROR_INVALID,
294 _("Remote files aren't supported"));
298 imp = imp_open (filename, &err);
304 EV_DOCUMENT_ERROR_INVALID,
305 _("Invalid document"));
309 impress_document->imp = imp;
315 impress_document_save (EvDocument *document,
323 impress_document_get_n_pages (EvDocument *document)
325 ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
327 g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0);
328 g_return_val_if_fail (impress_document->imp != NULL, 0);
330 return imp_nr_pages (impress_document->imp);
334 impress_document_get_page_size (EvDocument *document,
339 ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
341 g_return_if_fail (IMPRESS_IS_DOCUMENT (document));
342 g_return_if_fail (impress_document->imp != NULL);
346 *height = PAGE_HEIGHT;
350 imp_render_get_from_drawable (ImpressDocument *impress_document)
354 page = imp_get_page (impress_document->imp, impress_document->pagenum);
356 g_return_val_if_fail (page != NULL, FALSE);
358 ev_document_doc_mutex_lock ();
359 imp_context_set_page (impress_document->ctx, page);
360 imp_render (impress_document->ctx, impress_document);
361 ev_document_doc_mutex_unlock ();
363 impress_document->pixbuf = gdk_pixbuf_get_from_drawable (NULL,
364 GDK_DRAWABLE (impress_document->pixmap),
368 PAGE_WIDTH, PAGE_HEIGHT);
370 g_cond_broadcast (impress_document->cond);
375 impress_document_render_pixbuf (EvDocument *document,
378 ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
381 g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), NULL);
382 g_return_val_if_fail (impress_document->imp != NULL, NULL);
384 impress_document->pagenum = rc->page;
386 g_mutex_lock (impress_document->mutex);
387 impress_document->cond = g_cond_new ();
389 ev_document_fc_mutex_unlock ();
390 ev_document_doc_mutex_unlock ();
391 g_idle_add ((GSourceFunc) imp_render_get_from_drawable, impress_document);
392 g_cond_wait (impress_document->cond, impress_document->mutex);
393 g_cond_free (impress_document->cond);
394 ev_document_doc_mutex_lock ();
395 ev_document_fc_mutex_lock ();
397 g_mutex_unlock (impress_document->mutex);
399 pixbuf = impress_document->pixbuf;
400 impress_document->pixbuf = NULL;
405 static cairo_surface_t *
406 impress_document_render (EvDocument *document,
410 cairo_surface_t *surface, *scaled_surface;
412 pixbuf = impress_document_render_pixbuf (document, rc);
414 /* FIXME: impress backend should be ported to cairo */
415 surface = ev_document_misc_surface_from_pixbuf (pixbuf);
416 g_object_unref (pixbuf);
418 scaled_surface = ev_document_misc_surface_rotate_and_scale (surface,
419 (PAGE_WIDTH * rc->scale) + 0.5,
420 (PAGE_HEIGHT * rc->scale) + 0.5,
422 cairo_surface_destroy (surface);
424 return scaled_surface;
428 impress_document_finalize (GObject *object)
430 ImpressDocument *impress_document = IMPRESS_DOCUMENT (object);
432 if (impress_document->mutex)
433 g_mutex_free (impress_document->mutex);
435 if (impress_document->imp)
436 imp_close (impress_document->imp);
438 if (impress_document->ctx)
439 imp_delete_context (impress_document->ctx);
441 if (impress_document->pango_ctx)
442 g_object_unref (impress_document->pango_ctx);
444 if (impress_document->pixmap)
445 g_object_unref (G_OBJECT (impress_document->pixmap));
447 if (impress_document->gc)
448 g_object_unref (impress_document->gc);
450 G_OBJECT_CLASS (impress_document_parent_class)->finalize (object);
454 impress_document_class_init (ImpressDocumentClass *klass)
456 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
458 gobject_class->finalize = impress_document_finalize;
462 impress_document_can_get_text (EvDocument *document)
467 static EvDocumentInfo *
468 impress_document_get_info (EvDocument *document)
470 EvDocumentInfo *info;
472 info = g_new0 (EvDocumentInfo, 1);
473 info->fields_mask = 0;
479 impress_document_document_iface_init (EvDocumentIface *iface)
481 iface->load = impress_document_load;
482 iface->save = impress_document_save;
483 iface->can_get_text = impress_document_can_get_text;
484 iface->get_n_pages = impress_document_get_n_pages;
485 iface->get_page_size = impress_document_get_page_size;
486 iface->render = impress_document_render;
487 iface->get_info = impress_document_get_info;
491 impress_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
496 GdkPixbuf *scaled_pixbuf;
499 pixbuf = impress_document_render_pixbuf (EV_DOCUMENT (document), rc);
500 scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
501 (PAGE_WIDTH * rc->scale),
502 (PAGE_HEIGHT * rc->scale),
503 GDK_INTERP_BILINEAR);
504 g_object_unref (pixbuf);
508 GdkPixbuf *tmp_pixbuf = scaled_pixbuf;
510 scaled_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
511 g_object_unref (tmp_pixbuf);
514 return scaled_pixbuf;
518 impress_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
523 gdouble page_width, page_height;
525 impress_document_get_page_size (EV_DOCUMENT (document),
527 &page_width, &page_height);
529 if (rc->rotation == 90 || rc->rotation == 270)
531 *width = (gint) (page_height * rc->scale);
532 *height = (gint) (page_width * rc->scale);
536 *width = (gint) (page_width * rc->scale);
537 *height = (gint) (page_height * rc->scale);
542 impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
544 iface->get_thumbnail = impress_document_thumbnails_get_thumbnail;
545 iface->get_dimensions = impress_document_thumbnails_get_dimensions;
549 impress_document_init (ImpressDocument *impress_document)
553 impress_document->mutex = g_mutex_new ();
554 impress_document->ctx = imp_create_context(&imp_render_functions);
556 window = gdk_screen_get_root_window (gdk_screen_get_default ());
558 impress_document->pixmap = gdk_pixmap_new (window,
559 PAGE_WIDTH, PAGE_HEIGHT, -1);
560 impress_document->gc = gdk_gc_new (impress_document->pixmap);
561 impress_document->pango_ctx = gdk_pango_context_get_for_screen (gdk_screen_get_default ());
565 * vim: sw=2 ts=8 cindent noai bs=2