xps-link.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. #include "mupdf/fitz.h"
  23. #include "xps-imp.h"
  24. #include <string.h>
  25. #include <stdlib.h>
  26. /* Quick parsing of document to find links. */
  27. static void
  28. xps_load_links_in_element(fz_context *ctx, xps_document *doc, fz_matrix ctm,
  29. char *base_uri, xps_resource *dict, fz_xml *node, fz_link **link);
  30. static void
  31. xps_add_link(fz_context *ctx, xps_document *doc, fz_rect area, char *base_uri, char *target_uri, fz_link **head)
  32. {
  33. fz_link *link = fz_new_derived_link(ctx, fz_link, area, target_uri);
  34. link->next = *head;
  35. *head = link;
  36. }
  37. static void
  38. xps_load_links_in_path(fz_context *ctx, xps_document *doc, fz_matrix ctm,
  39. char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
  40. {
  41. char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
  42. if (navigate_uri_att)
  43. {
  44. char *transform_att = fz_xml_att(root, "RenderTransform");
  45. fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
  46. char *data_att = fz_xml_att(root, "Data");
  47. fz_xml *data_tag = fz_xml_down(fz_xml_find_down(root, "Path.Data"));
  48. fz_path *path = NULL;
  49. int fill_rule;
  50. fz_rect area;
  51. xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL);
  52. xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
  53. ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
  54. if (data_att)
  55. path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule);
  56. else if (data_tag)
  57. path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule);
  58. if (path)
  59. {
  60. fz_try(ctx)
  61. area = fz_bound_path(ctx, path, NULL, ctm);
  62. fz_always(ctx)
  63. fz_drop_path(ctx, path);
  64. fz_catch(ctx)
  65. fz_rethrow(ctx);
  66. xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link);
  67. }
  68. }
  69. }
  70. static void
  71. xps_load_links_in_glyphs(fz_context *ctx, xps_document *doc, fz_matrix ctm,
  72. char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
  73. {
  74. char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
  75. if (navigate_uri_att)
  76. {
  77. char *transform_att = fz_xml_att(root, "RenderTransform");
  78. fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
  79. char *bidi_level_att = fz_xml_att(root, "BidiLevel");
  80. char *font_size_att = fz_xml_att(root, "FontRenderingEmSize");
  81. char *font_uri_att = fz_xml_att(root, "FontUri");
  82. char *origin_x_att = fz_xml_att(root, "OriginX");
  83. char *origin_y_att = fz_xml_att(root, "OriginY");
  84. char *is_sideways_att = fz_xml_att(root, "IsSideways");
  85. char *indices_att = fz_xml_att(root, "Indices");
  86. char *unicode_att = fz_xml_att(root, "UnicodeString");
  87. char *style_att = fz_xml_att(root, "StyleSimulations");
  88. int is_sideways = 0;
  89. int bidi_level = 0;
  90. fz_font *font;
  91. fz_text *text = NULL;
  92. fz_rect area;
  93. xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
  94. ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
  95. if (is_sideways_att)
  96. is_sideways = !strcmp(is_sideways_att, "true");
  97. if (bidi_level_att)
  98. bidi_level = atoi(bidi_level_att);
  99. font = xps_lookup_font(ctx, doc, base_uri, font_uri_att, style_att);
  100. if (!font)
  101. return;
  102. fz_var(text);
  103. fz_try(ctx)
  104. {
  105. text = xps_parse_glyphs_imp(ctx, doc, ctm, font, fz_atof(font_size_att),
  106. fz_atof(origin_x_att), fz_atof(origin_y_att),
  107. is_sideways, bidi_level, indices_att, unicode_att);
  108. area = fz_bound_text(ctx, text, NULL, ctm);
  109. }
  110. fz_always(ctx)
  111. {
  112. fz_drop_text(ctx, text);
  113. fz_drop_font(ctx, font);
  114. }
  115. fz_catch(ctx)
  116. fz_rethrow(ctx);
  117. xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link);
  118. }
  119. }
  120. static void
  121. xps_load_links_in_canvas(fz_context *ctx, xps_document *doc, fz_matrix ctm,
  122. char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link)
  123. {
  124. xps_resource *new_dict = NULL;
  125. fz_xml *node;
  126. char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
  127. char *transform_att = fz_xml_att(root, "RenderTransform");
  128. fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform"));
  129. fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources"));
  130. if (resource_tag)
  131. {
  132. new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
  133. if (new_dict)
  134. {
  135. new_dict->parent = dict;
  136. dict = new_dict;
  137. }
  138. }
  139. xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
  140. ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
  141. if (navigate_uri_att)
  142. fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element");
  143. for (node = fz_xml_down(root); node; node = fz_xml_next(node))
  144. xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
  145. if (new_dict)
  146. xps_drop_resource_dictionary(ctx, doc, new_dict);
  147. }
  148. static void
  149. 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)
  150. {
  151. if (fz_xml_is_tag(node, "Path"))
  152. xps_load_links_in_path(ctx, doc, ctm, base_uri, dict, node, link);
  153. else if (fz_xml_is_tag(node, "Glyphs"))
  154. xps_load_links_in_glyphs(ctx, doc, ctm, base_uri, dict, node, link);
  155. else if (fz_xml_is_tag(node, "Canvas"))
  156. xps_load_links_in_canvas(ctx, doc, ctm, base_uri, dict, node, link);
  157. else if (fz_xml_is_tag(node, "AlternateContent"))
  158. {
  159. node = xps_lookup_alternate_content(ctx, doc, node);
  160. if (node)
  161. xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
  162. }
  163. }
  164. static void
  165. xps_load_links_in_fixed_page(fz_context *ctx, xps_document *doc, fz_matrix ctm, xps_page *page, fz_link **link)
  166. {
  167. fz_xml *root, *node, *resource_tag;
  168. xps_resource *dict = NULL;
  169. char base_uri[1024];
  170. char *s;
  171. root = fz_xml_root(page->xml);
  172. if (!root)
  173. return;
  174. fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
  175. s = strrchr(base_uri, '/');
  176. if (s)
  177. s[1] = 0;
  178. resource_tag = fz_xml_down(fz_xml_find_down(root, "FixedPage.Resources"));
  179. if (resource_tag)
  180. dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
  181. for (node = fz_xml_down(root); node; node = fz_xml_next(node))
  182. xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
  183. if (dict)
  184. xps_drop_resource_dictionary(ctx, doc, dict);
  185. }
  186. fz_link *
  187. xps_load_links(fz_context *ctx, fz_page *page_)
  188. {
  189. xps_page *page = (xps_page*)page_;
  190. fz_matrix ctm;
  191. fz_link *link = NULL;
  192. ctm = fz_scale(72.0f / 96.0f, 72.0f / 96.0f);
  193. xps_load_links_in_fixed_page(ctx, (xps_document*)page->super.doc, ctm, page, &link);
  194. return link;
  195. }