summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2016-10-17 17:13:32 +0200
committerTor Andersson <tor.andersson@artifex.com>2016-10-28 16:18:38 +0200
commit8a07b7fb14f11204a0d840792ab9f4bd54b066e5 (patch)
treee617a898c17aeb353f35d7b362ca2de290cf2b82 /source/pdf
parent4029b45e494634361a4205f8896ec429d11e990a (diff)
downloadmupdf-8a07b7fb14f11204a0d840792ab9f4bd54b066e5.tar.xz
Clean up link destination handling.
All link destinations should be URIs, and a document specific function can be called to resolve them to actual page numbers. Outlines have cached page numbers as well as string URIs.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-annot.c272
-rw-r--r--source/pdf/pdf-outline.c8
-rw-r--r--source/pdf/pdf-page.c6
-rw-r--r--source/pdf/pdf-xref.c1
4 files changed, 86 insertions, 201 deletions
diff --git a/source/pdf/pdf-annot.c b/source/pdf/pdf-annot.c
index a0220099..44c30fe9 100644
--- a/source/pdf/pdf-annot.c
+++ b/source/pdf/pdf-annot.c
@@ -1,19 +1,15 @@
#include "mupdf/pdf.h"
static pdf_obj *
-resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, fz_link_kind kind, int depth)
+resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, int depth)
{
if (depth > 10) /* Arbitrary to avoid infinite recursion */
return NULL;
if (pdf_is_name(ctx, dest) || pdf_is_string(ctx, dest))
{
- if (kind == FZ_LINK_GOTO)
- {
- dest = pdf_lookup_dest(ctx, doc, dest);
- dest = resolve_dest_rec(ctx, doc, dest, kind, depth+1);
- }
-
+ dest = pdf_lookup_dest(ctx, doc, dest);
+ dest = resolve_dest_rec(ctx, doc, dest, depth+1);
return dest;
}
@@ -25,7 +21,7 @@ resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, fz_link_kind
else if (pdf_is_dict(ctx, dest))
{
dest = pdf_dict_get(ctx, dest, PDF_NAME_D);
- return resolve_dest_rec(ctx, doc, dest, kind, depth+1);
+ return resolve_dest_rec(ctx, doc, dest, depth+1);
}
else if (pdf_is_indirect(ctx, dest))
@@ -35,193 +31,63 @@ resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, fz_link_kind
}
static pdf_obj *
-resolve_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest, fz_link_kind kind)
+resolve_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
- return resolve_dest_rec(ctx, doc, dest, kind, 0);
+ return resolve_dest_rec(ctx, doc, dest, 0);
}
-fz_link_dest
-pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, fz_link_kind kind, pdf_obj *dest)
+char *
+pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
- fz_link_dest ld;
pdf_obj *obj;
+ char buf[40];
+ char *ld;
- int l_from_2 = 0;
- int b_from_3 = 0;
- int r_from_4 = 0;
- int t_from_5 = 0;
- int t_from_3 = 0;
- int t_from_2 = 0;
- int z_from_4 = 0;
-
- ld.kind = kind;
- ld.ld.gotor.flags = 0;
- ld.ld.gotor.lt.x = 0;
- ld.ld.gotor.lt.y = 0;
- ld.ld.gotor.rb.x = 0;
- ld.ld.gotor.rb.y = 0;
- ld.ld.gotor.page = -1;
- ld.ld.gotor.dest = NULL;
-
- dest = resolve_dest(ctx, doc, dest, kind);
+ dest = resolve_dest(ctx, doc, dest);
if (dest == NULL)
{
fz_warn(ctx, "undefined link destination");
- return ld;
+ return NULL;
}
if (pdf_is_name(ctx, dest))
{
- ld.ld.gotor.dest = pdf_to_name(ctx, dest);
- return ld;
+ ld = pdf_to_name(ctx, dest);
+ return fz_strdup(ctx, ld);
}
else if (pdf_is_string(ctx, dest))
{
- ld.ld.gotor.dest = pdf_to_str_buf(ctx, dest);
- return ld;
+ ld = pdf_to_str_buf(ctx, dest);
+ return fz_strdup(ctx, ld);
}
obj = pdf_array_get(ctx, dest, 0);
if (pdf_is_int(ctx, obj))
- ld.ld.gotor.page = pdf_to_int(ctx, obj);
- else
- {
- fz_try(ctx)
- {
- ld.ld.gotor.page = pdf_lookup_page_number(ctx, doc, obj);
- }
- fz_catch(ctx)
- {
- ld.kind = FZ_LINK_NONE;
- return ld;
- }
- }
-
- obj = pdf_array_get(ctx, dest, 1);
- if (!pdf_is_name(ctx, obj))
- return ld;
-
- if (pdf_name_eq(ctx, PDF_NAME_XYZ, obj))
- {
- l_from_2 = t_from_3 = z_from_4 = 1;
- ld.ld.gotor.flags |= fz_link_flag_r_is_zoom;
- }
- else if ((pdf_name_eq(ctx, PDF_NAME_Fit, obj)) || (pdf_name_eq(ctx, PDF_NAME_FitB, obj)))
{
- ld.ld.gotor.flags |= fz_link_flag_fit_h;
- ld.ld.gotor.flags |= fz_link_flag_fit_v;
+ sprintf(buf, "#%d", pdf_to_int(ctx, obj) + 1);
+ return fz_strdup(ctx, buf);
}
- else if ((pdf_name_eq(ctx, PDF_NAME_FitH, obj)) || (pdf_name_eq(ctx, PDF_NAME_FitBH, obj)))
- {
- t_from_2 = 1;
- ld.ld.gotor.flags |= fz_link_flag_fit_h;
- }
- else if ((pdf_name_eq(ctx, PDF_NAME_FitV, obj)) || (pdf_name_eq(ctx, PDF_NAME_FitBV, obj)))
- {
- l_from_2 = 1;
- ld.ld.gotor.flags |= fz_link_flag_fit_v;
- }
- else if (pdf_name_eq(ctx, PDF_NAME_FitR, obj))
- {
- l_from_2 = b_from_3 = r_from_4 = t_from_5 = 1;
- ld.ld.gotor.flags |= fz_link_flag_fit_h;
- ld.ld.gotor.flags |= fz_link_flag_fit_v;
- }
-
- if (l_from_2)
- {
- obj = pdf_array_get(ctx, dest, 2);
- if (pdf_is_int(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_l_valid;
- ld.ld.gotor.lt.x = pdf_to_int(ctx, obj);
- }
- else if (pdf_is_real(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_l_valid;
- ld.ld.gotor.lt.x = pdf_to_real(ctx, obj);
- }
- }
- if (b_from_3)
- {
- obj = pdf_array_get(ctx, dest, 3);
- if (pdf_is_int(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_b_valid;
- ld.ld.gotor.rb.y = pdf_to_int(ctx, obj);
- }
- else if (pdf_is_real(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_b_valid;
- ld.ld.gotor.rb.y = pdf_to_real(ctx, obj);
- }
- }
- if (r_from_4)
- {
- obj = pdf_array_get(ctx, dest, 4);
- if (pdf_is_int(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_r_valid;
- ld.ld.gotor.rb.x = pdf_to_int(ctx, obj);
- }
- else if (pdf_is_real(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_r_valid;
- ld.ld.gotor.rb.x = pdf_to_real(ctx, obj);
- }
- }
- if (t_from_5 || t_from_3 || t_from_2)
- {
- if (t_from_5)
- obj = pdf_array_get(ctx, dest, 5);
- else if (t_from_3)
- obj = pdf_array_get(ctx, dest, 3);
- else
- obj = pdf_array_get(ctx, dest, 2);
- if (pdf_is_int(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_t_valid;
- ld.ld.gotor.lt.y = pdf_to_int(ctx, obj);
- }
- else if (pdf_is_real(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_t_valid;
- ld.ld.gotor.lt.y = pdf_to_real(ctx, obj);
- }
- }
- if (z_from_4)
+ else
{
- obj = pdf_array_get(ctx, dest, 4);
- if (pdf_is_int(ctx, obj))
+ int page = pdf_lookup_page_number(ctx, doc, obj);
+ if (page >= 0)
{
- ld.ld.gotor.flags |= fz_link_flag_r_valid;
- ld.ld.gotor.rb.x = pdf_to_int(ctx, obj);
- }
- else if (pdf_is_real(ctx, obj))
- {
- ld.ld.gotor.flags |= fz_link_flag_r_valid;
- ld.ld.gotor.rb.x = pdf_to_real(ctx, obj);
+ sprintf(buf, "#%d", page + 1);
+ return fz_strdup(ctx, buf);
}
}
- /* Duplicate the values out for the sake of stupid clients */
- if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid)) == fz_link_flag_l_valid)
- ld.ld.gotor.rb.x = ld.ld.gotor.lt.x;
- if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid | fz_link_flag_r_is_zoom)) == fz_link_flag_r_valid)
- ld.ld.gotor.lt.x = ld.ld.gotor.rb.x;
- if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_t_valid)
- ld.ld.gotor.rb.y = ld.ld.gotor.lt.y;
- if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_b_valid)
- ld.ld.gotor.lt.y = ld.ld.gotor.rb.y;
-
- return ld;
+ return NULL;
}
char *
-pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec)
+pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest)
{
pdf_obj *filename=NULL;
char *path = NULL;
+ char *uri = NULL;
+ char buf[256];
+ size_t n;
if (pdf_is_string(ctx, file_spec))
filename = file_spec;
@@ -260,54 +126,56 @@ pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec)
}
}
#endif
- return path;
+
+ if (pdf_is_array(ctx, dest))
+ fz_snprintf(buf, sizeof buf, "#%d", pdf_to_int(ctx, pdf_array_get(ctx, dest, 0)) + 1);
+ else if (pdf_is_name(ctx, dest))
+ fz_snprintf(buf, sizeof buf, "#%s", pdf_to_name(ctx, dest));
+ else if (pdf_is_stream(ctx, dest))
+ fz_snprintf(buf, sizeof buf, "#%s", pdf_to_str_buf(ctx, dest));
+ else
+ buf[0] = 0;
+
+ n = 7 + strlen(path) + strlen(buf) + 1;
+ uri = fz_malloc(ctx, n);
+ fz_strlcpy(uri, "file://", n);
+ fz_strlcat(uri, path, n);
+ fz_strlcat(uri, buf, n);
+ fz_free(ctx, path);
+ return uri;
}
-fz_link_dest
-pdf_parse_action(fz_context *ctx, pdf_document *doc, pdf_obj *action)
+char *
+pdf_parse_link_action(fz_context *ctx, pdf_document *doc, pdf_obj *action)
{
- fz_link_dest ld;
pdf_obj *obj, *dest, *file_spec;
- ld.kind = FZ_LINK_NONE;
-
if (!action)
- return ld;
+ return NULL;
obj = pdf_dict_get(ctx, action, PDF_NAME_S);
if (pdf_name_eq(ctx, PDF_NAME_GoTo, obj))
{
dest = pdf_dict_get(ctx, action, PDF_NAME_D);
- ld = pdf_parse_link_dest(ctx, doc, FZ_LINK_GOTO, dest);
+ return pdf_parse_link_dest(ctx, doc, dest);
}
else if (pdf_name_eq(ctx, PDF_NAME_URI, obj))
{
- ld.kind = FZ_LINK_URI;
- ld.ld.uri.is_map = pdf_to_bool(ctx, pdf_dict_get(ctx, action, PDF_NAME_IsMap));
- ld.ld.uri.uri = pdf_to_utf8(ctx, pdf_dict_get(ctx, action, PDF_NAME_URI));
+ return pdf_to_utf8(ctx, pdf_dict_get(ctx, action, PDF_NAME_URI));
}
else if (pdf_name_eq(ctx, PDF_NAME_Launch, obj))
{
- ld.kind = FZ_LINK_LAUNCH;
file_spec = pdf_dict_get(ctx, action, PDF_NAME_F);
- ld.ld.launch.file_spec = pdf_parse_file_spec(ctx, doc, file_spec);
- ld.ld.launch.new_window = pdf_to_int(ctx, pdf_dict_get(ctx, action, PDF_NAME_NewWindow));
- ld.ld.launch.is_uri = pdf_name_eq(ctx, PDF_NAME_URL, pdf_dict_get(ctx, file_spec, PDF_NAME_FS));
- }
- else if (pdf_name_eq(ctx, PDF_NAME_Named, obj))
- {
- ld.kind = FZ_LINK_NAMED;
- ld.ld.named.named = fz_strdup(ctx, pdf_to_name(ctx, pdf_dict_get(ctx, action, PDF_NAME_N)));
+ return pdf_parse_file_spec(ctx, doc, file_spec, NULL);
}
else if (pdf_name_eq(ctx, PDF_NAME_GoToR, obj))
{
dest = pdf_dict_get(ctx, action, PDF_NAME_D);
file_spec = pdf_dict_get(ctx, action, PDF_NAME_F);
- ld = pdf_parse_link_dest(ctx, doc, FZ_LINK_GOTOR, dest);
- ld.ld.gotor.file_spec = pdf_parse_file_spec(ctx, doc, file_spec);
- ld.ld.gotor.new_window = pdf_to_int(ctx, pdf_dict_get(ctx, action, PDF_NAME_NewWindow));
+ return pdf_parse_file_spec(ctx, doc, file_spec, dest);
}
- return ld;
+
+ return NULL;
}
static fz_link *
@@ -316,31 +184,34 @@ pdf_load_link(fz_context *ctx, pdf_document *doc, pdf_obj *dict, const fz_matrix
pdf_obj *action;
pdf_obj *obj;
fz_rect bbox;
- fz_link_dest ld;
+ char *uri;
+ fz_link *link;
obj = pdf_dict_get(ctx, dict, PDF_NAME_Rect);
- if (obj)
- pdf_to_rect(ctx, obj, &bbox);
- else
- bbox = fz_empty_rect;
+ if (!obj)
+ return NULL;
+ pdf_to_rect(ctx, obj, &bbox);
fz_transform_rect(&bbox, page_ctm);
obj = pdf_dict_get(ctx, dict, PDF_NAME_Dest);
if (obj)
- ld = pdf_parse_link_dest(ctx, doc, FZ_LINK_GOTO, obj);
+ uri = pdf_parse_link_dest(ctx, doc, obj);
else
{
action = pdf_dict_get(ctx, dict, PDF_NAME_A);
/* fall back to additional action button's down/up action */
if (!action)
action = pdf_dict_geta(ctx, pdf_dict_get(ctx, dict, PDF_NAME_AA), PDF_NAME_U, PDF_NAME_D);
-
- ld = pdf_parse_action(ctx, doc, action);
+ uri = pdf_parse_link_action(ctx, doc, action);
}
- if (ld.kind == FZ_LINK_NONE)
+
+ if (!uri)
return NULL;
- return fz_new_link(ctx, &bbox, ld);
+
+ link = fz_new_link(ctx, &bbox, doc, uri);
+ fz_free(ctx, uri);
+ return link;
}
fz_link *
@@ -383,6 +254,15 @@ pdf_load_link_annots(fz_context *ctx, pdf_document *doc, pdf_obj *annots, const
return head;
}
+int
+pdf_resolve_link(fz_context *ctx, pdf_document *doc, const char *uri)
+{
+ if (uri && uri[0] == '#')
+ return fz_atoi(uri + 1) - 1;
+ fz_warn(ctx, "unknown link uri '%s'", uri);
+ return -1;
+}
+
static void
pdf_drop_annot_imp(fz_context *ctx, pdf_annot *annot)
{
diff --git a/source/pdf/pdf-outline.c b/source/pdf/pdf-outline.c
index c9fd35fe..d82db02c 100644
--- a/source/pdf/pdf-outline.c
+++ b/source/pdf/pdf-outline.c
@@ -27,9 +27,13 @@ pdf_load_outline_imp(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
node->title = pdf_to_utf8(ctx, obj);
if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_Dest)) != NULL)
- node->dest = pdf_parse_link_dest(ctx, doc, FZ_LINK_GOTO, obj);
+ node->uri = pdf_parse_link_dest(ctx, doc, obj);
else if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_A)) != NULL)
- node->dest = pdf_parse_action(ctx, doc, obj);
+ node->uri = pdf_parse_link_action(ctx, doc, obj);
+ else
+ node->uri = NULL;
+
+ node->page = pdf_resolve_link(ctx, doc, node->uri);
obj = pdf_dict_get(ctx, dict, PDF_NAME_First);
if (obj)
diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c
index 0cfb5dae..7c7005e3 100644
--- a/source/pdf/pdf-page.c
+++ b/source/pdf/pdf-page.c
@@ -204,7 +204,7 @@ int
pdf_lookup_anchor(fz_context *ctx, pdf_document *doc, const char *name)
{
pdf_obj *needle, *dest;
- fz_link_dest ld;
+ char *uri;
needle = pdf_new_string(ctx, doc, name, strlen(name));
fz_try(ctx)
@@ -214,8 +214,8 @@ pdf_lookup_anchor(fz_context *ctx, pdf_document *doc, const char *name)
fz_catch(ctx)
fz_rethrow(ctx);
- ld = pdf_parse_link_dest(ctx, doc, FZ_LINK_GOTO, dest);
- return ld.ld.gotor.page;
+ uri = pdf_parse_link_dest(ctx, doc, dest);
+ return pdf_resolve_link(ctx, doc, uri);
}
static pdf_obj *
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index c46d9f52..070e0946 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -2343,6 +2343,7 @@ pdf_new_document(fz_context *ctx, fz_stream *file)
doc->super.authenticate_password = (fz_document_authenticate_password_fn *)pdf_authenticate_password;
doc->super.has_permission = (fz_document_has_permission_fn *)pdf_has_permission;
doc->super.load_outline = (fz_document_load_outline_fn *)pdf_load_outline;
+ doc->super.resolve_link = (fz_document_resolve_link_fn *)pdf_resolve_link;
doc->super.count_pages = (fz_document_count_pages_fn *)pdf_count_pages;
doc->super.load_page = (fz_document_load_page_fn *)pdf_load_page;
doc->super.lookup_metadata = (fz_document_lookup_metadata_fn *)pdf_lookup_metadata;