1 #include "mupdf/fitz.h"
2 #include "mupdf/pdf.h"
3 
4 static void
pdf_run_annot_with_usage(fz_context * ctx,pdf_document * doc,pdf_page * page,pdf_annot * annot,fz_device * dev,fz_matrix ctm,const char * usage,fz_cookie * cookie)5 pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
6 {
7 	fz_matrix page_ctm;
8 	fz_rect mediabox;
9 	pdf_processor *proc = NULL;
10 	fz_default_colorspaces *default_cs = NULL;
11 	int flags;
12 
13 	fz_var(proc);
14 	fz_var(default_cs);
15 
16 	if (cookie && page->super.incomplete)
17 		cookie->incomplete = 1;
18 
19 	/* Widgets only get displayed if they have both a T and a TF flag,
20 	 * apparently */
21 	if (pdf_name_eq(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)), PDF_NAME(Widget)))
22 	{
23 		pdf_obj *ft = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(FT));
24 		pdf_obj *t = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(T));
25 
26 		if (ft == NULL || t == NULL)
27 			return;
28 	}
29 
30 	fz_try(ctx)
31 	{
32 		default_cs = pdf_load_default_colorspaces(ctx, doc, page);
33 		if (default_cs)
34 			fz_set_default_colorspaces(ctx, dev, default_cs);
35 
36 		pdf_page_transform(ctx, page, &mediabox, &page_ctm);
37 
38 		flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
39 		if (flags & PDF_ANNOT_IS_NO_ROTATE)
40 		{
41 			int rotate = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Rotate)));
42 			fz_rect rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
43 			fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm);
44 			page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y));
45 			page_ctm = fz_concat(page_ctm, fz_rotate(-rotate));
46 			page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y));
47 		}
48 
49 		ctm = fz_concat(page_ctm, ctm);
50 
51 		proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie);
52 		pdf_process_annot(ctx, proc, doc, page, annot, cookie);
53 		pdf_close_processor(ctx, proc);
54 	}
55 	fz_always(ctx)
56 	{
57 		pdf_drop_processor(ctx, proc);
58 		fz_drop_default_colorspaces(ctx, default_cs);
59 	}
60 	fz_catch(ctx)
61 		fz_rethrow(ctx);
62 }
63 
64 static void
pdf_run_page_contents_with_usage(fz_context * ctx,pdf_document * doc,pdf_page * page,fz_device * dev,fz_matrix ctm,const char * usage,fz_cookie * cookie)65 pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
66 {
67 	fz_matrix page_ctm;
68 	pdf_obj *resources;
69 	pdf_obj *contents;
70 	fz_rect mediabox;
71 	pdf_processor *proc = NULL;
72 	fz_default_colorspaces *default_cs = NULL;
73 	fz_colorspace *colorspace = NULL;
74 
75 	fz_var(proc);
76 	fz_var(colorspace);
77 	fz_var(default_cs);
78 
79 	if (cookie && page->super.incomplete)
80 		cookie->incomplete = 1;
81 
82 	fz_try(ctx)
83 	{
84 		default_cs = pdf_load_default_colorspaces(ctx, doc, page);
85 		if (default_cs)
86 			fz_set_default_colorspaces(ctx, dev, default_cs);
87 
88 		pdf_page_transform(ctx, page, &mediabox, &page_ctm);
89 		ctm = fz_concat(page_ctm, ctm);
90 		mediabox = fz_transform_rect(mediabox, ctm);
91 
92 		resources = pdf_page_resources(ctx, page);
93 		contents = pdf_page_contents(ctx, page);
94 
95 		if (page->transparency)
96 		{
97 			pdf_obj *group = pdf_page_group(ctx, page);
98 
99 			if (group)
100 			{
101 				pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME(CS));
102 				if (cs)
103 				{
104 					fz_try(ctx)
105 						colorspace = pdf_load_colorspace(ctx, cs);
106 					fz_catch(ctx)
107 					{
108 						fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
109 						fz_warn(ctx, "Ignoring Page blending colorspace.");
110 					}
111 					if (!fz_is_valid_blend_colorspace(ctx, colorspace))
112 					{
113 						fz_warn(ctx, "Ignoring invalid Page blending colorspace: %s.", colorspace->name);
114 						fz_drop_colorspace(ctx, colorspace);
115 						colorspace = NULL;
116 					}
117 				}
118 			}
119 			else
120 				colorspace = fz_keep_colorspace(ctx, fz_default_output_intent(ctx, default_cs));
121 
122 			fz_begin_group(ctx, dev, mediabox, colorspace, 1, 0, 0, 1);
123 		}
124 
125 		proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie);
126 		pdf_process_contents(ctx, proc, doc, resources, contents, cookie);
127 		pdf_close_processor(ctx, proc);
128 
129 		if (page->transparency)
130 		{
131 			fz_end_group(ctx, dev);
132 		}
133 	}
134 	fz_always(ctx)
135 	{
136 		pdf_drop_processor(ctx, proc);
137 		fz_drop_colorspace(ctx, colorspace);
138 		fz_drop_default_colorspaces(ctx, default_cs);
139 	}
140 	fz_catch(ctx)
141 	{
142 		fz_rethrow(ctx);
143 	}
144 }
145 
pdf_run_page_contents(fz_context * ctx,pdf_page * page,fz_device * dev,fz_matrix ctm,fz_cookie * cookie)146 void pdf_run_page_contents(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
147 {
148 	pdf_document *doc = page->doc;
149 	int nocache;
150 
151 	nocache = !!(dev->hints & FZ_NO_CACHE);
152 	if (nocache)
153 		pdf_mark_xref(ctx, doc);
154 
155 	fz_try(ctx)
156 	{
157 		pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
158 	}
159 	fz_always(ctx)
160 	{
161 		if (nocache)
162 			pdf_clear_xref_to_mark(ctx, doc);
163 	}
164 	fz_catch(ctx)
165 	{
166 		fz_rethrow(ctx);
167 	}
168 }
169 
pdf_run_annot(fz_context * ctx,pdf_annot * annot,fz_device * dev,fz_matrix ctm,fz_cookie * cookie)170 void pdf_run_annot(fz_context *ctx, pdf_annot *annot, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
171 {
172 	pdf_page *page = annot->page;
173 	pdf_document *doc = page->doc;
174 	int nocache;
175 
176 	nocache = !!(dev->hints & FZ_NO_CACHE);
177 	if (nocache)
178 		pdf_mark_xref(ctx, doc);
179 	fz_try(ctx)
180 	{
181 		pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, "View", cookie);
182 	}
183 	fz_always(ctx)
184 	{
185 		if (nocache)
186 			pdf_clear_xref_to_mark(ctx, doc);
187 	}
188 	fz_catch(ctx)
189 	{
190 		fz_rethrow(ctx);
191 	}
192 }
193 
194 static void
pdf_run_page_widgets_with_usage(fz_context * ctx,pdf_document * doc,pdf_page * page,fz_device * dev,fz_matrix ctm,const char * usage,fz_cookie * cookie)195 pdf_run_page_widgets_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
196 {
197 	pdf_widget *widget;
198 
199 	if (cookie && cookie->progress_max != (size_t)-1)
200 	{
201 		int count = 1;
202 		for (widget = page->widgets; widget; widget = widget->next)
203 			count++;
204 		cookie->progress_max += count;
205 	}
206 
207 	for (widget = page->widgets; widget; widget = widget->next)
208 	{
209 		/* Check the cookie for aborting */
210 		if (cookie)
211 		{
212 			if (cookie->abort)
213 				break;
214 			cookie->progress++;
215 		}
216 
217 		pdf_run_annot_with_usage(ctx, doc, page, widget, dev, ctm, usage, cookie);
218 	}
219 }
220 
221 static void
pdf_run_page_annots_with_usage(fz_context * ctx,pdf_document * doc,pdf_page * page,fz_device * dev,fz_matrix ctm,const char * usage,fz_cookie * cookie)222 pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
223 {
224 	pdf_annot *annot;
225 
226 	if (cookie && cookie->progress_max != (size_t)-1)
227 	{
228 		int count = 1;
229 		for (annot = page->annots; annot; annot = annot->next)
230 			count++;
231 		cookie->progress_max += count;
232 	}
233 
234 	for (annot = page->annots; annot; annot = annot->next)
235 	{
236 		/* Check the cookie for aborting */
237 		if (cookie)
238 		{
239 			if (cookie->abort)
240 				break;
241 			cookie->progress++;
242 		}
243 
244 		pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, usage, cookie);
245 	}
246 }
247 
pdf_run_page_annots(fz_context * ctx,pdf_page * page,fz_device * dev,fz_matrix ctm,fz_cookie * cookie)248 void pdf_run_page_annots(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
249 {
250 	pdf_document *doc = page->doc;
251 	int nocache;
252 
253 	nocache = !!(dev->hints & FZ_NO_CACHE);
254 	if (nocache)
255 		pdf_mark_xref(ctx, doc);
256 
257 	fz_try(ctx)
258 	{
259 		pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
260 	}
261 	fz_always(ctx)
262 	{
263 		if (nocache)
264 			pdf_clear_xref_to_mark(ctx, doc);
265 	}
266 	fz_catch(ctx)
267 	{
268 		fz_rethrow(ctx);
269 	}
270 }
271 
pdf_run_page_widgets(fz_context * ctx,pdf_page * page,fz_device * dev,fz_matrix ctm,fz_cookie * cookie)272 void pdf_run_page_widgets(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
273 {
274 	pdf_document *doc = page->doc;
275 	int nocache;
276 
277 	nocache = !!(dev->hints & FZ_NO_CACHE);
278 	if (nocache)
279 		pdf_mark_xref(ctx, doc);
280 
281 	fz_try(ctx)
282 	{
283 		pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
284 	}
285 	fz_always(ctx)
286 	{
287 		if (nocache)
288 			pdf_clear_xref_to_mark(ctx, doc);
289 	}
290 	fz_catch(ctx)
291 	{
292 		fz_rethrow(ctx);
293 	}
294 }
295 
296 void
pdf_run_page_with_usage(fz_context * ctx,pdf_document * doc,pdf_page * page,fz_device * dev,fz_matrix ctm,const char * usage,fz_cookie * cookie)297 pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
298 {
299 	int nocache = !!(dev->hints & FZ_NO_CACHE);
300 
301 	if (nocache)
302 		pdf_mark_xref(ctx, doc);
303 	fz_try(ctx)
304 	{
305 		pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
306 		pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
307 		pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
308 	}
309 	fz_always(ctx)
310 	{
311 		if (nocache)
312 			pdf_clear_xref_to_mark(ctx, doc);
313 	}
314 	fz_catch(ctx)
315 	{
316 		fz_rethrow(ctx);
317 	}
318 }
319 
320 void
pdf_run_page(fz_context * ctx,pdf_page * page,fz_device * dev,fz_matrix ctm,fz_cookie * cookie)321 pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
322 {
323 	pdf_document *doc = page->doc;
324 	pdf_run_page_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
325 }
326 
327 void
pdf_run_glyph(fz_context * ctx,pdf_document * doc,pdf_obj * resources,fz_buffer * contents,fz_device * dev,fz_matrix ctm,void * gstate,fz_default_colorspaces * default_cs)328 pdf_run_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, fz_default_colorspaces *default_cs)
329 {
330 	pdf_processor *proc;
331 
332 	proc = pdf_new_run_processor(ctx, dev, ctm, "View", gstate, default_cs, NULL);
333 	fz_try(ctx)
334 	{
335 		pdf_process_glyph(ctx, proc, doc, resources, contents);
336 		pdf_close_processor(ctx, proc);
337 	}
338 	fz_always(ctx)
339 		pdf_drop_processor(ctx, proc);
340 	fz_catch(ctx)
341 		fz_rethrow(ctx);
342 }
343