Coverage Report

Created: 2025-01-11 06:55

/src/mupdf/source/xps/xps-link.c
Line
Count
Source (jump to first uncovered line)
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
0
{
38
0
  fz_link *link = fz_new_derived_link(ctx, fz_link, area, target_uri);
39
0
  link->next = *head;
40
0
  *head = link;
41
0
}
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
0
{
47
0
  char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
48
0
  if (navigate_uri_att)
49
0
  {
50
0
    char *transform_att = fz_xml_att(root, "RenderTransform");
51
0
    fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
52
53
0
    char *data_att = fz_xml_att(root, "Data");
54
0
    fz_xml *data_tag = fz_xml_down(fz_xml_find_down(root, "Path.Data"));
55
56
0
    fz_path *path = NULL;
57
0
    int fill_rule;
58
0
    fz_rect area;
59
60
0
    xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL);
61
0
    xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
62
63
0
    ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
64
65
0
    if (data_att)
66
0
      path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule);
67
0
    else if (data_tag)
68
0
      path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule);
69
0
    if (path)
70
0
    {
71
0
      fz_try(ctx)
72
0
        area = fz_bound_path(ctx, path, NULL, ctm);
73
0
      fz_always(ctx)
74
0
        fz_drop_path(ctx, path);
75
0
      fz_catch(ctx)
76
0
        fz_rethrow(ctx);
77
0
      xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link);
78
0
    }
79
0
  }
80
0
}
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
0
{
86
0
  char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
87
0
  if (navigate_uri_att)
88
0
  {
89
0
    char *transform_att = fz_xml_att(root, "RenderTransform");
90
0
    fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform"));
91
92
0
    char *bidi_level_att = fz_xml_att(root, "BidiLevel");
93
0
    char *font_size_att = fz_xml_att(root, "FontRenderingEmSize");
94
0
    char *font_uri_att = fz_xml_att(root, "FontUri");
95
0
    char *origin_x_att = fz_xml_att(root, "OriginX");
96
0
    char *origin_y_att = fz_xml_att(root, "OriginY");
97
0
    char *is_sideways_att = fz_xml_att(root, "IsSideways");
98
0
    char *indices_att = fz_xml_att(root, "Indices");
99
0
    char *unicode_att = fz_xml_att(root, "UnicodeString");
100
0
    char *style_att = fz_xml_att(root, "StyleSimulations");
101
102
0
    int is_sideways = 0;
103
0
    int bidi_level = 0;
104
0
    fz_font *font;
105
0
    fz_text *text = NULL;
106
0
    fz_rect area;
107
108
0
    xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
109
110
0
    ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
111
112
0
    if (is_sideways_att)
113
0
      is_sideways = !strcmp(is_sideways_att, "true");
114
0
    if (bidi_level_att)
115
0
      bidi_level = atoi(bidi_level_att);
116
117
0
    font = xps_lookup_font(ctx, doc, base_uri, font_uri_att, style_att);
118
0
    if (!font)
119
0
      return;
120
121
0
    fz_var(text);
122
0
    fz_try(ctx)
123
0
    {
124
0
      text = xps_parse_glyphs_imp(ctx, doc, ctm, font, fz_atof(font_size_att),
125
0
          fz_atof(origin_x_att), fz_atof(origin_y_att),
126
0
          is_sideways, bidi_level, indices_att, unicode_att);
127
0
      area = fz_bound_text(ctx, text, NULL, ctm);
128
0
    }
129
0
    fz_always(ctx)
130
0
    {
131
0
      fz_drop_text(ctx, text);
132
0
      fz_drop_font(ctx, font);
133
0
    }
134
0
    fz_catch(ctx)
135
0
      fz_rethrow(ctx);
136
137
0
    xps_add_link(ctx, doc, area, base_uri, navigate_uri_att, link);
138
0
  }
139
0
}
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
0
{
145
0
  xps_resource *new_dict = NULL;
146
0
  fz_xml *node;
147
148
0
  char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
149
0
  char *transform_att = fz_xml_att(root, "RenderTransform");
150
0
  fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform"));
151
0
  fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources"));
152
153
0
  if (resource_tag)
154
0
  {
155
0
    new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
156
0
    if (new_dict)
157
0
    {
158
0
      new_dict->parent = dict;
159
0
      dict = new_dict;
160
0
    }
161
0
  }
162
163
0
  xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
164
165
0
  ctm = xps_parse_transform(ctx, doc, transform_att, transform_tag, ctm);
166
167
0
  if (navigate_uri_att)
168
0
    fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element");
169
170
0
  for (node = fz_xml_down(root); node; node = fz_xml_next(node))
171
0
    xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
172
173
0
  if (new_dict)
174
0
    xps_drop_resource_dictionary(ctx, doc, new_dict);
175
0
}
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
0
{
180
0
  if (fz_xml_is_tag(node, "Path"))
181
0
    xps_load_links_in_path(ctx, doc, ctm, base_uri, dict, node, link);
182
0
  else if (fz_xml_is_tag(node, "Glyphs"))
183
0
    xps_load_links_in_glyphs(ctx, doc, ctm, base_uri, dict, node, link);
184
0
  else if (fz_xml_is_tag(node, "Canvas"))
185
0
    xps_load_links_in_canvas(ctx, doc, ctm, base_uri, dict, node, link);
186
0
  else if (fz_xml_is_tag(node, "AlternateContent"))
187
0
  {
188
0
    node = xps_lookup_alternate_content(ctx, doc, node);
189
0
    if (node)
190
0
      xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
191
0
  }
192
0
}
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
0
{
197
0
  fz_xml *root, *node, *resource_tag;
198
0
  xps_resource *dict = NULL;
199
0
  char base_uri[1024];
200
0
  char *s;
201
202
0
  root = fz_xml_root(page->xml);
203
204
0
  if (!root)
205
0
    return;
206
207
0
  fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
208
0
  s = strrchr(base_uri, '/');
209
0
  if (s)
210
0
    s[1] = 0;
211
212
0
  resource_tag = fz_xml_down(fz_xml_find_down(root, "FixedPage.Resources"));
213
0
  if (resource_tag)
214
0
    dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag);
215
216
0
  for (node = fz_xml_down(root); node; node = fz_xml_next(node))
217
0
    xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link);
218
219
0
  if (dict)
220
0
    xps_drop_resource_dictionary(ctx, doc, dict);
221
0
}
222
223
fz_link *
224
xps_load_links(fz_context *ctx, fz_page *page_)
225
0
{
226
0
  xps_page *page = (xps_page*)page_;
227
0
  fz_matrix ctm;
228
0
  fz_link *link = NULL;
229
0
  ctm = fz_scale(72.0f / 96.0f, 72.0f / 96.0f);
230
0
  xps_load_links_in_fixed_page(ctx, (xps_document*)page->super.doc, ctm, page, &link);
231
0
  return link;
232
0
}