]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/pdf-document.cc
ignore page offset here, to make search results independent of it,
[evince.git] / pdf / xpdf / pdf-document.cc
index a64dc4cecd3abfc311a24f29ed2bec51600ad116..22e7e4138ad3f5e543d3fce0ecfddcfc62b6180d 100644 (file)
@@ -26,6 +26,7 @@
 #include "gpdf-g-switch.h"
 #include "ev-document-links.h"
 #include "ev-document-misc.h"
+#include "ev-document-security.h"
 #include "ev-document-thumbnails.h"
 
 #include "GlobalParams.h"
@@ -33,6 +34,7 @@
 #include "SplashBitmap.h"
 #include "PDFDoc.h"
 #include "Outline.h"
+#include "ErrorCodes.h"
 #include "UnicodeMap.h"
 #include "GlobalParams.h"
 #include "GfxState.h"
@@ -84,20 +86,24 @@ struct _PdfDocument
        GDKSplashOutputDev *out;
        PSOutputDev *ps_out;
        PDFDoc *doc;
+       Links *links;
        UnicodeMap *umap;
 
+       gchar *password;
        gboolean page_valid;
 
        PdfDocumentSearch *search;
 };
 
-static void pdf_document_document_links_iface_init      (EvDocumentLinksIface  *iface);
+static void pdf_document_document_links_iface_init      (EvDocumentLinksIface      *iface);
 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
 static void pdf_document_document_iface_init            (EvDocumentIface           *iface);
-static void pdf_document_ps_exporter_iface_init (EvPSExporterIface   *iface);
-static void pdf_document_find_iface_init        (EvDocumentFindIface *iface);
-static void pdf_document_search_free            (PdfDocumentSearch   *search);
-static void pdf_document_search_page_changed    (PdfDocumentSearch   *search);
+static void pdf_document_ps_exporter_iface_init         (EvPSExporterIface         *iface);
+static void pdf_document_find_iface_init                (EvDocumentFindIface       *iface);
+static void pdf_document_security_iface_init            (EvDocumentSecurityIface   *iface);
+static void pdf_document_search_free                    (PdfDocumentSearch         *search);
+static void pdf_document_search_page_changed            (PdfDocumentSearch         *search);
+
 
 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
                          {
@@ -111,8 +117,25 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
                                                        pdf_document_ps_exporter_iface_init);
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
                                                        pdf_document_find_iface_init);
+                                G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
+                                                       pdf_document_security_iface_init);
                         });
 
+static void
+document_init_links (PdfDocument *pdf_document)
+{
+       Page *page;
+       Object obj;
+
+       if (pdf_document->links) {
+               delete pdf_document->links;
+       }
+       page = pdf_document->doc->getCatalog ()->getPage (pdf_document->page);
+       pdf_document->links = new Links (page->getAnnots (&obj),
+                                        pdf_document->doc->getCatalog ()->getBaseURI ());
+       obj.free ();
+}
+
 static gboolean
 document_validate_page (PdfDocument *pdf_document)
 {
@@ -122,8 +145,12 @@ document_validate_page (PdfDocument *pdf_document)
                                                72 * pdf_document->scale,
                                                0, gTrue, gTrue);
 
+               document_init_links (pdf_document);
+
                pdf_document->page_valid = TRUE;
 
+               ev_document_changed (EV_DOCUMENT (pdf_document));
+
                 /* Update the search results available to the app since
                  * we only provide full results on the current page
                  */
@@ -166,18 +193,27 @@ pdf_document_load (EvDocument  *document,
        g_free (filename);
 
        // open the PDF file, assumes ownership of filename_g
-       newDoc = new PDFDoc(filename_g, 0, 0);
+       GString *password = NULL;
+       if (pdf_document->password)
+               password = new GString (pdf_document->password);
+       newDoc = new PDFDoc(filename_g, password, password);
+       if (password)
+               delete password;
 
        if (!newDoc->isOk()) {
                err = newDoc->getErrorCode();
                delete newDoc;
-
-               /* FIXME: Add a real error enum to EvDocument */
-               g_set_error (error, G_FILE_ERROR,
-                            G_FILE_ERROR_FAILED,
-                            "Failed to load document (error %d) '%s'\n",
-                            err,
-                            uri);
+               if (err == errEncrypted) {
+                       g_set_error (error, EV_DOCUMENT_ERROR,
+                                    EV_DOCUMENT_ERROR_ENCRYPTED,
+                                    "Document is encrypted.");
+               } else {
+                       g_set_error (error, G_FILE_ERROR,
+                                    G_FILE_ERROR_FAILED,
+                                    "Failed to load document (error %d) '%s'\n",
+                                    err,
+                                    uri);
+               }
 
                return FALSE;
        }
@@ -240,8 +276,6 @@ pdf_document_set_page (EvDocument  *document,
                pdf_document->page = page;
                pdf_document->page_valid = FALSE;
        }
-
-       ev_document_changed (document);
 }
 
 static int
@@ -642,6 +676,25 @@ pdf_document_search_free (PdfDocumentSearch   *search)
        g_free (search);
 }
 
+static gboolean
+pdf_document_has_document_security (EvDocumentSecurity *document_security)
+{
+       /* FIXME: do we really need to have this? */
+       return FALSE;
+}
+
+static void
+pdf_document_set_password (EvDocumentSecurity *document_security,
+                          const char         *password)
+{
+       PdfDocument *document = PDF_DOCUMENT (document_security);
+
+       if (document->password)
+               g_free (document->password);
+
+       document->password = g_strdup (password);
+}
+
 static void
 pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
 {
@@ -740,27 +793,12 @@ pdf_document_links_begin_read (EvDocumentLinks *document_links)
        return (EvDocumentLinksIter *) iter;
 }
 
-/* FIXME This returns a new object every time, probably we should cache it
-   in the iter */
 static EvLink *
-pdf_document_links_get_link (EvDocumentLinks      *document_links,
-                                EvDocumentLinksIter  *links_iter)
+build_link_from_action (PdfDocument *pdf_document,
+                       LinkAction  *link_action,
+                       const char  *title)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
        EvLink *link = NULL;
-       LinksIter *iter = (LinksIter *)links_iter;
-       OutlineItem *anItem;
-       LinkAction *link_action;
-       Unicode *link_title;
-       const char *title;
-
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
-       g_return_val_if_fail (iter != NULL, FALSE);
-
-       anItem = (OutlineItem *)iter->items->get(iter->index);
-       link_action = anItem->getAction ();
-       link_title = anItem->getTitle ();
-       title = unicode_to_char (anItem, pdf_document->umap);
 
        if (link_action == NULL) {
                link = ev_link_new_title (title);
@@ -808,9 +846,33 @@ pdf_document_links_get_link (EvDocumentLinks      *document_links,
        return link;
 }
 
+/* FIXME This returns a new object every time, probably we should cache it
+   in the iter */
+static EvLink *
+pdf_document_links_get_link (EvDocumentLinks      *document_links,
+                            EvDocumentLinksIter  *links_iter)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
+       LinksIter *iter = (LinksIter *)links_iter;
+       OutlineItem *anItem;
+       LinkAction *link_action;
+       Unicode *link_title;
+       const char *title;
+
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
+       g_return_val_if_fail (iter != NULL, FALSE);
+
+       anItem = (OutlineItem *)iter->items->get(iter->index);
+       link_action = anItem->getAction ();
+       link_title = anItem->getTitle ();
+       title = unicode_to_char (anItem, pdf_document->umap);
+
+       return build_link_from_action (pdf_document, link_action, title);
+}
+
 static EvDocumentLinksIter *
 pdf_document_links_get_child (EvDocumentLinks     *document_links,
-                                 EvDocumentLinksIter *links_iter)
+                             EvDocumentLinksIter *links_iter)
 {
        LinksIter *iter = (LinksIter *)links_iter;
        LinksIter *child_iter;
@@ -834,7 +896,7 @@ pdf_document_links_get_child (EvDocumentLinks     *document_links,
 
 static gboolean
 pdf_document_links_next (EvDocumentLinks     *document_links,
-                            EvDocumentLinksIter *links_iter)
+                        EvDocumentLinksIter *links_iter)
 {
        LinksIter *iter = (LinksIter *) links_iter;
 
@@ -849,7 +911,7 @@ pdf_document_links_next (EvDocumentLinks     *document_links,
 
 static void
 pdf_document_links_free_iter (EvDocumentLinks     *document_links,
-                                 EvDocumentLinksIter *iter)
+                             EvDocumentLinksIter *iter)
 {
        g_return_if_fail (PDF_IS_DOCUMENT (document_links));
        g_return_if_fail (iter != NULL);
@@ -863,6 +925,10 @@ pdf_document_finalize (GObject *object)
 {
        PdfDocument *pdf_document = PDF_DOCUMENT (object);
 
+       if (pdf_document->links) {
+               delete pdf_document->links;
+       }
+
        if (pdf_document->umap) {
                pdf_document->umap->decRefCnt ();
                pdf_document->umap = NULL;
@@ -957,10 +1023,10 @@ pdf_document_get_text (EvDocument *document, GdkRectangle *rect)
        const char *text;
        int x1, y1, x2, y2;
 
-       x1 = rect->x;
-       y1 = rect->y;
-       x2 = x1 + rect->width;
-       y2 = y1 + rect->height;
+       x1 = rect->x + pdf_document->page_x_offset;
+       y1 = rect->y + pdf_document->page_y_offset;
+       x2 = x1 + rect->width + pdf_document->page_x_offset;
+       y2 = y1 + rect->height + pdf_document->page_y_offset;
 
        sel_text = pdf_document->out->getText (x1, y1, x2, y2);
        text = sel_text->getCString ();
@@ -968,6 +1034,37 @@ pdf_document_get_text (EvDocument *document, GdkRectangle *rect)
        return text ? g_strdup (text) : NULL;
 }
 
+static EvLink *
+pdf_document_get_link (EvDocument *document, int x, int y)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       LinkAction *action;
+       double link_x, link_y;
+
+       if (pdf_document->links == NULL) {
+               return NULL;
+       }
+
+       /* Offset */
+       link_x = x - pdf_document->page_x_offset;
+       link_y = y - pdf_document->page_y_offset;
+
+       /* Inverse y */
+       link_y = pdf_document->out->getBitmapHeight() - link_y;
+
+       /* Zoom */
+       link_x = link_x / pdf_document->scale;
+       link_y = link_y / pdf_document->scale;
+
+       action = pdf_document->links->find (link_x, link_y);
+       
+       if (action) {
+               return build_link_from_action (pdf_document, action, "");
+       } else {
+               return NULL;
+       }
+}
+
 static void
 pdf_document_get_property (GObject *object,
                           guint prop_id,
@@ -1005,6 +1102,7 @@ pdf_document_document_iface_init (EvDocumentIface *iface)
        iface->load = pdf_document_load;
        iface->save = pdf_document_save;
        iface->get_text = pdf_document_get_text;
+       iface->get_link = pdf_document_get_link;
        iface->get_n_pages = pdf_document_get_n_pages;
        iface->set_page = pdf_document_set_page;
        iface->get_page = pdf_document_get_page;
@@ -1031,6 +1129,13 @@ pdf_document_find_iface_init (EvDocumentFindIface *iface)
         iface->cancel = pdf_document_find_cancel;
 }
 
+static void
+pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
+{
+       iface->has_document_security = pdf_document_has_document_security;
+       iface->set_password = pdf_document_set_password;
+}
+
 static void
 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
 {
@@ -1144,8 +1249,6 @@ pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnail
        the_page = pdf_document->doc->getCatalog ()->getPage (page + 1);
        the_page->getThumb (&the_thumb);
 
-
-
        if (!(the_thumb.isNull () || the_thumb.isNone())) {
                /* Build the thumbnail object */
                thumb = new Thumb(pdf_document->doc->getXRef (),
@@ -1237,5 +1340,6 @@ pdf_document_init (PdfDocument *pdf_document)
        pdf_document->scale = 1.;
 
        pdf_document->page_valid = FALSE;
+       pdf_document->password = NULL;
 }