Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "mupdf/xps.h"
2
3
static inline int unhex(int a)
4
{
5
if (a >= 'A' && a <= 'F') return a - 'A' + 0xA;
6
if (a >= 'a' && a <= 'f') return a - 'a' + 0xA;
7
if (a >= '0' && a <= '9') return a - '0';
8
return 0;
9
}
10
11
fz_xml *
12
xps_lookup_alternate_content(fz_context *ctx, xps_document *doc, fz_xml *node)
13
{
14
for (node = fz_xml_down(node); node; node = fz_xml_next(node))
15
{
16
if (fz_xml_is_tag(node, "Choice") && fz_xml_att(node, "Requires"))
17
{
18
char list[64];
19
char *next = list, *item;
20
fz_strlcpy(list, fz_xml_att(node, "Requires"), sizeof(list));
21
while ((item = fz_strsep(&next, " \t\r\n")) != NULL && (!*item || !strcmp(item, "xps")));
22
if (!item)
23
return fz_xml_down(node);
24
}
25
else if (fz_xml_is_tag(node, "Fallback"))
26
return fz_xml_down(node);
27
}
28
return NULL;
29
}
30
31
void
32
xps_parse_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *node)
33
{
34
if (doc->cookie && doc->cookie->abort)
35
return;
36
/* SolidColorBrushes are handled in a special case and will never show up here */
37
if (fz_xml_is_tag(node, "ImageBrush"))
38
xps_parse_image_brush(ctx, doc, ctm, area, base_uri, dict, node);
39
else if (fz_xml_is_tag(node, "VisualBrush"))
40
xps_parse_visual_brush(ctx, doc, ctm, area, base_uri, dict, node);
41
else if (fz_xml_is_tag(node, "LinearGradientBrush"))
42
xps_parse_linear_gradient_brush(ctx, doc, ctm, area, base_uri, dict, node);
43
else if (fz_xml_is_tag(node, "RadialGradientBrush"))
44
xps_parse_radial_gradient_brush(ctx, doc, ctm, area, base_uri, dict, node);
45
else
46
fz_warn(ctx, "unknown brush tag: %s", fz_xml_tag(node));
47
}
48
49
void
50
xps_parse_element(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *node)
51
{
52
if (doc->cookie && doc->cookie->abort)
53
return;
54
if (fz_xml_is_tag(node, "Path"))
55
xps_parse_path(ctx, doc, ctm, base_uri, dict, node);
56
if (fz_xml_is_tag(node, "Glyphs"))
57
xps_parse_glyphs(ctx, doc, ctm, base_uri, dict, node);
58
if (fz_xml_is_tag(node, "Canvas"))
59
xps_parse_canvas(ctx, doc, ctm, area, base_uri, dict, node);
60
if (fz_xml_is_tag(node, "AlternateContent"))
61
{
62
node = xps_lookup_alternate_content(ctx, doc, node);
63
if (node)
64
xps_parse_element(ctx, doc, ctm, area, base_uri, dict, node);
65
}
66
/* skip unknown tags (like Foo.Resources and similar) */
67
}
68
69
void
70
xps_begin_opacity(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
71
char *base_uri, xps_resource *dict,
72
char *opacity_att, fz_xml *opacity_mask_tag)
73
{
74
fz_device *dev = doc->dev;
75
float opacity;
76
77
if (!opacity_att && !opacity_mask_tag)
78
return;
79
80
opacity = 1;
81
if (opacity_att)
82
opacity = fz_atof(opacity_att);
83
84
if (opacity_mask_tag && !strcmp(fz_xml_tag(opacity_mask_tag), "SolidColorBrush"))
85
{
86
char *scb_opacity_att = fz_xml_att(opacity_mask_tag, "Opacity");
87
char *scb_color_att = fz_xml_att(opacity_mask_tag, "Color");
88
if (scb_opacity_att)
89
opacity = opacity * fz_atof(scb_opacity_att);
90
if (scb_color_att)
91
{
92
fz_colorspace *colorspace;
93
float samples[FZ_MAX_COLORS];
94
xps_parse_color(ctx, doc, base_uri, scb_color_att, &colorspace, samples);
95
opacity = opacity * samples[0];
96
}
97
opacity_mask_tag = NULL;
98
}
99
100
if (doc->opacity_top + 1 < nelem(doc->opacity))
101
{
102
doc->opacity[doc->opacity_top + 1] = doc->opacity[doc->opacity_top] * opacity;
103
doc->opacity_top++;
104
}
105
106
if (opacity_mask_tag)
107
{
108
fz_begin_mask(ctx, dev, area, 0, NULL, NULL);
109
xps_parse_brush(ctx, doc, ctm, area, base_uri, dict, opacity_mask_tag);
110
fz_end_mask(ctx, dev);
111
}
112
}
113
114
void
115
xps_end_opacity(fz_context *ctx, xps_document *doc, char *base_uri, xps_resource *dict,
116
char *opacity_att, fz_xml *opacity_mask_tag)
117
{
118
fz_device *dev = doc->dev;
119
120
if (!opacity_att && !opacity_mask_tag)
121
return;
122
123
if (doc->opacity_top > 0)
124
doc->opacity_top--;
125
126
if (opacity_mask_tag)
127
{
128
if (strcmp(fz_xml_tag(opacity_mask_tag), "SolidColorBrush"))
129
fz_pop_clip(ctx, dev);
130
}
131
}
132
133
void
134
xps_parse_render_transform(fz_context *ctx, xps_document *doc, char *transform, fz_matrix *matrix)
135
{
136
float args[6];
137
char *s = transform;
138
int i;
139
140
args[0] = 1; args[1] = 0;
141
args[2] = 0; args[3] = 1;
142
args[4] = 0; args[5] = 0;
143
144
for (i = 0; i < 6 && *s; i++)
145
{
146
args[i] = fz_atof(s);
147
while (*s && *s != ',')
148
s++;
149
if (*s == ',')
150
s++;
151
}
152
153
matrix->a = args[0]; matrix->b = args[1];
154
matrix->c = args[2]; matrix->d = args[3];
155
matrix->e = args[4]; matrix->f = args[5];
156
}
157
158
void
159
xps_parse_matrix_transform(fz_context *ctx, xps_document *doc, fz_xml *root, fz_matrix *matrix)
160
{
161
char *transform;
162
163
*matrix = fz_identity;
164
165
if (fz_xml_is_tag(root, "MatrixTransform"))
166
{
167
transform = fz_xml_att(root, "Matrix");
168
if (transform)
169
xps_parse_render_transform(ctx, doc, transform, matrix);
170
}
171
}
172
173
void
174
xps_parse_rectangle(fz_context *ctx, xps_document *doc, char *text, fz_rect *rect)
175
{
176
float args[4];
177
char *s = text;
178
int i;
179
180
args[0] = 0; args[1] = 0;
181
args[2] = 1; args[3] = 1;
182
183
for (i = 0; i < 4 && *s; i++)
184
{
185
args[i] = fz_atof(s);
186
while (*s && *s != ',')
187
s++;
188
if (*s == ',')
189
s++;
190
}
191
192
rect->x0 = args[0];
193
rect->y0 = args[1];
194
rect->x1 = args[0] + args[2];
195
rect->y1 = args[1] + args[3];
196
}
197
198
static int count_commas(char *s)
199
{
200
int n = 0;
201
while (*s)
202
{
203
if (*s == ',')
204
n ++;
205
s ++;
206
}
207
return n;
208
}
209
210
void
211
xps_parse_color(fz_context *ctx, xps_document *doc, char *base_uri, char *string,
212
fz_colorspace **csp, float *samples)
213
{
214
char *p;
215
int i, n;
216
char buf[1024];
217
char *profile;
218
219
*csp = fz_device_rgb(ctx);
220
221
samples[0] = 1;
222
samples[1] = 0;
223
samples[2] = 0;
224
samples[3] = 0;
225
226
if (string[0] == '#')
227
{
228
if (strlen(string) == 9)
229
{
230
samples[0] = unhex(string[1]) * 16 + unhex(string[2]);
231
samples[1] = unhex(string[3]) * 16 + unhex(string[4]);
232
samples[2] = unhex(string[5]) * 16 + unhex(string[6]);
233
samples[3] = unhex(string[7]) * 16 + unhex(string[8]);
234
}
235
else
236
{
237
samples[0] = 255;
238
samples[1] = unhex(string[1]) * 16 + unhex(string[2]);
239
samples[2] = unhex(string[3]) * 16 + unhex(string[4]);
240
samples[3] = unhex(string[5]) * 16 + unhex(string[6]);
241
}
242
243
samples[0] /= 255;
244
samples[1] /= 255;
245
samples[2] /= 255;
246
samples[3] /= 255;
247
}
248
249
else if (string[0] == 's' && string[1] == 'c' && string[2] == '#')
250
{
251
if (count_commas(string) == 2)
252
sscanf(string, "sc#%g,%g,%g", samples + 1, samples + 2, samples + 3);
253
if (count_commas(string) == 3)
254
sscanf(string, "sc#%g,%g,%g,%g", samples, samples + 1, samples + 2, samples + 3);
255
}
256
257
else if (strstr(string, "ContextColor ") == string)
258
{
259
/* Crack the string for profile name and sample values */
260
fz_strlcpy(buf, string, sizeof buf);
261
262
profile = strchr(buf, ' ');
263
if (!profile)
264
{
265
fz_warn(ctx, "cannot find icc profile uri in '%s'", string);
266
return;
267
}
268
269
*profile++ = 0;
270
p = strchr(profile, ' ');
271
if (!p)
272
{
273
fz_warn(ctx, "cannot find component values in '%s'", profile);
274
return;
275
}
276
277
*p++ = 0;
278
n = count_commas(p) + 1;
279
if (n > FZ_MAX_COLORS)
280
{
281
fz_warn(ctx, "ignoring %d color components (max %d allowed)", n - FZ_MAX_COLORS, FZ_MAX_COLORS);
282
n = FZ_MAX_COLORS;
283
}
284
i = 0;
285
while (i < n)
286
{
287
samples[i++] = fz_atof(p);
288
p = strchr(p, ',');
289
if (!p)
290
break;
291
p ++;
292
if (*p == ' ')
293
p ++;
294
}
295
while (i < n)
296
{
297
samples[i++] = 0;
298
}
299
300
/* TODO: load ICC profile */
301
switch (n)
302
{
303
case 2: *csp = fz_device_gray(ctx); break;
304
case 4: *csp = fz_device_rgb(ctx); break;
305
case 5: *csp = fz_device_cmyk(ctx); break;
306
default: *csp = fz_device_gray(ctx); break;
307
}
308
}
309
}
310
311
void
312
xps_set_color(fz_context *ctx, xps_document *doc, fz_colorspace *colorspace, float *samples)
313
{
314
int i;
315
doc->colorspace = colorspace;
316
for (i = 0; i < colorspace->n; i++)
317
doc->color[i] = samples[i + 1];
318
doc->alpha = samples[0] * doc->opacity[doc->opacity_top];
319
}
320
321