X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=sidebyside;f=backend%2Fpdf%2Fev-poppler.cc;h=6d1c937a9401d231b6e1cec1d9d73831c7657f41;hb=1ff4db77238ee4f3b89c5cd7b94e3178e11fb543;hp=93064456aede70e507db2309163f1793144e8cba;hpb=c4b192c34c4758bd078d1a212d69c6ae5084d6c8;p=evince.git diff --git a/backend/pdf/ev-poppler.cc b/backend/pdf/ev-poppler.cc index 93064456..6d1c937a 100644 --- a/backend/pdf/ev-poppler.cc +++ b/backend/pdf/ev-poppler.cc @@ -1,5 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ -/* pdfdocument.h: Implementation of EvDocument for PDF +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2009, Juanjo Marín * Copyright (C) 2004, Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify @@ -63,6 +65,13 @@ #define HAVE_CAIRO_PRINT #endif +/* fields from the XMP Rights Management Schema, XMP Specification Sept 2005, pag. 45 */ +#define LICENSE_MARKED "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:Marked" +#define LICENSE_TEXT "/x:xmpmeta/rdf:RDF/rdf:Description/dc:rights/rdf:Alt/rdf:li[lang('%s')]" +#define LICENSE_WEB_STATEMENT "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:WebStatement" +/* license field from Creative Commons schema, http://creativecommons.org/ns */ +#define LICENSE_URI "/x:xmpmeta/rdf:RDF/rdf:Description/cc:license/@rdf:resource" + typedef struct { PdfDocument *document; char *text; @@ -135,12 +144,16 @@ static void pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails gint *height); static int pdf_document_get_n_pages (EvDocument *document); -static EvLinkDest *ev_link_dest_from_dest (PdfDocument *pdf_document, - PopplerDest *dest); -static EvLink *ev_link_from_action (PdfDocument *pdf_document, - PopplerAction *action); -static void pdf_document_search_free (PdfDocumentSearch *search); -static void pdf_print_context_free (PdfPrintContext *ctx); +static EvLinkDest *ev_link_dest_from_dest (PdfDocument *pdf_document, + PopplerDest *dest); +static EvLink *ev_link_from_action (PdfDocument *pdf_document, + PopplerAction *action); +static void pdf_document_search_free (PdfDocumentSearch *search); +static void pdf_print_context_free (PdfPrintContext *ctx); +static gboolean attachment_save_to_buffer (PopplerAttachment *attachment, + gchar **buffer, + gsize *buffer_size, + GError **error); EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document, { @@ -442,26 +455,15 @@ pdf_document_render (EvDocument *document, /* reference: 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 */ static char * -pdf_document_get_format_from_metadata (const char *metadata) +pdf_document_get_format_from_metadata (xmlDocPtr doc, + xmlXPathContextPtr xpathCtx) { - xmlDocPtr doc; - xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; xmlChar *part = NULL; xmlChar *conf = NULL; char *result = NULL; int i; - doc = xmlParseMemory (metadata, strlen (metadata)); - if (doc == NULL) - return NULL; /* invalid xml metadata */ - - xpathCtx = xmlXPathNewContext (doc); - if (xpathCtx == NULL) { - xmlFreeDoc (doc); - return NULL; /* invalid xpath context */ - } - /* add pdf/a namespaces */ xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/"); xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); @@ -519,12 +521,159 @@ pdf_document_get_format_from_metadata (const char *metadata) /* Cleanup */ xmlFree (part); xmlFree (conf); - xmlXPathFreeContext (xpathCtx); - xmlFreeDoc (doc); return result; } +static EvDocumentLicense * +pdf_document_get_license_from_metadata (xmlDocPtr doc, + xmlXPathContextPtr xpathCtx) +{ + xmlXPathObjectPtr xpathObj; + xmlChar *marked = NULL; + const char *language_string; + char *aux; + gchar **tags; + gchar *tag, *tag_aux; + int i, j; + EvDocumentLicense *license; + + /* register namespaces */ + xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/"); + xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + xmlXPathRegisterNs (xpathCtx, BAD_CAST "dc", BAD_CAST "http://purl.org/dc/elements/1.1/"); + /* XMP Rights Management Schema */ + xmlXPathRegisterNs (xpathCtx, BAD_CAST "xmpRights", BAD_CAST "http://ns.adobe.com/xap/1.0/rights/"); + /* Creative Commons Schema */ + xmlXPathRegisterNs (xpathCtx, BAD_CAST "cc", BAD_CAST "http://creativecommons.org/ns#"); + + /* checking if the document has been marked as defined on the XMP Rights + * Management Schema */ + xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_MARKED, xpathCtx); + if (xpathObj != NULL) { + if (xpathObj->nodesetval != NULL && + xpathObj->nodesetval->nodeNr != 0) + marked = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]); + xmlXPathFreeObject (xpathObj); + } + + /* a) Not marked => No XMP Rights information */ + if (!marked) { + xmlFree (marked); + return NULL; + } + + license = ev_document_license_new (); + + /* b) Marked False => Public Domain, no copyrighted material and no + * license needed */ + if (g_strrstr ((char *) marked, "False") != NULL) { + license->text = g_strdup (_("This work is in the Public Domain")); + /* c) Marked True => Copyrighted material */ + } else { + /* Checking usage terms as defined by the XMP Rights Management + * Schema. This field is recomended to be checked by Creative + * Commons */ + /* 1) checking for a suitable localized string */ + language_string = pango_language_to_string (gtk_get_default_language ()); + tags = g_strsplit (language_string, "-", -1); + i = g_strv_length (tags); + while (i-- && !license->text) { + tag = g_strdup (tags[0]); + for (j = 1; j <= i; j++) { + tag_aux = g_strdup_printf ("%s-%s", tag, tags[j]); + g_free (tag); + tag = tag_aux; + } + aux = g_strdup_printf (LICENSE_TEXT, tag); + xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx); + if (xpathObj != NULL) { + if (xpathObj->nodesetval != NULL && + xpathObj->nodesetval->nodeNr != 0) + license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]); + xmlXPathFreeObject (xpathObj); + } + g_free (tag); + g_free (aux); + } + g_strfreev(tags); + + /* 2) if not, use the default string */ + if (!license->text) { + aux = g_strdup_printf (LICENSE_TEXT, "x-default"); + xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx); + if (xpathObj != NULL) { + if (xpathObj->nodesetval != NULL && + xpathObj->nodesetval->nodeNr != 0) + license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]); + xmlXPathFreeObject (xpathObj); + } + g_free (aux); + } + + /* Checking the license URI as defined by the Creative Commons + * Schema. This field is recomended to be checked by Creative + * Commons */ + xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_URI, xpathCtx); + if (xpathObj != NULL) { + if (xpathObj->nodesetval != NULL && + xpathObj->nodesetval->nodeNr != 0) + license->uri = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]); + xmlXPathFreeObject (xpathObj); + } + + /* Checking the web statement as defined by the XMP Rights + * Management Schema. Checking it out is a sort of above-and-beyond + * the basic recommendations by Creative Commons. It can be + * considered as a "reinforcement" approach to add certainty. */ + xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_WEB_STATEMENT, xpathCtx); + if (xpathObj != NULL) { + if (xpathObj->nodesetval != NULL && + xpathObj->nodesetval->nodeNr != 0) + license->web_statement = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]); + xmlXPathFreeObject (xpathObj); + } + } + xmlFree (marked); + + if (!license->text && !license->uri && !license->web_statement) { + ev_document_license_free (license); + return NULL; + } + + return license; +} + +static void +pdf_document_parse_metadata (const gchar *metadata, + EvDocumentInfo *info) +{ + xmlDocPtr doc; + xmlXPathContextPtr xpathCtx; + gchar *fmt; + + doc = xmlParseMemory (metadata, strlen (metadata)); + if (doc == NULL) + return; /* invalid xml metadata */ + + xpathCtx = xmlXPathNewContext (doc); + if (xpathCtx == NULL) { + xmlFreeDoc (doc); + return; /* invalid xpath context */ + } + + fmt = pdf_document_get_format_from_metadata (doc, xpathCtx); + if (fmt != NULL) { + g_free (info->format); + info->format = fmt; + } + + info->license = pdf_document_get_license_from_metadata (doc, xpathCtx); + + xmlXPathFreeContext (xpathCtx); + xmlFreeDoc (doc); +} + static EvDocumentInfo * pdf_document_get_info (EvDocument *document) @@ -536,7 +685,6 @@ pdf_document_get_info (EvDocument *document) PopplerPermissions permissions; EvPage *page; char *metadata; - char *fmt; info = g_new0 (EvDocumentInfo, 1); @@ -556,7 +704,8 @@ pdf_document_get_info (EvDocument *document) EV_DOCUMENT_INFO_LINEARIZED | EV_DOCUMENT_INFO_N_PAGES | EV_DOCUMENT_INFO_SECURITY | - EV_DOCUMENT_INFO_PAPER_SIZE; + EV_DOCUMENT_INFO_PAPER_SIZE | + EV_DOCUMENT_INFO_LICENSE; g_object_get (PDF_DOCUMENT (document)->document, "title", &(info->title), @@ -577,11 +726,7 @@ pdf_document_get_info (EvDocument *document) NULL); if (metadata != NULL) { - fmt = pdf_document_get_format_from_metadata(metadata); - if (fmt != NULL) { - g_free (info->format); - info->format = fmt; - } + pdf_document_parse_metadata (metadata, info); g_free (metadata); } @@ -1115,7 +1260,7 @@ pdf_document_links_get_links_model (EvDocumentLinks *document_links) static GList * pdf_document_links_get_links (EvDocumentLinks *document_links, - gint page) + EvPage *page) { PdfDocument *pdf_document; PopplerPage *poppler_page; @@ -1125,8 +1270,7 @@ pdf_document_links_get_links (EvDocumentLinks *document_links, double height; pdf_document = PDF_DOCUMENT (document_links); - poppler_page = poppler_document_get_page (pdf_document->document, - page); + poppler_page = POPPLER_PAGE (page->backend_page); mapping_list = poppler_page_get_link_mapping (poppler_page); poppler_page_get_size (poppler_page, NULL, &height); @@ -1148,7 +1292,6 @@ pdf_document_links_get_links (EvDocumentLinks *document_links, } poppler_page_free_link_mapping (mapping_list); - g_object_unref (poppler_page); return g_list_reverse (retval); } @@ -1183,7 +1326,7 @@ pdf_document_document_links_iface_init (EvDocumentLinksIface *iface) static GList * pdf_document_images_get_image_mapping (EvDocumentImages *document_images, - gint page) + EvPage *page) { GList *retval = NULL; PdfDocument *pdf_document; @@ -1192,7 +1335,7 @@ pdf_document_images_get_image_mapping (EvDocumentImages *document_images, GList *list; pdf_document = PDF_DOCUMENT (document_images); - poppler_page = poppler_document_get_page (pdf_document->document, page); + poppler_page = POPPLER_PAGE (page->backend_page); mapping_list = poppler_page_get_image_mapping (poppler_page); for (list = mapping_list; list; list = list->next) { @@ -1203,7 +1346,7 @@ pdf_document_images_get_image_mapping (EvDocumentImages *document_images, ev_image_mapping = g_new (EvMapping, 1); - ev_image_mapping->data = ev_image_new (page, image_mapping->image_id); + ev_image_mapping->data = ev_image_new (page->index, image_mapping->image_id); ev_image_mapping->area.x1 = image_mapping->area.x1; ev_image_mapping->area.y1 = image_mapping->area.y1; ev_image_mapping->area.x2 = image_mapping->area.x2; @@ -1213,7 +1356,6 @@ pdf_document_images_get_image_mapping (EvDocumentImages *document_images, } poppler_page_free_image_mapping (mapping_list); - g_object_unref (poppler_page); return g_list_reverse (retval); } @@ -1867,15 +2009,15 @@ pdf_selection_get_selection_region (EvSelection *selection, } static GdkRegion * -pdf_selection_get_selection_map (EvSelection *selection, - EvRenderContext *rc) +pdf_selection_get_selection_map (EvSelection *selection, + EvPage *page) { PopplerPage *poppler_page; PopplerRectangle points; GList *region; GdkRegion *retval; - poppler_page = POPPLER_PAGE (rc->page->backend_page); + poppler_page = POPPLER_PAGE (page->backend_page); points.x1 = 0.0; points.y1 = 0.0; @@ -2366,7 +2508,7 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot, const gchar *unimplemented_annot = NULL; switch (poppler_annot_get_annot_type (poppler_annot)) { - case POPPLER_ANNOT_TEXT: + case POPPLER_ANNOT_TEXT: { PopplerAnnotText *poppler_text; EvAnnotationText *ev_annot_text; @@ -2376,8 +2518,41 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot, ev_annot_text = EV_ANNOTATION_TEXT (ev_annot); ev_annot_text->is_open = poppler_annot_text_get_is_open (poppler_text); + } + break; +#ifdef HAVE_POPPLER_ANNOT_FILE_ATTACHMENT_GET_ATTACHMENT + case POPPLER_ANNOT_FILE_ATTACHMENT: { + PopplerAnnotFileAttachment *poppler_annot_attachment; + EvAnnotationAttachment *ev_annot_attachment; + PopplerAttachment *poppler_attachment; + gchar *data = NULL; + gsize size; + GError *error = NULL; + + poppler_annot_attachment = POPPLER_ANNOT_FILE_ATTACHMENT (poppler_annot); + poppler_attachment = poppler_annot_file_attachment_get_attachment (poppler_annot_attachment); + + if (poppler_attachment && + attachment_save_to_buffer (poppler_attachment, &data, &size, &error)) { + EvAttachment *ev_attachment; + + ev_attachment = ev_attachment_new (poppler_attachment->name, + poppler_attachment->description, + poppler_attachment->mtime, + poppler_attachment->ctime, + size, data); + ev_annot = ev_annotation_attachment_new (page, ev_attachment); + g_object_unref (ev_attachment); + } else if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } + if (poppler_attachment) + g_object_unref (poppler_attachment); + } break; +#endif /* HAVE_POPPLER_ANNOT_FILE_ATTACHMENT_GET_ATTACHMENT */ case POPPLER_ANNOT_LINK: case POPPLER_ANNOT_WIDGET: /* Ignore link and widgets annots since they are already handled */