Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/xps/xps-link.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2022 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 #include "mupdf/fitz.h" | |
| 24 #include "xps-imp.h" | |
| 25 | |
| 26 #include <string.h> | |
| 27 #include <stdlib.h> | |
| 28 | |
| 29 /* Quick parsing of document to find links. */ | |
| 30 | |
| 31 static void | |
| 32 xps_load_links_in_element(fz_context *ctx, xps_document *doc, fz_matrix ctm, | |
| 33 char *base_uri, xps_resource *dict, fz_xml *node, fz_link **link); | |
| 34 | |
| 35 static void | |
| 36 xps_add_link(fz_context *ctx, xps_document *doc, fz_rect area, char *base_uri, char *target_uri, fz_link **head) | |
| 37 { | |
| 38 fz_link *link = fz_new_derived_link(ctx, fz_link, area, target_uri); | |
| 39 link->next = *head; | |
| 40 *head = link; | |
| 41 } | |
| 42 | |
| 43 static void | |
| 44 xps_load_links_in_path(fz_context *ctx, xps_document *doc, fz_matrix ctm, | |
| 45 char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) | |
| 46 { | |
| 47 char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); | |
| 48 if (navigate_uri_att) | |
| 49 { | |
| 50 char *transform_att = fz_xml_att(root, "RenderTransform"); | |
| 51 fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform")); | |
| 52 | |
| 53 char *data_att = fz_xml_att(root, "Data"); | |
| 54 fz_xml *data_tag = fz_xml_down(fz_xml_find_down(root, "Path.Data")); | |
| 55 | |
| 56 fz_path *path = NULL; | |
| 57 int fill_rule; | |
| 58 fz_rect area; | |
| 59 | |
| 60 xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL); | |
| 61 xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); | |
| 62 | |
| 63 ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm); | |
| 64 | |
| 65 if (data_att) | |
| 66 path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule); | |
| 67 else if (data_tag) | |
| 68 path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule); | |
| 69 if (path) | |
| 70 { | |
| 71 fz_try(ctx) | |
| 72 area = fz_bound_path(ctx, path, NULL, ctm); | |
| 73 fz_always(ctx) | |
| 74 fz_drop_path(ctx, path); | |
| 75 fz_catch(ctx) | |
| 76 fz_rethrow(ctx); | |
| 77 xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link); | |
| 78 } | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 static void | |
| 83 xps_load_links_in_glyphs(fz_context *ctx, xps_document *doc, fz_matrix ctm, | |
| 84 char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) | |
| 85 { | |
| 86 char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); | |
| 87 if (navigate_uri_att) | |
| 88 { | |
| 89 char *transform_att = fz_xml_att(root, "RenderTransform"); | |
| 90 fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform")); | |
| 91 | |
| 92 char *bidi_level_att = fz_xml_att(root, "BidiLevel"); | |
| 93 char *font_size_att = fz_xml_att(root, "FontRenderingEmSize"); | |
| 94 char *font_uri_att = fz_xml_att(root, "FontUri"); | |
| 95 char *origin_x_att = fz_xml_att(root, "OriginX"); | |
| 96 char *origin_y_att = fz_xml_att(root, "OriginY"); | |
| 97 char *is_sideways_att = fz_xml_att(root, "IsSideways"); | |
| 98 char *indices_att = fz_xml_att(root, "Indices"); | |
| 99 char *unicode_att = fz_xml_att(root, "UnicodeString"); | |
| 100 char *style_att = fz_xml_att(root, "StyleSimulations"); | |
| 101 | |
| 102 int is_sideways = 0; | |
| 103 int bidi_level = 0; | |
| 104 fz_font *font; | |
| 105 fz_text *text = NULL; | |
| 106 fz_rect area; | |
| 107 | |
| 108 xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); | |
| 109 | |
| 110 ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm); | |
| 111 | |
| 112 if (is_sideways_att) | |
| 113 is_sideways = !strcmp(is_sideways_att, "true"); | |
| 114 if (bidi_level_att) | |
| 115 bidi_level = atoi(bidi_level_att); | |
| 116 | |
| 117 font = xps_lookup_font(ctx, doc, base_uri, font_uri_att, style_att); | |
| 118 if (!font) | |
| 119 return; | |
| 120 | |
| 121 fz_var(text); | |
| 122 fz_try(ctx) | |
| 123 { | |
| 124 text = xps_parse_glyphs_imp(ctx, doc, ctm, font, fz_atof(font_size_att), | |
| 125 fz_atof(origin_x_att), fz_atof(origin_y_att), | |
| 126 is_sideways, bidi_level, indices_att, unicode_att); | |
| 127 area = fz_bound_text(ctx, text, NULL, ctm); | |
| 128 } | |
| 129 fz_always(ctx) | |
| 130 { | |
| 131 fz_drop_text(ctx, text); | |
| 132 fz_drop_font(ctx, font); | |
| 133 } | |
| 134 fz_catch(ctx) | |
| 135 fz_rethrow(ctx); | |
| 136 | |
| 137 xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 static void | |
| 142 xps_load_links_in_canvas(fz_context *ctx, xps_document *doc, fz_matrix ctm, | |
| 143 char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) | |
| 144 { | |
| 145 xps_resource *new_dict = NULL; | |
| 146 fz_xml *node; | |
| 147 | |
| 148 char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); | |
| 149 char *transform_att = fz_xml_att(root, "RenderTransform"); | |
| 150 fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform")); | |
| 151 fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources")); | |
| 152 | |
| 153 if (resource_tag) | |
| 154 { | |
| 155 new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag); | |
| 156 if (new_dict) | |
| 157 { | |
| 158 new_dict->parent = dict; | |
| 159 dict = new_dict; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); | |
| 164 | |
| 165 ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm); | |
| 166 | |
| 167 if (navigate_uri_att) | |
| 168 fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element"); | |
| 169 | |
| 170 for (node = fz_xml_down(root); node; node = fz_xml_next(node)) | |
| 171 xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link); | |
| 172 | |
| 173 if (new_dict) | |
| 174 xps_drop_resource_dictionary(ctx, doc, new_dict); | |
| 175 } | |
| 176 | |
| 177 static void | |
| 178 xps_load_links_in_element(fz_context *ctx, xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, fz_xml *node, fz_link **link) | |
| 179 { | |
| 180 if (fz_xml_is_tag(node, "Path")) | |
| 181 xps_load_links_in_path(ctx, doc, ctm, base_uri, dict, node, link); | |
| 182 else if (fz_xml_is_tag(node, "Glyphs")) | |
| 183 xps_load_links_in_glyphs(ctx, doc, ctm, base_uri, dict, node, link); | |
| 184 else if (fz_xml_is_tag(node, "Canvas")) | |
| 185 xps_load_links_in_canvas(ctx, doc, ctm, base_uri, dict, node, link); | |
| 186 else if (fz_xml_is_tag(node, "AlternateContent")) | |
| 187 { | |
| 188 node = xps_lookup_alternate_content(ctx, doc, node); | |
| 189 if (node) | |
| 190 xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 static void | |
| 195 xps_load_links_in_fixed_page(fz_context *ctx, xps_document *doc, fz_matrix ctm, xps_page *page, fz_link **link) | |
| 196 { | |
| 197 fz_xml *root, *node, *resource_tag; | |
| 198 xps_resource *dict = NULL; | |
| 199 char base_uri[1024]; | |
| 200 char *s; | |
| 201 | |
| 202 root = fz_xml_root(page->xml); | |
| 203 | |
| 204 if (!root) | |
| 205 return; | |
| 206 | |
| 207 fz_strlcpy(base_uri, page->fix->name, sizeof base_uri); | |
| 208 s = strrchr(base_uri, '/'); | |
| 209 if (s) | |
| 210 s[1] = 0; | |
| 211 | |
| 212 resource_tag = fz_xml_down(fz_xml_find_down(root, "FixedPage.Resources")); | |
| 213 if (resource_tag) | |
| 214 dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag); | |
| 215 | |
| 216 for (node = fz_xml_down(root); node; node = fz_xml_next(node)) | |
| 217 xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link); | |
| 218 | |
| 219 if (dict) | |
| 220 xps_drop_resource_dictionary(ctx, doc, dict); | |
| 221 } | |
| 222 | |
| 223 fz_link * | |
| 224 xps_load_links(fz_context *ctx, fz_page *page_) | |
| 225 { | |
| 226 xps_page *page = (xps_page*)page_; | |
| 227 fz_matrix ctm; | |
| 228 fz_link *link = NULL; | |
| 229 ctm = fz_scale(72.0f / 96.0f, 72.0f / 96.0f); | |
| 230 xps_load_links_in_fixed_page(ctx, (xps_document*)page->super.doc, ctm, page, &link); | |
| 231 return link; | |
| 232 } |
