1 #include "mupdf/fitz.h"
2
3 #include <string.h>
4
5 fz_device *
fz_new_device_of_size(fz_context * ctx,int size)6 fz_new_device_of_size(fz_context *ctx, int size)
7 {
8 fz_device *dev = Memento_label(fz_calloc(ctx, 1, size), "fz_device");
9 dev->refs = 1;
10 return dev;
11 }
12
13 static void
fz_disable_device(fz_context * ctx,fz_device * dev)14 fz_disable_device(fz_context *ctx, fz_device *dev)
15 {
16 dev->close_device = NULL;
17 dev->fill_path = NULL;
18 dev->stroke_path = NULL;
19 dev->clip_path = NULL;
20 dev->clip_stroke_path = NULL;
21 dev->fill_text = NULL;
22 dev->stroke_text = NULL;
23 dev->clip_text = NULL;
24 dev->clip_stroke_text = NULL;
25 dev->ignore_text = NULL;
26 dev->fill_shade = NULL;
27 dev->fill_image = NULL;
28 dev->fill_image_mask = NULL;
29 dev->clip_image_mask = NULL;
30 dev->pop_clip = NULL;
31 dev->begin_mask = NULL;
32 dev->end_mask = NULL;
33 dev->begin_group = NULL;
34 dev->end_group = NULL;
35 dev->begin_tile = NULL;
36 dev->end_tile = NULL;
37 dev->render_flags = NULL;
38 dev->set_default_colorspaces = NULL;
39 dev->begin_layer = NULL;
40 dev->end_layer = NULL;
41 }
42
43 void
fz_close_device(fz_context * ctx,fz_device * dev)44 fz_close_device(fz_context *ctx, fz_device *dev)
45 {
46 if (dev == NULL)
47 return;
48
49 fz_try(ctx)
50 {
51 if (dev->close_device)
52 dev->close_device(ctx, dev);
53 }
54 fz_always(ctx)
55 fz_disable_device(ctx, dev);
56 fz_catch(ctx)
57 fz_rethrow(ctx);
58 }
59
60 fz_device *
fz_keep_device(fz_context * ctx,fz_device * dev)61 fz_keep_device(fz_context *ctx, fz_device *dev)
62 {
63 return fz_keep_imp(ctx, dev, &dev->refs);
64 }
65
66 void
fz_drop_device(fz_context * ctx,fz_device * dev)67 fz_drop_device(fz_context *ctx, fz_device *dev)
68 {
69 if (fz_drop_imp(ctx, dev, &dev->refs))
70 {
71 if (dev->close_device)
72 fz_warn(ctx, "dropping unclosed device");
73 if (dev->drop_device)
74 dev->drop_device(ctx, dev);
75 fz_free(ctx, dev->container);
76 fz_free(ctx, dev);
77 }
78 }
79
80 void
fz_enable_device_hints(fz_context * ctx,fz_device * dev,int hints)81 fz_enable_device_hints(fz_context *ctx, fz_device *dev, int hints)
82 {
83 dev->hints |= hints;
84 }
85
86 void
fz_disable_device_hints(fz_context * ctx,fz_device * dev,int hints)87 fz_disable_device_hints(fz_context *ctx, fz_device *dev, int hints)
88 {
89 dev->hints &= ~hints;
90 }
91
92 static void
push_clip_stack(fz_context * ctx,fz_device * dev,fz_rect rect,int type)93 push_clip_stack(fz_context *ctx, fz_device *dev, fz_rect rect, int type)
94 {
95 if (dev->container_len == dev->container_cap)
96 {
97 int newmax = dev->container_cap * 2;
98 if (newmax == 0)
99 newmax = 4;
100 dev->container = fz_realloc_array(ctx, dev->container, newmax, fz_device_container_stack);
101 dev->container_cap = newmax;
102 }
103 if (dev->container_len == 0)
104 dev->container[0].scissor = rect;
105 else
106 {
107 dev->container[dev->container_len].scissor = fz_intersect_rect(dev->container[dev->container_len-1].scissor, rect);
108 }
109 dev->container[dev->container_len].type = type;
110 dev->container[dev->container_len].user = 0;
111 dev->container_len++;
112 }
113
114 static void
pop_clip_stack(fz_context * ctx,fz_device * dev,int type)115 pop_clip_stack(fz_context *ctx, fz_device *dev, int type)
116 {
117 if (dev->container_len == 0 || dev->container[dev->container_len-1].type != type)
118 {
119 fz_disable_device(ctx, dev);
120 fz_throw(ctx, FZ_ERROR_GENERIC, "device calls unbalanced");
121 }
122 dev->container_len--;
123 }
124
125 static void
pop_push_clip_stack(fz_context * ctx,fz_device * dev,int pop_type,int push_type)126 pop_push_clip_stack(fz_context *ctx, fz_device *dev, int pop_type, int push_type)
127 {
128 if (dev->container_len == 0 || dev->container[dev->container_len-1].type != pop_type)
129 {
130 fz_disable_device(ctx, dev);
131 fz_throw(ctx, FZ_ERROR_GENERIC, "device calls unbalanced");
132 }
133 dev->container[dev->container_len-1].type = push_type;
134 }
135
136 void
fz_fill_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)137 fz_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,
138 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
139 {
140 if (dev->fill_path)
141 {
142 fz_try(ctx)
143 dev->fill_path(ctx, dev, path, even_odd, ctm, colorspace, color, alpha, color_params);
144 fz_catch(ctx)
145 {
146 fz_disable_device(ctx, dev);
147 fz_rethrow(ctx);
148 }
149 }
150 }
151
152 void
fz_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)153 fz_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm,
154 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
155 {
156 if (dev->stroke_path)
157 {
158 fz_try(ctx)
159 dev->stroke_path(ctx, dev, path, stroke, ctm, colorspace, color, alpha, color_params);
160 fz_catch(ctx)
161 {
162 fz_disable_device(ctx, dev);
163 fz_rethrow(ctx);
164 }
165 }
166 }
167
168 void
fz_clip_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_rect scissor)169 fz_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor)
170 {
171 fz_rect bbox = fz_bound_path(ctx, path, NULL, ctm);
172 bbox = fz_intersect_rect(bbox, scissor);
173 push_clip_stack(ctx, dev, bbox, fz_device_container_stack_is_clip);
174
175 if (dev->clip_path)
176 {
177 fz_try(ctx)
178 dev->clip_path(ctx, dev, path, even_odd, ctm, scissor);
179 fz_catch(ctx)
180 {
181 fz_disable_device(ctx, dev);
182 fz_rethrow(ctx);
183 }
184 }
185 }
186
187 void
fz_clip_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_rect scissor)188 fz_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)
189 {
190 fz_rect bbox = fz_bound_path(ctx, path, stroke, ctm);
191 bbox = fz_intersect_rect(bbox, scissor);
192 push_clip_stack(ctx, dev, bbox, fz_device_container_stack_is_clip);
193
194 if (dev->clip_stroke_path)
195 {
196 fz_try(ctx)
197 dev->clip_stroke_path(ctx, dev, path, stroke, ctm, scissor);
198 fz_catch(ctx)
199 {
200 fz_disable_device(ctx, dev);
201 fz_rethrow(ctx);
202 }
203 }
204 }
205
206 void
fz_fill_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)207 fz_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm,
208 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
209 {
210 if (dev->fill_text)
211 {
212 fz_try(ctx)
213 dev->fill_text(ctx, dev, text, ctm, colorspace, color, alpha, color_params);
214 fz_catch(ctx)
215 {
216 fz_disable_device(ctx, dev);
217 fz_rethrow(ctx);
218 }
219 }
220 }
221
222 void
fz_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)223 fz_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm,
224 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
225 {
226 if (dev->stroke_text)
227 {
228 fz_try(ctx)
229 dev->stroke_text(ctx, dev, text, stroke, ctm, colorspace, color, alpha, color_params);
230 fz_catch(ctx)
231 {
232 fz_disable_device(ctx, dev);
233 fz_rethrow(ctx);
234 }
235 }
236 }
237
238 void
fz_clip_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_rect scissor)239 fz_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor)
240 {
241 fz_rect bbox = fz_bound_text(ctx, text, NULL, ctm);
242 bbox = fz_intersect_rect(bbox, scissor);
243 push_clip_stack(ctx, dev, bbox, fz_device_container_stack_is_clip);
244
245 if (dev->clip_text)
246 {
247 fz_try(ctx)
248 dev->clip_text(ctx, dev, text, ctm, scissor);
249 fz_catch(ctx)
250 {
251 fz_disable_device(ctx, dev);
252 fz_rethrow(ctx);
253 }
254 }
255 }
256
257 void
fz_clip_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_rect scissor)258 fz_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)
259 {
260 fz_rect bbox = fz_bound_text(ctx, text, stroke, ctm);
261 bbox = fz_intersect_rect(bbox, scissor);
262 push_clip_stack(ctx, dev, bbox, fz_device_container_stack_is_clip);
263
264 if (dev->clip_stroke_text)
265 {
266 fz_try(ctx)
267 dev->clip_stroke_text(ctx, dev, text, stroke, ctm, scissor);
268 fz_catch(ctx)
269 {
270 fz_disable_device(ctx, dev);
271 fz_rethrow(ctx);
272 }
273 }
274 }
275
276 void
fz_ignore_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm)277 fz_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm)
278 {
279 if (dev->ignore_text)
280 {
281 fz_try(ctx)
282 dev->ignore_text(ctx, dev, text, ctm);
283 fz_catch(ctx)
284 {
285 fz_disable_device(ctx, dev);
286 fz_rethrow(ctx);
287 }
288 }
289 }
290
291 void
fz_pop_clip(fz_context * ctx,fz_device * dev)292 fz_pop_clip(fz_context *ctx, fz_device *dev)
293 {
294 pop_clip_stack(ctx, dev, fz_device_container_stack_is_clip);
295
296 if (dev->pop_clip)
297 {
298 fz_try(ctx)
299 dev->pop_clip(ctx, dev);
300 fz_catch(ctx)
301 {
302 fz_disable_device(ctx, dev);
303 fz_rethrow(ctx);
304 }
305 }
306 }
307
308 void
fz_fill_shade(fz_context * ctx,fz_device * dev,fz_shade * shade,fz_matrix ctm,float alpha,fz_color_params color_params)309 fz_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params)
310 {
311 if (dev->fill_shade)
312 {
313 fz_try(ctx)
314 dev->fill_shade(ctx, dev, shade, ctm, alpha, color_params);
315 fz_catch(ctx)
316 {
317 fz_disable_device(ctx, dev);
318 fz_rethrow(ctx);
319 }
320 }
321 }
322
323 void
fz_fill_image(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,float alpha,fz_color_params color_params)324 fz_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params)
325 {
326 if (dev->fill_image)
327 {
328 fz_try(ctx)
329 dev->fill_image(ctx, dev, image, ctm, alpha, color_params);
330 fz_catch(ctx)
331 {
332 fz_disable_device(ctx, dev);
333 fz_rethrow(ctx);
334 }
335 }
336 }
337
338 void
fz_fill_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)339 fz_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm,
340 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
341 {
342 if (dev->fill_image_mask)
343 {
344 fz_try(ctx)
345 dev->fill_image_mask(ctx, dev, image, ctm, colorspace, color, alpha, color_params);
346 fz_catch(ctx)
347 {
348 fz_disable_device(ctx, dev);
349 fz_rethrow(ctx);
350 }
351 }
352 }
353
354 void
fz_clip_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_rect scissor)355 fz_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor)
356 {
357 fz_rect bbox = fz_transform_rect(fz_unit_rect, ctm);
358 bbox = fz_intersect_rect(bbox, scissor);
359 push_clip_stack(ctx, dev, bbox, fz_device_container_stack_is_clip);
360
361 if (dev->clip_image_mask)
362 {
363 fz_try(ctx)
364 dev->clip_image_mask(ctx, dev, image, ctm, scissor);
365 fz_catch(ctx)
366 {
367 fz_disable_device(ctx, dev);
368 fz_rethrow(ctx);
369 }
370 }
371 }
372
373 void
fz_begin_mask(fz_context * ctx,fz_device * dev,fz_rect area,int luminosity,fz_colorspace * colorspace,const float * bc,fz_color_params color_params)374 fz_begin_mask(fz_context *ctx, fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, const float *bc, fz_color_params color_params)
375 {
376 push_clip_stack(ctx, dev, area, fz_device_container_stack_is_mask);
377
378 if (dev->begin_mask)
379 {
380 fz_try(ctx)
381 dev->begin_mask(ctx, dev, area, luminosity, colorspace, bc, color_params);
382 fz_catch(ctx)
383 {
384 fz_disable_device(ctx, dev);
385 fz_rethrow(ctx);
386 }
387 }
388 }
389
390 void
fz_end_mask(fz_context * ctx,fz_device * dev)391 fz_end_mask(fz_context *ctx, fz_device *dev)
392 {
393 pop_push_clip_stack(ctx, dev, fz_device_container_stack_is_mask, fz_device_container_stack_is_clip);
394
395 if (dev->end_mask)
396 {
397 fz_try(ctx)
398 dev->end_mask(ctx, dev);
399 fz_catch(ctx)
400 {
401 fz_disable_device(ctx, dev);
402 fz_rethrow(ctx);
403 }
404 }
405 }
406
407 void
fz_begin_group(fz_context * ctx,fz_device * dev,fz_rect area,fz_colorspace * cs,int isolated,int knockout,int blendmode,float alpha)408 fz_begin_group(fz_context *ctx, fz_device *dev, fz_rect area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
409 {
410 push_clip_stack(ctx, dev, area, fz_device_container_stack_is_group);
411
412 if (dev->begin_group)
413 {
414 fz_try(ctx)
415 dev->begin_group(ctx, dev, area, cs, isolated, knockout, blendmode, alpha);
416 fz_catch(ctx)
417 {
418 fz_disable_device(ctx, dev);
419 fz_rethrow(ctx);
420 }
421 }
422 }
423
424 void
fz_end_group(fz_context * ctx,fz_device * dev)425 fz_end_group(fz_context *ctx, fz_device *dev)
426 {
427 pop_clip_stack(ctx, dev, fz_device_container_stack_is_group);
428
429 if (dev->end_group)
430 {
431 fz_try(ctx)
432 dev->end_group(ctx, dev);
433 fz_catch(ctx)
434 {
435 fz_disable_device(ctx, dev);
436 fz_rethrow(ctx);
437 }
438 }
439 }
440
441 void
fz_begin_tile(fz_context * ctx,fz_device * dev,fz_rect area,fz_rect view,float xstep,float ystep,fz_matrix ctm)442 fz_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
443 {
444 (void)fz_begin_tile_id(ctx, dev, area, view, xstep, ystep, ctm, 0);
445 }
446
447 int
fz_begin_tile_id(fz_context * ctx,fz_device * dev,fz_rect area,fz_rect view,float xstep,float ystep,fz_matrix ctm,int id)448 fz_begin_tile_id(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id)
449 {
450 int result = 0;
451
452 push_clip_stack(ctx, dev, area, fz_device_container_stack_is_tile);
453
454 if (xstep < 0)
455 xstep = -xstep;
456 if (ystep < 0)
457 ystep = -ystep;
458 if (dev->begin_tile)
459 {
460 fz_try(ctx)
461 result = dev->begin_tile(ctx, dev, area, view, xstep, ystep, ctm, id);
462 fz_catch(ctx)
463 {
464 fz_disable_device(ctx, dev);
465 fz_rethrow(ctx);
466 }
467 }
468
469 return result;
470 }
471
472 void
fz_end_tile(fz_context * ctx,fz_device * dev)473 fz_end_tile(fz_context *ctx, fz_device *dev)
474 {
475 pop_clip_stack(ctx, dev, fz_device_container_stack_is_tile);
476
477 if (dev->end_tile)
478 {
479 fz_try(ctx)
480 dev->end_tile(ctx, dev);
481 fz_catch(ctx)
482 {
483 fz_disable_device(ctx, dev);
484 fz_rethrow(ctx);
485 }
486 }
487 }
488
489 void
fz_render_flags(fz_context * ctx,fz_device * dev,int set,int clear)490 fz_render_flags(fz_context *ctx, fz_device *dev, int set, int clear)
491 {
492 if (dev->render_flags)
493 {
494 fz_try(ctx)
495 dev->render_flags(ctx, dev, set, clear);
496 fz_catch(ctx)
497 {
498 fz_disable_device(ctx, dev);
499 fz_rethrow(ctx);
500 }
501 }
502 }
503
504 void
fz_set_default_colorspaces(fz_context * ctx,fz_device * dev,fz_default_colorspaces * default_cs)505 fz_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs)
506 {
507 if (dev->set_default_colorspaces)
508 {
509 fz_try(ctx)
510 dev->set_default_colorspaces(ctx, dev, default_cs);
511 fz_catch(ctx)
512 {
513 fz_disable_device(ctx, dev);
514 fz_rethrow(ctx);
515 }
516 }
517 }
518
fz_begin_layer(fz_context * ctx,fz_device * dev,const char * layer_name)519 void fz_begin_layer(fz_context *ctx, fz_device *dev, const char *layer_name)
520 {
521 if (dev->begin_layer)
522 {
523 fz_try(ctx)
524 dev->begin_layer(ctx, dev, layer_name);
525 fz_catch(ctx)
526 {
527 fz_disable_device(ctx, dev);
528 fz_rethrow(ctx);
529 }
530 }
531 }
532
fz_end_layer(fz_context * ctx,fz_device * dev)533 void fz_end_layer(fz_context *ctx, fz_device *dev)
534 {
535 if (dev->end_layer)
536 {
537 fz_try(ctx)
538 dev->end_layer(ctx, dev);
539 fz_catch(ctx)
540 {
541 fz_disable_device(ctx, dev);
542 fz_rethrow(ctx);
543 }
544 }
545 }
546
547 fz_rect
fz_device_current_scissor(fz_context * ctx,fz_device * dev)548 fz_device_current_scissor(fz_context *ctx, fz_device *dev)
549 {
550 if (dev->container_len > 0)
551 return dev->container[dev->container_len-1].scissor;
552 return fz_infinite_rect;
553 }
554