diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2016-10-17 17:13:32 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2016-10-28 16:18:38 +0200 |
commit | 8a07b7fb14f11204a0d840792ab9f4bd54b066e5 (patch) | |
tree | e617a898c17aeb353f35d7b362ca2de290cf2b82 /source | |
parent | 4029b45e494634361a4205f8896ec429d11e990a (diff) | |
download | mupdf-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')
-rw-r--r-- | source/fitz/document.c | 9 | ||||
-rw-r--r-- | source/fitz/link.c | 58 | ||||
-rw-r--r-- | source/fitz/outline.c | 6 | ||||
-rw-r--r-- | source/html/epub-doc.c | 48 | ||||
-rw-r--r-- | source/html/html-layout.c | 14 | ||||
-rw-r--r-- | source/pdf/pdf-annot.c | 272 | ||||
-rw-r--r-- | source/pdf/pdf-outline.c | 8 | ||||
-rw-r--r-- | source/pdf/pdf-page.c | 6 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 1 | ||||
-rw-r--r-- | source/tools/murun.c | 29 | ||||
-rw-r--r-- | source/xps/xps-link.c | 18 | ||||
-rw-r--r-- | source/xps/xps-outline.c | 5 | ||||
-rw-r--r-- | source/xps/xps-zip.c | 1 |
13 files changed, 162 insertions, 313 deletions
diff --git a/source/fitz/document.c b/source/fitz/document.c index 43fcb133..87ad3884 100644 --- a/source/fitz/document.c +++ b/source/fitz/document.c @@ -215,6 +215,15 @@ fz_load_outline(fz_context *ctx, fz_document *doc) return NULL; } +int +fz_resolve_link(fz_context *ctx, fz_document *doc, const char *uri) +{ + fz_ensure_layout(ctx, doc); + if (doc && doc->resolve_link) + return doc->resolve_link(ctx, doc, uri); + return -1; +} + void fz_layout_document(fz_context *ctx, fz_document *doc, float w, float h, float em) { diff --git a/source/fitz/link.c b/source/fitz/link.c index eaed1402..430c9bfe 100644 --- a/source/fitz/link.c +++ b/source/fitz/link.c @@ -1,51 +1,25 @@ #include "mupdf/fitz.h" -void -fz_drop_link_dest(fz_context *ctx, fz_link_dest *dest) -{ - if (!dest) - return; - - switch (dest->kind) - { - case FZ_LINK_NONE: - break; - case FZ_LINK_GOTO: - fz_free(ctx, dest->ld.gotor.dest); - break; - case FZ_LINK_URI: - fz_free(ctx, dest->ld.uri.uri); - break; - case FZ_LINK_LAUNCH: - fz_free(ctx, dest->ld.launch.file_spec); - break; - case FZ_LINK_NAMED: - fz_free(ctx, dest->ld.named.named); - break; - case FZ_LINK_GOTOR: - fz_free(ctx, dest->ld.gotor.file_spec); - break; - } -} - fz_link * -fz_new_link(fz_context *ctx, const fz_rect *bbox, fz_link_dest dest) +fz_new_link(fz_context *ctx, const fz_rect *bbox, void *doc, const char *uri) { fz_link *link; + link = fz_malloc_struct(ctx, fz_link); + link->refs = 1; + link->rect = *bbox; + link->next = NULL; + link->doc = doc; /* don't take reference */ + link->uri = NULL; + fz_try(ctx) - { - link = fz_malloc_struct(ctx, fz_link); - link->refs = 1; - } + link->uri = fz_strdup(ctx, uri); fz_catch(ctx) { - fz_drop_link_dest(ctx, &dest); + fz_drop_link(ctx, link); fz_rethrow(ctx); } - link->dest = dest; - link->rect = *bbox; - link->next = NULL; + return link; } @@ -61,8 +35,16 @@ fz_drop_link(fz_context *ctx, fz_link *link) while (fz_drop_imp(ctx, link, &link->refs)) { fz_link *next = link->next; - fz_drop_link_dest(ctx, &link->dest); + fz_free(ctx, link->uri); fz_free(ctx, link); link = next; } } + +int +fz_is_external_link(fz_context *ctx, const char *uri) +{ + while (*uri >= 'a' && *uri <= 'z') + ++uri; + return uri[0] == ':' && uri[1] == '/' && uri[2] == '/'; +} diff --git a/source/fitz/outline.c b/source/fitz/outline.c index 257c44c1..888212bc 100644 --- a/source/fitz/outline.c +++ b/source/fitz/outline.c @@ -22,7 +22,7 @@ fz_drop_outline(fz_context *ctx, fz_outline *outline) fz_outline *next = outline->next; fz_drop_outline(ctx, outline->down); fz_free(ctx, outline->title); - fz_drop_link_dest(ctx, &outline->dest); + fz_free(ctx, outline->uri); fz_free(ctx, outline); outline = next; } @@ -33,7 +33,7 @@ fz_debug_outline_xml_imp(fz_context *ctx, fz_output *out, fz_outline *outline, i { while (outline) { - fz_printf(ctx, out, "<outline title=%q page=\"%d\"", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); + fz_printf(ctx, out, "<outline title=%q uri=\"%s\"", outline->title, outline->uri); if (outline->down) { fz_printf(ctx, out, ">\n"); @@ -62,7 +62,7 @@ fz_print_outline_imp(fz_context *ctx, fz_output *out, fz_outline *outline, int l { for (i = 0; i < level; i++) fz_printf(ctx, out, "\t"); - fz_printf(ctx, out, "%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); + fz_printf(ctx, out, "%s\t%s\n", outline->title, outline->uri); if (outline->down) fz_print_outline_imp(ctx, out, outline->down, level + 1); outline = outline->next; diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c index efc4ac18..0616bb70 100644 --- a/source/html/epub-doc.c +++ b/source/html/epub-doc.c @@ -63,41 +63,40 @@ find_anchor_box(fz_html_box *box, const char *anchor, float page_h, int *page) return 0; } -static void -resolve_link_dest(fz_context *ctx, epub_document *doc, fz_link_dest *ld) +static int +epub_resolve_link(fz_context *ctx, fz_document *doc_, const char *dest) { + epub_document *doc = (epub_document*)doc_; epub_chapter *ch; + int page = -1; - if (ld->kind == FZ_LINK_GOTO) - { - const char *dest = ld->ld.gotor.dest; - const char *s = strchr(dest, '#'); - int n = s ? s - dest : strlen(dest); - if (s && s[1] == 0) - s = NULL; + const char *s = strchr(dest, '#'); + int n = s ? s - dest : strlen(dest); + if (s && s[1] == 0) + s = NULL; - for (ch = doc->spine; ch; ch = ch->next) + for (ch = doc->spine; ch; ch = ch->next) + { + if (!strncmp(ch->path, dest, n) && ch->path[n] == 0) { - if (strncmp(ch->path, dest, n) || ch->path[n] != 0) - continue; - ld->ld.gotor.page = ch->start; + page = ch->start; if (s) { /* Search for a matching fragment */ - if (find_anchor_box(ch->html->root, s+1, ch->page_h, &ld->ld.gotor.page)) - continue; + find_anchor_box(ch->html->root, s+1, ch->page_h, &page); } - break; } } + + return page; } static void -epub_update_outline(fz_context *ctx, epub_document *doc, fz_outline *node) +epub_update_outline(fz_context *ctx, fz_document *doc, fz_outline *node) { while (node) { - resolve_link_dest(ctx, doc, &node->dest); + node->page = epub_resolve_link(ctx, doc, node->uri); epub_update_outline(ctx, doc, node->down); node = node->next; } @@ -124,7 +123,7 @@ epub_layout(fz_context *ctx, fz_document *doc_, float w, float h, float em) count += ceilf(ch->html->root->h / ch->page_h); } - epub_update_outline(ctx, doc, doc->outline); + epub_update_outline(ctx, doc_, doc->outline); } static int @@ -211,14 +210,13 @@ epub_load_links(fz_context *ctx, fz_page *page_) head = fz_load_html_links(ctx, ch->html, n - count, ch->page_h, ch->path); for (link = head; link; link = link->next) { + link->doc = doc; + /* Adjust for page margins */ link->rect.x0 += ch->page_margin[L]; link->rect.x1 += ch->page_margin[L]; link->rect.y0 += ch->page_margin[T]; link->rect.y1 += ch->page_margin[T]; - - /* Resolve local links */ - resolve_link_dest(ctx, doc, &link->dest); } return head; } @@ -343,9 +341,8 @@ epub_parse_ncx_imp(fz_context *ctx, epub_document *doc, fz_xml *node, char *base *tailp = outline = fz_new_outline(ctx); tailp = &(*tailp)->next; outline->title = fz_strdup(ctx, text); - outline->dest.kind = FZ_LINK_GOTO; - outline->dest.ld.gotor.dest = fz_strdup(ctx, path); - outline->dest.ld.gotor.page = 0; /* computed in epub_layout */ + outline->uri = fz_strdup(ctx, path); + outline->page = -1; outline->down = epub_parse_ncx_imp(ctx, doc, node, base_uri); } node = fz_xml_find_next(node, "navPoint"); @@ -494,6 +491,7 @@ epub_init(fz_context *ctx, fz_archive *zip) doc->super.drop_document = epub_drop_document; doc->super.layout = epub_layout; doc->super.load_outline = epub_load_outline; + doc->super.resolve_link = epub_resolve_link; doc->super.count_pages = epub_count_pages; doc->super.load_page = epub_load_page; doc->super.lookup_metadata = epub_lookup_metadata; diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 54a96c1d..b700b59b 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -1902,7 +1902,7 @@ static fz_link *load_link_flow(fz_context *ctx, fz_html_flow *flow, fz_link *hea fz_html_flow *next; char path[2048]; fz_rect bbox; - fz_link_dest dest; + char *dest; char *href; float end; @@ -1951,20 +1951,14 @@ static fz_link *load_link_flow(fz_context *ctx, fz_html_flow *flow, fz_link *hea fz_urldecode(path); fz_cleanname(path); - memset(&dest, 0, sizeof dest); - dest.kind = FZ_LINK_GOTO; - dest.ld.gotor.dest = fz_strdup(ctx, path); - dest.ld.gotor.page = 0; /* computed in epub_load_links */ + dest = path; } else { - memset(&dest, 0, sizeof dest); - dest.kind = FZ_LINK_URI; - dest.ld.uri.uri = fz_strdup(ctx, href); - dest.ld.uri.is_map = 0; + dest = href; } - link = fz_new_link(ctx, &bbox, dest); + link = fz_new_link(ctx, &bbox, NULL, dest); link->next = head; head = link; } 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; diff --git a/source/tools/murun.c b/source/tools/murun.c index fc887105..079a8c3c 100644 --- a/source/tools/murun.c +++ b/source/tools/murun.c @@ -1601,14 +1601,17 @@ static void to_outline(js_State *J, fz_outline *outline) js_pushundefined(J); js_setproperty(J, -2, "title"); - if (outline->dest.kind == FZ_LINK_GOTO) { - js_pushnumber(J, outline->dest.ld.gotor.page); - js_setproperty(J, -2, "page"); - } - if (outline->dest.kind == FZ_LINK_URI) { - js_pushstring(J, outline->dest.ld.uri.uri); - js_setproperty(J, -2, "uri"); - } + if (outline->uri) + js_pushstring(J, outline->uri); + else + js_pushundefined(J); + js_setproperty(J, -2, "uri"); + + if (outline->page >= 0) + js_pushnumber(J, outline->page); + else + js_pushundefined(J); + js_setproperty(J, -2, "page"); if (outline->down) { to_outline(J, outline->down); @@ -1821,14 +1824,8 @@ static void ffi_Page_getLinks(js_State *J) ffi_pushrect(J, link->rect); js_setproperty(J, -2, "bounds"); - if (link->dest.kind == FZ_LINK_GOTO) { - js_pushnumber(J, link->dest.ld.gotor.page); - js_setproperty(J, -2, "page"); - } - if (link->dest.kind == FZ_LINK_URI) { - js_pushstring(J, link->dest.ld.uri.uri); - js_setproperty(J, -2, "uri"); - } + js_pushstring(J, link->uri); + js_setproperty(J, -2, "uri"); js_setindex(J, -2, i++); } diff --git a/source/xps/xps-link.c b/source/xps/xps-link.c index 9986d25f..1b2423ad 100644 --- a/source/xps/xps-link.c +++ b/source/xps/xps-link.c @@ -10,23 +10,7 @@ xps_load_links_in_element(fz_context *ctx, xps_document *doc, const fz_matrix *c static void xps_add_link(fz_context *ctx, xps_document *doc, const fz_rect *area, char *base_uri, char *target_uri, fz_link **head) { - fz_link_dest dest; - fz_link *link; - - memset(&dest, 0, sizeof dest); - - if (xps_url_is_remote(ctx, doc, target_uri)) - { - dest.kind = FZ_LINK_URI; - dest.ld.uri.uri = fz_strdup(ctx, target_uri); - } - else - { - dest.kind = FZ_LINK_GOTO; - dest.ld.gotor.page = xps_lookup_link_target(ctx, doc, target_uri); - } - - link = fz_new_link(ctx, area, dest); + fz_link *link = fz_new_link(ctx, area, doc, target_uri); link->next = *head; *head = link; } diff --git a/source/xps/xps-outline.c b/source/xps/xps-outline.c index 50eaf960..1fe294fb 100644 --- a/source/xps/xps-outline.c +++ b/source/xps/xps-outline.c @@ -33,9 +33,8 @@ xps_parse_document_outline(fz_context *ctx, xps_document *doc, fz_xml *root) entry = fz_new_outline(ctx); entry->title = fz_strdup(ctx, description); - entry->dest.kind = FZ_LINK_GOTO; - entry->dest.ld.gotor.flags = 0; - entry->dest.ld.gotor.page = xps_lookup_link_target(ctx, doc, target); + entry->uri = fz_strdup(ctx, target); + entry->page = xps_lookup_link_target(ctx, doc, target); entry->down = NULL; entry->next = NULL; diff --git a/source/xps/xps-zip.c b/source/xps/xps-zip.c index b2cc9e77..ba9947c7 100644 --- a/source/xps/xps-zip.c +++ b/source/xps/xps-zip.c @@ -231,6 +231,7 @@ xps_init_document(fz_context *ctx, xps_document *doc) doc->super.refs = 1; doc->super.drop_document = (fz_document_drop_fn *)xps_drop_document; doc->super.load_outline = (fz_document_load_outline_fn *)xps_load_outline; + doc->super.resolve_link = (fz_document_resolve_link_fn *)xps_lookup_link_target; doc->super.count_pages = (fz_document_count_pages_fn *)xps_count_pages; doc->super.load_page = (fz_document_load_page_fn *)xps_load_page; doc->super.lookup_metadata = (fz_document_lookup_metadata_fn *)xps_lookup_metadata; |