summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/fitz/document.h9
-rw-r--r--include/mupdf/fitz/link.h145
-rw-r--r--include/mupdf/fitz/outline.h12
-rw-r--r--include/mupdf/pdf/annot.h7
-rw-r--r--platform/android/viewer/jni/mupdf.c62
-rw-r--r--platform/gl/gl-main.c17
-rw-r--r--platform/ios/Classes/MuDocumentController.m13
-rw-r--r--platform/ios/Classes/MuHitView.m11
-rw-r--r--platform/java/mupdf_native.c22
-rw-r--r--platform/x11/pdfapp.c8
-rw-r--r--source/fitz/document.c9
-rw-r--r--source/fitz/link.c58
-rw-r--r--source/fitz/outline.c6
-rw-r--r--source/html/epub-doc.c48
-rw-r--r--source/html/html-layout.c14
-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
-rw-r--r--source/tools/murun.c29
-rw-r--r--source/xps/xps-link.c18
-rw-r--r--source/xps/xps-outline.c5
-rw-r--r--source/xps/xps-zip.c1
23 files changed, 248 insertions, 533 deletions
diff --git a/include/mupdf/fitz/document.h b/include/mupdf/fitz/document.h
index 7f3c8ece..d8123a00 100644
--- a/include/mupdf/fitz/document.h
+++ b/include/mupdf/fitz/document.h
@@ -32,6 +32,7 @@ typedef int (fz_document_authenticate_password_fn)(fz_context *ctx, fz_document
typedef int (fz_document_has_permission_fn)(fz_context *ctx, fz_document *doc, fz_permission permission);
typedef fz_outline *(fz_document_load_outline_fn)(fz_context *ctx, fz_document *doc);
typedef void (fz_document_layout_fn)(fz_context *ctx, fz_document *doc, float w, float h, float em);
+typedef int (fz_document_resolve_link_fn)(fz_context *ctx, fz_document *doc, const char *uri);
typedef int (fz_document_count_pages_fn)(fz_context *ctx, fz_document *doc);
typedef fz_page *(fz_document_load_page_fn)(fz_context *ctx, fz_document *doc, int number);
typedef int (fz_document_lookup_metadata_fn)(fz_context *ctx, fz_document *doc, const char *key, char *buf, int size);
@@ -87,6 +88,7 @@ struct fz_document_s
fz_document_has_permission_fn *has_permission;
fz_document_load_outline_fn *load_outline;
fz_document_layout_fn *layout;
+ fz_document_resolve_link_fn *resolve_link;
fz_document_count_pages_fn *count_pages;
fz_document_load_page_fn *load_page;
fz_document_lookup_metadata_fn *lookup_metadata;
@@ -210,6 +212,13 @@ void fz_layout_document(fz_context *ctx, fz_document *doc, float w, float h, flo
int fz_count_pages(fz_context *ctx, fz_document *doc);
/*
+ fz_resolve_link: Resolve an internal link to a page number.
+
+ Returns -1 if the URI cannot be resolved.
+*/
+int fz_resolve_link(fz_context *ctx, fz_document *doc, const char *uri);
+
+/*
fz_load_page: Load a page.
After fz_load_page is it possible to retrieve the size of the
diff --git a/include/mupdf/fitz/link.h b/include/mupdf/fitz/link.h
index 47abe1b4..e00d66d4 100644
--- a/include/mupdf/fitz/link.h
+++ b/include/mupdf/fitz/link.h
@@ -7,135 +7,10 @@
/*
Links
-
- NOTE: The link destination struct is scheduled for imminent change!
- Use at your own peril.
*/
typedef struct fz_link_s fz_link;
-typedef struct fz_link_dest_s fz_link_dest;
-
-typedef enum fz_link_kind_e
-{
- FZ_LINK_NONE = 0,
- FZ_LINK_GOTO,
- FZ_LINK_URI,
- FZ_LINK_LAUNCH,
- FZ_LINK_NAMED,
- FZ_LINK_GOTOR
-} fz_link_kind;
-
-enum {
- fz_link_flag_l_valid = 1, /* lt.x is valid */
- fz_link_flag_t_valid = 2, /* lt.y is valid */
- fz_link_flag_r_valid = 4, /* rb.x is valid */
- fz_link_flag_b_valid = 8, /* rb.y is valid */
- fz_link_flag_fit_h = 16, /* Fit horizontally */
- fz_link_flag_fit_v = 32, /* Fit vertically */
- fz_link_flag_r_is_zoom = 64 /* rb.x is actually a zoom figure */
-};
-
-/*
- fz_link_dest: This structure represents the destination of
- an fz_link; this may be a page to display, a new file to open,
- a javascript action to perform, etc.
-
- kind: This identifies the kind of link destination. Different
- kinds use different sections of the union.
-
- For FZ_LINK_GOTO or FZ_LINK_GOTOR:
-
- gotor.page: The target page number to move to (0 being the
- first page in the document). In the FZ_LINK_GOTOR case, the
- page number either refers to to the file specified by
- gotor.file_spec, or the page number is -1 suggesting that
- the destination is given by gotor.dest.
-
- gotor.dest: If set, the target destination name to be
- resolved in the file specified by gotor.file_spec. Always
- NULL in the FZ_LINK_GOTO case.
-
- gotor.flags: A bitfield consisting of fz_link_flag_*
- describing the validity and meaning of the different parts
- of gotor.lt and gotor.rb. Link destinations are constructed
- (as far as possible) so that lt and rb can be treated as a
- bounding box, though the validity flags indicate which of the
- values was actually specified in the file.
-
- gotor.lt: The top left corner of the destination bounding box.
-
- gotor.rb: The bottom right corner of the destination bounding
- box. If fz_link_flag_r_is_zoom is set, then the r figure
- should actually be interpreted as a zoom ratio.
-
- gotor.file_spec: If set, this destination should cause a new
- file to be opened; this field holds a pointer to a remote
- file specification (UTF-8). Always NULL in the FZ_LINK_GOTO
- case.
-
- gotor.new_window: If true, the destination should open in a
- new window. Always false in the FZ_LINK_GOTO case.
-
- For FZ_LINK_URI:
-
- uri.uri: A UTF-8 encoded URI to launch.
-
- uri.is_map: If true, the x and y coords (as ints, in user
- space) should be appended to the URI before launch.
-
- For FZ_LINK_LAUNCH:
-
- launch.file_spec: A UTF-8 file specification to launch.
-
- launch.new_window: If true, the destination should be launched
- in a new window.
-
- launch.is_uri: If true, launch.file_spec is a URI to launch.
-
- For FZ_LINK_NAMED:
-
- named.named: The named action to perform. Likely to be
- client specific.
-*/
-struct fz_link_dest_s
-{
- fz_link_kind kind;
- union
- {
- struct
- {
- int page;
- char *dest;
- int flags;
- fz_point lt;
- fz_point rb;
- char *file_spec;
- int new_window;
- }
- gotor;
- struct
- {
- char *uri;
- int is_map;
- }
- uri;
- struct
- {
- char *file_spec;
- int new_window;
- int is_uri;
- }
- launch;
- struct
- {
- char *named;
- }
- named;
- }
- ld;
-};
-
/*
fz_link is a list of interactive links on a page.
@@ -149,30 +24,34 @@ struct fz_link_dest_s
rect: The hot zone. The area that can be clicked in
untransformed coordinates.
- dest: Link destinations come in two forms: Page and area that
- an application should display when this link is activated. Or
- as an URI that can be given to a browser.
+ uri: Link destinations come in two forms: internal and external.
+ Internal links refer to other pages in the same document.
+ External links are URLs to other documents.
next: A pointer to the next link on the same page.
*/
struct fz_link_s
{
int refs;
- fz_rect rect;
- fz_link_dest dest;
fz_link *next;
+ fz_rect rect;
+ void *doc;
+ char *uri;
};
-fz_link *fz_new_link(fz_context *ctx, const fz_rect *bbox, fz_link_dest dest);
+fz_link *fz_new_link(fz_context *ctx, const fz_rect *bbox, void *doc, const char *uri);
fz_link *fz_keep_link(fz_context *ctx, fz_link *link);
/*
+ Checks if a link destination is external or internal.
+*/
+int fz_is_external_link(fz_context *ctx, const char *uri);
+
+/*
fz_drop_link: Drop and free a list of links.
Does not throw exceptions.
*/
void fz_drop_link(fz_context *ctx, fz_link *link);
-void fz_drop_link_dest(fz_context *ctx, fz_link_dest *dest);
-
#endif
diff --git a/include/mupdf/fitz/outline.h b/include/mupdf/fitz/outline.h
index c3f724bc..0223ecfa 100644
--- a/include/mupdf/fitz/outline.h
+++ b/include/mupdf/fitz/outline.h
@@ -15,9 +15,12 @@
title: Title of outline item using UTF-8 encoding. May be NULL
if the outline item has no text string.
- dest: Destination in the document to be displayed when this
- outline item is activated. May be FZ_LINK_NONE if the outline
- item does not have a destination.
+ uri: Destination in the document to be displayed when this
+ outline item is activated. May be an internal or external
+ link, or NULL if the outline item does not have a destination.
+
+ page: The page number of an internal link, or -1 for external
+ links or links with no destination.
next: The next outline item at the same level as this outline
item. May be NULL if no more outline items exist at this level.
@@ -32,7 +35,8 @@ struct fz_outline_s
{
int refs;
char *title;
- fz_link_dest dest;
+ char *uri;
+ int page;
fz_outline *next;
fz_outline *down;
int is_open;
diff --git a/include/mupdf/pdf/annot.h b/include/mupdf/pdf/annot.h
index 9cd80e06..caaa9047 100644
--- a/include/mupdf/pdf/annot.h
+++ b/include/mupdf/pdf/annot.h
@@ -101,13 +101,14 @@ struct pdf_annot_s
pdf_annot *next;
};
-fz_link_dest pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, fz_link_kind kind, pdf_obj *dest);
-char *pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec);
-fz_link_dest pdf_parse_action(fz_context *ctx, pdf_document *doc, pdf_obj *action);
+char *pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest);
+char *pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *obj);
+char *pdf_parse_link_action(fz_context *ctx, pdf_document *doc, pdf_obj *obj);
pdf_obj *pdf_lookup_dest(fz_context *ctx, pdf_document *doc, pdf_obj *needle);
pdf_obj *pdf_lookup_name(fz_context *ctx, pdf_document *doc, pdf_obj *which, pdf_obj *needle);
pdf_obj *pdf_load_name_tree(fz_context *ctx, pdf_document *doc, pdf_obj *which);
+int pdf_resolve_link(fz_context *ctx, pdf_document *doc, const char *uri);
fz_link *pdf_load_link_annots(fz_context *ctx, pdf_document *, pdf_obj *annots, const fz_matrix *page_ctm);
void pdf_annot_transform(fz_context *ctx, pdf_annot *annot, fz_matrix *annot_ctm);
diff --git a/platform/android/viewer/jni/mupdf.c b/platform/android/viewer/jni/mupdf.c
index 383228e1..ba992a43 100644
--- a/platform/android/viewer/jni/mupdf.c
+++ b/platform/android/viewer/jni/mupdf.c
@@ -1116,9 +1116,7 @@ countOutlineItems(fz_outline *outline)
while (outline)
{
- if (outline->dest.kind == FZ_LINK_GOTO
- && outline->dest.ld.gotor.page >= 0
- && outline->title)
+ if (outline->page >= 0 && outline->title)
count++;
count += countOutlineItems(outline->down);
@@ -1133,21 +1131,18 @@ fillInOutlineItems(JNIEnv * env, jclass olClass, jmethodID ctor, jobjectArray ar
{
while (outline)
{
- if (outline->dest.kind == FZ_LINK_GOTO)
+ int page = outline->page;
+ if (page >= 0 && outline->title)
{
- int page = outline->dest.ld.gotor.page;
- if (page >= 0 && outline->title)
- {
- jobject ol;
- jstring title = (*env)->NewStringUTF(env, outline->title);
- if (title == NULL) return -1;
- ol = (*env)->NewObject(env, olClass, ctor, level, title, page);
- if (ol == NULL) return -1;
- (*env)->SetObjectArrayElement(env, arr, pos, ol);
- (*env)->DeleteLocalRef(env, ol);
- (*env)->DeleteLocalRef(env, title);
- pos++;
- }
+ jobject ol;
+ jstring title = (*env)->NewStringUTF(env, outline->title);
+ if (title == NULL) return -1;
+ ol = (*env)->NewObject(env, olClass, ctor, level, title, page);
+ if (ol == NULL) return -1;
+ (*env)->SetObjectArrayElement(env, arr, pos, ol);
+ (*env)->DeleteLocalRef(env, ol);
+ (*env)->DeleteLocalRef(env, title);
+ pos++;
}
pos = fillInOutlineItems(env, olClass, ctor, arr, pos, outline->down, level+1);
if (pos < 0) return -1;
@@ -1857,13 +1852,8 @@ JNI_FN(MuPDFCore_getPageLinksInternal)(JNIEnv * env, jobject thiz, int pageNumbe
count = 0;
for (link = list; link; link = link->next)
{
- switch (link->dest.kind)
- {
- case FZ_LINK_GOTO:
- case FZ_LINK_GOTOR:
- case FZ_LINK_URI:
+ if (link->uri)
count++ ;
- }
}
arr = (*env)->NewObjectArray(env, count, linkInfoClass, NULL);
@@ -1879,36 +1869,18 @@ JNI_FN(MuPDFCore_getPageLinksInternal)(JNIEnv * env, jobject thiz, int pageNumbe
fz_rect rect = link->rect;
fz_transform_rect(&rect, &ctm);
- switch (link->dest.kind)
- {
- case FZ_LINK_GOTO:
+ if (!fz_is_external_link(ctx, link->uri))
{
linkInfo = (*env)->NewObject(env, linkInfoInternalClass, ctorInternal,
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
- link->dest.ld.gotor.page);
- break;
- }
-
- case FZ_LINK_GOTOR:
- {
- jstring juri = (*env)->NewStringUTF(env, link->dest.ld.gotor.file_spec);
- linkInfo = (*env)->NewObject(env, linkInfoRemoteClass, ctorRemote,
- (float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
- juri, link->dest.ld.gotor.page, link->dest.ld.gotor.new_window ? JNI_TRUE : JNI_FALSE);
- break;
+ fz_resolve_link(ctx, link->doc, link->uri));
}
-
- case FZ_LINK_URI:
+ else
{
- jstring juri = (*env)->NewStringUTF(env, link->dest.ld.uri.uri);
+ jstring juri = (*env)->NewStringUTF(env, link->uri);
linkInfo = (*env)->NewObject(env, linkInfoExternalClass, ctorExternal,
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
juri);
- break;
- }
-
- default:
- continue;
}
if (linkInfo == NULL)
diff --git a/platform/gl/gl-main.c b/platform/gl/gl-main.c
index 34d061be..9084827c 100644
--- a/platform/gl/gl-main.c
+++ b/platform/gl/gl-main.c
@@ -464,10 +464,9 @@ static int do_outline_imp(fz_outline *node, int end, int x0, int x1, int x, int
while (node)
{
- if (node->dest.kind == FZ_LINK_GOTO)
+ p = node->page;
+ if (p >= 0)
{
- p = node->dest.ld.gotor.page;
-
if (ui.x >= x0 && ui.x < x1 && ui.y >= y + h && ui.y < y + h + ui.lineheight)
{
ui.hot = node;
@@ -480,9 +479,9 @@ static int do_outline_imp(fz_outline *node, int end, int x0, int x1, int x, int
}
n = end;
- if (node->next && node->next->dest.kind == FZ_LINK_GOTO)
+ if (node->next && node->next->page >= 0)
{
- n = node->next->dest.ld.gotor.page;
+ n = node->next->page;
}
if (currentpage == p || (currentpage > p && currentpage < n))
{
@@ -587,10 +586,10 @@ static void do_links(fz_link *link, int xofs, int yofs)
{
if (ui.hot == link)
{
- if (link->dest.kind == FZ_LINK_GOTO)
- jump_to_page(link->dest.ld.gotor.page);
- else if (link->dest.kind == FZ_LINK_URI)
- open_browser(link->dest.ld.uri.uri);
+ if (fz_is_external_link(ctx, link->uri))
+ open_browser(link->uri);
+ else
+ jump_to_page(fz_resolve_link(ctx, doc, link->uri));
}
ui_needs_update = 1;
}
diff --git a/platform/ios/Classes/MuDocumentController.m b/platform/ios/Classes/MuDocumentController.m
index 02efe1ee..1e9f954c 100644
--- a/platform/ios/Classes/MuDocumentController.m
+++ b/platform/ios/Classes/MuDocumentController.m
@@ -28,15 +28,12 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out
indent[level * 4] = 0;
while (outline)
{
- if (outline->dest.kind == FZ_LINK_GOTO)
+ int page = outline->page;
+ if (page >= 0 && outline->title)
{
- int page = outline->dest.ld.gotor.page;
- if (page >= 0 && outline->title)
- {
- NSString *title = @(outline->title);
- [titles addObject: [NSString stringWithFormat: @"%s%@", indent, title]];
- [pages addObject: @(page)];
- }
+ NSString *title = @(outline->title);
+ [titles addObject: [NSString stringWithFormat: @"%s%@", indent, title]];
+ [pages addObject: @(page)];
}
flattenOutline(titles, pages, outline->down, level + 1);
outline = outline->next;
diff --git a/platform/ios/Classes/MuHitView.m b/platform/ios/Classes/MuHitView.m
index e94ac94a..b0a1ac4a 100644
--- a/platform/ios/Classes/MuHitView.m
+++ b/platform/ios/Classes/MuHitView.m
@@ -44,14 +44,19 @@
pageSize = CGSizeMake(100,100);
while (link && hitCount < nelem(hitRects)) {
- if (link->dest.kind == FZ_LINK_GOTO || link->dest.kind == FZ_LINK_URI) {
+ if (link->uri) {
fz_rect bbox = link->rect;
hitRects[hitCount].origin.x = bbox.x0;
hitRects[hitCount].origin.y = bbox.y0;
hitRects[hitCount].size.width = bbox.x1 - bbox.x0;
hitRects[hitCount].size.height = bbox.y1 - bbox.y0;
- linkPage[hitCount] = link->dest.kind == FZ_LINK_GOTO ? link->dest.ld.gotor.page : -1;
- linkUrl[hitCount] = link->dest.kind == FZ_LINK_URI ? strdup(link->dest.ld.uri.uri) : nil;
+ if (fz_is_external_link(ctx, link->uri)) {
+ linkPage[hitCount] = -1;
+ linkUrl[hitCount] = strdup(link->uri);
+ } else {
+ linkPage[hitCount] = fz_resolve_link(ctx, doc, link->uri);
+ linkUrl[hitCount] = nil;
+ }
hitCount++;
}
link = link->next;
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index e2191c0d..6cf6716a 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -993,7 +993,7 @@ string_to_String(fz_context *ctx, JNIEnv *env, const char *str)
return stringlen_to_String(ctx, env, str, strlen(str));
}
-static inline jobject to_Outline_safe(fz_context *ctx, JNIEnv *env, fz_outline *outline)
+static inline jobject to_Outline_safe(fz_context *ctx, JNIEnv *env, fz_document *doc, fz_outline *outline)
{
jobject joutline = NULL;
jobject jarr = NULL;
@@ -1025,17 +1025,17 @@ static inline jobject to_Outline_safe(fz_context *ctx, JNIEnv *env, fz_outline *
if (!jtitle) return NULL;
}
- if (outline->dest.kind == FZ_LINK_GOTO)
- jpage = outline->dest.ld.gotor.page;
- else if (outline->dest.kind == FZ_LINK_URI)
+ if (fz_is_external_link(ctx, outline->uri))
{
- juri = string_to_String(ctx, env, outline->dest.ld.uri.uri);
+ juri = string_to_String(ctx, env, outline->uri);
if (!juri) return NULL;
}
+ else
+ jpage = fz_resolve_link(ctx, doc, outline->uri);
if (outline->down)
{
- jdown = to_Outline_safe(ctx, env, outline->down);
+ jdown = to_Outline_safe(ctx, env, doc, outline->down);
if (!jdown) return NULL;
}
@@ -4265,7 +4265,7 @@ FUN(Document_loadOutline)(JNIEnv *env, jobject self)
if (outline)
{
- joutline = to_Outline_safe(ctx, env, outline);
+ joutline = to_Outline_safe(ctx, env, doc, outline);
if (!joutline)
jni_throw(env, FZ_ERROR_GENERIC, "loadOutline failed");
fz_drop_outline(ctx, outline);
@@ -4558,13 +4558,13 @@ FUN(Page_getLinks)(JNIEnv *env, jobject self)
jbounds = to_Rect_safe(ctx, env, &link->rect);
if (!jbounds) return NULL;
- if (link->dest.kind == FZ_LINK_GOTO)
- page = link->dest.ld.gotor.page;
- else if (link->dest.kind == FZ_LINK_URI)
+ if (fz_is_external_link(ctx, link->uri))
{
- juri = string_to_String(ctx, env, link->dest.ld.uri.uri);
+ juri = string_to_String(ctx, env, link->uri);
if (!juri) return NULL;
}
+ else
+ page = fz_resolve_link(ctx, link->doc, link->uri);
jlink = (*env)->NewObject(env, cls_Link, mid_Link_init, jbounds, page, juri);
(*env)->DeleteLocalRef(env, jbounds);
diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c
index 512feb2e..19983ee9 100644
--- a/platform/x11/pdfapp.c
+++ b/platform/x11/pdfapp.c
@@ -1737,10 +1737,10 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
wincursor(app, HAND);
if (btn == 1 && state == 1 && !processed)
{
- if (link->dest.kind == FZ_LINK_URI)
- pdfapp_gotouri(app, link->dest.ld.uri.uri);
- else if (link->dest.kind == FZ_LINK_GOTO)
- pdfapp_gotopage(app, link->dest.ld.gotor.page + 1);
+ if (fz_is_external_link(ctx, link->uri))
+ pdfapp_gotouri(app, link->uri);
+ else
+ pdfapp_gotopage(app, fz_resolve_link(ctx, app->doc, link->uri) + 1);
return;
}
}
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;