summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2015-10-06 10:47:49 +0200
committerTor Andersson <tor.andersson@artifex.com>2015-10-06 11:20:30 +0200
commit6ffd32a570ab8a6f03737d0342667bee4d947985 (patch)
treea66134331d544812ba3c3b2b2c28e253e46f5a87
parent233baeea8e933c010c2270481b6a49ccc00454ca (diff)
downloadmupdf-6ffd32a570ab8a6f03737d0342667bee4d947985.tar.xz
xps: Add separate link parsing step.
Don't rely on having to run the page once with an identity transform before being able to load the links.
-rw-r--r--include/mupdf/xps.h7
-rw-r--r--platform/win32/libmupdf.vcproj4
-rw-r--r--source/xps/xps-doc.c85
-rw-r--r--source/xps/xps-glyphs.c5
-rw-r--r--source/xps/xps-link.c206
-rw-r--r--source/xps/xps-path.c5
-rw-r--r--source/xps/xps-tile.c6
7 files changed, 211 insertions, 107 deletions
diff --git a/include/mupdf/xps.h b/include/mupdf/xps.h
index 0e18eaba..eaeb331b 100644
--- a/include/mupdf/xps.h
+++ b/include/mupdf/xps.h
@@ -46,6 +46,7 @@ int xps_count_pages(fz_context *ctx, xps_document *doc);
xps_page *xps_load_page(fz_context *ctx, xps_document *doc, int number);
fz_outline *xps_load_outline(fz_context *ctx, xps_document *doc);
void xps_run_page(fz_context *ctx, xps_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie);
+fz_link *xps_load_links(fz_context *ctx, xps_page *page);
/* xps-internal.h */
@@ -96,8 +97,6 @@ struct xps_fixpage_s
int number;
int width;
int height;
- int links_resolved;
- fz_link *links;
xps_fixpage *next;
};
@@ -121,7 +120,6 @@ void xps_print_page_list(fz_context *ctx, xps_document *doc);
void xps_drop_page_list(fz_context *ctx, xps_document *doc);
int xps_lookup_link_target(fz_context *ctx, xps_document *doc, char *target_uri);
-void xps_add_link(fz_context *ctx, xps_document *doc, const fz_rect *area, char *base_uri, char *target_uri);
/*
* Images, fonts, and colorspaces.
@@ -259,9 +257,6 @@ struct xps_document_s
/* Current device */
fz_device *dev;
fz_cookie *cookie;
-
- /* Current page we are loading */
- xps_fixpage *current_page;
};
#endif
diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj
index ab335409..7c4b12be 100644
--- a/platform/win32/libmupdf.vcproj
+++ b/platform/win32/libmupdf.vcproj
@@ -691,6 +691,10 @@
>
</File>
<File
+ RelativePath="..\..\source\xps\xps-link.c"
+ >
+ </File>
+ <File
RelativePath="..\..\source\xps\xps-outline.c"
>
</File>
diff --git a/source/xps/xps-doc.c b/source/xps/xps-doc.c
index 6f45b431..95008e72 100644
--- a/source/xps/xps-doc.c
+++ b/source/xps/xps-doc.c
@@ -82,78 +82,6 @@ xps_add_fixed_document(fz_context *ctx, xps_document *doc, char *name)
}
}
-void
-xps_add_link(fz_context *ctx, xps_document *doc, const 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_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(ctx, len);
- xps_resolve_url(ctx, doc, buffer, base_uri, target_uri, len);
- if (xps_url_is_remote(ctx, doc, buffer))
- {
- dest.kind = FZ_LINK_URI;
- dest.ld.uri.is_map = 0;
- dest.ld.uri.uri = buffer;
- buffer = NULL;
- }
- else
- {
- 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 = 0;
- dest.ld.gotor.lt.x = 0;
- dest.ld.gotor.lt.y = 0;
- dest.ld.gotor.rb.x = 0;
- dest.ld.gotor.rb.y = 0;
- dest.ld.gotor.page = target->page;
- dest.ld.gotor.file_spec = NULL;
- dest.ld.gotor.new_window = 0;
- dest.ld.gotor.dest = NULL;
- }
-
- link = fz_new_link(ctx, area, dest);
- link->next = doc->current_page->links;
- doc->current_page->links = link;
- }
- fz_always(ctx)
- {
- fz_free(ctx, buffer);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
-}
-
static void
xps_add_fixed_page(fz_context *ctx, xps_document *doc, char *name, int width, int height)
{
@@ -169,8 +97,6 @@ xps_add_fixed_page(fz_context *ctx, xps_document *doc, char *name, int width, in
page->number = doc->page_count++;
page->width = width;
page->height = height;
- page->links = NULL;
- page->links_resolved = 0;
page->next = NULL;
if (!doc->first_page)
@@ -228,7 +154,6 @@ xps_drop_fixed_pages(fz_context *ctx, xps_document *doc)
while (page)
{
xps_fixpage *next = page->next;
- fz_drop_link(ctx, page->links);
fz_free(ctx, page->name);
fz_free(ctx, page);
page = next;
@@ -480,14 +405,6 @@ xps_load_fixed_page(fz_context *ctx, xps_document *doc, xps_fixpage *page)
return root;
}
-fz_link *
-xps_load_links(fz_context *ctx, xps_page *page)
-{
- if (!page->fix->links_resolved)
- fz_warn(ctx, "xps_load_links before page has been executed!");
- return fz_keep_link(ctx, page->fix->links);
-}
-
fz_rect *
xps_bound_page(fz_context *ctx, xps_page *page, fz_rect *bounds)
{
@@ -520,8 +437,6 @@ xps_load_page(fz_context *ctx, xps_document *doc, int number)
{
if (n == number)
{
- doc->current_page = fix;
-
root = xps_load_fixed_page(ctx, doc, fix);
fz_try(ctx)
{
diff --git a/source/xps/xps-glyphs.c b/source/xps/xps-glyphs.c
index f71bfac3..06d2820d 100644
--- a/source/xps/xps-glyphs.c
+++ b/source/xps/xps-glyphs.c
@@ -483,7 +483,6 @@ xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
char *clip_att;
char *opacity_att;
char *opacity_mask_att;
- char *navigate_uri_att;
fz_xml *transform_tag = NULL;
fz_xml *clip_tag = NULL;
@@ -521,7 +520,6 @@ xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
clip_att = fz_xml_att(root, "Clip");
opacity_att = fz_xml_att(root, "Opacity");
opacity_mask_att = fz_xml_att(root, "OpacityMask");
- navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
{
@@ -586,9 +584,6 @@ xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
fz_bound_text(ctx, text, NULL, &local_ctm, &area);
- if (navigate_uri_att)
- xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att);
-
xps_begin_opacity(ctx, doc, &local_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/source/xps/xps-link.c b/source/xps/xps-link.c
new file mode 100644
index 00000000..64abc2a7
--- /dev/null
+++ b/source/xps/xps-link.c
@@ -0,0 +1,206 @@
+#include "mupdf/xps.h"
+
+/* Quick parsing of document to find links. */
+
+static void
+xps_load_links_in_element(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
+ char *base_uri, xps_resource *dict, fz_xml *node, fz_link **link);
+
+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);
+ link->next = *head;
+ *head = link;
+}
+
+static void
+xps_load_links_in_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
+ char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
+{
+ char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
+ if (navigate_uri_att)
+ {
+ char *transform_att = fz_xml_att(root, "RenderTransform");
+ fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
+
+ char *data_att = fz_xml_att(root, "Data");
+ fz_xml *data_tag = fz_xml_down(fz_xml_find_down(root, "Path.Data"));
+
+ fz_path *path = NULL;
+ int fill_rule;
+ fz_matrix local_ctm;
+ fz_rect area;
+
+ xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL);
+ xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
+
+ xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm);
+
+ if (data_att)
+ path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule);
+ else if (data_tag)
+ path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule);
+ if (path)
+ {
+ fz_bound_path(ctx, path, NULL, &local_ctm, &area);
+ fz_drop_path(ctx, path);
+ xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att, link);
+ }
+ }
+}
+
+static void
+xps_load_links_in_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
+ char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
+{
+ char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
+ if (navigate_uri_att)
+ {
+ char *transform_att = fz_xml_att(root, "RenderTransform");
+ fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
+
+ char *bidi_level_att = fz_xml_att(root, "BidiLevel");
+ char *font_size_att = fz_xml_att(root, "FontRenderingEmSize");
+ char *font_uri_att = fz_xml_att(root, "FontUri");
+ char *origin_x_att = fz_xml_att(root, "OriginX");
+ char *origin_y_att = fz_xml_att(root, "OriginY");
+ char *is_sideways_att = fz_xml_att(root, "IsSideways");
+ char *indices_att = fz_xml_att(root, "Indices");
+ char *unicode_att = fz_xml_att(root, "UnicodeString");
+ char *style_att = fz_xml_att(root, "StyleSimulations");
+
+ int is_sideways = 0;
+ int bidi_level = 0;
+ fz_matrix local_ctm;
+ fz_font *font;
+ fz_text *text;
+ fz_rect area;
+
+ xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
+
+ xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm);
+
+ if (is_sideways_att)
+ is_sideways = !strcmp(is_sideways_att, "true");
+ if (bidi_level_att)
+ bidi_level = atoi(bidi_level_att);
+
+ font = xps_lookup_font(ctx, doc, base_uri, font_uri_att, style_att);
+ text = xps_parse_glyphs_imp(ctx, doc, &local_ctm, font, fz_atof(font_size_att),
+ fz_atof(origin_x_att), fz_atof(origin_y_att),
+ is_sideways, bidi_level, indices_att, unicode_att);
+ fz_bound_text(ctx, text, NULL, &local_ctm, &area);
+ fz_drop_text(ctx, text);
+ fz_drop_font(ctx, font);
+
+ xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att, link);
+ }
+}
+
+static void
+xps_load_links_in_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
+ char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
+{
+ xps_resource *new_dict = NULL;
+ fz_matrix local_ctm;
+ fz_xml *node;
+
+ char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
+ char *transform_att = fz_xml_att(root, "RenderTransform");
+ fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform"));
+ fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources"));
+
+ if (resource_tag)
+ {
+ new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
+ if (new_dict)
+ {
+ new_dict->parent = dict;
+ dict = new_dict;
+ }
+ }
+
+ xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
+
+ xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm);
+
+ if (navigate_uri_att)
+ fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element");
+
+ for (node = fz_xml_down(root); node; node = fz_xml_next(node))
+ xps_load_links_in_element(ctx, doc, &local_ctm, base_uri, dict, node, link);
+
+ if (new_dict)
+ xps_drop_resource_dictionary(ctx, doc, new_dict);
+}
+
+static void
+xps_load_links_in_element(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *node, fz_link **link)
+{
+ if (fz_xml_is_tag(node, "Path"))
+ xps_load_links_in_path(ctx, doc, ctm, base_uri, dict, node, link);
+ else if (fz_xml_is_tag(node, "Glyphs"))
+ xps_load_links_in_glyphs(ctx, doc, ctm, base_uri, dict, node, link);
+ else if (fz_xml_is_tag(node, "Canvas"))
+ xps_load_links_in_canvas(ctx, doc, ctm, base_uri, dict, node, link);
+ else if (fz_xml_is_tag(node, "AlternateContent"))
+ {
+ node = xps_lookup_alternate_content(ctx, doc, node);
+ if (node)
+ xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
+ }
+}
+
+static void
+xps_load_links_in_fixed_page(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_page *page, fz_link **link)
+{
+ fz_xml *node, *resource_tag;
+ xps_resource *dict = NULL;
+ char base_uri[1024];
+ char *s;
+
+ if (!page->root)
+ return;
+
+ fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
+ s = strrchr(base_uri, '/');
+ if (s)
+ s[1] = 0;
+
+ resource_tag = fz_xml_down(fz_xml_find_down(page->root, "FixedPage.Resources"));
+ if (resource_tag)
+ dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
+
+ for (node = fz_xml_down(page->root); node; node = fz_xml_next(node))
+ xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
+
+ if (dict)
+ xps_drop_resource_dictionary(ctx, doc, dict);
+}
+
+fz_link *
+xps_load_links(fz_context *ctx, xps_page *page)
+{
+ fz_matrix ctm;
+ fz_link *link = NULL;
+ fz_scale(&ctm, 72.0f / 96.0f, 72.0f / 96.0f);
+ xps_load_links_in_fixed_page(ctx, page->doc, &ctm, page, &link);
+ return link;
+}
diff --git a/source/xps/xps-path.c b/source/xps/xps-path.c
index 55d88fce..85910905 100644
--- a/source/xps/xps-path.c
+++ b/source/xps/xps-path.c
@@ -810,7 +810,6 @@ xps_parse_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *b
char *stroke_line_join_att;
char *stroke_miter_limit_att;
char *stroke_thickness_att;
- char *navigate_uri_att;
fz_stroke_state *stroke = NULL;
float samples[FZ_MAX_COLORS];
@@ -842,7 +841,6 @@ xps_parse_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *b
stroke_line_join_att = fz_xml_att(root, "StrokeLineJoin");
stroke_miter_limit_att = fz_xml_att(root, "StrokeMiterLimit");
stroke_thickness_att = fz_xml_att(root, "StrokeThickness");
- navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
{
@@ -991,9 +989,6 @@ xps_parse_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *b
else
fz_bound_path(ctx, path, NULL, &local_ctm, &area);
- if (navigate_uri_att)
- xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att);
-
xps_begin_opacity(ctx, doc, &local_ctm, &area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
if (fill_att)
diff --git a/source/xps/xps-tile.c b/source/xps/xps-tile.c
index 3921d1ce..6cecd9c0 100644
--- a/source/xps/xps-tile.c
+++ b/source/xps/xps-tile.c
@@ -256,7 +256,6 @@ xps_parse_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const
char *clip_att;
char *opacity_att;
char *opacity_mask_att;
- char *navigate_uri_att;
fz_xml *transform_tag = NULL;
fz_xml *clip_tag = NULL;
@@ -268,7 +267,6 @@ xps_parse_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const
clip_att = fz_xml_att(root, "Clip");
opacity_att = fz_xml_att(root, "Opacity");
opacity_mask_att = fz_xml_att(root, "OpacityMask");
- navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
{
@@ -304,9 +302,6 @@ xps_parse_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const
xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm);
- if (navigate_uri_att)
- xps_add_link(ctx, doc, area, base_uri, navigate_uri_att);
-
if (clip_att || clip_tag)
xps_clip(ctx, doc, &local_ctm, dict, clip_att, clip_tag);
@@ -379,5 +374,4 @@ xps_run_page(fz_context *ctx, xps_page *page, fz_device *dev, const fz_matrix *c
xps_parse_fixed_page(ctx, doc, &page_ctm, page);
doc->cookie = NULL;
doc->dev = NULL;
- page->fix->links_resolved = 1;
}