~ubuntu-branches/ubuntu/oneiric/evince/oneiric-updates

« back to all changes in this revision

Viewing changes to backend/impress/impress-document.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-01-10 19:35:11 UTC
  • mto: (1.3.1 experimental) (52.1.1 hardy-proposed)
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: james.westby@ubuntu.com-20070110193511-yjrnndv8e8wv03yy
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
 
2
/*
 
3
 * Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
 
4
 * Copyright (C) 2005, Bastien Nocera <hadess@hadess.net>
 
5
 *
 
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)
 
9
 * any later version.
 
10
 *
 
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.
 
15
 *
 
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.
 
19
 */
 
20
 
 
21
#include <gtk/gtk.h>
 
22
#include <string.h>
 
23
#include "imposter.h"
 
24
#include "impress-document.h"
 
25
#include "ev-document-thumbnails.h"
 
26
#include "ev-document-misc.h"
 
27
 
 
28
struct _ImpressDocumentClass
 
29
{
 
30
  GObjectClass parent_class;
 
31
};
 
32
 
 
33
struct _ImpressDocument
 
34
{
 
35
  GObject parent_instance;
 
36
 
 
37
  ImpDoc *imp;
 
38
  ImpRenderCtx *ctx;
 
39
 
 
40
  GMutex *mutex;
 
41
  GdkPixmap *pixmap;
 
42
  GdkGC *gc;
 
43
  PangoContext *pango_ctx;
 
44
 
 
45
  /* Only used while rendering inside the mainloop */
 
46
  int pagenum;
 
47
  GdkPixbuf *pixbuf;
 
48
  GCond *cond;
 
49
};
 
50
 
 
51
#define PAGE_WIDTH 1024
 
52
#define PAGE_HEIGHT 768
 
53
 
 
54
typedef struct _ImpressDocumentClass ImpressDocumentClass;
 
55
 
 
56
static void impress_document_document_iface_init (EvDocumentIface *iface);
 
57
static void impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
 
58
 
 
59
G_DEFINE_TYPE_WITH_CODE (ImpressDocument, impress_document, G_TYPE_OBJECT,
 
60
                         { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
 
61
                                                  impress_document_document_iface_init);
 
62
                           G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
 
63
                                                  impress_document_document_thumbnails_iface_init);
 
64
                         });
 
65
 
 
66
/* Renderer */
 
67
static void
 
68
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)
 
69
{
 
70
  int x, y, nx, ny;
 
71
  int ax, bx, cx, ay, by, cy;
 
72
  double t, t2, t3;
 
73
 
 
74
  x = x0;
 
75
  y = y0;
 
76
 
 
77
  cx = 3 * (x1 - x0);
 
78
  bx = 3 * (x2 - x1) - cx;
 
79
  ax = x3 - x0 - cx - bx;
 
80
  cy = 3 * (y1 - y0);
 
81
  by = 3 * (y2 - y1) - cy;
 
82
  ay = y3 - y0 - cy - by;
 
83
 
 
84
  for (t = 0; t < 1; t += 0.01) {
 
85
    t2 = t * t;
 
86
    t3 = t2 * t;
 
87
    nx = ax * t3 + bx * t2 + cx * t + x0;
 
88
    ny = ay * t3 + by * t2 + cy * t + y0;
 
89
    gdk_draw_line (d, gc, x, y, nx, ny);
 
90
    x = nx;
 
91
    y = ny;
 
92
  }
 
93
}
 
94
 
 
95
static void
 
96
imp_render_get_size(void *drw_data, int *w, int *h)
 
97
{
 
98
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
99
 
 
100
  gdk_drawable_get_size(impress_document->pixmap, w, h);
 
101
}
 
102
 
 
103
static void
 
104
imp_render_set_fg_color(void *drw_data, ImpColor *color)
 
105
{
 
106
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
107
  GdkColor c;
 
108
 
 
109
  c.red = color->red;
 
110
  c.green = color->green;
 
111
  c.blue = color->blue;
 
112
  gdk_gc_set_rgb_fg_color(impress_document->gc, &c);
 
113
}
 
114
 
 
115
static void
 
116
imp_render_draw_line(void *drw_data, int x1, int y1, int x2, int y2)
 
117
{
 
118
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
119
 
 
120
  gdk_draw_line(impress_document->pixmap, impress_document->gc, x1, y1, x2, y2);
 
121
}
 
122
 
 
123
static void
 
124
imp_render_draw_rect(void *drw_data, int fill, int x, int y, int w, int h)
 
125
{
 
126
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
127
 
 
128
  gdk_draw_rectangle(impress_document->pixmap, impress_document->gc, fill, x, y, w, h);
 
129
}
 
130
 
 
131
static void
 
132
imp_render_draw_polygon(void *drw_data, int fill, ImpPoint *pts, int nr_pts)
 
133
{
 
134
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
135
 
 
136
  gdk_draw_polygon(impress_document->pixmap, impress_document->gc, fill, (GdkPoint *)pts, nr_pts);
 
137
}
 
138
 
 
139
static void
 
140
imp_render_draw_arc(void *drw_data, int fill, int x, int y, int w, int h, int sa, int ea)
 
141
{
 
142
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
143
 
 
144
  gdk_draw_arc(impress_document->pixmap, impress_document->gc, fill, x, y, w, h, sa * 64, ea * 64);
 
145
}
 
146
 
 
147
static void
 
148
imp_render_draw_bezier(void *drw_data, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
 
149
{
 
150
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
151
 
 
152
  imp_render_draw_bezier_real (impress_document->pixmap, impress_document->gc, x0, y0, x1, y1, x2, y2, x3, y3);
 
153
}
 
154
 
 
155
static void *
 
156
imp_render_open_image(void *drw_data, const unsigned char *pix, size_t size)
 
157
{
 
158
  GdkPixbufLoader *gpl;
 
159
  GdkPixbuf *pb;
 
160
 
 
161
  gpl = gdk_pixbuf_loader_new();
 
162
  gdk_pixbuf_loader_write(gpl, pix, size, NULL);
 
163
  gdk_pixbuf_loader_close(gpl, NULL);
 
164
  pb = gdk_pixbuf_loader_get_pixbuf(gpl);
 
165
  return pb;
 
166
}
 
167
 
 
168
static void
 
169
imp_render_get_image_size(void *drw_data, void *img_data, int *w, int *h)
 
170
{
 
171
  GdkPixbuf *pb = (GdkPixbuf *) img_data;
 
172
 
 
173
  *w = gdk_pixbuf_get_width(pb);
 
174
  *h = gdk_pixbuf_get_height(pb);
 
175
}
 
176
 
 
177
static void *
 
178
imp_render_scale_image(void *drw_data, void *img_data, int w, int h)
 
179
{
 
180
  GdkPixbuf *pb = (GdkPixbuf *) img_data;
 
181
 
 
182
  return gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR);
 
183
}
 
184
 
 
185
static void
 
186
imp_render_draw_image(void *drw_data, void *img_data, int x, int y, int w, int h)
 
187
{
 
188
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
189
  GdkPixbuf *pb = (GdkPixbuf *) img_data;
 
190
 
 
191
  gdk_draw_pixbuf(impress_document->pixmap, impress_document->gc, pb, 0, 0, x, y, w, h, GDK_RGB_DITHER_NONE, 0, 0);
 
192
}
 
193
 
 
194
static void
 
195
imp_render_close_image(void *drw_data, void *img_data)
 
196
{
 
197
  GdkPixbuf *pb = (GdkPixbuf *) img_data;
 
198
 
 
199
  g_object_unref(G_OBJECT(pb));
 
200
}
 
201
 
 
202
static char *
 
203
imp_render_markup(const char *text, size_t len, int styles, int size)
 
204
{
 
205
  double scr_mm, scr_px, dpi;
 
206
  char *esc;
 
207
  char *ret;
 
208
  int sz;
 
209
 
 
210
  scr_mm = gdk_screen_get_height_mm(gdk_screen_get_default());
 
211
  scr_px = gdk_screen_get_height(gdk_screen_get_default());
 
212
  dpi = (scr_px / scr_mm) * 25.4; 
 
213
  sz = (int) ((double) size * 72.0 * PANGO_SCALE / dpi);
 
214
  esc = g_markup_escape_text(text, len);
 
215
  ret = g_strdup_printf("<span size ='%d'>%s</span>", sz, esc);
 
216
  g_free(esc);
 
217
  return ret;
 
218
}
 
219
 
 
220
static void
 
221
imp_render_get_text_size(void *drw_data, const char *text, size_t len, int size, int styles, int *w, int *h)
 
222
{
 
223
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
224
  PangoLayout *lay;
 
225
  int pw, ph;
 
226
  char *m;
 
227
 
 
228
  g_return_if_fail (impress_document->pango_ctx != NULL);
 
229
 
 
230
  lay = pango_layout_new(impress_document->pango_ctx);
 
231
  m = imp_render_markup(text, len, styles, size);
 
232
  pango_layout_set_markup(lay, m, strlen(m));
 
233
  pango_layout_get_size(lay, &pw, &ph);
 
234
  g_object_unref(lay);
 
235
  g_free(m);
 
236
  *w = pw / PANGO_SCALE;
 
237
  *h = ph / PANGO_SCALE;
 
238
}
 
239
 
 
240
static void
 
241
imp_render_draw_text(void *drw_data, int x, int y, const char *text, size_t len, int size, int styles)
 
242
{
 
243
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
 
244
  PangoLayout *lay;
 
245
  char *m;
 
246
 
 
247
  g_return_if_fail (impress_document->pango_ctx != NULL);
 
248
 
 
249
  lay = pango_layout_new(impress_document->pango_ctx);
 
250
  m = imp_render_markup(text, len, styles, size);
 
251
  pango_layout_set_markup(lay, m, strlen(m));
 
252
  gdk_draw_layout(impress_document->pixmap, impress_document->gc, x, y, lay);
 
253
  g_object_unref(lay);
 
254
  g_free(m);
 
255
}
 
256
 
 
257
static const ImpDrawer imp_render_functions = {
 
258
  imp_render_get_size,
 
259
  imp_render_set_fg_color,
 
260
  imp_render_draw_line,
 
261
  imp_render_draw_rect,
 
262
  imp_render_draw_polygon,
 
263
  imp_render_draw_arc,
 
264
  imp_render_draw_bezier,
 
265
  imp_render_open_image,
 
266
  imp_render_get_image_size,
 
267
  imp_render_scale_image,
 
268
  imp_render_draw_image,
 
269
  imp_render_close_image,
 
270
  imp_render_get_text_size,
 
271
  imp_render_draw_text
 
272
};
 
273
 
 
274
/* Document interface */
 
275
static gboolean
 
276
impress_document_load (EvDocument  *document,
 
277
                    const char  *uri,
 
278
                    GError     **error)
 
279
{
 
280
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
 
281
  gchar *filename;
 
282
  ImpDoc *imp;
 
283
  int err;
 
284
 
 
285
  /* FIXME: Could we actually load uris ? */
 
286
  filename = g_filename_from_uri (uri, NULL, error);
 
287
  if (!filename)
 
288
    {
 
289
      //FIXME
 
290
      //g_error_set ();
 
291
      return FALSE;
 
292
    }
 
293
 
 
294
  imp = imp_open (filename, &err);
 
295
 
 
296
  if (!imp)
 
297
    {
 
298
      //FIXME translate the err, set error
 
299
      g_free (filename);
 
300
      return FALSE;
 
301
    }
 
302
  impress_document->imp = imp;
 
303
 
 
304
  return TRUE;
 
305
}
 
306
 
 
307
static gboolean
 
308
impress_document_save (EvDocument  *document,
 
309
                      const char  *uri,
 
310
                      GError     **error)
 
311
{
 
312
        return FALSE;
 
313
}
 
314
 
 
315
static int
 
316
impress_document_get_n_pages (EvDocument  *document)
 
317
{
 
318
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
 
319
 
 
320
  g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0);
 
321
  g_return_val_if_fail (impress_document->imp != NULL, 0);
 
322
 
 
323
  return imp_nr_pages (impress_document->imp);
 
324
}
 
325
 
 
326
static void
 
327
impress_document_get_page_size (EvDocument   *document,
 
328
                             int           page,
 
329
                             double       *width,
 
330
                             double       *height)
 
331
{
 
332
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
 
333
 
 
334
  g_return_if_fail (IMPRESS_IS_DOCUMENT (document));
 
335
  g_return_if_fail (impress_document->imp != NULL);
 
336
 
 
337
  //FIXME
 
338
  *width = PAGE_WIDTH;
 
339
  *height = PAGE_HEIGHT;
 
340
}
 
341
 
 
342
static gboolean
 
343
imp_render_get_from_drawable (ImpressDocument *impress_document)
 
344
{
 
345
  ImpPage *page;
 
346
 
 
347
  page = imp_get_page (impress_document->imp, impress_document->pagenum);
 
348
 
 
349
  g_return_val_if_fail (page != NULL, FALSE);
 
350
 
 
351
  imp_context_set_page (impress_document->ctx, page);
 
352
  imp_render (impress_document->ctx, impress_document);
 
353
 
 
354
  impress_document->pixbuf = gdk_pixbuf_get_from_drawable (NULL,
 
355
                                         GDK_DRAWABLE (impress_document->pixmap),
 
356
                                         NULL,
 
357
                                         0, 0,
 
358
                                         0, 0,
 
359
                                         PAGE_WIDTH, PAGE_HEIGHT);
 
360
  g_cond_broadcast (impress_document->cond);
 
361
  return FALSE;
 
362
}
 
363
 
 
364
static GdkPixbuf *
 
365
impress_document_render_pixbuf (EvDocument  *document,
 
366
                                EvRenderContext *rc)
 
367
{
 
368
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
 
369
  GdkPixbuf *scaled_pixbuf;
 
370
 
 
371
  g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0);
 
372
  g_return_val_if_fail (impress_document->imp != NULL, 0);
 
373
 
 
374
  impress_document->pagenum = rc->page;
 
375
 
 
376
  g_mutex_lock (impress_document->mutex);
 
377
  impress_document->cond = g_cond_new ();
 
378
 
 
379
  g_idle_add ((GSourceFunc) imp_render_get_from_drawable, impress_document);
 
380
 
 
381
  g_cond_wait (impress_document->cond, impress_document->mutex);
 
382
  g_cond_free (impress_document->cond);
 
383
  g_mutex_unlock (impress_document->mutex);
 
384
 
 
385
  scaled_pixbuf = gdk_pixbuf_scale_simple (impress_document->pixbuf,
 
386
                                           PAGE_WIDTH * rc->scale,
 
387
                                           PAGE_HEIGHT * rc->scale,
 
388
                                           GDK_INTERP_BILINEAR);
 
389
  gdk_pixbuf_unref (impress_document->pixbuf);
 
390
  impress_document->pixbuf = NULL;
 
391
 
 
392
  return scaled_pixbuf;
 
393
}
 
394
 
 
395
static void
 
396
impress_document_finalize (GObject *object)
 
397
{
 
398
  ImpressDocument *impress_document = IMPRESS_DOCUMENT (object);
 
399
 
 
400
  g_mutex_free (impress_document->mutex);
 
401
 
 
402
  imp_close (impress_document->imp);
 
403
  imp_delete_context (impress_document->ctx);
 
404
  g_free (impress_document->pango_ctx);
 
405
  g_object_unref (G_OBJECT (impress_document->pixmap));
 
406
  g_object_unref (impress_document->gc);
 
407
 
 
408
  G_OBJECT_CLASS (impress_document_parent_class)->finalize (object);
 
409
}
 
410
 
 
411
static void
 
412
impress_document_class_init (ImpressDocumentClass *klass)
 
413
{
 
414
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
415
 
 
416
  gobject_class->finalize = impress_document_finalize;
 
417
}
 
418
 
 
419
static gboolean
 
420
impress_document_can_get_text (EvDocument *document)
 
421
{
 
422
  return FALSE;
 
423
}
 
424
 
 
425
static EvDocumentInfo *
 
426
impress_document_get_info (EvDocument *document)
 
427
{
 
428
  EvDocumentInfo *info;
 
429
 
 
430
  info = g_new0 (EvDocumentInfo, 1);
 
431
  info->fields_mask = 0;
 
432
 
 
433
  return info;
 
434
}
 
435
 
 
436
static void
 
437
impress_document_document_iface_init (EvDocumentIface *iface)
 
438
{
 
439
  iface->load = impress_document_load;
 
440
  iface->save = impress_document_save;
 
441
  iface->can_get_text = impress_document_can_get_text;
 
442
  iface->get_n_pages = impress_document_get_n_pages;
 
443
  iface->get_page_size = impress_document_get_page_size;
 
444
  iface->render_pixbuf = impress_document_render_pixbuf;
 
445
  iface->get_info = impress_document_get_info;
 
446
}
 
447
 
 
448
static GdkPixbuf *
 
449
impress_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
 
450
                                        gint                  page,
 
451
                                        gint                  rotation,
 
452
                                        gint                  size,
 
453
                                        gboolean              border)
 
454
{
 
455
  GdkPixbuf *pixbuf = NULL;
 
456
  gdouble w, h;
 
457
  EvRenderContext *rc;
 
458
 
 
459
  impress_document_get_page_size (EV_DOCUMENT (document),
 
460
                               page,
 
461
                               &w, &h);
 
462
 
 
463
  rc = ev_render_context_new (rotation, page, size/w);
 
464
  pixbuf = impress_document_render_pixbuf (EV_DOCUMENT (document), rc);
 
465
  g_object_unref (G_OBJECT (rc));
 
466
 
 
467
  if (border)
 
468
    {
 
469
      GdkPixbuf *tmp_pixbuf = pixbuf;
 
470
      pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, 0, tmp_pixbuf);
 
471
      g_object_unref (tmp_pixbuf);
 
472
    }
 
473
 
 
474
  return pixbuf;
 
475
}
 
476
 
 
477
static void
 
478
impress_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
 
479
                                         gint                  page,
 
480
                                         gint                  suggested_width,
 
481
                                         gint                 *width,
 
482
                                         gint                 *height)
 
483
{
 
484
  gdouble page_ratio;
 
485
  gdouble w, h;
 
486
 
 
487
  impress_document_get_page_size (EV_DOCUMENT (document),
 
488
                               page,
 
489
                               &w, &h);
 
490
  g_return_if_fail (w > 0);
 
491
  page_ratio = h/w;
 
492
  *width = suggested_width;
 
493
  *height = (gint) (suggested_width * page_ratio);
 
494
}
 
495
 
 
496
static void
 
497
impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
 
498
{
 
499
  iface->get_thumbnail = impress_document_thumbnails_get_thumbnail;
 
500
  iface->get_dimensions = impress_document_thumbnails_get_dimensions;
 
501
}
 
502
 
 
503
static void
 
504
impress_document_init (ImpressDocument *impress_document)
 
505
{
 
506
  GdkWindow *window;
 
507
 
 
508
  impress_document->mutex = g_mutex_new ();
 
509
  impress_document->ctx = imp_create_context(&imp_render_functions);
 
510
 
 
511
  window = gdk_screen_get_root_window (gdk_screen_get_default ());
 
512
 
 
513
  impress_document->pixmap = gdk_pixmap_new (window,
 
514
                                             PAGE_WIDTH, PAGE_HEIGHT, -1);
 
515
  impress_document->gc = gdk_gc_new (impress_document->pixmap);
 
516
  impress_document->pango_ctx = gdk_pango_context_get ();
 
517
}
 
518
 
 
519
/*
 
520
 * vim: sw=2 ts=8 cindent noai bs=2
 
521
 */