1 #include "mupdf/fitz.h"
2
3 #include <string.h>
4
5 enum
6 {
7 FZ_DOCUMENT_HANDLER_MAX = 10
8 };
9
10 #define DEFW (450)
11 #define DEFH (600)
12 #define DEFEM (12)
13
14 struct fz_document_handler_context
15 {
16 int refs;
17 int count;
18 const fz_document_handler *handler[FZ_DOCUMENT_HANDLER_MAX];
19 };
20
fz_new_document_handler_context(fz_context * ctx)21 void fz_new_document_handler_context(fz_context *ctx)
22 {
23 ctx->handler = fz_malloc_struct(ctx, fz_document_handler_context);
24 ctx->handler->refs = 1;
25 }
26
fz_keep_document_handler_context(fz_context * ctx)27 fz_document_handler_context *fz_keep_document_handler_context(fz_context *ctx)
28 {
29 if (!ctx || !ctx->handler)
30 return NULL;
31 return fz_keep_imp(ctx, ctx->handler, &ctx->handler->refs);
32 }
33
fz_drop_document_handler_context(fz_context * ctx)34 void fz_drop_document_handler_context(fz_context *ctx)
35 {
36 if (!ctx)
37 return;
38
39 if (fz_drop_imp(ctx, ctx->handler, &ctx->handler->refs))
40 {
41 fz_free(ctx, ctx->handler);
42 ctx->handler = NULL;
43 }
44 }
45
fz_register_document_handler(fz_context * ctx,const fz_document_handler * handler)46 void fz_register_document_handler(fz_context *ctx, const fz_document_handler *handler)
47 {
48 fz_document_handler_context *dc;
49 int i;
50
51 if (!handler)
52 return;
53
54 dc = ctx->handler;
55 if (dc == NULL)
56 fz_throw(ctx, FZ_ERROR_GENERIC, "Document handler list not found");
57
58 for (i = 0; i < dc->count; i++)
59 if (dc->handler[i] == handler)
60 return;
61
62 if (dc->count >= FZ_DOCUMENT_HANDLER_MAX)
63 fz_throw(ctx, FZ_ERROR_GENERIC, "Too many document handlers");
64
65 dc->handler[dc->count++] = handler;
66 }
67
68 const fz_document_handler *
fz_recognize_document(fz_context * ctx,const char * magic)69 fz_recognize_document(fz_context *ctx, const char *magic)
70 {
71 fz_document_handler_context *dc;
72 int i, best_score, best_i;
73 const char *ext, *needle;
74
75 dc = ctx->handler;
76 if (dc->count == 0)
77 fz_throw(ctx, FZ_ERROR_GENERIC, "No document handlers registered");
78
79 ext = strrchr(magic, '.');
80 if (ext)
81 needle = ext + 1;
82 else
83 needle = magic;
84
85 best_score = 0;
86 best_i = -1;
87
88 for (i = 0; i < dc->count; i++)
89 {
90 int score = 0;
91 const char **entry;
92
93 if (dc->handler[i]->recognize)
94 score = dc->handler[i]->recognize(ctx, magic);
95
96 if (!ext)
97 {
98 for (entry = &dc->handler[i]->mimetypes[0]; *entry; entry++)
99 if (!fz_strcasecmp(needle, *entry) && score < 100)
100 {
101 score = 100;
102 break;
103 }
104 }
105
106 for (entry = &dc->handler[i]->extensions[0]; *entry; entry++)
107 if (!fz_strcasecmp(needle, *entry) && score < 100)
108 {
109 score = 100;
110 break;
111 }
112
113 if (best_score < score)
114 {
115 best_score = score;
116 best_i = i;
117 }
118 }
119
120 if (best_i < 0)
121 return NULL;
122
123 return dc->handler[best_i];
124 }
125
126 #if FZ_ENABLE_PDF
127 extern fz_document_handler pdf_document_handler;
128 #endif
129
130 fz_document *
fz_open_accelerated_document_with_stream(fz_context * ctx,const char * magic,fz_stream * stream,fz_stream * accel)131 fz_open_accelerated_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream, fz_stream *accel)
132 {
133 const fz_document_handler *handler;
134
135 if (magic == NULL || stream == NULL)
136 fz_throw(ctx, FZ_ERROR_GENERIC, "no document to open");
137
138 handler = fz_recognize_document(ctx, magic);
139 if (!handler)
140 #if FZ_ENABLE_PDF
141 handler = &pdf_document_handler;
142 #else
143 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find document handler for file type: %s", magic);
144 #endif
145 if (handler->open_accel_with_stream)
146 if (accel || handler->open_with_stream == NULL)
147 return handler->open_accel_with_stream(ctx, stream, accel);
148 if (accel)
149 {
150 /* We've had an accelerator passed to a format that doesn't
151 * handle it. This should never happen, as how did the
152 * accelerator get created? */
153 fz_drop_stream(ctx, accel);
154 }
155 return handler->open_with_stream(ctx, stream);
156 }
157
158 fz_document *
fz_open_document_with_stream(fz_context * ctx,const char * magic,fz_stream * stream)159 fz_open_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream)
160 {
161 return fz_open_accelerated_document_with_stream(ctx, magic, stream, NULL);
162 }
163
164 fz_document *
fz_open_accelerated_document(fz_context * ctx,const char * filename,const char * accel)165 fz_open_accelerated_document(fz_context *ctx, const char *filename, const char *accel)
166 {
167 const fz_document_handler *handler;
168 fz_stream *file;
169 fz_stream *afile = NULL;
170 fz_document *doc = NULL;
171
172 fz_var(afile);
173
174 if (filename == NULL)
175 fz_throw(ctx, FZ_ERROR_GENERIC, "no document to open");
176
177 handler = fz_recognize_document(ctx, filename);
178 if (!handler)
179 #if FZ_ENABLE_PDF
180 handler = &pdf_document_handler;
181 #else
182 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find document handler for file: %s", filename);
183 #endif
184
185 if (accel) {
186 if (handler->open_accel)
187 return handler->open_accel(ctx, filename, accel);
188 if (handler->open_accel_with_stream == NULL)
189 {
190 /* We're not going to be able to use the accelerator - this
191 * should never happen, as how can one have been created? */
192 accel = NULL;
193 }
194 }
195 if (!accel && handler->open)
196 return handler->open(ctx, filename);
197
198 file = fz_open_file(ctx, filename);
199
200 fz_try(ctx)
201 {
202 if (accel || handler->open_with_stream == NULL)
203 {
204 if (accel)
205 afile = fz_open_file(ctx, accel);
206 doc = handler->open_accel_with_stream(ctx, file, afile);
207 }
208 else
209 doc = handler->open_with_stream(ctx, file);
210 }
211 fz_always(ctx)
212 {
213 fz_drop_stream(ctx, afile);
214 fz_drop_stream(ctx, file);
215 }
216 fz_catch(ctx)
217 fz_rethrow(ctx);
218
219 return doc;
220 }
221
222 fz_document *
fz_open_document(fz_context * ctx,const char * filename)223 fz_open_document(fz_context *ctx, const char *filename)
224 {
225 return fz_open_accelerated_document(ctx, filename, NULL);
226 }
227
fz_save_accelerator(fz_context * ctx,fz_document * doc,const char * accel)228 void fz_save_accelerator(fz_context *ctx, fz_document *doc, const char *accel)
229 {
230 if (doc == NULL)
231 return;
232 if (doc->output_accelerator == NULL)
233 return;
234
235 fz_output_accelerator(ctx, doc, fz_new_output_with_path(ctx, accel, 0));
236 }
237
fz_output_accelerator(fz_context * ctx,fz_document * doc,fz_output * accel)238 void fz_output_accelerator(fz_context *ctx, fz_document *doc, fz_output *accel)
239 {
240 if (doc == NULL || accel == NULL)
241 return;
242 if (doc->output_accelerator == NULL)
243 {
244 fz_drop_output(ctx, accel);
245 fz_throw(ctx, FZ_ERROR_GENERIC, "Document does not support writing an accelerator");
246 }
247
248 doc->output_accelerator(ctx, doc, accel);
249 }
250
fz_document_supports_accelerator(fz_context * ctx,fz_document * doc)251 int fz_document_supports_accelerator(fz_context *ctx, fz_document *doc)
252 {
253 if (doc == NULL)
254 return 0;
255 return (doc->output_accelerator) != NULL;
256 }
257
258 void *
fz_new_document_of_size(fz_context * ctx,int size)259 fz_new_document_of_size(fz_context *ctx, int size)
260 {
261 fz_document *doc = fz_calloc(ctx, 1, size);
262 doc->refs = 1;
263 return doc;
264 }
265
266 fz_document *
fz_keep_document(fz_context * ctx,fz_document * doc)267 fz_keep_document(fz_context *ctx, fz_document *doc)
268 {
269 return fz_keep_imp(ctx, doc, &doc->refs);
270 }
271
272 void
fz_drop_document(fz_context * ctx,fz_document * doc)273 fz_drop_document(fz_context *ctx, fz_document *doc)
274 {
275 if (fz_drop_imp(ctx, doc, &doc->refs))
276 {
277 if (doc->drop_document)
278 doc->drop_document(ctx, doc);
279 fz_free(ctx, doc);
280 }
281 }
282
283 static void
fz_ensure_layout(fz_context * ctx,fz_document * doc)284 fz_ensure_layout(fz_context *ctx, fz_document *doc)
285 {
286 if (doc && doc->layout && !doc->did_layout)
287 {
288 doc->layout(ctx, doc, DEFW, DEFH, DEFEM);
289 doc->did_layout = 1;
290 }
291 }
292
293 int
fz_is_document_reflowable(fz_context * ctx,fz_document * doc)294 fz_is_document_reflowable(fz_context *ctx, fz_document *doc)
295 {
296 return doc ? doc->is_reflowable : 0;
297 }
298
fz_make_bookmark(fz_context * ctx,fz_document * doc,fz_location loc)299 fz_bookmark fz_make_bookmark(fz_context *ctx, fz_document *doc, fz_location loc)
300 {
301 if (doc && doc->make_bookmark)
302 return doc->make_bookmark(ctx, doc, loc);
303 return (loc.chapter<<16) + loc.page;
304 }
305
fz_lookup_bookmark(fz_context * ctx,fz_document * doc,fz_bookmark mark)306 fz_location fz_lookup_bookmark(fz_context *ctx, fz_document *doc, fz_bookmark mark)
307 {
308 if (doc && doc->lookup_bookmark)
309 return doc->lookup_bookmark(ctx, doc, mark);
310 return fz_make_location((mark>>16) & 0xffff, mark & 0xffff);
311 }
312
313 int
fz_needs_password(fz_context * ctx,fz_document * doc)314 fz_needs_password(fz_context *ctx, fz_document *doc)
315 {
316 if (doc && doc->needs_password)
317 return doc->needs_password(ctx, doc);
318 return 0;
319 }
320
321 int
fz_authenticate_password(fz_context * ctx,fz_document * doc,const char * password)322 fz_authenticate_password(fz_context *ctx, fz_document *doc, const char *password)
323 {
324 if (doc && doc->authenticate_password)
325 return doc->authenticate_password(ctx, doc, password);
326 return 1;
327 }
328
329 int
fz_has_permission(fz_context * ctx,fz_document * doc,fz_permission p)330 fz_has_permission(fz_context *ctx, fz_document *doc, fz_permission p)
331 {
332 if (doc && doc->has_permission)
333 return doc->has_permission(ctx, doc, p);
334 return 1;
335 }
336
337 fz_outline *
fz_load_outline(fz_context * ctx,fz_document * doc)338 fz_load_outline(fz_context *ctx, fz_document *doc)
339 {
340 fz_ensure_layout(ctx, doc);
341 if (doc && doc->load_outline)
342 return doc->load_outline(ctx, doc);
343 return NULL;
344 }
345
346 fz_location
fz_resolve_link(fz_context * ctx,fz_document * doc,const char * uri,float * xp,float * yp)347 fz_resolve_link(fz_context *ctx, fz_document *doc, const char *uri, float *xp, float *yp)
348 {
349 fz_ensure_layout(ctx, doc);
350 if (xp) *xp = 0;
351 if (yp) *yp = 0;
352 if (doc && doc->resolve_link)
353 return doc->resolve_link(ctx, doc, uri, xp, yp);
354 return fz_make_location(-1, -1);
355 }
356
357 void
fz_layout_document(fz_context * ctx,fz_document * doc,float w,float h,float em)358 fz_layout_document(fz_context *ctx, fz_document *doc, float w, float h, float em)
359 {
360 if (doc && doc->layout)
361 {
362 doc->layout(ctx, doc, w, h, em);
363 doc->did_layout = 1;
364 }
365 }
366
367 int
fz_count_chapters(fz_context * ctx,fz_document * doc)368 fz_count_chapters(fz_context *ctx, fz_document *doc)
369 {
370 fz_ensure_layout(ctx, doc);
371 if (doc && doc->count_chapters)
372 return doc->count_chapters(ctx, doc);
373 return 1;
374 }
375
376 int
fz_count_chapter_pages(fz_context * ctx,fz_document * doc,int chapter)377 fz_count_chapter_pages(fz_context *ctx, fz_document *doc, int chapter)
378 {
379 fz_ensure_layout(ctx, doc);
380 if (doc && doc->count_pages)
381 return doc->count_pages(ctx, doc, chapter);
382 return 0;
383 }
384
385 int
fz_count_pages(fz_context * ctx,fz_document * doc)386 fz_count_pages(fz_context *ctx, fz_document *doc)
387 {
388 int i, c, n = 0;
389 c = fz_count_chapters(ctx, doc);
390 for (i = 0; i < c; ++i)
391 n += fz_count_chapter_pages(ctx, doc, i);
392 return n;
393 }
394
395 fz_page *
fz_load_page(fz_context * ctx,fz_document * doc,int number)396 fz_load_page(fz_context *ctx, fz_document *doc, int number)
397 {
398 int i, n = fz_count_chapters(ctx, doc);
399 int start = 0;
400 for (i = 0; i < n; ++i)
401 {
402 int m = fz_count_chapter_pages(ctx, doc, i);
403 if (number < start + m)
404 return fz_load_chapter_page(ctx, doc, i, number - start);
405 start += m;
406 }
407 fz_throw(ctx, FZ_ERROR_GENERIC, "Page not found: %d", number+1);
408 }
409
fz_last_page(fz_context * ctx,fz_document * doc)410 fz_location fz_last_page(fz_context *ctx, fz_document *doc)
411 {
412 int nc = fz_count_chapters(ctx, doc);
413 int np = fz_count_chapter_pages(ctx, doc, nc-1);
414 return fz_make_location(nc-1, np-1);
415 }
416
fz_next_page(fz_context * ctx,fz_document * doc,fz_location loc)417 fz_location fz_next_page(fz_context *ctx, fz_document *doc, fz_location loc)
418 {
419 int nc = fz_count_chapters(ctx, doc);
420 int np = fz_count_chapter_pages(ctx, doc, loc.chapter);
421 if (loc.page + 1 == np)
422 {
423 if (loc.chapter + 1 < nc)
424 {
425 return fz_make_location(loc.chapter + 1, 0);
426 }
427 }
428 else
429 {
430 return fz_make_location(loc.chapter, loc.page + 1);
431 }
432 return loc;
433 }
434
fz_previous_page(fz_context * ctx,fz_document * doc,fz_location loc)435 fz_location fz_previous_page(fz_context *ctx, fz_document *doc, fz_location loc)
436 {
437 if (loc.page == 0)
438 {
439 if (loc.chapter > 0)
440 {
441 int np = fz_count_chapter_pages(ctx, doc, loc.chapter - 1);
442 return fz_make_location(loc.chapter - 1, np - 1);
443 }
444 }
445 else
446 {
447 return fz_make_location(loc.chapter, loc.page - 1);
448 }
449 return loc;
450 }
451
fz_clamp_location(fz_context * ctx,fz_document * doc,fz_location loc)452 fz_location fz_clamp_location(fz_context *ctx, fz_document *doc, fz_location loc)
453 {
454 int nc = fz_count_chapters(ctx, doc);
455 int np;
456 if (loc.chapter < 0) loc.chapter = 0;
457 if (loc.chapter >= nc) loc.chapter = nc - 1;
458 np = fz_count_chapter_pages(ctx, doc, loc.chapter);
459 if (loc.page < 0) loc.page = 0;
460 if (loc.page >= np) loc.page = np - 1;
461 return loc;
462 }
463
fz_location_from_page_number(fz_context * ctx,fz_document * doc,int number)464 fz_location fz_location_from_page_number(fz_context *ctx, fz_document *doc, int number)
465 {
466 int i, m = 0, n = fz_count_chapters(ctx, doc);
467 int start = 0;
468 if (number < 0)
469 number = 0;
470 for (i = 0; i < n; ++i)
471 {
472 m = fz_count_chapter_pages(ctx, doc, i);
473 if (number < start + m)
474 return fz_make_location(i, number - start);
475 start += m;
476 }
477 return fz_make_location(i-1, m-1);
478 }
479
fz_page_number_from_location(fz_context * ctx,fz_document * doc,fz_location loc)480 int fz_page_number_from_location(fz_context *ctx, fz_document *doc, fz_location loc)
481 {
482 int i, n, start = 0;
483 n = fz_count_chapters(ctx, doc);
484 for (i = 0; i < n; ++i)
485 {
486 if (i == loc.chapter)
487 return start + loc.page;
488 start += fz_count_chapter_pages(ctx, doc, i);
489 }
490 return -1;
491 }
492
493 int
fz_lookup_metadata(fz_context * ctx,fz_document * doc,const char * key,char * buf,int size)494 fz_lookup_metadata(fz_context *ctx, fz_document *doc, const char *key, char *buf, int size)
495 {
496 if (buf && size > 0)
497 buf[0] = 0;
498 if (doc && doc->lookup_metadata)
499 return doc->lookup_metadata(ctx, doc, key, buf, size);
500 return -1;
501 }
502
503 fz_colorspace *
fz_document_output_intent(fz_context * ctx,fz_document * doc)504 fz_document_output_intent(fz_context *ctx, fz_document *doc)
505 {
506 if (doc && doc->get_output_intent)
507 return doc->get_output_intent(ctx, doc);
508 return NULL;
509 }
510
511 fz_page *
fz_load_chapter_page(fz_context * ctx,fz_document * doc,int chapter,int number)512 fz_load_chapter_page(fz_context *ctx, fz_document *doc, int chapter, int number)
513 {
514 fz_page *page;
515
516 if (doc == NULL)
517 return NULL;
518
519 fz_ensure_layout(ctx, doc);
520
521 /* Protect modifications to the page list to cope with
522 * destruction of pages on other threads. */
523 fz_lock(ctx, FZ_LOCK_ALLOC);
524 for (page = doc->open; page; page = page->next)
525 if (page->chapter == chapter && page->number == number)
526 {
527 fz_unlock(ctx, FZ_LOCK_ALLOC);
528 return fz_keep_page(ctx, page);
529 }
530 fz_unlock(ctx, FZ_LOCK_ALLOC);
531
532 if (doc->load_page)
533 {
534 page = doc->load_page(ctx, doc, chapter, number);
535 page->chapter = chapter;
536 page->number = number;
537
538 /* Insert new page at the head of the list of open pages. */
539 if (!page->incomplete)
540 {
541 fz_lock(ctx, FZ_LOCK_ALLOC);
542 if ((page->next = doc->open) != NULL)
543 doc->open->prev = &page->next;
544 doc->open = page;
545 page->prev = &doc->open;
546 fz_unlock(ctx, FZ_LOCK_ALLOC);
547 }
548 return page;
549 }
550
551 return NULL;
552 }
553
554 fz_link *
fz_load_links(fz_context * ctx,fz_page * page)555 fz_load_links(fz_context *ctx, fz_page *page)
556 {
557 if (page && page->load_links)
558 return page->load_links(ctx, page);
559 return NULL;
560 }
561
562 fz_rect
fz_bound_page(fz_context * ctx,fz_page * page)563 fz_bound_page(fz_context *ctx, fz_page *page)
564 {
565 if (page && page->bound_page)
566 return page->bound_page(ctx, page);
567 return fz_empty_rect;
568 }
569
570 void
fz_run_page_contents(fz_context * ctx,fz_page * page,fz_device * dev,fz_matrix transform,fz_cookie * cookie)571 fz_run_page_contents(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
572 {
573 if (page && page->run_page_contents)
574 {
575 fz_try(ctx)
576 {
577 page->run_page_contents(ctx, page, dev, transform, cookie);
578 }
579 fz_catch(ctx)
580 {
581 dev->close_device = NULL; /* aborted run, don't warn about unclosed device */
582 if (fz_caught(ctx) != FZ_ERROR_ABORT)
583 fz_rethrow(ctx);
584 }
585 }
586 }
587
588 void
fz_run_page_annots(fz_context * ctx,fz_page * page,fz_device * dev,fz_matrix transform,fz_cookie * cookie)589 fz_run_page_annots(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
590 {
591 if (page && page->run_page_annots)
592 {
593 fz_try(ctx)
594 {
595 page->run_page_annots(ctx, page, dev, transform, cookie);
596 }
597 fz_catch(ctx)
598 {
599 dev->close_device = NULL; /* aborted run, don't warn about unclosed device */
600 if (fz_caught(ctx) != FZ_ERROR_ABORT)
601 fz_rethrow(ctx);
602 }
603 }
604 }
605
606 void
fz_run_page_widgets(fz_context * ctx,fz_page * page,fz_device * dev,fz_matrix transform,fz_cookie * cookie)607 fz_run_page_widgets(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
608 {
609 if (page && page->run_page_widgets)
610 {
611 fz_try(ctx)
612 {
613 page->run_page_widgets(ctx, page, dev, transform, cookie);
614 }
615 fz_catch(ctx)
616 {
617 dev->close_device = NULL; /* aborted run, don't warn about unclosed device */
618 if (fz_caught(ctx) != FZ_ERROR_ABORT)
619 fz_rethrow(ctx);
620 }
621 }
622 }
623
624 void
fz_run_page(fz_context * ctx,fz_page * page,fz_device * dev,fz_matrix transform,fz_cookie * cookie)625 fz_run_page(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
626 {
627 fz_run_page_contents(ctx, page, dev, transform, cookie);
628 fz_run_page_annots(ctx, page, dev, transform, cookie);
629 fz_run_page_widgets(ctx, page, dev, transform, cookie);
630 }
631
632 fz_page *
fz_new_page_of_size(fz_context * ctx,int size)633 fz_new_page_of_size(fz_context *ctx, int size)
634 {
635 fz_page *page = Memento_label(fz_calloc(ctx, 1, size), "fz_page");
636 page->refs = 1;
637 return page;
638 }
639
640 fz_page *
fz_keep_page(fz_context * ctx,fz_page * page)641 fz_keep_page(fz_context *ctx, fz_page *page)
642 {
643 return fz_keep_imp(ctx, page, &page->refs);
644 }
645
646 void
fz_drop_page(fz_context * ctx,fz_page * page)647 fz_drop_page(fz_context *ctx, fz_page *page)
648 {
649 if (fz_drop_imp(ctx, page, &page->refs))
650 {
651 /* Remove page from the list of open pages */
652 fz_lock(ctx, FZ_LOCK_ALLOC);
653 if (page->next != NULL)
654 page->next->prev = page->prev;
655 if (page->prev != NULL)
656 *page->prev = page->next;
657 fz_unlock(ctx, FZ_LOCK_ALLOC);
658
659 if (page->drop_page)
660 page->drop_page(ctx, page);
661
662 fz_free(ctx, page);
663 }
664 }
665
666 fz_transition *
fz_page_presentation(fz_context * ctx,fz_page * page,fz_transition * transition,float * duration)667 fz_page_presentation(fz_context *ctx, fz_page *page, fz_transition *transition, float *duration)
668 {
669 float dummy;
670 if (duration)
671 *duration = 0;
672 else
673 duration = &dummy;
674 if (page && page->page_presentation && page)
675 return page->page_presentation(ctx, page, transition, duration);
676 return NULL;
677 }
678
679 fz_separations *
fz_page_separations(fz_context * ctx,fz_page * page)680 fz_page_separations(fz_context *ctx, fz_page *page)
681 {
682 if (page && page->separations)
683 return page->separations(ctx, page);
684 return NULL;
685 }
686
fz_page_uses_overprint(fz_context * ctx,fz_page * page)687 int fz_page_uses_overprint(fz_context *ctx, fz_page *page)
688 {
689 if (page && page->overprint)
690 return page->overprint(ctx, page);
691 return 0;
692 }
693