diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2015-10-06 10:47:49 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2015-10-06 11:20:30 +0200 |
commit | 6ffd32a570ab8a6f03737d0342667bee4d947985 (patch) | |
tree | a66134331d544812ba3c3b2b2c28e253e46f5a87 | |
parent | 233baeea8e933c010c2270481b6a49ccc00454ca (diff) | |
download | mupdf-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.h | 7 | ||||
-rw-r--r-- | platform/win32/libmupdf.vcproj | 4 | ||||
-rw-r--r-- | source/xps/xps-doc.c | 85 | ||||
-rw-r--r-- | source/xps/xps-glyphs.c | 5 | ||||
-rw-r--r-- | source/xps/xps-link.c | 206 | ||||
-rw-r--r-- | source/xps/xps-path.c | 5 | ||||
-rw-r--r-- | source/xps/xps-tile.c | 6 |
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; } |