]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/pdf-document.cc
Keep offset in consideration in a few places
[evince.git] / pdf / xpdf / pdf-document.cc
index 6e077162c59e138e45eefe1246006e94255171bd..b9180bd9988b1e712c4c79a445401f5777e33e3e 100644 (file)
@@ -24,8 +24,9 @@
 #include "ev-ps-exporter.h"
 #include "ev-document-find.h"
 #include "gpdf-g-switch.h"
-#include "ev-document-bookmarks.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,35 +86,56 @@ 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_bookmarks_iface_init  (EvDocumentBookmarksIface  *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,
                          {
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
                                                        pdf_document_document_iface_init);
-                                G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_BOOKMARKS,
-                                                       pdf_document_document_bookmarks_iface_init);
+                                G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
+                                                       pdf_document_document_links_iface_init);
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
                                                        pdf_document_document_thumbnails_iface_init);
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
                                                        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
@@ -450,8 +484,8 @@ pdf_document_search_page_changed (PdfDocumentSearch   *search)
                                          &xMin, &yMin, &xMax, &yMax)) {
                 result.page_num = pdf_document->page;
 
-                result.highlight_area.x = xMin;
-                result.highlight_area.y = yMin;
+                result.highlight_area.x = xMin + pdf_document->page_x_offset;
+                result.highlight_area.y = yMin + pdf_document->page_y_offset;
                 result.highlight_area.width = xMax - xMin;
                 result.highlight_area.height = yMax - yMin;
 
@@ -465,8 +499,8 @@ pdf_document_search_page_changed (PdfDocumentSearch   *search)
 
                         result.page_num = pdf_document->page;
 
-                        result.highlight_area.x = xMin;
-                        result.highlight_area.y = yMin;
+                        result.highlight_area.x = xMin + pdf_document->page_x_offset;
+                        result.highlight_area.y = yMin + pdf_document->page_y_offset;
                         result.highlight_area.width = xMax - xMin;
                         result.highlight_area.height = yMax - yMin;
 
@@ -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)
 {
@@ -675,14 +728,14 @@ pdf_document_ps_export_end (EvPSExporter *exporter)
 }
 
 
-/* EvDocumentBookmarks Implementation */
+/* EvDocumentLinks Implementation */
 typedef struct
 {
        /* goo GList, not glib */
        GList *items;
        int index;
        int level;
-} BookmarksIter;
+} LinksIter;
 
 static gchar *
 unicode_to_char (OutlineItem *outline_item,
@@ -702,12 +755,12 @@ unicode_to_char (OutlineItem *outline_item,
 
 
 static gboolean
-pdf_document_bookmarks_has_document_bookmarks (EvDocumentBookmarks *document_bookmarks)
+pdf_document_links_has_document_links (EvDocumentLinks *document_links)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks);
+       PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
        Outline *outline;
 
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE);
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
 
        outline = pdf_document->doc->getOutline();
        if (outline->getItems() != NULL &&
@@ -717,51 +770,38 @@ pdf_document_bookmarks_has_document_bookmarks (EvDocumentBookmarks *document_boo
        return FALSE;
 }
 
-static EvDocumentBookmarksIter *
-pdf_document_bookmarks_begin_read (EvDocumentBookmarks *document_bookmarks)
+static EvDocumentLinksIter *
+pdf_document_links_begin_read (EvDocumentLinks *document_links)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks);
+       PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
        Outline *outline;
-       BookmarksIter *iter;
+       LinksIter *iter;
        GList *items;
 
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), NULL);
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
 
        outline = pdf_document->doc->getOutline();
        items = outline->getItems();
        if (! items)
                return NULL;
 
-       iter = g_new0 (BookmarksIter, 1);
+       iter = g_new0 (LinksIter, 1);
        iter->items = items;
        iter->index = 0;
        iter->level = 0;
 
-       return (EvDocumentBookmarksIter *) iter;
+       return (EvDocumentLinksIter *) iter;
 }
 
-static EvBookmark *
-pdf_document_bookmarks_get_bookmark (EvDocumentBookmarks      *document_bookmarks,
-                                    EvDocumentBookmarksIter  *bookmarks_iter)
+static EvLink *
+build_link_from_action (PdfDocument *pdf_document,
+                       LinkAction  *link_action,
+                       const char  *title)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks);
-       EvBookmark *bookmark = NULL;
-       BookmarksIter *iter = (BookmarksIter *)bookmarks_iter;
-       OutlineItem *anItem;
-       LinkAction *link_action;
-       Unicode *link_title;
-       const char *title;
-
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), 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);
+       EvLink *link = NULL;
 
        if (link_action == NULL) {
-               bookmark = ev_bookmark_new_title (title);
+               link = ev_link_new_title (title);
        } else if (link_action->getKind () == actionGoTo) {
                LinkDest *link_dest;
                LinkGoTo *link_goto;
@@ -792,51 +832,75 @@ pdf_document_bookmarks_get_bookmark (EvDocumentBookmarks      *document_bookmark
                        delete link_dest;
                }
 
-               bookmark = ev_bookmark_new_link (title, page_num);
+               link = ev_link_new_page (title, page_num);
        } else if (link_action->getKind () == actionURI) {
                LinkURI *link_uri;
 
                link_uri = dynamic_cast <LinkURI *> (link_action);
-               bookmark = ev_bookmark_new_external
+               link = ev_link_new_external
                        (title, link_uri->getURI()->getCString());
        } else if (link_action->getKind () == actionNamed) {
                        /*Skip, for now */
        }
 
-       return bookmark;
+       return link;
 }
 
-static EvDocumentBookmarksIter *
-pdf_document_bookmarks_get_child (EvDocumentBookmarks     *document_bookmarks,
-                                 EvDocumentBookmarksIter *bookmarks_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)
 {
-       BookmarksIter *iter = (BookmarksIter *)bookmarks_iter;
-       BookmarksIter *child_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);
+}
 
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE);
+static EvDocumentLinksIter *
+pdf_document_links_get_child (EvDocumentLinks     *document_links,
+                             EvDocumentLinksIter *links_iter)
+{
+       LinksIter *iter = (LinksIter *)links_iter;
+       LinksIter *child_iter;
+       OutlineItem *anItem;
+
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
 
        anItem = (OutlineItem *)iter->items->get(iter->index);
        anItem->open ();
        if (! (anItem->hasKids() && anItem->getKids()) )
                return NULL;
 
-       child_iter = g_new0 (BookmarksIter, 1);
+       child_iter = g_new0 (LinksIter, 1);
        child_iter->index = 0;
        child_iter->level = iter->level + 1;
        child_iter->items = anItem->getKids ();
        g_assert (child_iter->items);
 
-       return (EvDocumentBookmarksIter *) child_iter;
+       return (EvDocumentLinksIter *) child_iter;
 }
 
 static gboolean
-pdf_document_bookmarks_next (EvDocumentBookmarks     *document_bookmarks,
-                            EvDocumentBookmarksIter *bookmarks_iter)
+pdf_document_links_next (EvDocumentLinks     *document_links,
+                        EvDocumentLinksIter *links_iter)
 {
-       BookmarksIter *iter = (BookmarksIter *) bookmarks_iter;
+       LinksIter *iter = (LinksIter *) links_iter;
 
-       g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE);
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
 
        iter->index++;
        if (iter->index >= iter->items->getLength())
@@ -846,10 +910,10 @@ pdf_document_bookmarks_next (EvDocumentBookmarks     *document_bookmarks,
 }
 
 static void
-pdf_document_bookmarks_free_iter (EvDocumentBookmarks     *document_bookmarks,
-                                 EvDocumentBookmarksIter *iter)
+pdf_document_links_free_iter (EvDocumentLinks     *document_links,
+                             EvDocumentLinksIter *iter)
 {
-       g_return_if_fail (PDF_IS_DOCUMENT (document_bookmarks));
+       g_return_if_fail (PDF_IS_DOCUMENT (document_links));
        g_return_if_fail (iter != NULL);
 
        /* FIXME: Should I close all the nodes?? Free them? */
@@ -861,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;
@@ -914,7 +982,7 @@ pdf_info_dict_get_string (Dict *info_dict, const gchar *key) {
 
        if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
                obj.free ();
-               return g_strdup (_("Unknown"));
+               return NULL;
        }
 
        value = obj.getString ();
@@ -955,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 ();
@@ -966,6 +1034,33 @@ 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;
+
+       /* Zoom */
+       link_x = x / pdf_document->scale;
+       link_y = y / pdf_document->scale;
+
+       /* Offset */
+       link_x -= pdf_document->page_x_offset;
+       link_y -= pdf_document->page_y_offset;
+
+       /* Inverse y */
+       link_y = pdf_document->out->getBitmapHeight() - link_y;
+
+       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,
@@ -1003,6 +1098,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;
@@ -1030,14 +1126,21 @@ pdf_document_find_iface_init (EvDocumentFindIface *iface)
 }
 
 static void
-pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface)
+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)
 {
-       iface->has_document_bookmarks = pdf_document_bookmarks_has_document_bookmarks;
-       iface->begin_read = pdf_document_bookmarks_begin_read;
-       iface->get_bookmark = pdf_document_bookmarks_get_bookmark;
-       iface->get_child = pdf_document_bookmarks_get_child;
-       iface->next = pdf_document_bookmarks_next;
-       iface->free_iter = pdf_document_bookmarks_free_iter;
+       iface->has_document_links = pdf_document_links_has_document_links;
+       iface->begin_read = pdf_document_links_begin_read;
+       iface->get_link = pdf_document_links_get_link;
+       iface->get_child = pdf_document_links_get_child;
+       iface->next = pdf_document_links_next;
+       iface->free_iter = pdf_document_links_free_iter;
 }
 
 /* Thumbnails */
@@ -1142,8 +1245,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 (),
@@ -1235,5 +1336,6 @@ pdf_document_init (PdfDocument *pdf_document)
        pdf_document->scale = 1.;
 
        pdf_document->page_valid = FALSE;
+       pdf_document->password = NULL;
 }