Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
xps-document.c
Go to the documentation of this file.
1 /* this file is part of evince, a gnome document viewer
2  *
3  * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 
22 #include <glib/gi18n-lib.h>
23 #include <libgxps/gxps.h>
24 
25 #include "xps-document.h"
26 #include "ev-document-links.h"
27 #include "ev-document-print.h"
28 #include "ev-document-misc.h"
29 
30 struct _XPSDocument {
32 
33  GFile *file;
34  GXPSFile *xps;
35  GXPSDocument *doc;
36 };
37 
40 };
41 
44 
46  {
51  })
52 
53 /* XPSDocument */
54 static void
55 xps_document_init (XPSDocument *ps_document)
56 {
57 }
58 
59 static void
60 xps_document_dispose (GObject *object)
61 {
62  XPSDocument *xps = XPS_DOCUMENT (object);
63 
64  if (xps->file) {
65  g_object_unref (xps->file);
66  xps->file = NULL;
67  }
68 
69  if (xps->xps) {
70  g_object_unref (xps->xps);
71  xps->xps = NULL;
72  }
73 
74  if (xps->doc) {
75  g_object_unref (xps->doc);
76  xps->doc = NULL;
77  }
78 
79  G_OBJECT_CLASS (xps_document_parent_class)->dispose (object);
80 }
81 
82 /* EvDocumentIface */
83 static gboolean
85  const char *uri,
86  GError **error)
87 {
88  XPSDocument *xps = XPS_DOCUMENT (document);
89 
90  xps->file = g_file_new_for_uri (uri);
91  xps->xps = gxps_file_new (xps->file, error);
92 
93  if (!xps->xps)
94  return FALSE;
95 
96  /* FIXME: what if there are multiple docs? */
97  xps->doc = gxps_file_get_document (xps->xps, 0, error);
98  if (!xps->doc) {
99  g_object_unref (xps->xps);
100  xps->xps = NULL;
101 
102  return FALSE;
103  }
104 
105  return TRUE;
106 }
107 
108 static gboolean
110  const char *uri,
111  GError **error)
112 {
113  XPSDocument *xps = XPS_DOCUMENT (document);
114  GFile *dest;
115  gboolean retval;
116 
117  dest = g_file_new_for_uri (uri);
118  retval = g_file_copy (xps->file, dest,
119  G_FILE_COPY_TARGET_DEFAULT_PERMS |
120  G_FILE_COPY_OVERWRITE,
121  NULL, NULL, NULL, error);
122  g_object_unref (dest);
123 
124  return retval;
125 }
126 
127 static gint
129 {
130  XPSDocument *xps = XPS_DOCUMENT (document);
131 
132  return gxps_document_get_n_pages (xps->doc);
133 }
134 
135 static EvPage *
137  gint index)
138 {
139  XPSDocument *xps = XPS_DOCUMENT (document);
140  GXPSPage *xps_page;
141  EvPage *page;
142 
143  xps_page = gxps_document_get_page (xps->doc, index, NULL);
144  page = ev_page_new (index);
145  if (xps_page) {
146  page->backend_page = (EvBackendPage)xps_page;
147  page->backend_destroy_func = (EvBackendPageDestroyFunc)g_object_unref;
148  }
149 
150  return page;
151 }
152 
153 static void
155  EvPage *page,
156  double *width,
157  double *height)
158 {
159  gxps_page_get_size (GXPS_PAGE (page->backend_page), width, height);
160 }
161 
162 static EvDocumentInfo *
164 {
165  XPSDocument *xps = XPS_DOCUMENT (document);
166  EvDocumentInfo *info;
167 
168  info = g_new0 (EvDocumentInfo, 1);
169  info->fields_mask =
172 
173 
174  info->n_pages = gxps_document_get_n_pages (xps->doc);
175  if (info->n_pages > 0) {
176  GXPSPage *gxps_page;
177 
178  gxps_page = gxps_document_get_page (xps->doc, 0, NULL);
179  gxps_page_get_size (gxps_page, &(info->paper_width), &(info->paper_height));
180  g_object_unref (gxps_page);
181 
182  info->paper_width = info->paper_width / 96.0f * 25.4f;
183  info->paper_height = info->paper_height / 96.0f * 25.4f;
184  }
185 
186  return info;
187 }
188 
189 static gboolean
191  EvDocumentBackendInfo *info)
192 {
193  info->name = "libgxps";
194  info->version = GXPS_VERSION_STRING;
195 
196  return TRUE;
197 }
198 
199 static cairo_surface_t *
201  EvRenderContext *rc)
202 {
203  GXPSPage *xps_page;
204  gdouble page_width, page_height;
205  gint width, height;
206  double scale_x, scale_y;
207  cairo_surface_t *surface;
208  cairo_t *cr;
209  GError *error = NULL;
210 
211  xps_page = GXPS_PAGE (rc->page->backend_page);
212 
213  gxps_page_get_size (xps_page, &page_width, &page_height);
214  ev_render_context_compute_transformed_size (rc, page_width, page_height,
215  &width, &height);
216 
217  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
218  width, height);
219  cr = cairo_create (surface);
220 
221  cairo_set_source_rgb (cr, 1., 1., 1.);
222  cairo_paint (cr);
223 
224  switch (rc->rotation) {
225  case 90:
226  cairo_translate (cr, width, 0);
227  break;
228  case 180:
229  cairo_translate (cr, width, height);
230  break;
231  case 270:
232  cairo_translate (cr, 0, height);
233  break;
234  default:
235  cairo_translate (cr, 0, 0);
236  }
237 
238  ev_render_context_compute_scales (rc, page_width, page_height,
239  &scale_x, &scale_y);
240  cairo_scale (cr, scale_x, scale_y);
241 
242  cairo_rotate (cr, rc->rotation * G_PI / 180.0);
243  gxps_page_render (xps_page, cr, &error);
244  cairo_destroy (cr);
245 
246  if (error) {
247  g_warning ("Error rendering page %d: %s\n",
248  rc->page->index, error->message);
249  g_error_free (error);
250  }
251 
252  return surface;
253 }
254 
255 static void
257 {
258  GObjectClass *object_class = G_OBJECT_CLASS (klass);
259  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
260 
261  object_class->dispose = xps_document_dispose;
262 
263  ev_document_class->load = xps_document_load;
264  ev_document_class->save = xps_document_save;
265  ev_document_class->get_n_pages = xps_document_get_n_pages;
266  ev_document_class->get_page = xps_document_get_page;
267  ev_document_class->get_page_size = xps_document_get_page_size;
268  ev_document_class->get_info = xps_document_get_info;
269  ev_document_class->get_backend_info = xps_document_get_backend_info;
270  ev_document_class->render = xps_document_render;
271 }
272 
273 /* EvDocumentLinks */
274 static gboolean
276 {
277  XPSDocument *xps_document = XPS_DOCUMENT (document_links);
278  GXPSDocumentStructure *structure;
279  gboolean retval;
280 
281  structure = gxps_document_get_structure (xps_document->doc);
282  if (!structure)
283  return FALSE;
284 
285  retval = gxps_document_structure_has_outline (structure);
286  g_object_unref (structure);
287 
288  return retval;
289 }
290 
291 static EvLinkAction *
293  GXPSLinkTarget *target)
294 {
295  EvLinkAction *ev_action;
296 
297  if (gxps_link_target_is_internal (target)) {
298  EvLinkDest *dest = NULL;
299  gint doc;
300  const gchar *anchor;
301 
302  anchor = gxps_link_target_get_anchor (target);
303 
304  /* FIXME: multidoc */
305  doc = gxps_file_get_document_for_link_target (xps_document->xps, target);
306  if (doc == 0) {
307  if (!anchor)
308  return NULL;
309 
310  dest = ev_link_dest_new_named (anchor);
311  ev_action = ev_link_action_new_dest (dest);
312  g_object_unref (dest);
313  } else if (doc == -1 && anchor &&
314  gxps_document_get_page_for_anchor (xps_document->doc, anchor) >= 0) {
315  /* Internal, but source is not a doc,
316  * let's try with doc = 0
317  */
318  dest = ev_link_dest_new_named (anchor);
319  ev_action = ev_link_action_new_dest (dest);
320  g_object_unref (dest);
321  } else {
322  gchar *filename;
323 
324  /* FIXME: remote uri? */
325  filename = g_file_get_path (xps_document->file);
326 
327  if (anchor)
328  dest = ev_link_dest_new_named (anchor);
329  ev_action = ev_link_action_new_remote (dest, filename);
330  g_clear_object (&dest);
331  g_free (filename);
332  }
333  } else {
334  const gchar *uri;
335 
336  uri = gxps_link_target_get_uri (target);
337  ev_action = ev_link_action_new_external_uri (uri);
338  }
339 
340  return ev_action;
341 }
342 
343 static void
344 build_tree (XPSDocument *xps_document,
345  GtkTreeModel *model,
346  GtkTreeIter *parent,
347  GXPSOutlineIter *iter)
348 {
349  do {
350  GtkTreeIter tree_iter;
351  GXPSOutlineIter child_iter;
352  EvLinkAction *action;
353  EvLink *link;
354  GXPSLinkTarget *target;
355  gchar *title;
356 
357  target = gxps_outline_iter_get_target (iter);
358  title = g_markup_escape_text (gxps_outline_iter_get_description (iter), -1);
359  action = link_action_from_target (xps_document, target);
360  link = ev_link_new (title, action);
361  g_object_unref (action);
362  gxps_link_target_free (target);
363 
364  gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
365  gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
369  -1);
370  g_object_unref (link);
371  g_free (title);
372 
373  if (gxps_outline_iter_children (&child_iter, iter))
374  build_tree (xps_document, model, &tree_iter, &child_iter);
375  } while (gxps_outline_iter_next (iter));
376 }
377 
378 static GtkTreeModel *
380 {
381  XPSDocument *xps_document = XPS_DOCUMENT (document_links);
382  GXPSDocumentStructure *structure;
383  GXPSOutlineIter iter;
384  GtkTreeModel *model = NULL;
385 
386  structure = gxps_document_get_structure (xps_document->doc);
387  if (!structure)
388  return NULL;
389 
390  if (gxps_document_structure_outline_iter_init (&iter, structure)) {
391  model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
392  G_TYPE_STRING,
393  G_TYPE_OBJECT,
394  G_TYPE_BOOLEAN,
395  G_TYPE_STRING);
396  build_tree (xps_document, model, NULL, &iter);
397  }
398 
399  g_object_unref (structure);
400 
401  return model;
402 }
403 
404 static EvMappingList *
406  EvPage *page)
407 {
408  XPSDocument *xps_document = XPS_DOCUMENT (document_links);
409  GXPSPage *xps_page;
410  GList *retval = NULL;
411  GList *mapping_list;
412  GList *list;
413 
414  xps_page = GXPS_PAGE (page->backend_page);
415  mapping_list = gxps_page_get_links (xps_page, NULL);
416 
417  for (list = mapping_list; list; list = list->next) {
418  GXPSLink *xps_link;
419  GXPSLinkTarget *target;
420  EvLinkAction *action;
421  EvMapping *ev_link_mapping;
422  cairo_rectangle_t area;
423 
424  xps_link = (GXPSLink *)list->data;
425  ev_link_mapping = g_new (EvMapping, 1);
426  gxps_link_get_area (xps_link, &area);
427  target = gxps_link_get_target (xps_link);
428  action = link_action_from_target (xps_document, target);
429 
430  ev_link_mapping->data = ev_link_new (NULL, action);
431  ev_link_mapping->area.x1 = area.x;
432  ev_link_mapping->area.x2 = area.x + area.width;
433  ev_link_mapping->area.y1 = area.y;
434  ev_link_mapping->area.y2 = area.y + area.height;
435 
436  retval = g_list_prepend (retval, ev_link_mapping);
437  gxps_link_free (xps_link);
438  g_object_unref (action);
439  }
440 
441  g_list_free (mapping_list);
442 
443  return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
444 }
445 
446 static EvLinkDest *
448  const gchar *link_name)
449 {
450  XPSDocument *xps_document = XPS_DOCUMENT (document_links);
451  GXPSPage *xps_page;
452  gint page;
453  cairo_rectangle_t area;
454  EvLinkDest *dest = NULL;
455 
456  page = gxps_document_get_page_for_anchor (xps_document->doc, link_name);
457  if (page == -1)
458  return NULL;
459 
460  xps_page = gxps_document_get_page (xps_document->doc, page, NULL);
461  if (!xps_page)
462  return NULL;
463 
464  if (gxps_page_get_anchor_destination (xps_page, link_name, &area, NULL))
465  dest = ev_link_dest_new_xyz (page, area.x, area.y, 1., TRUE, TRUE, FALSE);
466 
467  g_object_unref (xps_page);
468 
469  return dest;
470 }
471 
472 static gint
474  const gchar *link_name)
475 {
476  XPSDocument *xps_document = XPS_DOCUMENT (document_links);
477 
478  return gxps_document_get_page_for_anchor (xps_document->doc, link_name);
479 }
480 
481 static void
483 {
489 }
490 
491 /* EvDocumentPrint */
492 static void
494  EvPage *page,
495  cairo_t *cr)
496 {
497  GError *error = NULL;
498 
499  gxps_page_render (GXPS_PAGE (page->backend_page), cr, &error);
500  if (error) {
501  g_warning ("Error rendering page %d for printing: %s\n",
502  page->index, error->message);
503  g_error_free (error);
504  }
505 }
506 
507 static void
509 {
511 }