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
ev-poppler.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009, Juanjo MarĂ­n <juanj.marin@juntadeandalucia.es>
5  * Copyright (C) 2004, Red Hat, Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #include "config.h"
23 
24 #include <math.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <poppler.h>
28 #include <poppler-document.h>
29 #include <poppler-page.h>
30 #ifdef HAVE_CAIRO_PDF
31 #include <cairo-pdf.h>
32 #endif
33 #ifdef HAVE_CAIRO_PS
34 #include <cairo-ps.h>
35 #endif
36 #include <glib/gi18n-lib.h>
37 
38 #include "ev-poppler.h"
39 #include "ev-file-exporter.h"
40 #include "ev-document-find.h"
41 #include "ev-document-misc.h"
42 #include "ev-document-links.h"
43 #include "ev-document-images.h"
44 #include "ev-document-fonts.h"
45 #include "ev-document-security.h"
46 #include "ev-document-transition.h"
47 #include "ev-document-forms.h"
48 #include "ev-document-layers.h"
49 #include "ev-document-media.h"
50 #include "ev-document-print.h"
53 #include "ev-document-text.h"
54 #include "ev-selection.h"
55 #include "ev-transition-effect.h"
56 #include "ev-attachment.h"
57 #include "ev-image.h"
58 #include "ev-media.h"
59 #include "ev-file-helpers.h"
60 
61 #include <libxml/tree.h>
62 #include <libxml/parser.h>
63 #include <libxml/xpath.h>
64 #include <libxml/xpathInternals.h>
65 
66 #if (defined (HAVE_CAIRO_PDF) || defined (HAVE_CAIRO_PS))
67 #define HAVE_CAIRO_PRINT
68 #endif
69 
70 /* fields from the XMP Rights Management Schema, XMP Specification Sept 2005, pag. 45 */
71 #define LICENSE_MARKED "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:Marked"
72 #define LICENSE_TEXT "/x:xmpmeta/rdf:RDF/rdf:Description/dc:rights/rdf:Alt/rdf:li[lang('%s')]"
73 #define LICENSE_WEB_STATEMENT "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:WebStatement"
74 /* license field from Creative Commons schema, http://creativecommons.org/ns */
75 #define LICENSE_URI "/x:xmpmeta/rdf:RDF/rdf:Description/cc:license/@rdf:resource"
76 
77 typedef struct {
79 
80  /* Pages per sheet */
83  gint pages_x;
84  gint pages_y;
85  gdouble paper_width;
86  gdouble paper_height;
87 
88 #ifdef HAVE_CAIRO_PRINT
89  cairo_t *cr;
90 #else
91  PopplerPSFile *ps_file;
92 #endif
94 
96 {
98 };
99 
101 {
103 
104  PopplerDocument *document;
105  gchar *password;
106  gboolean forms_modified;
107  gboolean annots_modified;
108 
109  PopplerFontInfo *font_info;
110  PopplerFontsIter *fonts_iter;
112  gboolean missing_fonts;
113 
115 
116  GHashTable *annots;
117 };
118 
134 static int pdf_document_get_n_pages (EvDocument *document);
135 
136 static EvLinkDest *ev_link_dest_from_dest (PdfDocument *pdf_document,
137  PopplerDest *dest);
138 static EvLink *ev_link_from_action (PdfDocument *pdf_document,
139  PopplerAction *action);
140 static void pdf_print_context_free (PdfPrintContext *ctx);
141 static gboolean attachment_save_to_buffer (PopplerAttachment *attachment,
142  gchar **buffer,
143  gsize *buffer_size,
144  GError **error);
145 
147  {
178  });
179 
180 static void
181 pdf_document_dispose (GObject *object)
182 {
183  PdfDocument *pdf_document = PDF_DOCUMENT(object);
184 
185  if (pdf_document->print_ctx) {
186  pdf_print_context_free (pdf_document->print_ctx);
187  pdf_document->print_ctx = NULL;
188  }
189 
190  if (pdf_document->annots) {
191  g_hash_table_destroy (pdf_document->annots);
192  pdf_document->annots = NULL;
193  }
194 
195  if (pdf_document->document) {
196  g_object_unref (pdf_document->document);
197  }
198 
199  if (pdf_document->font_info) {
200  poppler_font_info_free (pdf_document->font_info);
201  }
202 
203  if (pdf_document->fonts_iter) {
204  poppler_fonts_iter_free (pdf_document->fonts_iter);
205  }
206 
207  G_OBJECT_CLASS (pdf_document_parent_class)->dispose (object);
208 }
209 
210 static void
212 {
213  pdf_document->password = NULL;
214 }
215 
216 static void
217 convert_error (GError *poppler_error,
218  GError **error)
219 {
220  if (poppler_error == NULL)
221  return;
222 
223  if (poppler_error->domain == POPPLER_ERROR) {
224  /* convert poppler errors into EvDocument errors */
225  gint code = EV_DOCUMENT_ERROR_INVALID;
226  if (poppler_error->code == POPPLER_ERROR_INVALID)
228  else if (poppler_error->code == POPPLER_ERROR_ENCRYPTED)
230 
231  g_set_error_literal (error,
233  code,
234  poppler_error->message);
235 
236  g_error_free (poppler_error);
237  } else {
238  g_propagate_error (error, poppler_error);
239  }
240 }
241 
242 
243 /* EvDocument */
244 static gboolean
246  const char *uri,
247  GError **error)
248 {
249  PdfDocument *pdf_document = PDF_DOCUMENT (document);
250  gboolean retval;
251  GError *poppler_error = NULL;
252 
253  if (pdf_document->forms_modified || pdf_document->annots_modified) {
254  retval = poppler_document_save (pdf_document->document,
255  uri, &poppler_error);
256  if (retval) {
257  pdf_document->forms_modified = FALSE;
258  pdf_document->annots_modified = FALSE;
259  }
260  } else {
261  retval = poppler_document_save_a_copy (pdf_document->document,
262  uri, &poppler_error);
263  }
264 
265  if (! retval)
266  convert_error (poppler_error, error);
267 
268  return retval;
269 }
270 
271 static gboolean
273  const char *uri,
274  GError **error)
275 {
276  GError *poppler_error = NULL;
277  PdfDocument *pdf_document = PDF_DOCUMENT (document);
278 
279  pdf_document->document =
280  poppler_document_new_from_file (uri, pdf_document->password, &poppler_error);
281 
282  if (pdf_document->document == NULL) {
283  convert_error (poppler_error, error);
284  return FALSE;
285  }
286 
287  return TRUE;
288 }
289 
290 static gboolean
292  GInputStream *stream,
293  EvDocumentLoadFlags flags,
294  GCancellable *cancellable,
295  GError **error)
296 {
297  GError *err = NULL;
298  PdfDocument *pdf_document = PDF_DOCUMENT (document);
299 
300  pdf_document->document =
301  poppler_document_new_from_stream (stream, -1,
302  pdf_document->password,
303  cancellable,
304  &err);
305 
306  if (pdf_document->document == NULL) {
307  convert_error (err, error);
308  return FALSE;
309  }
310 
311  return TRUE;
312 }
313 
314 static gboolean
316  GFile *file,
317  EvDocumentLoadFlags flags,
318  GCancellable *cancellable,
319  GError **error)
320 {
321  GError *err = NULL;
322  PdfDocument *pdf_document = PDF_DOCUMENT (document);
323 
324  pdf_document->document =
325  poppler_document_new_from_gfile (file,
326  pdf_document->password,
327  cancellable,
328  &err);
329 
330  if (pdf_document->document == NULL) {
331  convert_error (err, error);
332  return FALSE;
333  }
334 
335  return TRUE;
336 }
337 
338 static int
340 {
341  return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
342 }
343 
344 static EvPage *
346  gint index)
347 {
348  PdfDocument *pdf_document = PDF_DOCUMENT (document);
349  PopplerPage *poppler_page;
350  EvPage *page;
351 
352  poppler_page = poppler_document_get_page (pdf_document->document, index);
353  page = ev_page_new (index);
354  page->backend_page = (EvBackendPage)g_object_ref (poppler_page);
355  page->backend_destroy_func = (EvBackendPageDestroyFunc)g_object_unref;
356  g_object_unref (poppler_page);
357 
358  return page;
359 }
360 
361 static void
363  EvPage *page,
364  double *width,
365  double *height)
366 {
367  g_return_if_fail (POPPLER_IS_PAGE (page->backend_page));
368 
369  poppler_page_get_size (POPPLER_PAGE (page->backend_page), width, height);
370 }
371 
372 static char *
374  EvPage *page)
375 {
376  char *label = NULL;
377 
378  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
379 
380  g_object_get (G_OBJECT (page->backend_page),
381  "label", &label,
382  NULL);
383  return label;
384 }
385 
386 static cairo_surface_t *
387 pdf_page_render (PopplerPage *page,
388  gint width,
389  gint height,
390  EvRenderContext *rc)
391 {
392  cairo_surface_t *surface;
393  cairo_t *cr;
394  double page_width, page_height;
395  double xscale, yscale;
396 
397  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
398  width, height);
399  cr = cairo_create (surface);
400 
401  switch (rc->rotation) {
402  case 90:
403  cairo_translate (cr, width, 0);
404  break;
405  case 180:
406  cairo_translate (cr, width, height);
407  break;
408  case 270:
409  cairo_translate (cr, 0, height);
410  break;
411  default:
412  cairo_translate (cr, 0, 0);
413  }
414 
415  poppler_page_get_size (page,
416  &page_width, &page_height);
417 
418  ev_render_context_compute_scales (rc, page_width, page_height, &xscale, &yscale);
419  cairo_scale (cr, xscale, yscale);
420  cairo_rotate (cr, rc->rotation * G_PI / 180.0);
421  poppler_page_render (page, cr);
422 
423  cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
424  cairo_set_source_rgb (cr, 1., 1., 1.);
425  cairo_paint (cr);
426 
427  cairo_destroy (cr);
428 
429  return surface;
430 }
431 
432 static cairo_surface_t *
434  EvRenderContext *rc)
435 {
436  PopplerPage *poppler_page;
437  double width_points, height_points;
438  gint width, height;
439 
440  poppler_page = POPPLER_PAGE (rc->page->backend_page);
441 
442  poppler_page_get_size (poppler_page,
443  &width_points, &height_points);
444 
445  ev_render_context_compute_transformed_size (rc, width_points, height_points,
446  &width, &height);
447  return pdf_page_render (poppler_page,
448  width, height, rc);
449 }
450 
451 static GdkPixbuf *
452 make_thumbnail_for_page (PopplerPage *poppler_page,
453  EvRenderContext *rc,
454  gint width,
455  gint height)
456 {
457  GdkPixbuf *pixbuf;
458  cairo_surface_t *surface;
459 
461  surface = pdf_page_render (poppler_page, width, height, rc);
463 
464  pixbuf = ev_document_misc_pixbuf_from_surface (surface);
465  cairo_surface_destroy (surface);
466 
467  return pixbuf;
468 }
469 
470 static GdkPixbuf *
472  EvRenderContext *rc)
473 {
474  PopplerPage *poppler_page;
475  cairo_surface_t *surface;
476  GdkPixbuf *pixbuf = NULL;
477  double page_width, page_height;
478  gint width, height;
479 
480  poppler_page = POPPLER_PAGE (rc->page->backend_page);
481 
482  poppler_page_get_size (poppler_page,
483  &page_width, &page_height);
484 
485  ev_render_context_compute_transformed_size (rc, page_width, page_height,
486  &width, &height);
487 
488  surface = poppler_page_get_thumbnail (poppler_page);
489  if (surface) {
490  pixbuf = ev_document_misc_pixbuf_from_surface (surface);
491  cairo_surface_destroy (surface);
492  }
493 
494  if (pixbuf != NULL) {
495  int thumb_width = (rc->rotation == 90 || rc->rotation == 270) ?
496  gdk_pixbuf_get_height (pixbuf) :
497  gdk_pixbuf_get_width (pixbuf);
498 
499  if (thumb_width == width) {
500  GdkPixbuf *rotated_pixbuf;
501 
502  rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf,
503  (GdkPixbufRotation) (360 - rc->rotation));
504  g_object_unref (pixbuf);
505  pixbuf = rotated_pixbuf;
506  } else {
507  /* The provided thumbnail has a different size */
508  g_object_unref (pixbuf);
509  pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
510  }
511  } else {
512  /* There is no provided thumbnail. We need to make one. */
513  pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
514  }
515 
516  return pixbuf;
517 }
518 
519 static cairo_surface_t *
521  EvRenderContext *rc)
522 {
523 
524  PopplerPage *poppler_page;
525  cairo_surface_t *surface;
526  GdkPixbuf *pixbuf = NULL;
527  double page_width, page_height;
528  gint width, height;
529 
530  poppler_page = POPPLER_PAGE (rc->page->backend_page);
531 
532  poppler_page_get_size (poppler_page,
533  &page_width, &page_height);
534 
535  ev_render_context_compute_transformed_size (rc, page_width, page_height,
536  &width, &height);
537 
538  surface = poppler_page_get_thumbnail (poppler_page);
539  if (surface) {
540  int surface_width = (rc->rotation == 90 || rc->rotation == 270) ?
541  cairo_image_surface_get_height (surface) :
542  cairo_image_surface_get_width (surface);
543 
544  if (surface_width == width) {
545  cairo_surface_t *rotated_surface;
546 
547  rotated_surface = ev_document_misc_surface_rotate_and_scale (surface, width, height, rc->rotation);
548  cairo_surface_destroy (surface);
549  return rotated_surface;
550  } else {
551  /* The provided thumbnail has a different size */
552  cairo_surface_destroy (surface);
553  }
554  }
555 
557  surface = pdf_page_render (poppler_page, width, height, rc);
559 
560  return surface;
561 }
562 
563 /* reference:
564 http://www.pdfa.org/lib/exe/fetch.php?id=pdfa%3Aen%3Atechdoc&cache=cache&media=pdfa:techdoc:tn0001_pdfa-1_and_namespaces_2008-03-18.pdf */
565 static char *
567  xmlXPathContextPtr xpathCtx)
568 {
569  xmlXPathObjectPtr xpathObj;
570  xmlChar *part = NULL;
571  xmlChar *conf = NULL;
572  char *result = NULL;
573  int i;
574 
575  /* add pdf/a namespaces */
576  xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
577  xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
578  xmlXPathRegisterNs (xpathCtx, BAD_CAST "pdfaid", BAD_CAST "http://www.aiim.org/pdfa/ns/id/");
579 
580  /* reads pdf/a part */
581  /* first syntax: child node */
582  xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/pdfaid:part", xpathCtx);
583  if (xpathObj != NULL) {
584  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
585  part = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
586 
587  xmlXPathFreeObject (xpathObj);
588  }
589  if (part == NULL) {
590  /* second syntax: attribute */
591  xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/@pdfaid:part", xpathCtx);
592  if (xpathObj != NULL) {
593  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
594  part = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
595 
596  xmlXPathFreeObject (xpathObj);
597  }
598  }
599 
600  /* reads pdf/a conformance */
601  /* first syntax: child node */
602  xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/pdfaid:conformance", xpathCtx);
603  if (xpathObj != NULL) {
604  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
605  conf = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
606 
607  xmlXPathFreeObject (xpathObj);
608  }
609  if (conf == NULL) {
610  /* second syntax: attribute */
611  xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/@pdfaid:conformance", xpathCtx);
612  if (xpathObj != NULL) {
613  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
614  conf = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
615 
616  xmlXPathFreeObject (xpathObj);
617  }
618  }
619 
620  if (part != NULL && conf != NULL) {
621  /* makes conf lowercase */
622  for (i = 0; conf[i]; i++)
623  conf[i] = g_ascii_tolower (conf[i]);
624 
625  /* return buffer */
626  result = g_strdup_printf ("PDF/A - %s%s", part, conf);
627  }
628 
629  /* Cleanup */
630  xmlFree (part);
631  xmlFree (conf);
632 
633  return result;
634 }
635 
636 static EvDocumentLicense *
638  xmlXPathContextPtr xpathCtx)
639 {
640  xmlXPathObjectPtr xpathObj;
641  xmlChar *marked = NULL;
642  const char *language_string;
643  char *aux;
644  gchar **tags;
645  gchar *tag, *tag_aux;
646  int i, j;
647  EvDocumentLicense *license;
648 
649  /* register namespaces */
650  xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
651  xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
652  xmlXPathRegisterNs (xpathCtx, BAD_CAST "dc", BAD_CAST "http://purl.org/dc/elements/1.1/");
653  /* XMP Rights Management Schema */
654  xmlXPathRegisterNs (xpathCtx, BAD_CAST "xmpRights", BAD_CAST "http://ns.adobe.com/xap/1.0/rights/");
655  /* Creative Commons Schema */
656  xmlXPathRegisterNs (xpathCtx, BAD_CAST "cc", BAD_CAST "http://creativecommons.org/ns#");
657 
658  /* checking if the document has been marked as defined on the XMP Rights
659  * Management Schema */
660  xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_MARKED, xpathCtx);
661  if (xpathObj != NULL) {
662  if (xpathObj->nodesetval != NULL &&
663  xpathObj->nodesetval->nodeNr != 0)
664  marked = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
665  xmlXPathFreeObject (xpathObj);
666  }
667 
668  /* a) Not marked => No XMP Rights information */
669  if (!marked) {
670  xmlFree (marked);
671  return NULL;
672  }
673 
674  license = ev_document_license_new ();
675 
676  /* b) Marked False => Public Domain, no copyrighted material and no
677  * license needed */
678  if (g_strrstr ((char *) marked, "False") != NULL) {
679  license->text = g_strdup (_("This work is in the Public Domain"));
680  /* c) Marked True => Copyrighted material */
681  } else {
682  /* Checking usage terms as defined by the XMP Rights Management
683  * Schema. This field is recomended to be checked by Creative
684  * Commons */
685  /* 1) checking for a suitable localized string */
686  language_string = pango_language_to_string (gtk_get_default_language ());
687  tags = g_strsplit (language_string, "-", -1);
688  i = g_strv_length (tags);
689  while (i-- && !license->text) {
690  tag = g_strdup (tags[0]);
691  for (j = 1; j <= i; j++) {
692  tag_aux = g_strdup_printf ("%s-%s", tag, tags[j]);
693  g_free (tag);
694  tag = tag_aux;
695  }
696  aux = g_strdup_printf (LICENSE_TEXT, tag);
697  xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
698  if (xpathObj != NULL) {
699  if (xpathObj->nodesetval != NULL &&
700  xpathObj->nodesetval->nodeNr != 0)
701  license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
702  xmlXPathFreeObject (xpathObj);
703  }
704  g_free (tag);
705  g_free (aux);
706  }
707  g_strfreev(tags);
708 
709  /* 2) if not, use the default string */
710  if (!license->text) {
711  aux = g_strdup_printf (LICENSE_TEXT, "x-default");
712  xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
713  if (xpathObj != NULL) {
714  if (xpathObj->nodesetval != NULL &&
715  xpathObj->nodesetval->nodeNr != 0)
716  license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
717  xmlXPathFreeObject (xpathObj);
718  }
719  g_free (aux);
720  }
721 
722  /* Checking the license URI as defined by the Creative Commons
723  * Schema. This field is recomended to be checked by Creative
724  * Commons */
725  xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_URI, xpathCtx);
726  if (xpathObj != NULL) {
727  if (xpathObj->nodesetval != NULL &&
728  xpathObj->nodesetval->nodeNr != 0)
729  license->uri = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
730  xmlXPathFreeObject (xpathObj);
731  }
732 
733  /* Checking the web statement as defined by the XMP Rights
734  * Management Schema. Checking it out is a sort of above-and-beyond
735  * the basic recommendations by Creative Commons. It can be
736  * considered as a "reinforcement" approach to add certainty. */
737  xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_WEB_STATEMENT, xpathCtx);
738  if (xpathObj != NULL) {
739  if (xpathObj->nodesetval != NULL &&
740  xpathObj->nodesetval->nodeNr != 0)
741  license->web_statement = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
742  xmlXPathFreeObject (xpathObj);
743  }
744  }
745  xmlFree (marked);
746 
747  if (!license->text && !license->uri && !license->web_statement) {
748  ev_document_license_free (license);
749  return NULL;
750  }
751 
752  return license;
753 }
754 
755 static void
756 pdf_document_parse_metadata (const gchar *metadata,
757  EvDocumentInfo *info)
758 {
759  xmlDocPtr doc;
760  xmlXPathContextPtr xpathCtx;
761  gchar *fmt;
762 
763  doc = xmlParseMemory (metadata, strlen (metadata));
764  if (doc == NULL)
765  return; /* invalid xml metadata */
766 
767  xpathCtx = xmlXPathNewContext (doc);
768  if (xpathCtx == NULL) {
769  xmlFreeDoc (doc);
770  return; /* invalid xpath context */
771  }
772 
773  fmt = pdf_document_get_format_from_metadata (doc, xpathCtx);
774  if (fmt != NULL) {
775  g_free (info->format);
776  info->format = fmt;
777  }
778 
779  info->license = pdf_document_get_license_from_metadata (doc, xpathCtx);
780 
781  xmlXPathFreeContext (xpathCtx);
782  xmlFreeDoc (doc);
783 }
784 
785 
786 static EvDocumentInfo *
788 {
789  EvDocumentInfo *info;
790  PopplerPageLayout layout;
791  PopplerPageMode mode;
792  PopplerViewerPreferences view_prefs;
793  PopplerPermissions permissions;
794  char *metadata;
795  gboolean linearized;
796 
797  info = g_new0 (EvDocumentInfo, 1);
798 
799  info->fields_mask = EV_DOCUMENT_INFO_TITLE |
817 
818  g_object_get (PDF_DOCUMENT (document)->document,
819  "title", &(info->title),
820  "format", &(info->format),
821  "author", &(info->author),
822  "subject", &(info->subject),
823  "keywords", &(info->keywords),
824  "page-mode", &mode,
825  "page-layout", &layout,
826  "viewer-preferences", &view_prefs,
827  "permissions", &permissions,
828  "creator", &(info->creator),
829  "producer", &(info->producer),
830  "creation-date", &(info->creation_date),
831  "mod-date", &(info->modified_date),
832  "linearized", &linearized,
833  "metadata", &metadata,
834  NULL);
835 
836  if (metadata != NULL) {
837  pdf_document_parse_metadata (metadata, info);
838  g_free (metadata);
839  }
840 
841  info->n_pages = poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
842 
843  if (info->n_pages > 0) {
844  PopplerPage *poppler_page;
845 
846  poppler_page = poppler_document_get_page (PDF_DOCUMENT (document)->document, 0);
847  poppler_page_get_size (poppler_page, &(info->paper_width), &(info->paper_height));
848  g_object_unref (poppler_page);
849 
850  // Convert to mm.
851  info->paper_width = info->paper_width / 72.0f * 25.4f;
852  info->paper_height = info->paper_height / 72.0f * 25.4f;
853  }
854 
855  switch (layout) {
856  case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
857  info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
858  break;
859  case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
860  info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
861  break;
862  case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
863  info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
864  break;
865  case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
867  case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
868  info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
869  break;
870  case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
871  info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
872  break;
873  default:
874  break;
875  }
876 
877  switch (mode) {
878  case POPPLER_PAGE_MODE_NONE:
879  info->mode = EV_DOCUMENT_MODE_NONE;
880  break;
881  case POPPLER_PAGE_MODE_USE_THUMBS:
882  info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
883  break;
884  case POPPLER_PAGE_MODE_USE_OC:
885  info->mode = EV_DOCUMENT_MODE_USE_OC;
886  break;
887  case POPPLER_PAGE_MODE_FULL_SCREEN:
888  info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
889  break;
890  case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
892  default:
893  break;
894  }
895 
896  info->ui_hints = 0;
897  if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
898  info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
899  }
900  if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
901  info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
902  }
903  if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
904  info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
905  }
906  if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
907  info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
908  }
909  if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
910  info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
911  }
912  if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
913  info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
914  }
915  if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
916  info->ui_hints |= EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
917  }
918 
919  info->permissions = 0;
920  if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
921  info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
922  }
923  if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
924  info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
925  }
926  if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
927  info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
928  }
929  if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
930  info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
931  }
932 
934  /* translators: this is the document security state */
935  info->security = g_strdup (_("Yes"));
936  } else {
937  /* translators: this is the document security state */
938  info->security = g_strdup (_("No"));
939  }
940 
941  info->linearized = linearized ? g_strdup (_("Yes")) : g_strdup (_("No"));
942 
943  return info;
944 }
945 
946 static gboolean
948 {
949  PopplerBackend backend;
950 
951  backend = poppler_get_backend ();
952  switch (backend) {
953  case POPPLER_BACKEND_CAIRO:
954  info->name = "poppler/cairo";
955  break;
956  case POPPLER_BACKEND_SPLASH:
957  info->name = "poppler/splash";
958  break;
959  default:
960  info->name = "poppler/unknown";
961  break;
962  }
963 
964  info->version = poppler_get_version ();
965 
966  return TRUE;
967 }
968 
969 static gboolean
971 {
972  return TRUE;
973 }
974 
975 static void
977 {
978  GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
979  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
980 
981  g_object_class->dispose = pdf_document_dispose;
982 
983  ev_document_class->save = pdf_document_save;
984  ev_document_class->load = pdf_document_load;
985  ev_document_class->load_stream = pdf_document_load_stream;
986  ev_document_class->load_gfile = pdf_document_load_gfile;
987  ev_document_class->get_n_pages = pdf_document_get_n_pages;
988  ev_document_class->get_page = pdf_document_get_page;
989  ev_document_class->get_page_size = pdf_document_get_page_size;
990  ev_document_class->get_page_label = pdf_document_get_page_label;
991  ev_document_class->render = pdf_document_render;
992  ev_document_class->get_thumbnail = pdf_document_get_thumbnail;
994  ev_document_class->get_info = pdf_document_get_info;
995  ev_document_class->get_backend_info = pdf_document_get_backend_info;
996  ev_document_class->support_synctex = pdf_document_support_synctex;
997 }
998 
999 /* EvDocumentSecurity */
1000 static gboolean
1002 {
1003  /* FIXME: do we really need to have this? */
1004  return FALSE;
1005 }
1006 
1007 static void
1009  const char *password)
1010 {
1011  PdfDocument *document = PDF_DOCUMENT (document_security);
1012 
1013  if (document->password)
1014  g_free (document->password);
1015 
1016  document->password = g_strdup (password);
1017 }
1018 
1019 static void
1021 {
1024 }
1025 
1026 static gdouble
1028 {
1029  PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
1030  int n_pages;
1031 
1032  n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1033 
1034  return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
1035 }
1036 
1037 static gboolean
1039  int n_pages)
1040 {
1041  PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
1042  gboolean result;
1043 
1044  g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
1045 
1046  if (pdf_document->font_info == NULL) {
1047  pdf_document->font_info = poppler_font_info_new (pdf_document->document);
1048  }
1049 
1050  if (pdf_document->fonts_iter) {
1051  poppler_fonts_iter_free (pdf_document->fonts_iter);
1052  }
1053 
1054  pdf_document->fonts_scanned_pages += n_pages;
1055 
1056  result = poppler_font_info_scan (pdf_document->font_info, n_pages,
1057  &pdf_document->fonts_iter);
1058  if (!result) {
1059  pdf_document->fonts_scanned_pages = 0;
1060  poppler_font_info_free (pdf_document->font_info);
1061  pdf_document->font_info = NULL;
1062  }
1063 
1064  return result;
1065 }
1066 
1067 static const char *
1068 font_type_to_string (PopplerFontType type)
1069 {
1070  switch (type) {
1071  case POPPLER_FONT_TYPE_TYPE1:
1072  return _("Type 1");
1073  case POPPLER_FONT_TYPE_TYPE1C:
1074  return _("Type 1C");
1075  case POPPLER_FONT_TYPE_TYPE3:
1076  return _("Type 3");
1077  case POPPLER_FONT_TYPE_TRUETYPE:
1078  return _("TrueType");
1079  case POPPLER_FONT_TYPE_CID_TYPE0:
1080  return _("Type 1 (CID)");
1081  case POPPLER_FONT_TYPE_CID_TYPE0C:
1082  return _("Type 1C (CID)");
1083  case POPPLER_FONT_TYPE_CID_TYPE2:
1084  return _("TrueType (CID)");
1085  default:
1086  return _("Unknown font type");
1087  }
1088 }
1089 
1090 static gboolean
1091 is_standard_font (const gchar *name, PopplerFontType type)
1092 {
1093  /* list borrowed from Poppler: poppler/GfxFont.cc */
1094  static const char *base_14_subst_fonts[14] = {
1095  "Courier",
1096  "Courier-Oblique",
1097  "Courier-Bold",
1098  "Courier-BoldOblique",
1099  "Helvetica",
1100  "Helvetica-Oblique",
1101  "Helvetica-Bold",
1102  "Helvetica-BoldOblique",
1103  "Times-Roman",
1104  "Times-Italic",
1105  "Times-Bold",
1106  "Times-BoldItalic",
1107  "Symbol",
1108  "ZapfDingbats"
1109  };
1110  unsigned int i;
1111 
1112  /* The Standard 14 fonts are all Type 1 fonts. A non embedded TrueType
1113  * font with the same name is not a Standard 14 font. */
1114  if (type != POPPLER_FONT_TYPE_TYPE1)
1115  return FALSE;
1116 
1117  for (i = 0; i < G_N_ELEMENTS (base_14_subst_fonts); i++) {
1118  if (g_str_equal (name, base_14_subst_fonts[i]))
1119  return TRUE;
1120  }
1121  return FALSE;
1122 }
1123 
1124 static const gchar *
1126 {
1127  PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
1128 
1129  if (pdf_document->missing_fonts)
1130  return _("This document contains non-embedded fonts that are not from the "
1131  "PDF Standard 14 fonts. If the substitute fonts selected by fontconfig "
1132  "are not the same as the fonts used to create the PDF, the rendering may "
1133  "not be correct.");
1134  else
1135  return _("All fonts are either standard or embedded.");
1136 }
1137 
1138 static void
1140  GtkTreeModel *model)
1141 {
1142  PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
1143  PopplerFontsIter *iter = pdf_document->fonts_iter;
1144 
1145  g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
1146 
1147  if (!iter)
1148  return;
1149 
1150  do {
1151  GtkTreeIter list_iter;
1152  const char *name;
1153  PopplerFontType type;
1154  const char *type_str;
1155  const char *embedded;
1156  const char *standard_str = "";
1157  const gchar *substitute;
1158  const gchar *substitute_text;
1159  const gchar *filename;
1160  const gchar *encoding;
1161  const gchar *encoding_text;
1162  char *details;
1163 
1164  name = poppler_fonts_iter_get_name (iter);
1165 
1166  if (name == NULL) {
1167  name = _("No name");
1168  }
1169 
1170  encoding = poppler_fonts_iter_get_encoding (iter);
1171  if (!encoding) {
1172  /* translators: When a font type does not have
1173  encoding information or it is unknown. Example:
1174  Encoding: None
1175  */
1176  encoding = _("None");
1177  }
1178 
1179  type = poppler_fonts_iter_get_font_type (iter);
1180  type_str = font_type_to_string (type);
1181 
1182  if (poppler_fonts_iter_is_embedded (iter)) {
1183  if (poppler_fonts_iter_is_subset (iter))
1184  embedded = _("Embedded subset");
1185  else
1186  embedded = _("Embedded");
1187  } else {
1188  embedded = _("Not embedded");
1189  if (is_standard_font (name, type)) {
1190  /* Translators: string starting with a space
1191  * because it is directly appended to the font
1192  * type. Example:
1193  * "Type 1 (One of the Standard 14 Fonts)"
1194  */
1195  standard_str = _(" (One of the Standard 14 Fonts)");
1196  } else {
1197  /* Translators: string starting with a space
1198  * because it is directly appended to the font
1199  * type. Example:
1200  * "TrueType (Not one of the Standard 14 Fonts)"
1201  */
1202  standard_str = _(" (Not one of the Standard 14 Fonts)");
1203  pdf_document->missing_fonts = TRUE;
1204  }
1205  }
1206 
1207  substitute = poppler_fonts_iter_get_substitute_name (iter);
1208  filename = poppler_fonts_iter_get_file_name (iter);
1209  encoding_text = _("Encoding");
1210  substitute_text = _("Substituting with");
1211 
1212  if (substitute && filename)
1213  details = g_markup_printf_escaped ("%s%s\n%s: %s\n%s\n%s <b>%s</b>\n(%s)",
1214  type_str, standard_str,
1215  encoding_text, encoding, embedded,
1216  substitute_text, substitute, filename);
1217  else
1218  details = g_markup_printf_escaped ("%s%s\n%s: %s\n%s",
1219  type_str, standard_str,
1220  encoding_text, encoding, embedded);
1221 
1222  gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
1223  gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
1226  -1);
1227 
1228  g_free (details);
1229  } while (poppler_fonts_iter_next (iter));
1230 }
1231 
1232 static void
1234 {
1237  iface->scan = pdf_document_fonts_scan;
1239 }
1240 
1241 static gboolean
1243 {
1244  PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1245  PopplerIndexIter *iter;
1246 
1247  g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
1248 
1249  iter = poppler_index_iter_new (pdf_document->document);
1250  if (iter == NULL)
1251  return FALSE;
1252  poppler_index_iter_free (iter);
1253 
1254  return TRUE;
1255 }
1256 
1257 static EvLinkDest *
1259  PopplerDest *dest)
1260 {
1261  EvLinkDest *ev_dest = NULL;
1262  const char *unimplemented_dest = NULL;
1263 
1264  g_assert (dest != NULL);
1265 
1266  switch (dest->type) {
1267  case POPPLER_DEST_XYZ: {
1268  PopplerPage *poppler_page;
1269  double height;
1270 
1271  poppler_page = poppler_document_get_page (pdf_document->document,
1272  MAX (0, dest->page_num - 1));
1273  poppler_page_get_size (poppler_page, NULL, &height);
1274  ev_dest = ev_link_dest_new_xyz (dest->page_num - 1,
1275  dest->left,
1276  height - MIN (height, dest->top),
1277  dest->zoom,
1278  dest->change_left,
1279  dest->change_top,
1280  dest->change_zoom);
1281  g_object_unref (poppler_page);
1282  }
1283  break;
1284  case POPPLER_DEST_FITB:
1285  case POPPLER_DEST_FIT:
1286  ev_dest = ev_link_dest_new_fit (dest->page_num - 1);
1287  break;
1288  case POPPLER_DEST_FITBH:
1289  case POPPLER_DEST_FITH: {
1290  PopplerPage *poppler_page;
1291  double height;
1292 
1293  poppler_page = poppler_document_get_page (pdf_document->document,
1294  MAX (0, dest->page_num - 1));
1295  poppler_page_get_size (poppler_page, NULL, &height);
1296  ev_dest = ev_link_dest_new_fith (dest->page_num - 1,
1297  height - MIN (height, dest->top),
1298  dest->change_top);
1299  g_object_unref (poppler_page);
1300  }
1301  break;
1302  case POPPLER_DEST_FITBV:
1303  case POPPLER_DEST_FITV:
1304  ev_dest = ev_link_dest_new_fitv (dest->page_num - 1,
1305  dest->left,
1306  dest->change_left);
1307  break;
1308  case POPPLER_DEST_FITR: {
1309  PopplerPage *poppler_page;
1310  double height;
1311 
1312  poppler_page = poppler_document_get_page (pdf_document->document,
1313  MAX (0, dest->page_num - 1));
1314  poppler_page_get_size (poppler_page, NULL, &height);
1315  /* for evince we ensure that bottom <= top and left <= right */
1316  /* also evince has its origin in the top left, so we invert the y axis. */
1317  ev_dest = ev_link_dest_new_fitr (dest->page_num - 1,
1318  MIN (dest->left, dest->right),
1319  height - MIN (height, MIN (dest->bottom, dest->top)),
1320  MAX (dest->left, dest->right),
1321  height - MIN (height, MAX (dest->bottom, dest->top)));
1322  g_object_unref (poppler_page);
1323  }
1324  break;
1325  case POPPLER_DEST_NAMED:
1326  ev_dest = ev_link_dest_new_named (dest->named_dest);
1327  break;
1328  case POPPLER_DEST_UNKNOWN:
1329  unimplemented_dest = "POPPLER_DEST_UNKNOWN";
1330  break;
1331  }
1332 
1333  if (unimplemented_dest) {
1334  g_warning ("Unimplemented destination: %s, please post a "
1335  "bug report in Evince bugzilla "
1336  "(http://bugzilla.gnome.org) with a testcase.",
1337  unimplemented_dest);
1338  }
1339 
1340  if (!ev_dest)
1341  ev_dest = ev_link_dest_new_page (dest->page_num - 1);
1342 
1343  return ev_dest;
1344 }
1345 
1346 static EvLink *
1348  PopplerAction *action)
1349 {
1350  EvLink *link = NULL;
1351  EvLinkAction *ev_action = NULL;
1352  const char *unimplemented_action = NULL;
1353 
1354  switch (action->type) {
1355  case POPPLER_ACTION_NONE:
1356  break;
1357  case POPPLER_ACTION_GOTO_DEST: {
1358  EvLinkDest *dest;
1359 
1360  dest = ev_link_dest_from_dest (pdf_document, action->goto_dest.dest);
1361  ev_action = ev_link_action_new_dest (dest);
1362  g_object_unref (dest);
1363  }
1364  break;
1365  case POPPLER_ACTION_GOTO_REMOTE: {
1366  EvLinkDest *dest;
1367 
1368  dest = ev_link_dest_from_dest (pdf_document, action->goto_remote.dest);
1369  ev_action = ev_link_action_new_remote (dest,
1370  action->goto_remote.file_name);
1371  g_object_unref (dest);
1372 
1373  }
1374  break;
1375  case POPPLER_ACTION_LAUNCH:
1376  ev_action = ev_link_action_new_launch (action->launch.file_name,
1377  action->launch.params);
1378  break;
1379  case POPPLER_ACTION_URI:
1380  ev_action = ev_link_action_new_external_uri (action->uri.uri);
1381  break;
1382  case POPPLER_ACTION_NAMED:
1383  ev_action = ev_link_action_new_named (action->named.named_dest);
1384  break;
1385  case POPPLER_ACTION_MOVIE:
1386  unimplemented_action = "POPPLER_ACTION_MOVIE";
1387  break;
1388  case POPPLER_ACTION_RENDITION:
1389  unimplemented_action = "POPPLER_ACTION_RENDITION";
1390  break;
1391  case POPPLER_ACTION_OCG_STATE: {
1392  GList *on_list = NULL;
1393  GList *off_list = NULL;
1394  GList *toggle_list = NULL;
1395  GList *l, *m;
1396 
1397  for (l = action->ocg_state.state_list; l; l = g_list_next (l)) {
1398  PopplerActionLayer *action_layer = (PopplerActionLayer *)l->data;
1399 
1400  for (m = action_layer->layers; m; m = g_list_next (m)) {
1401  PopplerLayer *layer = (PopplerLayer *)m->data;
1402  EvLayer *ev_layer;
1403 
1404  ev_layer = ev_layer_new (poppler_layer_is_parent (layer),
1405  poppler_layer_get_radio_button_group_id (layer));
1406  g_object_set_data_full (G_OBJECT (ev_layer),
1407  "poppler-layer",
1408  g_object_ref (layer),
1409  (GDestroyNotify)g_object_unref);
1410 
1411  switch (action_layer->action) {
1412  case POPPLER_ACTION_LAYER_ON:
1413  on_list = g_list_prepend (on_list, ev_layer);
1414  break;
1415  case POPPLER_ACTION_LAYER_OFF:
1416  off_list = g_list_prepend (off_list, ev_layer);
1417  break;
1418  case POPPLER_ACTION_LAYER_TOGGLE:
1419  toggle_list = g_list_prepend (toggle_list, ev_layer);
1420  break;
1421  }
1422  }
1423  }
1424 
1425  /* The action takes the ownership of the lists */
1426  ev_action = ev_link_action_new_layers_state (g_list_reverse (on_list),
1427  g_list_reverse (off_list),
1428  g_list_reverse (toggle_list));
1429 
1430 
1431  }
1432  break;
1433  case POPPLER_ACTION_JAVASCRIPT:
1434  unimplemented_action = "POPPLER_ACTION_JAVASCRIPT";
1435  break;
1436  case POPPLER_ACTION_UNKNOWN:
1437  unimplemented_action = "POPPLER_ACTION_UNKNOWN";
1438  }
1439 
1440  if (unimplemented_action) {
1441  g_warning ("Unimplemented action: %s, please post a bug report "
1442  "in Evince bugzilla (http://bugzilla.gnome.org) "
1443  "with a testcase.", unimplemented_action);
1444  }
1445 
1446  link = ev_link_new (action->any.title, ev_action);
1447  if (ev_action)
1448  g_object_unref (ev_action);
1449 
1450  return link;
1451 }
1452 
1453 static void
1454 build_tree (PdfDocument *pdf_document,
1455  GtkTreeModel *model,
1456  GtkTreeIter *parent,
1457  PopplerIndexIter *iter)
1458 {
1459 
1460  do {
1461  GtkTreeIter tree_iter;
1462  PopplerIndexIter *child;
1463  PopplerAction *action;
1464  EvLink *link = NULL;
1465  gboolean expand;
1466  char *title_markup;
1467 
1468  action = poppler_index_iter_get_action (iter);
1469  expand = poppler_index_iter_is_open (iter);
1470 
1471  if (!action)
1472  continue;
1473 
1474  link = ev_link_from_action (pdf_document, action);
1475  if (!link || strlen (ev_link_get_title (link)) <= 0) {
1476  poppler_action_free (action);
1477  if (link)
1478  g_object_unref (link);
1479 
1480  continue;
1481  }
1482 
1483  gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
1484  title_markup = g_markup_escape_text (ev_link_get_title (link), -1);
1485 
1486  gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
1487  EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
1490  -1);
1491 
1492  g_free (title_markup);
1493  g_object_unref (link);
1494 
1495  child = poppler_index_iter_get_child (iter);
1496  if (child)
1497  build_tree (pdf_document, model, &tree_iter, child);
1498  poppler_index_iter_free (child);
1499  poppler_action_free (action);
1500 
1501  } while (poppler_index_iter_next (iter));
1502 }
1503 
1504 static GtkTreeModel *
1506 {
1507  PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1508  GtkTreeModel *model = NULL;
1509  PopplerIndexIter *iter;
1510 
1511  g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
1512 
1513  iter = poppler_index_iter_new (pdf_document->document);
1514  /* Create the model if we have items*/
1515  if (iter != NULL) {
1516  model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
1517  G_TYPE_STRING,
1518  G_TYPE_OBJECT,
1519  G_TYPE_BOOLEAN,
1520  G_TYPE_STRING);
1521  build_tree (pdf_document, model, NULL, iter);
1522  poppler_index_iter_free (iter);
1523  }
1524 
1525  return model;
1526 }
1527 
1528 static EvMappingList *
1530  EvPage *page)
1531 {
1532  PdfDocument *pdf_document;
1533  PopplerPage *poppler_page;
1534  GList *retval = NULL;
1535  GList *mapping_list;
1536  GList *list;
1537  double height;
1538 
1539  pdf_document = PDF_DOCUMENT (document_links);
1540  poppler_page = POPPLER_PAGE (page->backend_page);
1541  mapping_list = poppler_page_get_link_mapping (poppler_page);
1542  poppler_page_get_size (poppler_page, NULL, &height);
1543 
1544  for (list = mapping_list; list; list = list->next) {
1545  PopplerLinkMapping *link_mapping;
1546  EvMapping *ev_link_mapping;
1547 
1548  link_mapping = (PopplerLinkMapping *)list->data;
1549  ev_link_mapping = g_new (EvMapping, 1);
1550  ev_link_mapping->data = ev_link_from_action (pdf_document,
1551  link_mapping->action);
1552  ev_link_mapping->area.x1 = link_mapping->area.x1;
1553  ev_link_mapping->area.x2 = link_mapping->area.x2;
1554  /* Invert this for X-style coordinates */
1555  ev_link_mapping->area.y1 = height - link_mapping->area.y2;
1556  ev_link_mapping->area.y2 = height - link_mapping->area.y1;
1557 
1558  retval = g_list_prepend (retval, ev_link_mapping);
1559  }
1560 
1561  poppler_page_free_link_mapping (mapping_list);
1562 
1563  return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
1564 }
1565 
1566 static EvLinkDest *
1568  const gchar *link_name)
1569 {
1570  PdfDocument *pdf_document;
1571  PopplerDest *dest;
1572  EvLinkDest *ev_dest = NULL;
1573 
1574  pdf_document = PDF_DOCUMENT (document_links);
1575  dest = poppler_document_find_dest (pdf_document->document,
1576  link_name);
1577  if (dest) {
1578  ev_dest = ev_link_dest_from_dest (pdf_document, dest);
1579  poppler_dest_free (dest);
1580  }
1581 
1582  return ev_dest;
1583 }
1584 
1585 static gint
1587  const gchar *link_name)
1588 {
1589  PdfDocument *pdf_document;
1590  PopplerDest *dest;
1591  gint retval = -1;
1592 
1593  pdf_document = PDF_DOCUMENT (document_links);
1594  dest = poppler_document_find_dest (pdf_document->document,
1595  link_name);
1596  if (dest) {
1597  retval = dest->page_num - 1;
1598  poppler_dest_free (dest);
1599  }
1600 
1601  return retval;
1602 }
1603 
1604 static void
1606 {
1612 }
1613 
1614 static EvMappingList *
1616  EvPage *page)
1617 {
1618  GList *retval = NULL;
1619  PopplerPage *poppler_page;
1620  GList *mapping_list;
1621  GList *list;
1622 
1623  poppler_page = POPPLER_PAGE (page->backend_page);
1624  mapping_list = poppler_page_get_image_mapping (poppler_page);
1625 
1626  for (list = mapping_list; list; list = list->next) {
1627  PopplerImageMapping *image_mapping;
1628  EvMapping *ev_image_mapping;
1629 
1630  image_mapping = (PopplerImageMapping *)list->data;
1631 
1632  ev_image_mapping = g_new (EvMapping, 1);
1633 
1634  ev_image_mapping->data = ev_image_new (page->index, image_mapping->image_id);
1635  ev_image_mapping->area.x1 = image_mapping->area.x1;
1636  ev_image_mapping->area.y1 = image_mapping->area.y1;
1637  ev_image_mapping->area.x2 = image_mapping->area.x2;
1638  ev_image_mapping->area.y2 = image_mapping->area.y2;
1639 
1640  retval = g_list_prepend (retval, ev_image_mapping);
1641  }
1642 
1643  poppler_page_free_image_mapping (mapping_list);
1644 
1645  return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
1646 }
1647 
1648 GdkPixbuf *
1650  EvImage *image)
1651 {
1652  GdkPixbuf *retval = NULL;
1653  PdfDocument *pdf_document;
1654  PopplerPage *poppler_page;
1655  cairo_surface_t *surface;
1656 
1657  pdf_document = PDF_DOCUMENT (document_images);
1658  poppler_page = poppler_document_get_page (pdf_document->document,
1659  ev_image_get_page (image));
1660 
1661  surface = poppler_page_get_image (poppler_page, ev_image_get_id (image));
1662  if (surface) {
1663  retval = ev_document_misc_pixbuf_from_surface (surface);
1664  cairo_surface_destroy (surface);
1665  }
1666 
1667  g_object_unref (poppler_page);
1668 
1669  return retval;
1670 }
1671 
1672 static void
1674 {
1677 }
1678 
1679 static GList *
1681  EvPage *page,
1682  const gchar *text,
1683  EvFindOptions options)
1684 {
1685  GList *matches, *l;
1686  PopplerPage *poppler_page;
1687  gdouble height;
1688  GList *retval = NULL;
1689  guint find_flags = 0;
1690 
1691  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1692  g_return_val_if_fail (text != NULL, NULL);
1693 
1694  poppler_page = POPPLER_PAGE (page->backend_page);
1695 
1696  if (options & EV_FIND_CASE_SENSITIVE)
1697  find_flags |= POPPLER_FIND_CASE_SENSITIVE;
1698  if (options & EV_FIND_WHOLE_WORDS_ONLY)
1699  find_flags |= POPPLER_FIND_WHOLE_WORDS_ONLY;
1700  matches = poppler_page_find_text_with_options (poppler_page, text, (PopplerFindFlags)find_flags);
1701  if (!matches)
1702  return NULL;
1703 
1704  poppler_page_get_size (poppler_page, NULL, &height);
1705  for (l = matches; l && l->data; l = g_list_next (l)) {
1706  PopplerRectangle *rect = (PopplerRectangle *)l->data;
1707  EvRectangle *ev_rect;
1708 
1709  ev_rect = ev_rectangle_new ();
1710  ev_rect->x1 = rect->x1;
1711  ev_rect->x2 = rect->x2;
1712  /* Invert this for X-style coordinates */
1713  ev_rect->y1 = height - rect->y2;
1714  ev_rect->y2 = height - rect->y1;
1715 
1716  retval = g_list_prepend (retval, ev_rect);
1717  }
1718 
1719  g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
1720  g_list_free (matches);
1721 
1722  return g_list_reverse (retval);
1723 }
1724 
1725 static GList *
1727  EvPage *page,
1728  const gchar *text,
1729  gboolean case_sensitive)
1730 {
1731  guint options = 0;
1732 
1733  if (case_sensitive)
1734  options |= EV_FIND_CASE_SENSITIVE;
1735 
1736  return pdf_document_find_find_text_with_options (document_find, page, text, (EvFindOptions)options);
1737 }
1738 
1739 static EvFindOptions
1741 {
1743 }
1744 
1745 static void
1747 {
1751 }
1752 
1753 static void
1755 {
1756  if (!ctx)
1757  return;
1758 
1759 #ifdef HAVE_CAIRO_PRINT
1760  if (ctx->cr) {
1761  cairo_destroy (ctx->cr);
1762  ctx->cr = NULL;
1763  }
1764 #else
1765  if (ctx->ps_file) {
1766  poppler_ps_file_free (ctx->ps_file);
1767  ctx->ps_file = NULL;
1768  }
1769 #endif
1770  g_free (ctx);
1771 }
1772 
1773 static void
1776 {
1777  PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1778  PdfPrintContext *ctx;
1779 #ifdef HAVE_CAIRO_PRINT
1780  cairo_surface_t *surface = NULL;
1781 #endif
1782 
1783  if (pdf_document->print_ctx)
1784  pdf_print_context_free (pdf_document->print_ctx);
1785  pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1786  ctx = pdf_document->print_ctx;
1787  ctx->format = fc->format;
1788 
1789 #ifdef HAVE_CAIRO_PRINT
1790  ctx->pages_per_sheet = CLAMP (fc->pages_per_sheet, 1, 16);
1791 
1792  ctx->paper_width = fc->paper_width;
1793  ctx->paper_height = fc->paper_height;
1794 
1795  switch (fc->pages_per_sheet) {
1796  default:
1797  case 1:
1798  ctx->pages_x = 1;
1799  ctx->pages_y = 1;
1800  break;
1801  case 2:
1802  ctx->pages_x = 1;
1803  ctx->pages_y = 2;
1804  break;
1805  case 4:
1806  ctx->pages_x = 2;
1807  ctx->pages_y = 2;
1808  break;
1809  case 6:
1810  ctx->pages_x = 2;
1811  ctx->pages_y = 3;
1812  break;
1813  case 9:
1814  ctx->pages_x = 3;
1815  ctx->pages_y = 3;
1816  break;
1817  case 16:
1818  ctx->pages_x = 4;
1819  ctx->pages_y = 4;
1820  break;
1821  }
1822 
1823  ctx->pages_printed = 0;
1824 
1825  switch (fc->format) {
1826  case EV_FILE_FORMAT_PS:
1827 #ifdef HAVE_CAIRO_PS
1828  surface = cairo_ps_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1829 #endif
1830  break;
1831  case EV_FILE_FORMAT_PDF:
1832 #ifdef HAVE_CAIRO_PDF
1833  surface = cairo_pdf_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1834 #endif
1835  break;
1836  default:
1837  g_assert_not_reached ();
1838  }
1839 
1840  ctx->cr = cairo_create (surface);
1841  cairo_surface_destroy (surface);
1842 
1843 #else /* HAVE_CAIRO_PRINT */
1844  if (ctx->format == EV_FILE_FORMAT_PS) {
1845  ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1846  fc->filename, fc->first_page,
1847  fc->last_page - fc->first_page + 1);
1848  poppler_ps_file_set_paper_size (ctx->ps_file, fc->paper_width, fc->paper_height);
1849  poppler_ps_file_set_duplex (ctx->ps_file, fc->duplex);
1850  }
1851 #endif /* HAVE_CAIRO_PRINT */
1852 }
1853 
1854 static void
1856 {
1857  PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1858  PdfPrintContext *ctx = pdf_document->print_ctx;
1859 
1860  g_return_if_fail (pdf_document->print_ctx != NULL);
1861 
1862  ctx->pages_printed = 0;
1863 
1864 #ifdef HAVE_CAIRO_PRINT
1865  if (ctx->paper_width > ctx->paper_height) {
1866  if (ctx->format == EV_FILE_FORMAT_PS) {
1867  cairo_ps_surface_set_size (cairo_get_target (ctx->cr),
1868  ctx->paper_height,
1869  ctx->paper_width);
1870  } else if (ctx->format == EV_FILE_FORMAT_PDF) {
1871  cairo_pdf_surface_set_size (cairo_get_target (ctx->cr),
1872  ctx->paper_height,
1873  ctx->paper_width);
1874  }
1875  }
1876 #endif /* HAVE_CAIRO_PRINT */
1877 }
1878 
1879 static void
1881  EvRenderContext *rc)
1882 {
1883  PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1884  PdfPrintContext *ctx = pdf_document->print_ctx;
1885  PopplerPage *poppler_page;
1886 #ifdef HAVE_CAIRO_PRINT
1887  gdouble page_width, page_height;
1888  gint x, y;
1889  gboolean rotate;
1890  gdouble width, height;
1891  gdouble pwidth, pheight;
1892  gdouble xscale, yscale;
1893 #endif
1894 
1895  g_return_if_fail (pdf_document->print_ctx != NULL);
1896 
1897  poppler_page = POPPLER_PAGE (rc->page->backend_page);
1898 
1899 #ifdef HAVE_CAIRO_PRINT
1900  x = (ctx->pages_printed % ctx->pages_per_sheet) % ctx->pages_x;
1901  y = (ctx->pages_printed % ctx->pages_per_sheet) / ctx->pages_x;
1902  poppler_page_get_size (poppler_page, &page_width, &page_height);
1903 
1904  if (page_width > page_height && page_width > ctx->paper_width) {
1905  rotate = TRUE;
1906  } else {
1907  rotate = FALSE;
1908  }
1909 
1910  /* Use always portrait mode and rotate when necessary */
1911  if (ctx->paper_width > ctx->paper_height) {
1912  width = ctx->paper_height;
1913  height = ctx->paper_width;
1914  rotate = !rotate;
1915  } else {
1916  width = ctx->paper_width;
1917  height = ctx->paper_height;
1918  }
1919 
1920  if (ctx->pages_per_sheet == 2 || ctx->pages_per_sheet == 6) {
1921  rotate = !rotate;
1922  }
1923 
1924  if (rotate) {
1925  gint tmp1;
1926  gdouble tmp2;
1927 
1928  tmp1 = x;
1929  x = y;
1930  y = tmp1;
1931 
1932  tmp2 = page_width;
1933  page_width = page_height;
1934  page_height = tmp2;
1935  }
1936 
1937  pwidth = width / ctx->pages_x;
1938  pheight = height / ctx->pages_y;
1939 
1940  if ((page_width > pwidth || page_height > pheight) ||
1941  (page_width < pwidth && page_height < pheight)) {
1942  xscale = pwidth / page_width;
1943  yscale = pheight / page_height;
1944 
1945  if (yscale < xscale) {
1946  xscale = yscale;
1947  } else {
1948  yscale = xscale;
1949  }
1950 
1951  } else {
1952  xscale = yscale = 1;
1953  }
1954 
1955  /* TODO: center */
1956 
1957  cairo_save (ctx->cr);
1958  if (rotate) {
1959  cairo_matrix_t matrix;
1960 
1961  cairo_translate (ctx->cr, (2 * y + 1) * pwidth, 0);
1962  cairo_matrix_init (&matrix,
1963  0, 1,
1964  -1, 0,
1965  0, 0);
1966  cairo_transform (ctx->cr, &matrix);
1967  }
1968 
1969  cairo_translate (ctx->cr,
1970  x * (rotate ? pheight : pwidth),
1971  y * (rotate ? pwidth : pheight));
1972  cairo_scale (ctx->cr, xscale, yscale);
1973 
1974  poppler_page_render_for_printing (poppler_page, ctx->cr);
1975 
1976  ctx->pages_printed++;
1977 
1978  cairo_restore (ctx->cr);
1979 #else /* HAVE_CAIRO_PRINT */
1980  if (ctx->format == EV_FILE_FORMAT_PS)
1981  poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1982 #endif /* HAVE_CAIRO_PRINT */
1983 }
1984 
1985 static void
1987 {
1988  PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1989  PdfPrintContext *ctx = pdf_document->print_ctx;
1990 
1991  g_return_if_fail (pdf_document->print_ctx != NULL);
1992 
1993 #ifdef HAVE_CAIRO_PRINT
1994  cairo_show_page (ctx->cr);
1995 #endif
1996 }
1997 
1998 static void
2000 {
2001  PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
2002 
2003  pdf_print_context_free (pdf_document->print_ctx);
2004  pdf_document->print_ctx = NULL;
2005 }
2006 
2009 {
2010  return (EvFileExporterCapabilities) (
2016 #ifdef HAVE_CAIRO_PRINT
2018 #endif
2019 
2020 #ifdef HAVE_CAIRO_PDF
2022 #endif
2024 }
2025 
2026 static void
2028 {
2035 }
2036 
2037 /* EvDocumentPrint */
2038 static void
2040  EvPage *page,
2041  cairo_t *cr)
2042 {
2043  poppler_page_render_for_printing (POPPLER_PAGE (page->backend_page), cr);
2044 }
2045 
2046 static void
2048 {
2050 }
2051 
2052 static void
2054  EvRenderContext *rc,
2055  cairo_surface_t **surface,
2056  EvRectangle *points,
2057  EvRectangle *old_points,
2058  EvSelectionStyle style,
2059  GdkColor *text,
2060  GdkColor *base)
2061 {
2062  PopplerPage *poppler_page;
2063  cairo_t *cr;
2064  PopplerColor text_color, base_color;
2065  double width_points, height_points;
2066  gint width, height;
2067  double xscale, yscale;
2068 
2069  poppler_page = POPPLER_PAGE (rc->page->backend_page);
2070 
2071  poppler_page_get_size (poppler_page,
2072  &width_points, &height_points);
2073  ev_render_context_compute_scaled_size (rc, width_points, height_points, &width, &height);
2074 
2075  text_color.red = text->red;
2076  text_color.green = text->green;
2077  text_color.blue = text->blue;
2078 
2079  base_color.red = base->red;
2080  base_color.green = base->green;
2081  base_color.blue = base->blue;
2082 
2083  if (*surface == NULL) {
2084  *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2085  width, height);
2086 
2087  }
2088 
2089  cr = cairo_create (*surface);
2090  ev_render_context_compute_scales (rc, width_points, height_points, &xscale, &yscale);
2091  cairo_scale (cr, xscale, yscale);
2092  cairo_surface_set_device_offset (*surface, 0, 0);
2093  memset (cairo_image_surface_get_data (*surface), 0x00,
2094  cairo_image_surface_get_height (*surface) *
2095  cairo_image_surface_get_stride (*surface));
2096  poppler_page_render_selection (poppler_page,
2097  cr,
2098  (PopplerRectangle *)points,
2099  (PopplerRectangle *)old_points,
2100  (PopplerSelectionStyle)style,
2101  &text_color,
2102  &base_color);
2103  cairo_destroy (cr);
2104 }
2105 
2106 static gchar *
2108  EvPage *page,
2109  EvSelectionStyle style,
2110  EvRectangle *points)
2111 {
2112  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2113 
2114  return poppler_page_get_selected_text (POPPLER_PAGE (page->backend_page),
2115  (PopplerSelectionStyle)style,
2116  (PopplerRectangle *)points);
2117 }
2118 
2119 static cairo_region_t *
2120 create_region_from_poppler_region (GList *region, gdouble xscale, gdouble yscale)
2121 {
2122  GList *l;
2123  cairo_region_t *retval;
2124 
2125  retval = cairo_region_create ();
2126 
2127  for (l = region; l; l = g_list_next (l)) {
2128  PopplerRectangle *rectangle;
2129  cairo_rectangle_int_t rect;
2130 
2131  rectangle = (PopplerRectangle *)l->data;
2132 
2133  rect.x = (gint) ((rectangle->x1 * xscale) + 0.5);
2134  rect.y = (gint) ((rectangle->y1 * yscale) + 0.5);
2135  rect.width = (gint) ((rectangle->x2 * xscale) + 0.5) - rect.x;
2136  rect.height = (gint) ((rectangle->y2 * yscale) + 0.5) - rect.y;
2137  cairo_region_union_rectangle (retval, &rect);
2138 
2139  poppler_rectangle_free (rectangle);
2140  }
2141 
2142  return retval;
2143 }
2144 
2145 static cairo_region_t *
2147  EvRenderContext *rc,
2148  EvSelectionStyle style,
2149  EvRectangle *points)
2150 {
2151  PopplerPage *poppler_page;
2152  cairo_region_t *retval;
2153  GList *region;
2154  double page_width, page_height;
2155  double xscale, yscale;
2156 
2157  poppler_page = POPPLER_PAGE (rc->page->backend_page);
2158  region = poppler_page_get_selection_region (poppler_page,
2159  1.0,
2160  (PopplerSelectionStyle)style,
2161  (PopplerRectangle *) points);
2162  poppler_page_get_size (poppler_page,
2163  &page_width, &page_height);
2164  ev_render_context_compute_scales (rc, page_width, page_height, &xscale, &yscale);
2165  retval = create_region_from_poppler_region (region, xscale, yscale);
2166  g_list_free (region);
2167 
2168  return retval;
2169 }
2170 
2171 static void
2173 {
2177 }
2178 
2179 
2180 /* EvDocumentText */
2181 static cairo_region_t *
2183  EvPage *page)
2184 {
2185  PopplerPage *poppler_page;
2186  PopplerRectangle points;
2187  GList *region;
2188  cairo_region_t *retval;
2189 
2190  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2191 
2192  poppler_page = POPPLER_PAGE (page->backend_page);
2193 
2194  points.x1 = 0.0;
2195  points.y1 = 0.0;
2196  poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
2197 
2198  region = poppler_page_get_selection_region (poppler_page, 1.0,
2199  POPPLER_SELECTION_GLYPH,
2200  &points);
2201  retval = create_region_from_poppler_region (region, 1.0, 1.0);
2202  g_list_free (region);
2203 
2204  return retval;
2205 }
2206 
2207 static gchar *
2209  EvPage *page)
2210 {
2211  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2212 
2213  return poppler_page_get_text (POPPLER_PAGE (page->backend_page));
2214 }
2215 
2216 static gboolean
2218  EvPage *page,
2219  EvRectangle **areas,
2220  guint *n_areas)
2221 {
2222  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), FALSE);
2223 
2224  return poppler_page_get_text_layout (POPPLER_PAGE (page->backend_page),
2225  (PopplerRectangle **)areas, n_areas);
2226 }
2227 
2228 static PangoAttrList *
2230  EvPage *page)
2231 {
2232  GList *backend_attrs_list, *l;
2233  PangoAttrList *attrs_list;
2234 
2235  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2236 
2237  backend_attrs_list = poppler_page_get_text_attributes (POPPLER_PAGE (page->backend_page));
2238  if (!backend_attrs_list)
2239  return NULL;
2240 
2241  attrs_list = pango_attr_list_new ();
2242  for (l = backend_attrs_list; l; l = g_list_next (l)) {
2243  PopplerTextAttributes *backend_attrs = (PopplerTextAttributes *)l->data;
2244  PangoAttribute *attr;
2245 
2246  if (backend_attrs->is_underlined) {
2247  attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
2248  attr->start_index = backend_attrs->start_index;
2249  attr->end_index = backend_attrs->end_index;
2250  pango_attr_list_insert (attrs_list, attr);
2251  }
2252 
2253  attr = pango_attr_foreground_new (backend_attrs->color.red,
2254  backend_attrs->color.green,
2255  backend_attrs->color.blue);
2256  attr->start_index = backend_attrs->start_index;
2257  attr->end_index = backend_attrs->end_index;
2258  pango_attr_list_insert (attrs_list, attr);
2259 
2260  if (backend_attrs->font_name) {
2261  attr = pango_attr_family_new (backend_attrs->font_name);
2262  attr->start_index = backend_attrs->start_index;
2263  attr->end_index = backend_attrs->end_index;
2264  pango_attr_list_insert (attrs_list, attr);
2265  }
2266 
2267  if (backend_attrs->font_size) {
2268  attr = pango_attr_size_new (backend_attrs->font_size * PANGO_SCALE);
2269  attr->start_index = backend_attrs->start_index;
2270  attr->end_index = backend_attrs->end_index;
2271  pango_attr_list_insert (attrs_list, attr);
2272  }
2273  }
2274 
2275  poppler_page_free_text_attributes (backend_attrs_list);
2276 
2277  return attrs_list;
2278 }
2279 
2280 static void
2282 {
2287 }
2288 
2289 /* Page Transitions */
2290 static gdouble
2292  gint page)
2293 {
2294  PdfDocument *pdf_document;
2295  PopplerPage *poppler_page;
2296  gdouble duration = -1;
2297 
2298  pdf_document = PDF_DOCUMENT (trans);
2299  poppler_page = poppler_document_get_page (pdf_document->document, page);
2300  if (!poppler_page)
2301  return -1;
2302 
2303  duration = poppler_page_get_duration (poppler_page);
2304  g_object_unref (poppler_page);
2305 
2306  return duration;
2307 }
2308 
2309 static EvTransitionEffect *
2311  gint page)
2312 {
2313  PdfDocument *pdf_document;
2314  PopplerPage *poppler_page;
2315  PopplerPageTransition *page_transition;
2316  EvTransitionEffect *effect;
2317 
2318  pdf_document = PDF_DOCUMENT (trans);
2319  poppler_page = poppler_document_get_page (pdf_document->document, page);
2320 
2321  if (!poppler_page)
2322  return NULL;
2323 
2324  page_transition = poppler_page_get_transition (poppler_page);
2325 
2326  if (!page_transition) {
2327  g_object_unref (poppler_page);
2328  return NULL;
2329  }
2330 
2331  /* enums in PopplerPageTransition match the EvTransitionEffect ones */
2332  effect = ev_transition_effect_new ((EvTransitionEffectType) page_transition->type,
2333  "alignment", page_transition->alignment,
2334  "direction", page_transition->direction,
2335  "duration", page_transition->duration,
2336  "angle", page_transition->angle,
2337  "scale", page_transition->scale,
2338  "rectangular", page_transition->rectangular,
2339  NULL);
2340 
2341  poppler_page_transition_free (page_transition);
2342  g_object_unref (poppler_page);
2343 
2344  return effect;
2345 }
2346 
2347 static void
2349 {
2352 }
2353 
2354 /* Forms */
2355 #if 0
2356 static void
2357 pdf_document_get_crop_box (EvDocument *document,
2358  int page,
2359  EvRectangle *rect)
2360 {
2361  PdfDocument *pdf_document;
2362  PopplerPage *poppler_page;
2363  PopplerRectangle poppler_rect;
2364 
2365  pdf_document = PDF_DOCUMENT (document);
2366  poppler_page = poppler_document_get_page (pdf_document->document, page);
2367  poppler_page_get_crop_box (poppler_page, &poppler_rect);
2368  rect->x1 = poppler_rect.x1;
2369  rect->x2 = poppler_rect.x2;
2370  rect->y1 = poppler_rect.y1;
2371  rect->y2 = poppler_rect.y2;
2372 }
2373 #endif
2374 
2375 static EvFormField *
2377  PopplerFormField *poppler_field)
2378 {
2379  EvFormField *ev_field = NULL;
2380  gint id;
2381  gdouble font_size;
2382  gboolean is_read_only;
2383  PopplerAction *action;
2384 
2385  id = poppler_form_field_get_id (poppler_field);
2386  font_size = poppler_form_field_get_font_size (poppler_field);
2387  is_read_only = poppler_form_field_is_read_only (poppler_field);
2388  action = poppler_form_field_get_action (poppler_field);
2389 
2390  switch (poppler_form_field_get_field_type (poppler_field)) {
2391  case POPPLER_FORM_FIELD_TEXT: {
2392  EvFormFieldText *field_text;
2394 
2395  switch (poppler_form_field_text_get_text_type (poppler_field)) {
2396  case POPPLER_FORM_TEXT_NORMAL:
2397  ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
2398  break;
2399  case POPPLER_FORM_TEXT_MULTILINE:
2400  ev_text_type = EV_FORM_FIELD_TEXT_MULTILINE;
2401  break;
2402  case POPPLER_FORM_TEXT_FILE_SELECT:
2403  ev_text_type = EV_FORM_FIELD_TEXT_FILE_SELECT;
2404  break;
2405  }
2406 
2407  ev_field = ev_form_field_text_new (id, ev_text_type);
2408  field_text = EV_FORM_FIELD_TEXT (ev_field);
2409 
2410  field_text->do_spell_check = poppler_form_field_text_do_spell_check (poppler_field);
2411  field_text->do_scroll = poppler_form_field_text_do_scroll (poppler_field);
2412  field_text->is_rich_text = poppler_form_field_text_is_rich_text (poppler_field);
2413  field_text->is_password = poppler_form_field_text_is_password (poppler_field);
2414  field_text->max_len = poppler_form_field_text_get_max_len (poppler_field);
2415  field_text->text = poppler_form_field_text_get_text (poppler_field);
2416 
2417  }
2418  break;
2419  case POPPLER_FORM_FIELD_BUTTON: {
2420  EvFormFieldButton *field_button;
2422 
2423  switch (poppler_form_field_button_get_button_type (poppler_field)) {
2424  case POPPLER_FORM_BUTTON_PUSH:
2425  ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
2426  break;
2427  case POPPLER_FORM_BUTTON_CHECK:
2428  ev_button_type = EV_FORM_FIELD_BUTTON_CHECK;
2429  break;
2430  case POPPLER_FORM_BUTTON_RADIO:
2431  ev_button_type = EV_FORM_FIELD_BUTTON_RADIO;
2432  break;
2433  }
2434 
2435  ev_field = ev_form_field_button_new (id, ev_button_type);
2436  field_button = EV_FORM_FIELD_BUTTON (ev_field);
2437 
2438  field_button->state = poppler_form_field_button_get_state (poppler_field);
2439  }
2440  break;
2441  case POPPLER_FORM_FIELD_CHOICE: {
2442  EvFormFieldChoice *field_choice;
2444 
2445  switch (poppler_form_field_choice_get_choice_type (poppler_field)) {
2446  case POPPLER_FORM_CHOICE_COMBO:
2447  ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
2448  break;
2450  ev_choice_type = EV_FORM_FIELD_CHOICE_LIST;
2451  break;
2452  }
2453 
2454  ev_field = ev_form_field_choice_new (id, ev_choice_type);
2455  field_choice = EV_FORM_FIELD_CHOICE (ev_field);
2456 
2457  field_choice->is_editable = poppler_form_field_choice_is_editable (poppler_field);
2458  field_choice->multi_select = poppler_form_field_choice_can_select_multiple (poppler_field);
2459  field_choice->do_spell_check = poppler_form_field_choice_do_spell_check (poppler_field);
2460  field_choice->commit_on_sel_change = poppler_form_field_choice_commit_on_change (poppler_field);
2461 
2462  /* TODO: we need poppler_form_field_choice_get_selected_items in poppler
2463  field_choice->selected_items = poppler_form_field_choice_get_selected_items (poppler_field);*/
2464  if (field_choice->is_editable)
2465  field_choice->text = poppler_form_field_choice_get_text (poppler_field);
2466  }
2467  break;
2468  case POPPLER_FORM_FIELD_SIGNATURE:
2469  /* TODO */
2470  ev_field = ev_form_field_signature_new (id);
2471  break;
2472  case POPPLER_FORM_FIELD_UNKNOWN:
2473  return NULL;
2474  }
2475 
2476  ev_field->font_size = font_size;
2477  ev_field->is_read_only = is_read_only;
2478 
2479  if (action)
2480  ev_field->activation_link = ev_link_from_action (pdf_document, action);
2481 
2482  return ev_field;
2483 }
2484 
2485 static EvMappingList *
2487  EvPage *page)
2488 {
2489  PopplerPage *poppler_page;
2490  GList *retval = NULL;
2491  GList *fields;
2492  GList *list;
2493  double height;
2494 
2495  g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2496 
2497  poppler_page = POPPLER_PAGE (page->backend_page);
2498  fields = poppler_page_get_form_field_mapping (poppler_page);
2499  poppler_page_get_size (poppler_page, NULL, &height);
2500 
2501  for (list = fields; list; list = list->next) {
2502  PopplerFormFieldMapping *mapping;
2503  EvMapping *field_mapping;
2504  EvFormField *ev_field;
2505 
2506  mapping = (PopplerFormFieldMapping *)list->data;
2507 
2508  ev_field = ev_form_field_from_poppler_field (PDF_DOCUMENT (document), mapping->field);
2509  if (!ev_field)
2510  continue;
2511 
2512  field_mapping = g_new0 (EvMapping, 1);
2513  field_mapping->area.x1 = mapping->area.x1;
2514  field_mapping->area.x2 = mapping->area.x2;
2515  field_mapping->area.y1 = height - mapping->area.y2;
2516  field_mapping->area.y2 = height - mapping->area.y1;
2517  field_mapping->data = ev_field;
2518  ev_field->page = EV_PAGE (g_object_ref (page));
2519 
2520  g_object_set_data_full (G_OBJECT (ev_field),
2521  "poppler-field",
2522  g_object_ref (mapping->field),
2523  (GDestroyNotify) g_object_unref);
2524 
2525  retval = g_list_prepend (retval, field_mapping);
2526  }
2527 
2528  poppler_page_free_form_field_mapping (fields);
2529 
2530  return retval ? ev_mapping_list_new (page->index,
2531  g_list_reverse (retval),
2532  (GDestroyNotify)g_object_unref) : NULL;
2533 }
2534 
2535 static gboolean
2537 {
2538  return PDF_DOCUMENT (document)->forms_modified;
2539 }
2540 
2541 static gchar *
2543  EvFormField *field)
2544 
2545 {
2546  PopplerFormField *poppler_field;
2547  gchar *text;
2548 
2549  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2550  if (!poppler_field)
2551  return NULL;
2552 
2553  text = poppler_form_field_text_get_text (poppler_field);
2554 
2555  return text;
2556 }
2557 
2558 static void
2560  EvFormField *field,
2561  const gchar *text)
2562 {
2563  PopplerFormField *poppler_field;
2564 
2565  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2566  if (!poppler_field)
2567  return;
2568 
2569  poppler_form_field_text_set_text (poppler_field, text);
2570  PDF_DOCUMENT (document)->forms_modified = TRUE;
2571 }
2572 
2573 static void
2575  EvFormField *field,
2576  gboolean state)
2577 {
2578  PopplerFormField *poppler_field;
2579 
2580  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2581  if (!poppler_field)
2582  return;
2583 
2584  poppler_form_field_button_set_state (poppler_field, state);
2585  PDF_DOCUMENT (document)->forms_modified = TRUE;
2586 }
2587 
2588 static gboolean
2590  EvFormField *field)
2591 {
2592  PopplerFormField *poppler_field;
2593  gboolean state;
2594 
2595  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2596  if (!poppler_field)
2597  return FALSE;
2598 
2599  state = poppler_form_field_button_get_state (poppler_field);
2600 
2601  return state;
2602 }
2603 
2604 static gchar *
2606  EvFormField *field,
2607  gint index)
2608 {
2609  PopplerFormField *poppler_field;
2610  gchar *text;
2611 
2612  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2613  if (!poppler_field)
2614  return NULL;
2615 
2616  text = poppler_form_field_choice_get_item (poppler_field, index);
2617 
2618  return text;
2619 }
2620 
2621 static int
2623  EvFormField *field)
2624 {
2625  PopplerFormField *poppler_field;
2626  gint n_items;
2627 
2628  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2629  if (!poppler_field)
2630  return -1;
2631 
2632  n_items = poppler_form_field_choice_get_n_items (poppler_field);
2633 
2634  return n_items;
2635 }
2636 
2637 static gboolean
2639  EvFormField *field,
2640  gint index)
2641 {
2642  PopplerFormField *poppler_field;
2643  gboolean selected;
2644 
2645  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2646  if (!poppler_field)
2647  return FALSE;
2648 
2649  selected = poppler_form_field_choice_is_item_selected (poppler_field, index);
2650 
2651  return selected;
2652 }
2653 
2654 static void
2656  EvFormField *field,
2657  gint index)
2658 {
2659  PopplerFormField *poppler_field;
2660 
2661  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2662  if (!poppler_field)
2663  return;
2664 
2665  poppler_form_field_choice_select_item (poppler_field, index);
2666  PDF_DOCUMENT (document)->forms_modified = TRUE;
2667 }
2668 
2669 static void
2671  EvFormField *field,
2672  gint index)
2673 {
2674  PopplerFormField *poppler_field;
2675 
2676  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2677  if (!poppler_field)
2678  return;
2679 
2680  poppler_form_field_choice_toggle_item (poppler_field, index);
2681  PDF_DOCUMENT (document)->forms_modified = TRUE;
2682 }
2683 
2684 static void
2686  EvFormField *field)
2687 {
2688  PopplerFormField *poppler_field;
2689 
2690  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2691  if (!poppler_field)
2692  return;
2693 
2694  poppler_form_field_choice_unselect_all (poppler_field);
2695  PDF_DOCUMENT (document)->forms_modified = TRUE;
2696 }
2697 
2698 static void
2700  EvFormField *field,
2701  const gchar *text)
2702 {
2703  PopplerFormField *poppler_field;
2704 
2705  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2706  if (!poppler_field)
2707  return;
2708 
2709  poppler_form_field_choice_set_text (poppler_field, text);
2710  PDF_DOCUMENT (document)->forms_modified = TRUE;
2711 }
2712 
2713 static gchar *
2715  EvFormField *field)
2716 {
2717  PopplerFormField *poppler_field;
2718  gchar *text;
2719 
2720  poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2721  if (!poppler_field)
2722  return NULL;
2723 
2724  text = poppler_form_field_choice_get_text (poppler_field);
2725 
2726  return text;
2727 }
2728 
2729 static void
2731 {
2746 }
2747 
2748 /* Annotations */
2749 static void
2750 poppler_annot_color_to_gdk_color (PopplerAnnot *poppler_annot,
2751  GdkColor *color)
2752 {
2753  PopplerColor *poppler_color;
2754 
2755  poppler_color = poppler_annot_get_color (poppler_annot);
2756  if (poppler_color) {
2757  color->red = poppler_color->red;
2758  color->green = poppler_color->green;
2759  color->blue = poppler_color->blue;
2760 
2761  g_free (poppler_color);
2762  } /* TODO: else use a default color */
2763 }
2764 
2765 static EvAnnotationTextIcon
2766 get_annot_text_icon (PopplerAnnotText *poppler_annot)
2767 {
2768  gchar *icon = poppler_annot_text_get_icon (poppler_annot);
2769  EvAnnotationTextIcon retval;
2770 
2771  if (!icon)
2773 
2774  if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NOTE) == 0)
2776  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_COMMENT) == 0)
2778  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_KEY) == 0)
2779  retval = EV_ANNOTATION_TEXT_ICON_KEY;
2780  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_HELP) == 0)
2782  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH) == 0)
2784  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_PARAGRAPH) == 0)
2786  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_INSERT) == 0)
2788  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CROSS) == 0)
2790  else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CIRCLE) == 0)
2792  else
2794 
2795  g_free (icon);
2796 
2797  return retval;
2798 }
2799 
2800 static const gchar *
2802 {
2803  switch (icon) {
2805  return POPPLER_ANNOT_TEXT_ICON_NOTE;
2807  return POPPLER_ANNOT_TEXT_ICON_COMMENT;
2809  return POPPLER_ANNOT_TEXT_ICON_KEY;
2811  return POPPLER_ANNOT_TEXT_ICON_HELP;
2813  return POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH;
2815  return POPPLER_ANNOT_TEXT_ICON_PARAGRAPH;
2817  return POPPLER_ANNOT_TEXT_ICON_INSERT;
2819  return POPPLER_ANNOT_TEXT_ICON_CROSS;
2821  return POPPLER_ANNOT_TEXT_ICON_CIRCLE;
2823  default:
2824  return POPPLER_ANNOT_TEXT_ICON_NOTE;
2825  }
2826 }
2827 
2828 static gboolean
2829 poppler_annot_can_have_popup_window (PopplerAnnot *poppler_annot)
2830 {
2831  switch (poppler_annot_get_annot_type (poppler_annot)) {
2832  case POPPLER_ANNOT_TEXT:
2833  case POPPLER_ANNOT_LINE:
2834  case POPPLER_ANNOT_SQUARE:
2835  case POPPLER_ANNOT_CIRCLE:
2836  case POPPLER_ANNOT_POLYGON:
2837  case POPPLER_ANNOT_POLY_LINE:
2838  case POPPLER_ANNOT_HIGHLIGHT:
2839  case POPPLER_ANNOT_UNDERLINE:
2840  case POPPLER_ANNOT_SQUIGGLY:
2841  case POPPLER_ANNOT_STRIKE_OUT:
2842  case POPPLER_ANNOT_STAMP:
2843  case POPPLER_ANNOT_CARET:
2844  case POPPLER_ANNOT_INK:
2845  case POPPLER_ANNOT_FILE_ATTACHMENT:
2846  return TRUE;
2847  default:
2848  return FALSE;
2849  }
2850 }
2851 
2852 static EvAnnotation *
2853 ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
2854  EvPage *page)
2855 {
2856  EvAnnotation *ev_annot = NULL;
2857  const gchar *unimplemented_annot = NULL;
2858  gboolean reported_annot = FALSE;
2859 
2860  switch (poppler_annot_get_annot_type (poppler_annot)) {
2861  case POPPLER_ANNOT_TEXT: {
2862  PopplerAnnotText *poppler_text;
2863  EvAnnotationText *ev_annot_text;
2864 
2865  poppler_text = POPPLER_ANNOT_TEXT (poppler_annot);
2866 
2867  ev_annot = ev_annotation_text_new (page);
2868 
2869  ev_annot_text = EV_ANNOTATION_TEXT (ev_annot);
2870  ev_annotation_text_set_is_open (ev_annot_text,
2871  poppler_annot_text_get_is_open (poppler_text));
2872  ev_annotation_text_set_icon (ev_annot_text, get_annot_text_icon (poppler_text));
2873  }
2874  break;
2875  case POPPLER_ANNOT_FILE_ATTACHMENT: {
2876  PopplerAnnotFileAttachment *poppler_annot_attachment;
2877  PopplerAttachment *poppler_attachment;
2878  gchar *data = NULL;
2879  gsize size;
2880  GError *error = NULL;
2881 
2882  poppler_annot_attachment = POPPLER_ANNOT_FILE_ATTACHMENT (poppler_annot);
2883  poppler_attachment = poppler_annot_file_attachment_get_attachment (poppler_annot_attachment);
2884 
2885  if (poppler_attachment &&
2886  attachment_save_to_buffer (poppler_attachment, &data, &size, &error)) {
2887  EvAttachment *ev_attachment;
2888 
2889  ev_attachment = ev_attachment_new (poppler_attachment->name,
2890  poppler_attachment->description,
2891  poppler_attachment->mtime,
2892  poppler_attachment->ctime,
2893  size, data);
2894  ev_annot = ev_annotation_attachment_new (page, ev_attachment);
2895  g_object_unref (ev_attachment);
2896  } else if (error) {
2897  g_warning ("%s", error->message);
2898  g_error_free (error);
2899  }
2900 
2901  if (poppler_attachment)
2902  g_object_unref (poppler_attachment);
2903  }
2904  break;
2905  case POPPLER_ANNOT_HIGHLIGHT:
2906  ev_annot = ev_annotation_text_markup_highlight_new (page);
2907  break;
2908  case POPPLER_ANNOT_STRIKE_OUT:
2909  ev_annot = ev_annotation_text_markup_strike_out_new (page);
2910  break;
2911  case POPPLER_ANNOT_UNDERLINE:
2912  ev_annot = ev_annotation_text_markup_underline_new (page);
2913  break;
2914  case POPPLER_ANNOT_SQUIGGLY:
2915  ev_annot = ev_annotation_text_markup_squiggly_new (page);
2916  break;
2917  case POPPLER_ANNOT_LINK:
2918  case POPPLER_ANNOT_WIDGET:
2919  case POPPLER_ANNOT_MOVIE:
2920  /* Ignore link, widgets and movie annots since they are already handled */
2921  break;
2922  case POPPLER_ANNOT_SCREEN: {
2923  PopplerAction *action;
2924 
2925  /* Ignore screen annots containing a rendition action */
2926  action = poppler_annot_screen_get_action (POPPLER_ANNOT_SCREEN (poppler_annot));
2927  if (action && action->type == POPPLER_ACTION_RENDITION)
2928  break;
2929  }
2930  /* Fall through */
2931  case POPPLER_ANNOT_3D:
2932  case POPPLER_ANNOT_CARET:
2933  case POPPLER_ANNOT_FREE_TEXT:
2934  case POPPLER_ANNOT_LINE:
2935  case POPPLER_ANNOT_SOUND:
2936  case POPPLER_ANNOT_SQUARE:
2937  case POPPLER_ANNOT_STAMP: {
2938  /* FIXME: These annotations are unimplemented, but they were already
2939  * reported in Evince Bugzilla with test case. We add a special
2940  * warning to let the user know it is unimplemented, yet we do not
2941  * want more duplicates of known issues.
2942  */
2943  GEnumValue *enum_value;
2944  reported_annot = TRUE;
2945 
2946  enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_ANNOT_TYPE),
2947  poppler_annot_get_annot_type (poppler_annot));
2948  unimplemented_annot = enum_value ? enum_value->value_name : "Unknown annotation";
2949  }
2950  break;
2951  default: {
2952  GEnumValue *enum_value;
2953  reported_annot = FALSE;
2954 
2955  enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_ANNOT_TYPE),
2956  poppler_annot_get_annot_type (poppler_annot));
2957  unimplemented_annot = enum_value ? enum_value->value_name : "Unknown annotation";
2958  }
2959  }
2960 
2961  if (unimplemented_annot) {
2962  if (reported_annot) {
2963  g_warning ("Unimplemented annotation: %s. It is a known issue "
2964  "and it might be implemented in the future.",
2965  unimplemented_annot);
2966  } else {
2967  g_warning ("Unimplemented annotation: %s, please post a "
2968  "bug report in Evince bugzilla "
2969  "(http://bugzilla.gnome.org) with a testcase.",
2970  unimplemented_annot);
2971  }
2972  }
2973 
2974  if (ev_annot) {
2975  time_t utime;
2976  gchar *modified;
2977  gchar *contents;
2978  gchar *name;
2979  GdkColor color;
2980 
2981  contents = poppler_annot_get_contents (poppler_annot);
2982  if (contents) {
2983  ev_annotation_set_contents (ev_annot, contents);
2984  g_free (contents);
2985  }
2986 
2987  name = poppler_annot_get_name (poppler_annot);
2988  if (name) {
2989  ev_annotation_set_name (ev_annot, name);
2990  g_free (name);
2991  }
2992 
2993  modified = poppler_annot_get_modified (poppler_annot);
2994  if (poppler_date_parse (modified, &utime)) {
2995  ev_annotation_set_modified_from_time (ev_annot, utime);
2996  } else {
2997  ev_annotation_set_modified (ev_annot, modified);
2998  }
2999  g_free (modified);
3000 
3001  poppler_annot_color_to_gdk_color (poppler_annot, &color);
3002  ev_annotation_set_color (ev_annot, &color);
3003 
3004  if (poppler_annot_can_have_popup_window (poppler_annot)) {
3005  PopplerAnnotMarkup *markup;
3006  gchar *label;
3007  gdouble opacity;
3008  PopplerRectangle poppler_rect;
3009 
3010  markup = POPPLER_ANNOT_MARKUP (poppler_annot);
3011 
3012  if (poppler_annot_markup_get_popup_rectangle (markup, &poppler_rect)) {
3013  EvRectangle ev_rect;
3014  gboolean is_open;
3015  gdouble height;
3016 
3017  poppler_page_get_size (POPPLER_PAGE (page->backend_page),
3018  NULL, &height);
3019  ev_rect.x1 = poppler_rect.x1;
3020  ev_rect.x2 = poppler_rect.x2;
3021  ev_rect.y1 = height - poppler_rect.y2;
3022  ev_rect.y2 = height - poppler_rect.y1;
3023 
3024  is_open = poppler_annot_markup_get_popup_is_open (markup);
3025 
3026  g_object_set (ev_annot,
3027  "rectangle", &ev_rect,
3028  "popup_is_open", is_open,
3029  "has_popup", TRUE,
3030  NULL);
3031  } else {
3032  g_object_set (ev_annot,
3033  "has_popup", FALSE,
3034  NULL);
3035  }
3036 
3037  label = poppler_annot_markup_get_label (markup);
3038  opacity = poppler_annot_markup_get_opacity (markup);
3039 
3040  g_object_set (ev_annot,
3041  "label", label,
3042  "opacity", opacity,
3043  "can_have_popup", TRUE,
3044  NULL);
3045 
3046  g_free (label);
3047  }
3048  }
3049 
3050  return ev_annot;
3051 }
3052 
3053 static void
3055 {
3056  gchar *name;
3057 
3058  name = g_strdup_printf ("annot-%" G_GUINT64_FORMAT, g_get_real_time ());
3059  ev_annotation_set_name (annot, name);
3060  g_free (name);
3061 }
3062 
3063 static void
3065  GParamSpec *spec,
3066  EvMapping *mapping)
3067 {
3068  ev_annotation_get_area (annot, &mapping->area);
3069 }
3070 
3071 static EvMappingList *
3073  EvPage *page)
3074 {
3075  GList *retval = NULL;
3076  PdfDocument *pdf_document;
3077  PopplerPage *poppler_page;
3078  EvMappingList *mapping_list;
3079  GList *annots;
3080  GList *list;
3081  gdouble height;
3082  gint i = 0;
3083 
3084  pdf_document = PDF_DOCUMENT (document_annotations);
3085  poppler_page = POPPLER_PAGE (page->backend_page);
3086 
3087  if (pdf_document->annots) {
3088  mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
3089  GINT_TO_POINTER (page->index));
3090  if (mapping_list)
3091  return ev_mapping_list_ref (mapping_list);
3092  }
3093 
3094  annots = poppler_page_get_annot_mapping (poppler_page);
3095  poppler_page_get_size (poppler_page, NULL, &height);
3096 
3097  for (list = annots; list; list = list->next) {
3098  PopplerAnnotMapping *mapping;
3099  EvMapping *annot_mapping;
3100  EvAnnotation *ev_annot;
3101 
3102  mapping = (PopplerAnnotMapping *)list->data;
3103 
3104  ev_annot = ev_annot_from_poppler_annot (mapping->annot, page);
3105  if (!ev_annot)
3106  continue;
3107 
3108  i++;
3109 
3110  /* Make sure annot has a unique name */
3111  if (!ev_annotation_get_name (ev_annot))
3112  annot_set_unique_name (ev_annot);
3113 
3114  annot_mapping = g_new (EvMapping, 1);
3115  if (EV_IS_ANNOTATION_TEXT (ev_annot)) {
3116  /* Force 24x24 rectangle */
3117  annot_mapping->area.x1 = mapping->area.x1;
3118  annot_mapping->area.x2 = annot_mapping->area.x1 + 24;
3119  annot_mapping->area.y1 = height - mapping->area.y2;
3120  annot_mapping->area.y2 = MIN(height, annot_mapping->area.y1 + 24);
3121  } else {
3122  annot_mapping->area.x1 = mapping->area.x1;
3123  annot_mapping->area.x2 = mapping->area.x2;
3124  annot_mapping->area.y1 = height - mapping->area.y2;
3125  annot_mapping->area.y2 = height - mapping->area.y1;
3126  }
3127  annot_mapping->data = ev_annot;
3128  ev_annotation_set_area (ev_annot, &annot_mapping->area);
3129  g_signal_connect (ev_annot, "notify::area",
3130  G_CALLBACK (annot_area_changed_cb),
3131  annot_mapping);
3132 
3133  g_object_set_data_full (G_OBJECT (ev_annot),
3134  "poppler-annot",
3135  g_object_ref (mapping->annot),
3136  (GDestroyNotify) g_object_unref);
3137 
3138  retval = g_list_prepend (retval, annot_mapping);
3139  }
3140 
3141  poppler_page_free_annot_mapping (annots);
3142 
3143  if (!retval)
3144  return NULL;
3145 
3146  if (!pdf_document->annots) {
3147  pdf_document->annots = g_hash_table_new_full (g_direct_hash,
3148  g_direct_equal,
3149  (GDestroyNotify)NULL,
3150  (GDestroyNotify)ev_mapping_list_unref);
3151  }
3152 
3153  mapping_list = ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
3154  g_hash_table_insert (pdf_document->annots,
3155  GINT_TO_POINTER (page->index),
3156  ev_mapping_list_ref (mapping_list));
3157 
3158  return mapping_list;
3159 }
3160 
3161 static gboolean
3163 {
3164  return PDF_DOCUMENT (document_annotations)->annots_modified;
3165 }
3166 
3167 static void
3169  EvAnnotation *annot)
3170 {
3171  PopplerPage *poppler_page;
3172  PdfDocument *pdf_document;
3173  EvPage *page;
3174  PopplerAnnot *poppler_annot;
3175  EvMappingList *mapping_list;
3176  EvMapping *annot_mapping;
3177  GList *list;
3178 
3179  poppler_annot = POPPLER_ANNOT (g_object_get_data (G_OBJECT (annot), "poppler-annot"));
3180  pdf_document = PDF_DOCUMENT (document_annotations);
3181  page = ev_annotation_get_page (annot);
3182  poppler_page = POPPLER_PAGE (page->backend_page);
3183 
3184  poppler_page_remove_annot (poppler_page, poppler_annot);
3185 
3186  /* We don't check for pdf_document->annots, if it were NULL then something is really wrong */
3187  mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
3188  GINT_TO_POINTER (page->index));
3189  if (mapping_list) {
3190  annot_mapping = ev_mapping_list_find (mapping_list, annot);
3191  ev_mapping_list_remove (mapping_list, annot_mapping);
3192  if (ev_mapping_list_length (mapping_list) == 0)
3193  g_hash_table_remove (pdf_document->annots, GINT_TO_POINTER (page->index));
3194  }
3195 
3196  pdf_document->annots_modified = TRUE;
3197 }
3198 
3199 /* FIXME: this could be moved to poppler */
3200 static GArray *
3201 get_quads_for_area (PopplerPage *page,
3202  EvRectangle *area,
3203  PopplerRectangle *bbox)
3204 {
3205  GList *rects, *l;
3206  guint n_rects;
3207  guint i;
3208  GArray *quads;
3209  gdouble height;
3210  gdouble max_x, max_y, min_x, min_y;
3211 
3212  if (bbox) {
3213  bbox->x1 = G_MAXDOUBLE;
3214  bbox->y1 = G_MAXDOUBLE;
3215  bbox->x2 = G_MINDOUBLE;
3216  bbox->y2 = G_MINDOUBLE;
3217  }
3218 
3219  poppler_page_get_size (page, NULL, &height);
3220 
3221  rects = poppler_page_get_selection_region (page, 1.0, POPPLER_SELECTION_GLYPH,
3222  (PopplerRectangle *)area);
3223  n_rects = g_list_length (rects);
3224 
3225  quads = g_array_sized_new (TRUE, TRUE,
3226  sizeof (PopplerQuadrilateral),
3227  n_rects);
3228  g_array_set_size (quads, MAX (1, n_rects));
3229 
3230  for (l = rects, i = 0; i < n_rects; i++, l = l->next) {
3231  PopplerRectangle *r = (PopplerRectangle *) l->data;
3232  PopplerQuadrilateral *quad = &g_array_index (quads, PopplerQuadrilateral, i);
3233 
3234  quad->p1.x = r->x1;
3235  quad->p1.y = height - r->y1;
3236  quad->p2.x = r->x2;
3237  quad->p2.y = height - r->y1;
3238  quad->p3.x = r->x1;
3239  quad->p3.y = height - r->y2;
3240  quad->p4.x = r->x2;
3241  quad->p4.y = height - r->y2;
3242  poppler_rectangle_free (r);
3243 
3244  if (!bbox)
3245  continue;
3246 
3247  max_x = MAX (quad->p1.x, MAX (quad->p2.x, MAX (quad->p3.x, quad->p4.x)));
3248  max_y = MAX (quad->p1.y, MAX (quad->p2.y, MAX (quad->p3.y, quad->p4.y)));
3249  min_x = MIN (quad->p1.x, MIN (quad->p2.x, MIN (quad->p3.x, quad->p4.x)));
3250  min_y = MIN (quad->p1.y, MIN (quad->p2.y, MIN (quad->p3.y, quad->p4.y)));
3251 
3252  if (min_x < bbox->x1)
3253  bbox->x1 = min_x;
3254  if (min_y < bbox->y1)
3255  bbox->y1 = min_y;
3256  if (max_x > bbox->x2)
3257  bbox->x2 = max_x;
3258  if (max_y > bbox->y2)
3259  bbox->y2 = max_y;
3260  }
3261  g_list_free (rects);
3262 
3263  if (n_rects == 0 && bbox) {
3264  bbox->x1 = 0;
3265  bbox->y1 = 0;
3266  bbox->x2 = 0;
3267  bbox->y2 = 0;
3268  }
3269 
3270  return quads;
3271 }
3272 
3273 static void
3275  EvAnnotation *annot,
3276  EvRectangle *rect_deprecated)
3277 {
3278  PopplerAnnot *poppler_annot;
3279  PdfDocument *pdf_document;
3280  EvPage *page;
3281  PopplerPage *poppler_page;
3282  GList *list = NULL;
3283  EvMappingList *mapping_list;
3284  EvMapping *annot_mapping;
3285  PopplerRectangle poppler_rect;
3286  gdouble height;
3287  PopplerColor poppler_color;
3288  GdkColor color;
3289  EvRectangle rect;
3290 
3291  pdf_document = PDF_DOCUMENT (document_annotations);
3292  page = ev_annotation_get_page (annot);
3293  poppler_page = POPPLER_PAGE (page->backend_page);
3294 
3295  ev_annotation_get_area (annot, &rect);
3296 
3297  poppler_page_get_size (poppler_page, NULL, &height);
3298  poppler_rect.x1 = rect.x1;
3299  poppler_rect.x2 = rect.x2;
3300  poppler_rect.y1 = height - rect.y2;
3301  poppler_rect.y2 = height - rect.y1;
3302 
3303  switch (ev_annotation_get_annotation_type (annot)) {
3304  case EV_ANNOTATION_TYPE_TEXT: {
3305  EvAnnotationText *text = EV_ANNOTATION_TEXT (annot);
3306  EvAnnotationTextIcon icon;
3307 
3308  poppler_annot = poppler_annot_text_new (pdf_document->document, &poppler_rect);
3309 
3310  icon = ev_annotation_text_get_icon (text);
3311  poppler_annot_text_set_icon (POPPLER_ANNOT_TEXT (poppler_annot),
3313  }
3314  break;
3316  GArray *quads;
3317 
3318  quads = get_quads_for_area (poppler_page, &rect, NULL);
3319 
3322  poppler_annot = poppler_annot_text_markup_new_highlight (pdf_document->document, &poppler_rect, quads);
3323  break;
3324  default:
3325  g_assert_not_reached ();
3326  }
3327  g_array_unref (quads);
3328  }
3329  break;
3330  default:
3331  g_assert_not_reached ();
3332  }
3333 
3334  ev_annotation_get_color (annot, &color);
3335  poppler_color.red = color.red;
3336  poppler_color.green = color.green;
3337  poppler_color.blue = color.blue;
3338  poppler_annot_set_color (poppler_annot, &poppler_color);
3339 
3340  if (EV_IS_ANNOTATION_MARKUP (annot)) {
3341  EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (annot);
3342  const gchar *label;
3343 
3344  if (ev_annotation_markup_has_popup (markup)) {
3345  EvRectangle popup_rect;
3346 
3347  ev_annotation_markup_get_rectangle (markup, &popup_rect);
3348  poppler_rect.x1 = popup_rect.x1;
3349  poppler_rect.x2 = popup_rect.x2;
3350  poppler_rect.y1 = height - popup_rect.y2;
3351  poppler_rect.y2 = height - popup_rect.y1;
3352  poppler_annot_markup_set_popup (POPPLER_ANNOT_MARKUP (poppler_annot), &poppler_rect);
3353  poppler_annot_markup_set_popup_is_open (POPPLER_ANNOT_MARKUP (poppler_annot),
3355  }
3356 
3357  label = ev_annotation_markup_get_label (markup);
3358  if (label)
3359  poppler_annot_markup_set_label (POPPLER_ANNOT_MARKUP (poppler_annot), label);
3360  }
3361 
3362  poppler_page_add_annot (poppler_page, poppler_annot);
3363 
3364  annot_mapping = g_new (EvMapping, 1);
3365  annot_mapping->area = rect;
3366  annot_mapping->data = annot;
3367  g_signal_connect (annot, "notify::area",
3368  G_CALLBACK (annot_area_changed_cb),
3369  annot_mapping);
3370  g_object_set_data_full (G_OBJECT (annot),
3371  "poppler-annot",
3372  poppler_annot,
3373  (GDestroyNotify) g_object_unref);
3374 
3375  if (pdf_document->annots) {
3376  mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
3377  GINT_TO_POINTER (page->index));
3378  } else {
3379  pdf_document->annots = g_hash_table_new_full (g_direct_hash,
3380  g_direct_equal,
3381  (GDestroyNotify)NULL,
3382  (GDestroyNotify)ev_mapping_list_unref);
3383  mapping_list = NULL;
3384  }
3385 
3386  annot_set_unique_name (annot);
3387 
3388  if (mapping_list) {
3389  list = ev_mapping_list_get_list (mapping_list);
3390  list = g_list_append (list, annot_mapping);
3391  } else {
3392  list = g_list_append (list, annot_mapping);
3393  mapping_list = ev_mapping_list_new (page->index, list, (GDestroyNotify)g_object_unref);
3394  g_hash_table_insert (pdf_document->annots,
3395  GINT_TO_POINTER (page->index),
3396  ev_mapping_list_ref (mapping_list));
3397  }
3398 
3399  pdf_document->annots_modified = TRUE;
3400 }
3401 
3402 /* FIXME: We could probably add this to poppler */
3403 static void
3404 copy_poppler_annot (PopplerAnnot* src_annot,
3405  PopplerAnnot* dst_annot)
3406 {
3407  char *contents;
3408  PopplerColor *color;
3409 
3410  contents = poppler_annot_get_contents (src_annot);
3411  poppler_annot_set_contents (dst_annot, contents);
3412  g_free (contents);
3413 
3414  poppler_annot_set_flags (dst_annot, poppler_annot_get_flags (src_annot));
3415 
3416  color = poppler_annot_get_color (src_annot);
3417  poppler_annot_set_color (dst_annot, color);
3418  g_free (color);
3419 
3420  if (POPPLER_IS_ANNOT_MARKUP (src_annot) && POPPLER_IS_ANNOT_MARKUP (dst_annot)) {
3421  PopplerAnnotMarkup *src_markup = POPPLER_ANNOT_MARKUP (src_annot);
3422  PopplerAnnotMarkup *dst_markup = POPPLER_ANNOT_MARKUP (dst_annot);
3423  char *label;
3424 
3425  label = poppler_annot_markup_get_label (src_markup);
3426  poppler_annot_markup_set_label (dst_markup, label);
3427  g_free (label);
3428 
3429  poppler_annot_markup_set_opacity (dst_markup, poppler_annot_markup_get_opacity (src_markup));
3430 
3431  if (poppler_annot_markup_has_popup (src_markup)) {
3432  PopplerRectangle popup_rect;
3433 
3434  if (poppler_annot_markup_get_popup_rectangle (src_markup, &popup_rect)) {
3435  poppler_annot_markup_set_popup (dst_markup, &popup_rect);
3436  poppler_annot_markup_set_popup_is_open (dst_markup, poppler_annot_markup_get_popup_is_open (src_markup));
3437  }
3438 
3439  }
3440  }
3441 }
3442 
3443 static void
3445  EvAnnotation *annot,
3446  EvAnnotationsSaveMask mask)
3447 {
3448  PopplerAnnot *poppler_annot;
3449 
3450  poppler_annot = POPPLER_ANNOT (g_object_get_data (G_OBJECT (annot), "poppler-annot"));
3451  if (!poppler_annot)
3452  return;
3453 
3454  if (mask & EV_ANNOTATIONS_SAVE_CONTENTS)
3455  poppler_annot_set_contents (poppler_annot,
3456  ev_annotation_get_contents (annot));
3457 
3458  if (mask & EV_ANNOTATIONS_SAVE_COLOR) {
3459  PopplerColor color;
3460  GdkColor ev_color;
3461 
3462  ev_annotation_get_color (annot, &ev_color);
3463  color.red = ev_color.red;
3464  color.green = ev_color.green;
3465  color.blue = ev_color.blue;
3466  poppler_annot_set_color (poppler_annot, &color);
3467  }
3468 
3469  if (mask & EV_ANNOTATIONS_SAVE_AREA && !EV_IS_ANNOTATION_TEXT_MARKUP (annot)) {
3470  EvRectangle area;
3471  PopplerRectangle poppler_rect;
3472  EvPage *page;
3473  gdouble height;
3474 
3475  page = ev_annotation_get_page (annot);
3476  poppler_page_get_size (POPPLER_PAGE (page->backend_page), NULL, &height);
3477 
3478  ev_annotation_get_area (annot, &area);
3479  poppler_rect.x1 = area.x1;
3480  poppler_rect.x2 = area.x2;
3481  poppler_rect.y1 = height - area.y2;
3482  poppler_rect.y2 = height - area.y1;
3483  poppler_annot_set_rectangle (poppler_annot, &poppler_rect);
3484  }
3485 
3486  if (EV_IS_ANNOTATION_MARKUP (annot)) {
3487  EvAnnotationMarkup *ev_markup = EV_ANNOTATION_MARKUP (annot);
3488  PopplerAnnotMarkup *markup = POPPLER_ANNOT_MARKUP (poppler_annot);
3489 
3490  if (mask & EV_ANNOTATIONS_SAVE_LABEL)
3491  poppler_annot_markup_set_label (markup, ev_annotation_markup_get_label (ev_markup));
3492  if (mask & EV_ANNOTATIONS_SAVE_OPACITY)
3493  poppler_annot_markup_set_opacity (markup, ev_annotation_markup_get_opacity (ev_markup));
3494  if (mask & EV_ANNOTATIONS_SAVE_POPUP_RECT) {
3495  EvPage *page;
3496  EvRectangle ev_rect;
3497  PopplerRectangle poppler_rect;
3498  gdouble height;
3499 
3500  page = ev_annotation_get_page (annot);
3501  poppler_page_get_size (POPPLER_PAGE (page->backend_page),
3502  NULL, &height);
3503  ev_annotation_markup_get_rectangle (ev_markup, &ev_rect);
3504 
3505  poppler_rect.x1 = ev_rect.x1;
3506  poppler_rect.x2 = ev_rect.x2;
3507  poppler_rect.y1 = height - ev_rect.y2;
3508  poppler_rect.y2 = height - ev_rect.y1;
3509 
3510  if (poppler_annot_markup_has_popup (markup))
3511  poppler_annot_markup_set_popup_rectangle (markup, &poppler_rect);
3512  else
3513  poppler_annot_markup_set_popup (markup, &poppler_rect);
3514  }
3516  poppler_annot_markup_set_popup_is_open (markup, ev_annotation_markup_get_popup_is_open (ev_markup));
3517  }
3518 
3519  if (EV_IS_ANNOTATION_TEXT (annot)) {
3520  EvAnnotationText *ev_text = EV_ANNOTATION_TEXT (annot);
3521  PopplerAnnotText *text = POPPLER_ANNOT_TEXT (poppler_annot);
3522 
3523  if (mask & EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN) {
3524  poppler_annot_text_set_is_open (text,
3525  ev_annotation_text_get_is_open (ev_text));
3526  }
3527  if (mask & EV_ANNOTATIONS_SAVE_TEXT_ICON) {
3528  EvAnnotationTextIcon icon;
3529 
3530  icon = ev_annotation_text_get_icon (ev_text);
3531  poppler_annot_text_set_icon (text, get_poppler_annot_text_icon (icon));
3532  }
3533  }
3534 
3535  if (EV_IS_ANNOTATION_TEXT_MARKUP (annot)) {
3536  EvAnnotationTextMarkup *ev_text_markup = EV_ANNOTATION_TEXT_MARKUP (annot);
3537  PopplerAnnotTextMarkup *text_markup = POPPLER_ANNOT_TEXT_MARKUP (poppler_annot);
3538 
3540  /* In poppler every text markup annotation type is a different class */
3541  GArray *quads;
3542  PopplerRectangle rect;
3543  PopplerAnnot *new_annot = NULL;
3544  PdfDocument *pdf_document;
3545  EvPage *page;
3546  PopplerPage *poppler_page;
3547 
3548  pdf_document = PDF_DOCUMENT (document_annotations);
3549 
3550  quads = poppler_annot_text_markup_get_quadrilaterals (text_markup);
3551  poppler_annot_get_rectangle (POPPLER_ANNOT (text_markup), &rect);
3552 
3553  switch (ev_annotation_text_markup_get_markup_type (ev_text_markup)) {
3555  new_annot = poppler_annot_text_markup_new_highlight (pdf_document->document, &rect, quads);
3556  break;
3558  new_annot = poppler_annot_text_markup_new_strikeout (pdf_document->document, &rect, quads);
3559  break;
3561  new_annot = poppler_annot_text_markup_new_underline (pdf_document->document, &rect, quads);
3562  break;
3564  new_annot = poppler_annot_text_markup_new_squiggly (pdf_document->document, &rect, quads);
3565  break;
3566  }
3567 
3568  g_array_unref (quads);
3569 
3570  copy_poppler_annot (poppler_annot, new_annot);
3571 
3572  page = ev_annotation_get_page (annot);
3573  poppler_page = POPPLER_PAGE (page->backend_page);
3574 
3575  poppler_page_remove_annot (poppler_page, poppler_annot);
3576  poppler_page_add_annot (poppler_page, new_annot);
3577  g_object_set_data_full (G_OBJECT (annot),
3578  "poppler-annot",
3579  new_annot,
3580  (GDestroyNotify) g_object_unref);
3581  }
3582 
3583  if (mask & EV_ANNOTATIONS_SAVE_AREA) {
3584  EvRectangle area;
3585  GArray *quads;
3586  PopplerRectangle bbox;
3587  EvPage *page;
3588  PopplerPage *poppler_page;
3589 
3590  page = ev_annotation_get_page (annot);
3591  poppler_page = POPPLER_PAGE (page->backend_page);
3592 
3593  ev_annotation_get_area (annot, &area);
3594  quads = get_quads_for_area (poppler_page, &area, &bbox);
3595  poppler_annot_text_markup_set_quadrilaterals (text_markup, quads);
3596  poppler_annot_set_rectangle (poppler_annot, &bbox);
3597  g_array_unref (quads);
3598 
3599  if (bbox.x1 != 0 && bbox.y1 != 0 && bbox.x2 != 0 && bbox.y2 != 0) {
3600  gdouble height;
3601 
3602  poppler_page_get_size (poppler_page, NULL, &height);
3603  area.x1 = bbox.x1;
3604  area.x2 = bbox.x2;
3605  area.y1 = height - bbox.y2;
3606  area.y2 = height - bbox.y1;
3607  } else {
3608  area.x1 = 0;
3609  area.x2 = 0;
3610  area.y1 = 0;
3611  area.y2 = 0;
3612  }
3613  ev_annotation_set_area (annot, &area);
3614  }
3615  }
3616 
3617  PDF_DOCUMENT (document_annotations)->annots_modified = TRUE;
3618 }
3619 
3620 static void
3622 {
3628 }
3629 
3630 /* Media */
3631 static GFile *
3632 get_media_file (const gchar *filename,
3633  EvDocument *document)
3634 {
3635  GFile *file;
3636 
3637  if (g_path_is_absolute (filename)) {
3638  file = g_file_new_for_path (filename);
3639  } else if (g_strrstr (filename, "://")) {
3640  file = g_file_new_for_uri (filename);
3641  } else {
3642  gchar *doc_path;
3643  gchar *path;
3644  gchar *base_dir;
3645 
3646  doc_path = g_filename_from_uri (ev_document_get_uri (document), NULL, NULL);
3647  base_dir = g_path_get_dirname (doc_path);
3648  g_free (doc_path);
3649 
3650  path = g_build_filename (base_dir, filename, NULL);
3651  g_free (base_dir);
3652 
3653  file = g_file_new_for_path (path);
3654  g_free (path);
3655  }
3656 
3657  return file;
3658 }
3659 
3660 static EvMedia *
3662  EvPage *page,
3663  PopplerMovie *movie)
3664 {
3665  EvMedia *media;
3666  GFile *file;
3667  gchar *uri;
3668 
3669  file = get_media_file (poppler_movie_get_filename (movie), document);
3670  uri = g_file_get_uri (file);
3671  g_object_unref (file);
3672 
3673  media = ev_media_new_for_uri (page, uri);
3674  g_free (uri);
3675  ev_media_set_show_controls (media, poppler_movie_show_controls (movie));
3676 
3677  return media;
3678 }
3679 
3680 static void
3681 delete_temp_file (GFile *file)
3682 {
3683  g_file_delete (file, NULL, NULL);
3684  g_object_unref (file);
3685 }
3686 
3687 static gboolean
3688 media_save_to_file_callback (const gchar *buffer,
3689  gsize count,
3690  gpointer data,
3691  GError **error)
3692 {
3693  gint fd = GPOINTER_TO_INT (data);
3694 
3695  return write (fd, buffer, count) == (gssize)count;
3696 }
3697 
3698 static EvMedia *
3700  EvPage *page,
3701  PopplerMedia *poppler_media)
3702 {
3703  EvMedia *media;
3704  GFile *file = NULL;
3705  gchar *uri;
3706  gboolean is_temp_file = FALSE;
3707 
3708  if (!poppler_media)
3709  return NULL;
3710 
3711  if (poppler_media_is_embedded (poppler_media)) {
3712  gint fd;
3713  gchar *filename;
3714 
3715  fd = ev_mkstemp ("evmedia.XXXXXX", &filename, NULL);
3716  if (fd == -1)
3717  return NULL;
3718 
3719  if (poppler_media_save_to_callback (poppler_media,
3721  GINT_TO_POINTER (fd), NULL)) {
3722  file = g_file_new_for_path (filename);
3723  is_temp_file = TRUE;
3724  }
3725  close (fd);
3726  g_free (filename);
3727  } else {
3728  file = get_media_file (poppler_media_get_filename (poppler_media), document);
3729  }
3730 
3731  if (!file)
3732  return NULL;
3733 
3734  uri = g_file_get_uri (file);
3735  media = ev_media_new_for_uri (page, uri);
3737  g_free (uri);
3738 
3739  if (is_temp_file)
3740  g_object_set_data_full (G_OBJECT (media), "poppler-media-temp-file", file, (GDestroyNotify)delete_temp_file);
3741  else
3742  g_object_unref (file);
3743 
3744  return media;
3745 }
3746 
3747 static EvMappingList *
3749  EvPage *page)
3750 {
3751  GList *retval = NULL;
3752  PdfDocument *pdf_document;
3753  PopplerPage *poppler_page;
3754  EvMappingList *mapping_list;
3755  GList *annots;
3756  GList *list;
3757  gdouble height;
3758  gint i = 0;
3759 
3760  pdf_document = PDF_DOCUMENT (document_media);
3761  poppler_page = POPPLER_PAGE (page->backend_page);
3762 
3763  annots = poppler_page_get_annot_mapping (poppler_page);
3764  poppler_page_get_size (poppler_page, NULL, &height);
3765 
3766  for (list = annots; list; list = list->next) {
3767  PopplerAnnotMapping *mapping;
3768  EvMapping *media_mapping;
3769  EvMedia *media = NULL;
3770 
3771  mapping = (PopplerAnnotMapping *)list->data;
3772 
3773  switch (poppler_annot_get_annot_type (mapping->annot)) {
3774  case POPPLER_ANNOT_MOVIE: {
3775  PopplerAnnotMovie *poppler_annot;
3776 
3777  poppler_annot = POPPLER_ANNOT_MOVIE (mapping->annot);
3778  media = ev_media_from_poppler_movie (EV_DOCUMENT (pdf_document), page,
3779  poppler_annot_movie_get_movie (poppler_annot));
3780  }
3781  break;
3782  case POPPLER_ANNOT_SCREEN: {
3783  PopplerAction *action;
3784 
3785  action = poppler_annot_screen_get_action (POPPLER_ANNOT_SCREEN (mapping->annot));
3786  if (action && action->type == POPPLER_ACTION_RENDITION) {
3787  media = ev_media_from_poppler_rendition (EV_DOCUMENT (pdf_document), page,
3788  action->rendition.media);
3789  }
3790  }
3791  break;
3792  default:
3793  break;
3794  }
3795 
3796  if (!media)
3797  continue;
3798 
3799  media_mapping = g_new (EvMapping, 1);
3800 
3801  media_mapping->data = media;
3802  media_mapping->area.x1 = mapping->area.x1;
3803  media_mapping->area.x2 = mapping->area.x2;
3804  media_mapping->area.y1 = height - mapping->area.y2;
3805  media_mapping->area.y2 = height - mapping->area.y1;
3806 
3807  retval = g_list_prepend (retval, media_mapping);
3808  }
3809 
3810  poppler_page_free_annot_mapping (annots);
3811 
3812  if (!retval)
3813  return NULL;
3814 
3815  return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
3816 }
3817 
3818 static void
3820 {
3822 }
3823 
3824 /* Attachments */
3826  gchar *buffer;
3827  gsize len, max;
3828 };
3829 
3830 static gboolean
3832  gsize count,
3833  gpointer user_data,
3834  GError **error)
3835 {
3836  struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
3837  gchar *new_buffer;
3838  gsize new_max;
3839 
3840  if (sdata->len + count > sdata->max) {
3841  new_max = MAX (sdata->max * 2, sdata->len + count);
3842  new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
3843 
3844  sdata->buffer = new_buffer;
3845  sdata->max = new_max;
3846  }
3847 
3848  memcpy (sdata->buffer + sdata->len, buf, count);
3849  sdata->len += count;
3850 
3851  return TRUE;
3852 }
3853 
3854 static gboolean
3855 attachment_save_to_buffer (PopplerAttachment *attachment,
3856  gchar **buffer,
3857  gsize *buffer_size,
3858  GError **error)
3859 {
3860  static const gint initial_max = 1024;
3861  struct SaveToBufferData sdata;
3862 
3863  *buffer = NULL;
3864  *buffer_size = 0;
3865 
3866  sdata.buffer = (gchar *) g_malloc (initial_max);
3867  sdata.max = initial_max;
3868  sdata.len = 0;
3869 
3870  if (! poppler_attachment_save_to_callback (attachment,
3872  &sdata,
3873  error)) {
3874  g_free (sdata.buffer);
3875  return FALSE;
3876  }
3877 
3878  *buffer = sdata.buffer;
3879  *buffer_size = sdata.len;
3880 
3881  return TRUE;
3882 }
3883 
3884 static GList *
3886 {
3887  PdfDocument *pdf_document = PDF_DOCUMENT (document);
3888  GList *attachments;
3889  GList *list;
3890  GList *retval = NULL;
3891 
3892  attachments = poppler_document_get_attachments (pdf_document->document);
3893 
3894  for (list = attachments; list; list = list->next) {
3895  PopplerAttachment *attachment;
3896  EvAttachment *ev_attachment;
3897  gchar *data = NULL;
3898  gsize size;
3899  GError *error = NULL;
3900 
3901  attachment = (PopplerAttachment *) list->data;
3902 
3903  if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
3904  ev_attachment = ev_attachment_new (attachment->name,
3905  attachment->description,
3906  attachment->mtime,
3907  attachment->ctime,
3908  size, data);
3909 
3910  retval = g_list_prepend (retval, ev_attachment);
3911  } else {
3912  if (error) {
3913  g_warning ("%s", error->message);
3914  g_error_free (error);
3915 
3916  g_free (data);
3917  }
3918  }
3919 
3920  g_object_unref (attachment);
3921  }
3922 
3923  return g_list_reverse (retval);
3924 }
3925 
3926 static gboolean
3928 {
3929  PdfDocument *pdf_document = PDF_DOCUMENT (document);
3930 
3931  return poppler_document_has_attachments (pdf_document->document);
3932 }
3933 
3934 static void
3936 {
3939 }
3940 
3941 /* Layers */
3942 static gboolean
3944 {
3945  PdfDocument *pdf_document = PDF_DOCUMENT (document);
3946  PopplerLayersIter *iter;
3947 
3948  iter = poppler_layers_iter_new (pdf_document->document);
3949  if (!iter)
3950  return FALSE;
3951  poppler_layers_iter_free (iter);
3952 
3953  return TRUE;
3954 }
3955 
3956 static void
3958  GtkTreeModel *model,
3959  GtkTreeIter *parent,
3960  PopplerLayersIter *iter)
3961 {
3962  do {
3963  GtkTreeIter tree_iter;
3964  PopplerLayersIter *child;
3965  PopplerLayer *layer;
3966  EvLayer *ev_layer = NULL;
3967  gboolean visible;
3968  gchar *markup;
3969  gint rb_group = 0;
3970 
3971  layer = poppler_layers_iter_get_layer (iter);
3972  if (layer) {
3973  markup = g_markup_escape_text (poppler_layer_get_title (layer), -1);
3974  visible = poppler_layer_is_visible (layer);
3975  rb_group = poppler_layer_get_radio_button_group_id (layer);
3976  ev_layer = ev_layer_new (poppler_layer_is_parent (layer),
3977  rb_group);
3978  g_object_set_data_full (G_OBJECT (ev_layer),
3979  "poppler-layer",
3980  g_object_ref (layer),
3981  (GDestroyNotify) g_object_unref);
3982  } else {
3983  gchar *title;
3984 
3985  title = poppler_layers_iter_get_title (iter);
3986  markup = g_markup_escape_text (title, -1);
3987  g_free (title);
3988 
3989  visible = FALSE;
3990  layer = NULL;
3991  }
3992 
3993  gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
3994  gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
3998  EV_DOCUMENT_LAYERS_COLUMN_SHOWTOGGLE, (layer != NULL),
4001  -1);
4002  if (ev_layer)
4003  g_object_unref (ev_layer);
4004  g_free (markup);
4005 
4006  child = poppler_layers_iter_get_child (iter);
4007  if (child)
4008  build_layers_tree (pdf_document, model, &tree_iter, child);
4009  poppler_layers_iter_free (child);
4010  } while (poppler_layers_iter_next (iter));
4011 }
4012 
4013 static GtkTreeModel *
4015 {
4016  GtkTreeModel *model = NULL;
4017  PdfDocument *pdf_document = PDF_DOCUMENT (document);
4018  PopplerLayersIter *iter;
4019 
4020  iter = poppler_layers_iter_new (pdf_document->document);
4021  if (iter) {
4022  model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LAYERS_N_COLUMNS,
4023  G_TYPE_STRING, /* TITLE */
4024  G_TYPE_OBJECT, /* LAYER */
4025  G_TYPE_BOOLEAN, /* VISIBLE */
4026  G_TYPE_BOOLEAN, /* ENABLED */
4027  G_TYPE_BOOLEAN, /* SHOWTOGGLE */
4028  G_TYPE_INT); /* RBGROUP */
4029  build_layers_tree (pdf_document, model, NULL, iter);
4030  poppler_layers_iter_free (iter);
4031  }
4032  return model;
4033 }
4034 
4035 static void
4037  EvLayer *layer)
4038 {
4039  PopplerLayer *poppler_layer;
4040 
4041  poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
4042  poppler_layer_show (poppler_layer);
4043 }
4044 
4045 static void
4047  EvLayer *layer)
4048 {
4049  PopplerLayer *poppler_layer;
4050 
4051  poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
4052  poppler_layer_hide (poppler_layer);
4053 }
4054 
4055 static gboolean
4057  EvLayer *layer)
4058 {
4059  PopplerLayer *poppler_layer;
4060 
4061  poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
4062  return poppler_layer_is_visible (poppler_layer);
4063 }
4064 
4065 static void
4067 {
4073 }