Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "mupdf/xps.h"
2
3
#define TILE
4
5
/*
6
* Parse a tiling brush (visual and image brushes at this time) common
7
* properties. Use the callback to draw the individual tiles.
8
*/
9
10
enum { TILE_NONE, TILE_TILE, TILE_FLIP_X, TILE_FLIP_Y, TILE_FLIP_X_Y };
11
12
struct closure
13
{
14
char *base_uri;
15
xps_resource *dict;
16
fz_xml *root;
17
void *user;
18
void (*func)(fz_context *ctx, xps_document*, const fz_matrix *, const fz_rect *, char*, xps_resource*, fz_xml*, void*);
19
};
20
21
static void
22
xps_paint_tiling_brush_clipped(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *viewbox, struct closure *c)
23
{
24
fz_device *dev = doc->dev;
25
26
fz_path *path = fz_new_path(ctx);
27
fz_moveto(ctx, path, viewbox->x0, viewbox->y0);
28
fz_lineto(ctx, path, viewbox->x0, viewbox->y1);
29
fz_lineto(ctx, path, viewbox->x1, viewbox->y1);
30
fz_lineto(ctx, path, viewbox->x1, viewbox->y0);
31
fz_closepath(ctx, path);
32
fz_clip_path(ctx, dev, path, NULL, 0, ctm);
33
fz_drop_path(ctx, path);
34
c->func(ctx, doc, ctm, viewbox, c->base_uri, c->dict, c->root, c->user);
35
fz_pop_clip(ctx, dev);
36
}
37
38
static void
39
xps_paint_tiling_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *viewbox, int tile_mode, struct closure *c)
40
{
41
fz_matrix ttm;
42
43
xps_paint_tiling_brush_clipped(ctx, doc, ctm, viewbox, c);
44
45
if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y)
46
{
47
ttm = *ctm;
48
fz_pre_scale(fz_pre_translate(&ttm, viewbox->x1 * 2, 0), -1, 1);
49
xps_paint_tiling_brush_clipped(ctx, doc, &ttm, viewbox, c);
50
}
51
52
if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y)
53
{
54
ttm = *ctm;
55
fz_pre_scale(fz_pre_translate(&ttm, 0, viewbox->y1 * 2), 1, -1);
56
xps_paint_tiling_brush_clipped(ctx, doc, &ttm, viewbox, c);
57
}
58
59
if (tile_mode == TILE_FLIP_X_Y)
60
{
61
ttm = *ctm;
62
fz_pre_scale(fz_pre_translate(&ttm, viewbox->x1 * 2, viewbox->y1 * 2), -1, -1);
63
xps_paint_tiling_brush_clipped(ctx, doc, &ttm, viewbox, c);
64
}
65
}
66
67
void
68
xps_parse_tiling_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
69
char *base_uri, xps_resource *dict, fz_xml *root,
70
void (*func)(fz_context *ctx, xps_document*, const fz_matrix*, const fz_rect*, char*, xps_resource*, fz_xml*, void*), void *user)
71
{
72
fz_device *dev = doc->dev;
73
fz_xml *node;
74
struct closure c;
75
76
char *opacity_att;
77
char *transform_att;
78
char *viewbox_att;
79
char *viewport_att;
80
char *tile_mode_att;
81
82
fz_xml *transform_tag = NULL;
83
84
fz_matrix transform;
85
fz_rect viewbox;
86
fz_rect viewport;
87
float xstep, ystep;
88
float xscale, yscale;
89
int tile_mode;
90
91
opacity_att = fz_xml_att(root, "Opacity");
92
transform_att = fz_xml_att(root, "Transform");
93
viewbox_att = fz_xml_att(root, "Viewbox");
94
viewport_att = fz_xml_att(root, "Viewport");
95
tile_mode_att = fz_xml_att(root, "TileMode");
96
97
c.base_uri = base_uri;
98
c.dict = dict;
99
c.root = root;
100
c.user = user;
101
c.func = func;
102
103
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
104
{
105
if (fz_xml_is_tag(node, "ImageBrush.Transform"))
106
transform_tag = fz_xml_down(node);
107
if (fz_xml_is_tag(node, "VisualBrush.Transform"))
108
transform_tag = fz_xml_down(node);
109
}
110
111
xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
112
113
transform = fz_identity;
114
if (transform_att)
115
xps_parse_render_transform(ctx, doc, transform_att, &transform);
116
if (transform_tag)
117
xps_parse_matrix_transform(ctx, doc, transform_tag, &transform);
118
fz_concat(&transform, &transform, ctm);
119
120
viewbox = fz_unit_rect;
121
if (viewbox_att)
122
xps_parse_rectangle(ctx, doc, viewbox_att, &viewbox);
123
124
viewport = fz_unit_rect;
125
if (viewport_att)
126
xps_parse_rectangle(ctx, doc, viewport_att, &viewport);
127
128
if (fabsf(viewport.x1 - viewport.x0) < 0.01f || fabsf(viewport.y1 - viewport.y0) < 0.01f)
129
fz_warn(ctx, "not drawing tile for viewport size %.4f x %.4f", viewport.x1 - viewport.x0, viewport.y1 - viewport.y0);
130
else if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f || fabsf(viewbox.y1 - viewbox.y0) < 0.01f)
131
fz_warn(ctx, "not drawing tile for viewbox size %.4f x %.4f", viewbox.x1 - viewbox.x0, viewbox.y1 - viewbox.y0);
132
133
/* some sanity checks on the viewport/viewbox size */
134
if (fabsf(viewport.x1 - viewport.x0) < 0.01f) return;
135
if (fabsf(viewport.y1 - viewport.y0) < 0.01f) return;
136
if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f) return;
137
if (fabsf(viewbox.y1 - viewbox.y0) < 0.01f) return;
138
139
xstep = viewbox.x1 - viewbox.x0;
140
ystep = viewbox.y1 - viewbox.y0;
141
142
xscale = (viewport.x1 - viewport.x0) / xstep;
143
yscale = (viewport.y1 - viewport.y0) / ystep;
144
145
tile_mode = TILE_NONE;
146
if (tile_mode_att)
147
{
148
if (!strcmp(tile_mode_att, "None"))
149
tile_mode = TILE_NONE;
150
if (!strcmp(tile_mode_att, "Tile"))
151
tile_mode = TILE_TILE;
152
if (!strcmp(tile_mode_att, "FlipX"))
153
tile_mode = TILE_FLIP_X;
154
if (!strcmp(tile_mode_att, "FlipY"))
155
tile_mode = TILE_FLIP_Y;
156
if (!strcmp(tile_mode_att, "FlipXY"))
157
tile_mode = TILE_FLIP_X_Y;
158
}
159
160
if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y)
161
xstep *= 2;
162
if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y)
163
ystep *= 2;
164
165
xps_begin_opacity(ctx, doc, &transform, area, base_uri, dict, opacity_att, NULL);
166
167
fz_pre_translate(&transform, viewport.x0, viewport.y0);
168
fz_pre_scale(&transform, xscale, yscale);
169
fz_pre_translate(&transform, -viewbox.x0, -viewbox.y0);
170
171
if (tile_mode != TILE_NONE)
172
{
173
int x0, y0, x1, y1;
174
fz_matrix invctm;
175
fz_rect local_area = *area;
176
fz_transform_rect(&local_area, fz_invert_matrix(&invctm, &transform));
177
x0 = floorf(local_area.x0 / xstep);
178
y0 = floorf(local_area.y0 / ystep);
179
x1 = ceilf(local_area.x1 / xstep);
180
y1 = ceilf(local_area.y1 / ystep);
181
182
#ifdef TILE
183
if ((x1 - x0) * (y1 - y0) > 1)
184
#else
185
if (0)
186
#endif
187
{
188
fz_rect bigview = viewbox;
189
bigview.x1 = bigview.x0 + xstep;
190
bigview.y1 = bigview.y0 + ystep;
191
fz_begin_tile(ctx, dev, &local_area, &bigview, xstep, ystep, &transform);
192
xps_paint_tiling_brush(ctx, doc, &transform, &viewbox, tile_mode, &c);
193
fz_end_tile(ctx, dev);
194
}
195
else
196
{
197
int x, y;
198
for (y = y0; y < y1; y++)
199
{
200
for (x = x0; x < x1; x++)
201
{
202
fz_matrix ttm = transform;
203
fz_pre_translate(&ttm, xstep * x, ystep * y);
204
xps_paint_tiling_brush(ctx, doc, &ttm, &viewbox, tile_mode, &c);
205
}
206
}
207
}
208
}
209
else
210
{
211
xps_paint_tiling_brush(ctx, doc, &transform, &viewbox, tile_mode, &c);
212
}
213
214
xps_end_opacity(ctx, doc, base_uri, dict, opacity_att, NULL);
215
}
216
217
static void
218
xps_paint_visual_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
219
char *base_uri, xps_resource *dict, fz_xml *root, void *visual_tag)
220
{
221
xps_parse_element(ctx, doc, ctm, area, base_uri, dict, (fz_xml *)visual_tag);
222
}
223
224
void
225
xps_parse_visual_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
226
char *base_uri, xps_resource *dict, fz_xml *root)
227
{
228
fz_xml *node;
229
230
char *visual_uri;
231
char *visual_att;
232
fz_xml *visual_tag = NULL;
233
234
visual_att = fz_xml_att(root, "Visual");
235
236
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
237
{
238
if (fz_xml_is_tag(node, "VisualBrush.Visual"))
239
visual_tag = fz_xml_down(node);
240
}
241
242
visual_uri = base_uri;
243
xps_resolve_resource_reference(ctx, doc, dict, &visual_att, &visual_tag, &visual_uri);
244
245
if (visual_tag)
246
{
247
xps_parse_tiling_brush(ctx, doc, ctm, area,
248
visual_uri, dict, root, xps_paint_visual_brush, visual_tag);
249
}
250
}
251
252
void
253
xps_parse_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root)
254
{
255
fz_device *dev = doc->dev;
256
xps_resource *new_dict = NULL;
257
fz_xml *node;
258
char *opacity_mask_uri;
259
260
char *transform_att;
261
char *clip_att;
262
char *opacity_att;
263
char *opacity_mask_att;
264
char *navigate_uri_att;
265
266
fz_xml *transform_tag = NULL;
267
fz_xml *clip_tag = NULL;
268
fz_xml *opacity_mask_tag = NULL;
269
270
fz_matrix transform;
271
272
transform_att = fz_xml_att(root, "RenderTransform");
273
clip_att = fz_xml_att(root, "Clip");
274
opacity_att = fz_xml_att(root, "Opacity");
275
opacity_mask_att = fz_xml_att(root, "OpacityMask");
276
navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");
277
278
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
279
{
280
if (fz_xml_is_tag(node, "Canvas.Resources") && fz_xml_down(node))
281
{
282
if (new_dict)
283
{
284
fz_warn(ctx, "ignoring follow-up resource dictionaries");
285
}
286
else
287
{
288
new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, fz_xml_down(node));
289
if (new_dict)
290
{
291
new_dict->parent = dict;
292
dict = new_dict;
293
}
294
}
295
}
296
297
if (fz_xml_is_tag(node, "Canvas.RenderTransform"))
298
transform_tag = fz_xml_down(node);
299
if (fz_xml_is_tag(node, "Canvas.Clip"))
300
clip_tag = fz_xml_down(node);
301
if (fz_xml_is_tag(node, "Canvas.OpacityMask"))
302
opacity_mask_tag = fz_xml_down(node);
303
}
304
305
opacity_mask_uri = base_uri;
306
xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL);
307
xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL);
308
xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);
309
310
transform = fz_identity;
311
if (transform_att)
312
xps_parse_render_transform(ctx, doc, transform_att, &transform);
313
if (transform_tag)
314
xps_parse_matrix_transform(ctx, doc, transform_tag, &transform);
315
fz_concat(&transform, &transform, ctm);
316
317
if (navigate_uri_att)
318
xps_add_link(ctx, doc, area, base_uri, navigate_uri_att);
319
320
if (clip_att || clip_tag)
321
xps_clip(ctx, doc, &transform, dict, clip_att, clip_tag);
322
323
xps_begin_opacity(ctx, doc, &transform, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
324
325
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
326
{
327
xps_parse_element(ctx, doc, &transform, area, base_uri, dict, node);
328
}
329
330
xps_end_opacity(ctx, doc, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);
331
332
if (clip_att || clip_tag)
333
fz_pop_clip(ctx, dev);
334
335
if (new_dict)
336
xps_drop_resource_dictionary(ctx, doc, new_dict);
337
}
338
339
void
340
xps_parse_fixed_page(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_page *page)
341
{
342
fz_xml *node;
343
xps_resource *dict;
344
char base_uri[1024];
345
fz_rect area;
346
char *s;
347
fz_matrix scm;
348
349
fz_strlcpy(base_uri, page->fix->name, sizeof base_uri);
350
s = strrchr(base_uri, '/');
351
if (s)
352
s[1] = 0;
353
354
dict = NULL;
355
356
doc->opacity_top = 0;
357
doc->opacity[0] = 1;
358
359
if (!page->root)
360
return;
361
362
area = fz_unit_rect;
363
fz_transform_rect(&area, fz_scale(&scm, page->fix->width, page->fix->height));
364
365
for (node = fz_xml_down(page->root); node; node = fz_xml_next(node))
366
{
367
if (fz_xml_is_tag(node, "FixedPage.Resources") && fz_xml_down(node))
368
{
369
if (dict)
370
fz_warn(ctx, "ignoring follow-up resource dictionaries");
371
else
372
dict = xps_parse_resource_dictionary(ctx, doc, base_uri, fz_xml_down(node));
373
}
374
xps_parse_element(ctx, doc, ctm, &area, base_uri, dict, node);
375
}
376
377
if (dict)
378
xps_drop_resource_dictionary(ctx, doc, dict);
379
}
380
381
void
382
xps_run_page(fz_context *ctx, xps_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie)
383
{
384
xps_document *doc = page->doc;
385
fz_matrix page_ctm = *ctm;
386
387
fz_pre_scale(&page_ctm, 72.0f / 96.0f, 72.0f / 96.0f);
388
389
doc->cookie = cookie;
390
doc->dev = dev;
391
xps_parse_fixed_page(ctx, doc, &page_ctm, page);
392
doc->cookie = NULL;
393
doc->dev = NULL;
394
page->fix->links_resolved = 1;
395
}
396
397