summaryrefslogtreecommitdiff
path: root/xps
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-02-01 15:06:55 +0000
committerRobin Watts <robin@ghostscript.com>2012-02-02 00:16:48 +0000
commit4ab5924753d32b5eaeb80138c6626057f61b516f (patch)
treed60def29f688c36ca474c5b06221d58ee82268db /xps
parent16c575d5b9fb0ce4488cac07d2b09ccbcaaf95c9 (diff)
downloadmupdf-4ab5924753d32b5eaeb80138c6626057f61b516f.tar.xz
Work on supporting links in xps documents.
Currently, this only works with local links. When running the page, check for NavigateUri entries; if found, and that page is not already marked as having resolved it's links, add a new link entry to doc->current_page links. When the page finishes running, mark the page as having resolved it's links. This avoids the links being generated multiple times. Update the mupdf viewer to use these links - but only AFTER the page has been run.
Diffstat (limited to 'xps')
-rw-r--r--xps/muxps.h7
-rw-r--r--xps/xps_doc.c68
-rw-r--r--xps/xps_glyphs.c5
-rw-r--r--xps/xps_path.c5
-rw-r--r--xps/xps_tile.c5
-rw-r--r--xps/xps_util.c4
6 files changed, 93 insertions, 1 deletions
diff --git a/xps/muxps.h b/xps/muxps.h
index fe0e5de1..2f87edc6 100644
--- a/xps/muxps.h
+++ b/xps/muxps.h
@@ -89,6 +89,8 @@ struct xps_page_s
int width;
int height;
xml_element *root;
+ int links_resolved;
+ fz_link *links;
xps_page *next;
};
@@ -111,7 +113,7 @@ void xps_free_page(xps_document *doc, xps_page *page);
fz_outline *xps_load_outline(xps_document *doc);
int xps_find_link_target(xps_document *doc, char *target_uri);
-
+void xps_add_link(xps_document *doc, fz_rect area, char *base_uri, char *target_uri);
/*
* Images, fonts, and colorspaces.
*/
@@ -245,6 +247,9 @@ struct xps_document_s
/* Current device */
fz_cookie *cookie;
fz_device *dev;
+
+ /* Current page we are loading */
+ xps_page *current_page;
};
xps_document *xps_open_document(fz_context *ctx, char *filename);
diff --git a/xps/xps_doc.c b/xps/xps_doc.c
index 36903266..d1943fc0 100644
--- a/xps/xps_doc.c
+++ b/xps/xps_doc.c
@@ -69,6 +69,69 @@ xps_add_fixed_document(xps_document *doc, char *name)
}
}
+void
+xps_add_link(xps_document *doc, fz_rect area, char *base_uri, char *target_uri)
+{
+ int len;
+ char *buffer = NULL;
+ char *uri;
+ xps_target *target;
+ fz_link_dest dest;
+ fz_link *link;
+ fz_context *ctx = doc->ctx;
+
+ fz_var(buffer);
+
+ if (doc->current_page == NULL || doc->current_page->links_resolved)
+ return;
+
+ fz_try(ctx)
+ {
+ len = 2 + (base_uri ? strlen(base_uri) : 0) +
+ (target_uri ? strlen(target_uri) : 0);
+ buffer = fz_malloc(doc->ctx, len);
+ xps_absolute_path(buffer, base_uri, target_uri, len);
+ uri = buffer;
+
+ /* FIXME: This won't work for remote docs */
+ /* Skip until we find the fragment marker */
+ while (*uri && *uri != '#')
+ uri++;
+ if (*uri == '#')
+ uri++;
+
+ for (target = doc->target; target; target = target->next)
+ if (!strcmp(target->name, uri))
+ break;
+
+ if (target == NULL)
+ break;
+
+ dest.kind = FZ_LINK_GOTO;
+ dest.ld.gotor.flags = fz_link_flag_l_valid | fz_link_flag_t_valid | fz_link_flag_r_valid | fz_link_flag_b_valid;
+ dest.ld.gotor.lt.x = area.x0;
+ dest.ld.gotor.lt.y = area.y0;
+ dest.ld.gotor.rb.x = area.x1;
+ dest.ld.gotor.rb.y = area.y1;
+ dest.ld.gotor.page = target->page;
+ dest.ld.gotor.file_spec = NULL;
+ dest.ld.gotor.new_window = 0;
+
+ link = fz_new_link(doc->ctx, area, dest);
+ link->next = doc->current_page->links;
+ doc->current_page->links = link;
+ }
+ fz_always(ctx)
+ {
+ fz_free(doc->ctx, buffer);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
+
static void
xps_add_fixed_page(xps_document *doc, char *name, int width, int height)
{
@@ -84,6 +147,8 @@ xps_add_fixed_page(xps_document *doc, char *name, int width, int height)
page->number = doc->page_count++;
page->width = width;
page->height = height;
+ page->links = NULL;
+ page->links_resolved = 0;
page->root = NULL;
page->next = NULL;
@@ -353,8 +418,10 @@ xps_load_page(xps_document *doc, int number)
{
if (n == number)
{
+ doc->current_page = page;
if (!page->root)
xps_load_fixed_page(doc, page);
+ page->links_resolved = 1;
return page;
}
n ++;
@@ -380,5 +447,6 @@ xps_free_page(xps_document *doc, xps_page *page)
/* only free the XML contents */
if (page->root)
xml_free_element(doc->ctx, page->root);
+ fz_free_link(doc->ctx, page->links);
page->root = NULL;
}
diff --git a/xps/xps_glyphs.c b/xps/xps_glyphs.c
index bbc49af1..0cc4af5d 100644
--- a/xps/xps_glyphs.c
+++ b/xps/xps_glyphs.c
@@ -387,6 +387,7 @@ xps_parse_glyphs(xps_document *doc, fz_matrix ctm,
char *clip_att;
char *opacity_att;
char *opacity_mask_att;
+ char *navigate_uri_att;
xml_element *transform_tag = NULL;
xml_element *clip_tag = NULL;
@@ -428,6 +429,7 @@ xps_parse_glyphs(xps_document *doc, fz_matrix ctm,
clip_att = xml_att(root, "Clip");
opacity_att = xml_att(root, "Opacity");
opacity_mask_att = xml_att(root, "OpacityMask");
+ navigate_uri_att = xml_att(root, "FixedPage.NavigateUri");
for (node = xml_down(root); node; node = xml_next(node))
{
@@ -545,6 +547,9 @@ xps_parse_glyphs(xps_document *doc, fz_matrix ctm,
area = fz_bound_text(doc->ctx, text, ctm);
+ if (navigate_uri_att)
+ xps_add_link(doc, area, base_uri, navigate_uri_att);
+
xps_begin_opacity(doc, ctm, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
/* If it's a solid color brush fill/stroke do a simple fill */
diff --git a/xps/xps_path.c b/xps/xps_path.c
index c49a55a6..77bb6a36 100644
--- a/xps/xps_path.c
+++ b/xps/xps_path.c
@@ -837,6 +837,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
char *stroke_line_join_att;
char *stroke_miter_limit_att;
char *stroke_thickness_att;
+ char *navigate_uri_att;
fz_stroke_state stroke;
fz_matrix transform;
@@ -866,6 +867,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
stroke_line_join_att = xml_att(root, "StrokeLineJoin");
stroke_miter_limit_att = xml_att(root, "StrokeMiterLimit");
stroke_thickness_att = xml_att(root, "StrokeThickness");
+ navigate_uri_att = xml_att(root, "FixedPage.NavigateUri");
for (node = xml_down(root); node; node = xml_next(node))
{
@@ -976,6 +978,9 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
else
area = fz_bound_path(path, NULL, ctm);
+ if (navigate_uri_att)
+ xps_add_link(doc, area, base_uri, navigate_uri_att);
+
xps_begin_opacity(doc, ctm, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
if (fill_att)
diff --git a/xps/xps_tile.c b/xps/xps_tile.c
index b672724b..fe4d2350 100644
--- a/xps/xps_tile.c
+++ b/xps/xps_tile.c
@@ -255,6 +255,7 @@ xps_parse_canvas(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri,
char *clip_att;
char *opacity_att;
char *opacity_mask_att;
+ char *navigate_uri_att;
xml_element *transform_tag = NULL;
xml_element *clip_tag = NULL;
@@ -266,6 +267,7 @@ xps_parse_canvas(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri,
clip_att = xml_att(root, "Clip");
opacity_att = xml_att(root, "Opacity");
opacity_mask_att = xml_att(root, "OpacityMask");
+ navigate_uri_att = xml_att(root, "FixedPage.NavigateUri");
for (node = xml_down(root); node; node = xml_next(node))
{
@@ -301,6 +303,9 @@ xps_parse_canvas(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri,
xps_parse_matrix_transform(doc, transform_tag, &transform);
ctm = fz_concat(transform, ctm);
+ if (navigate_uri_att)
+ xps_add_link(doc, area, base_uri, navigate_uri_att);
+
if (clip_att || clip_tag)
xps_clip(doc, ctm, dict, clip_att, clip_tag);
diff --git a/xps/xps_util.c b/xps/xps_util.c
index d6e226b5..6af4da91 100644
--- a/xps/xps_util.c
+++ b/xps/xps_util.c
@@ -77,6 +77,10 @@ xps_clean_path(char *name)
return name;
}
+/* RJW: Possible problems here:
+ * "/foo" + "../../bar" = "/bar" not "../bar"
+ * "http://something/" + ... doesn't work.
+ */
void
xps_absolute_path(char *output, char *base_uri, char *path, int output_size)
{