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