/src/ghostpdl/xps/xpstop.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* Top-level API implementation of XML Paper Specification */ |
17 | | |
18 | | /* Language wrapper implementation (see pltop.h) */ |
19 | | |
20 | | #include "ghostxps.h" |
21 | | |
22 | | #include "pltop.h" |
23 | | #include "plmain.h" |
24 | | |
25 | | #include "plparse.h" /* for e_ExitLanguage */ |
26 | | #include "plmain.h" |
27 | | #include "gxdevice.h" /* so we can include gxht.h below */ |
28 | | #include "gxht.h" /* gsht1.h is incomplete, we need storage size of gs_halftone */ |
29 | | #include "gsht1.h" |
30 | | #include "gsparam.h" |
31 | | |
32 | | #include <assert.h> |
33 | | |
34 | | static int xps_install_halftone(xps_context_t *ctx, gx_device *pdevice); |
35 | | |
36 | | /* |
37 | | * The XPS interpeter is identical to pl_interp_t. |
38 | | * The XPS interpreter instance is derived from pl_interp_implementation_t. |
39 | | */ |
40 | | |
41 | | typedef struct xps_interp_instance_s xps_interp_instance_t; |
42 | | |
43 | | struct xps_interp_instance_s |
44 | | { |
45 | | gs_memory_t *memory; /* memory allocator to use */ |
46 | | |
47 | | xps_context_t *ctx; |
48 | | gp_file *scratch_file; |
49 | | char scratch_name[gp_file_name_sizeof]; |
50 | | }; |
51 | | |
52 | | static int |
53 | | xps_detect_language(const char *s, int len) |
54 | 17.7k | { |
55 | 17.7k | if (len < 2) |
56 | 19 | return 0; |
57 | 17.7k | if (memcmp(s, "PK", 2) == 0) |
58 | 307 | return 80; /* Pretty sure, but not 100, so the SO one can override us. */ |
59 | 17.4k | return 0; |
60 | 17.7k | } |
61 | | |
62 | | static const pl_interp_characteristics_t * |
63 | | xps_impl_characteristics(const pl_interp_implementation_t *pimpl) |
64 | 37.5k | { |
65 | 37.5k | static pl_interp_characteristics_t xps_characteristics = |
66 | 37.5k | { |
67 | 37.5k | "XPS", |
68 | 37.5k | xps_detect_language, |
69 | 37.5k | }; |
70 | 37.5k | return &xps_characteristics; |
71 | 37.5k | } |
72 | | |
73 | | static void |
74 | | xps_set_nocache(pl_interp_implementation_t *impl, gs_font_dir *font_dir) |
75 | 90 | { |
76 | 90 | bool nocache; |
77 | 90 | xps_interp_instance_t *xpsi = impl->interp_client_data; |
78 | 90 | nocache = pl_main_get_nocache(xpsi->memory); |
79 | 90 | if (nocache) |
80 | 0 | gs_setcachelimit(font_dir, 0); |
81 | 90 | return; |
82 | 90 | } |
83 | | |
84 | | |
85 | | static int |
86 | | xps_set_icc_user_params(pl_interp_implementation_t *impl, gs_gstate *pgs) |
87 | 90 | { |
88 | 90 | xps_interp_instance_t *xpsi = impl->interp_client_data; |
89 | 90 | return pl_set_icc_params(xpsi->memory, pgs); |
90 | 90 | } |
91 | | |
92 | | /* Do per-instance interpreter allocation/init. No device is set yet */ |
93 | | static int |
94 | | xps_impl_allocate_interp_instance(pl_interp_implementation_t *impl, |
95 | | gs_memory_t *pmem) |
96 | 8.09k | { |
97 | 8.09k | int code = 0; |
98 | 8.09k | xps_interp_instance_t *instance; |
99 | 8.09k | xps_context_t *ctx; |
100 | 8.09k | gs_gstate *pgs; |
101 | | |
102 | 8.09k | instance = (xps_interp_instance_t *) gs_alloc_bytes(pmem, |
103 | 8.09k | sizeof(xps_interp_instance_t), "xps_impl_allocate_interp_instance"); |
104 | | |
105 | 8.09k | ctx = (xps_context_t *) gs_alloc_bytes(pmem, |
106 | 8.09k | sizeof(xps_context_t), "xps_impl_allocate_interp_instance"); |
107 | | |
108 | 8.09k | pgs = gs_gstate_alloc(pmem); |
109 | | |
110 | 8.09k | if (!instance || !ctx || !pgs) |
111 | 0 | { |
112 | 0 | code = gs_error_VMerror; |
113 | 0 | goto end; |
114 | 0 | } |
115 | | |
116 | | /* FIXME: check return value */ |
117 | 8.09k | gsicc_init_iccmanager(pgs); |
118 | 8.09k | memset(ctx, 0, sizeof(xps_context_t)); |
119 | | |
120 | 8.09k | ctx->instance = instance; |
121 | 8.09k | ctx->memory = pmem; |
122 | 8.09k | ctx->pgs = pgs; |
123 | | /* Declare PDL client support for high level patterns, for the benefit |
124 | | * of pdfwrite and other high-level devices |
125 | | */ |
126 | 8.09k | ctx->pgs->have_pattern_streams = true; |
127 | 8.09k | ctx->fontdir = NULL; |
128 | 8.09k | ctx->preserve_tr_mode = 0; |
129 | | |
130 | 8.09k | ctx->file = NULL; |
131 | 8.09k | ctx->zip_count = 0; |
132 | 8.09k | ctx->zip_table = NULL; |
133 | 8.09k | ctx->in_high_level_pattern = false; |
134 | | |
135 | | /* Gray, RGB and CMYK profiles set when color spaces installed in graphics lib */ |
136 | 8.09k | ctx->gray_lin = gs_cspace_new_ICC(ctx->memory, ctx->pgs, -1); |
137 | 8.09k | ctx->gray = gs_cspace_new_ICC(ctx->memory, ctx->pgs, 1); |
138 | 8.09k | ctx->cmyk = gs_cspace_new_ICC(ctx->memory, ctx->pgs, 4); |
139 | 8.09k | ctx->srgb = gs_cspace_new_ICC(ctx->memory, ctx->pgs, 3); |
140 | | |
141 | | /* scrgb needs special treatment */ |
142 | 8.09k | ctx->scrgb = gs_cspace_new_scrgb(ctx->memory, ctx->pgs); |
143 | | |
144 | 8.09k | instance->ctx = ctx; |
145 | 8.09k | instance->scratch_file = NULL; |
146 | 8.09k | instance->scratch_name[0] = 0; |
147 | 8.09k | instance->memory = pmem; |
148 | | |
149 | | /* NB needs error handling */ |
150 | 8.09k | ctx->fontdir = gs_font_dir_alloc(ctx->memory); |
151 | 8.09k | if (!ctx->fontdir) { |
152 | 0 | code = gs_error_VMerror; |
153 | 0 | goto end; |
154 | 0 | } |
155 | 8.09k | gs_setaligntopixels(ctx->fontdir, 1); /* no subpixels */ |
156 | 8.09k | gs_setgridfittt(ctx->fontdir, 1); /* see gx_ttf_outline in gxttfn.c for values */ |
157 | | |
158 | 8.09k | impl->interp_client_data = instance; |
159 | | |
160 | 8.09k | end: |
161 | 8.09k | if (code < 0) { |
162 | 0 | if (instance) { |
163 | 0 | gs_free_object(pmem, instance, "xps_impl_allocate_interp_instance"); |
164 | 0 | } |
165 | 0 | if (ctx) { |
166 | 0 | assert(!ctx->fontdir); |
167 | 0 | rc_decrement(ctx->gray_lin, "gs_cspace_new_ICC"); |
168 | 0 | rc_decrement(ctx->gray, "gs_cspace_new_ICC"); |
169 | 0 | rc_decrement(ctx->cmyk, "gs_cspace_new_ICC"); |
170 | 0 | rc_decrement(ctx->srgb, "gs_cspace_new_ICC"); |
171 | 0 | rc_decrement(ctx->scrgb, "gs_cspace_new_ICC"); |
172 | 0 | gs_free_object(pmem, ctx, "xps_impl_allocate_interp_instance"); |
173 | 0 | } |
174 | 0 | if (pgs) { |
175 | 0 | gs_gstate_free(pgs); |
176 | 0 | } |
177 | 0 | } |
178 | 8.09k | return code; |
179 | 8.09k | } |
180 | | |
181 | | /* Prepare interp instance for the next "job" */ |
182 | | static int |
183 | | xps_impl_init_job(pl_interp_implementation_t *impl, |
184 | | gx_device *pdevice) |
185 | 90 | { |
186 | 90 | xps_interp_instance_t *instance = impl->interp_client_data; |
187 | 90 | xps_context_t *ctx = instance->ctx; |
188 | 90 | gs_c_param_list list; |
189 | 90 | int code; |
190 | 90 | bool disable_page_handler = false; |
191 | 90 | bool true_val = true; |
192 | 90 | gs_memory_t* mem = ctx->memory; |
193 | | |
194 | 90 | ctx->font_table = xps_hash_new(ctx); |
195 | 90 | ctx->colorspace_table = xps_hash_new(ctx); |
196 | | |
197 | 90 | ctx->start_part = NULL; |
198 | | |
199 | 90 | ctx->use_transparency = 1; |
200 | 90 | if (getenv("XPS_DISABLE_TRANSPARENCY")) |
201 | 0 | ctx->use_transparency = 0; |
202 | | |
203 | 90 | ctx->opacity_only = 0; |
204 | 90 | ctx->fill_rule = 0; |
205 | | |
206 | 90 | code = gs_setdevice_no_erase(ctx->pgs, pdevice); |
207 | 90 | if (code < 0) |
208 | 0 | goto cleanup_setdevice; |
209 | | |
210 | | /* Check if the device wants PreserveTrMode (pdfwrite) */ |
211 | 90 | gs_c_param_list_write(&list, pdevice->memory); |
212 | 90 | code = gs_getdeviceparams(pdevice, (gs_param_list *)&list); |
213 | 90 | if (code >= 0) { |
214 | 90 | bool trm = false; |
215 | 90 | gs_c_param_list_read(&list); |
216 | 90 | code = param_read_bool((gs_param_list *)&list, "PreserveTrMode", &trm); |
217 | 90 | ctx->preserve_tr_mode = (int)trm; |
218 | 90 | } |
219 | 90 | gs_c_param_list_release(&list); |
220 | 90 | if (code < 0) |
221 | 0 | return code; |
222 | | |
223 | 90 | gs_setaccuratecurves(ctx->pgs, true); /* NB not sure */ |
224 | 90 | gs_setfilladjust(ctx->pgs, 0, 0); |
225 | 90 | (void)xps_set_icc_user_params(impl, ctx->pgs); |
226 | 90 | xps_set_nocache(impl, ctx->fontdir); |
227 | | |
228 | 90 | gs_setscanconverter(ctx->pgs, pl_main_get_scanconverter(ctx->memory)); |
229 | | |
230 | | /* Disable the page handler as the XPS interpreter will handle page range. |
231 | | List takes precedent over firstpage lastpage */ |
232 | 90 | if (pdevice->PageList != NULL && pdevice->PageHandlerPushed) |
233 | 0 | { |
234 | 0 | ctx->page_range = xps_alloc(ctx, sizeof(xps_page_range_t)); |
235 | 0 | if (!ctx->page_range) |
236 | 0 | { |
237 | 0 | return gs_rethrow(gs_error_VMerror, "out of memory: page_range struct"); |
238 | 0 | } |
239 | | |
240 | 0 | ctx->page_range->page_list = xps_strdup(ctx, pdevice->PageList->Pages); |
241 | 0 | if (!ctx->page_range->page_list) |
242 | 0 | { |
243 | 0 | return gs_rethrow(gs_error_VMerror, "out of memory: page_list"); |
244 | 0 | } |
245 | 0 | disable_page_handler = true; |
246 | 0 | ctx->page_range->reverse = false; |
247 | 0 | } |
248 | 90 | else if ((pdevice->FirstPage > 0 || pdevice->LastPage > 0) && |
249 | 0 | pdevice->PageHandlerPushed) |
250 | 0 | { |
251 | 0 | disable_page_handler = true; |
252 | |
|
253 | 0 | ctx->page_range = xps_alloc(ctx, sizeof(xps_page_range_t)); |
254 | 0 | if (!ctx->page_range) |
255 | 0 | { |
256 | 0 | return gs_throw(gs_error_VMerror, "out of memory: page_range struct"); |
257 | 0 | } |
258 | 0 | ctx->page_range->first = pdevice->FirstPage; |
259 | 0 | ctx->page_range->last = pdevice->LastPage; |
260 | 0 | ctx->page_range->current = 0; |
261 | 0 | ctx->page_range->page_list = NULL; |
262 | |
|
263 | 0 | if (ctx->page_range->first != 0 && |
264 | 0 | ctx->page_range->last != 0 && |
265 | 0 | ctx->page_range->first > ctx->page_range->last) |
266 | 0 | ctx->page_range->reverse = true; |
267 | 0 | else |
268 | 0 | ctx->page_range->reverse = false; |
269 | 0 | } |
270 | | |
271 | 90 | if (disable_page_handler) |
272 | 0 | { |
273 | 0 | gs_c_param_list_write(&list, mem); |
274 | 0 | code = param_write_bool((gs_param_list*)&list, "DisablePageHandler", &(true_val)); |
275 | 0 | if (code >= 0) |
276 | 0 | { |
277 | 0 | gs_c_param_list_read(&list); |
278 | 0 | code = gs_putdeviceparams(pdevice, (gs_param_list*)&list); |
279 | 0 | gs_c_param_list_release(&list); |
280 | 0 | if (code < 0) { |
281 | 0 | return gs_rethrow(code, "cannot set device parameters"); |
282 | 0 | } |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | /* gsave and grestore (among other places) assume that */ |
287 | | /* there are at least 2 gstates on the graphics stack. */ |
288 | | /* Ensure that now. */ |
289 | 90 | code = gs_gsave(ctx->pgs); |
290 | 90 | if (code < 0) |
291 | 0 | goto cleanup_gsave; |
292 | | |
293 | 90 | code = gs_erasepage(ctx->pgs); |
294 | 90 | if (code < 0) |
295 | 0 | goto cleanup_erase; |
296 | | |
297 | 90 | code = xps_install_halftone(ctx, pdevice); |
298 | 90 | if (code < 0) |
299 | 0 | goto cleanup_halftone; |
300 | | |
301 | 90 | return 0; |
302 | | |
303 | 0 | cleanup_halftone: |
304 | 0 | cleanup_erase: |
305 | | /* undo gsave */ |
306 | 0 | gs_grestore_only(ctx->pgs); /* destroys gs_save stack */ |
307 | |
|
308 | 0 | cleanup_gsave: |
309 | | /* undo setdevice */ |
310 | 0 | gs_nulldevice(ctx->pgs); |
311 | |
|
312 | 0 | cleanup_setdevice: |
313 | | /* nothing to undo */ |
314 | 0 | return code; |
315 | 0 | } |
316 | | |
317 | | /* Parse an entire random access file */ |
318 | | static int |
319 | | xps_impl_process_file(pl_interp_implementation_t *impl, const char *filename) |
320 | 90 | { |
321 | 90 | xps_interp_instance_t *instance = impl->interp_client_data; |
322 | 90 | xps_context_t *ctx = instance->ctx; |
323 | 90 | int code; |
324 | | |
325 | 90 | code = xps_process_file(ctx, filename); |
326 | 90 | if (code) |
327 | 87 | gs_catch1(code, "cannot process xps file '%s'", filename); |
328 | | |
329 | 90 | return code; |
330 | 90 | } |
331 | | |
332 | | /* Do any setup for parser per-cursor */ |
333 | | static int /* ret 0 or +ve if ok, else -ve error code */ |
334 | | xps_impl_process_begin(pl_interp_implementation_t * impl) |
335 | 0 | { |
336 | 0 | return 0; |
337 | 0 | } |
338 | | |
339 | | /* Parse a cursor-full of data */ |
340 | | static int |
341 | | xps_impl_process(pl_interp_implementation_t *impl, stream_cursor_read *cursor) |
342 | 0 | { |
343 | 0 | xps_interp_instance_t *instance = impl->interp_client_data; |
344 | 0 | xps_context_t *ctx = instance->ctx; |
345 | 0 | int avail, n; |
346 | |
|
347 | 0 | if (!instance->scratch_file) |
348 | 0 | { |
349 | 0 | instance->scratch_file = gp_open_scratch_file(ctx->memory, |
350 | 0 | "ghostxps-scratch-", instance->scratch_name, "wb"); |
351 | 0 | if (!instance->scratch_file) |
352 | 0 | { |
353 | 0 | gs_catch(gs_error_invalidfileaccess, "cannot open scratch file"); |
354 | 0 | return e_ExitLanguage; |
355 | 0 | } |
356 | 0 | if_debug1m('|', ctx->memory, "xps: open scratch file '%s'\n", instance->scratch_name); |
357 | 0 | } |
358 | | |
359 | 0 | avail = cursor->limit - cursor->ptr; |
360 | 0 | n = gp_fwrite(cursor->ptr + 1, 1, avail, instance->scratch_file); |
361 | 0 | if (n != avail) |
362 | 0 | { |
363 | 0 | gs_catch(gs_error_invalidfileaccess, "cannot write to scratch file"); |
364 | 0 | return e_ExitLanguage; |
365 | 0 | } |
366 | 0 | cursor->ptr = cursor->limit; |
367 | |
|
368 | 0 | return 0; |
369 | 0 | } |
370 | | |
371 | | static int /* ret 0 or +ve if ok, else -ve error code */ |
372 | | xps_impl_process_end(pl_interp_implementation_t * impl) |
373 | 0 | { |
374 | 0 | return 0; |
375 | 0 | } |
376 | | |
377 | | /* Skip to end of job. |
378 | | * Return 1 if done, 0 ok but EOJ not found, else negative error code. |
379 | | */ |
380 | | static int |
381 | | xps_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *pcursor) |
382 | 0 | { |
383 | | /* assume XPS cannot be pjl embedded */ |
384 | 0 | pcursor->ptr = pcursor->limit; |
385 | 0 | return 0; |
386 | 0 | } |
387 | | |
388 | | /* Parser action for end-of-file */ |
389 | | static int |
390 | | xps_impl_process_eof(pl_interp_implementation_t *impl) |
391 | 0 | { |
392 | 0 | xps_interp_instance_t *instance = impl->interp_client_data; |
393 | 0 | xps_context_t *ctx = instance->ctx; |
394 | 0 | int code; |
395 | |
|
396 | 0 | if (instance->scratch_file) |
397 | 0 | { |
398 | 0 | if_debug0m('|', ctx->memory, "xps: executing scratch file\n"); |
399 | 0 | gp_fclose(instance->scratch_file); |
400 | 0 | instance->scratch_file = NULL; |
401 | 0 | code = xps_process_file(ctx, instance->scratch_name); |
402 | 0 | gp_unlink(ctx->memory, instance->scratch_name); |
403 | 0 | if (code < 0) |
404 | 0 | { |
405 | 0 | gs_catch(code, "cannot process XPS file"); |
406 | 0 | return e_ExitLanguage; |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | 0 | return 0; |
411 | 0 | } |
412 | | |
413 | | /* Report any errors after running a job */ |
414 | | static int |
415 | | xps_impl_report_errors(pl_interp_implementation_t *impl, |
416 | | int code, /* prev termination status */ |
417 | | long file_position, /* file position of error, -1 if unknown */ |
418 | | bool force_to_cout /* force errors to cout */ |
419 | | ) |
420 | 0 | { |
421 | 0 | return 0; |
422 | 0 | } |
423 | | |
424 | | static void xps_free_key_func(xps_context_t *ctx, void *ptr) |
425 | 2 | { |
426 | 2 | xps_free(ctx, ptr); |
427 | 2 | } |
428 | | |
429 | | static void xps_free_font_func(xps_context_t *ctx, void *ptr) |
430 | 2 | { |
431 | 2 | xps_free_font(ctx, ptr); |
432 | 2 | } |
433 | | |
434 | | static void xps_free_hashed_colorspace(xps_context_t *ctx, void *ptr) |
435 | 0 | { |
436 | 0 | gs_color_space *cs = (gs_color_space *)ptr; |
437 | 0 | rc_decrement(cs, "xps_free_hashed_colorspace"); |
438 | 0 | } |
439 | | |
440 | | /* Wrap up interp instance after a "job" */ |
441 | | static int |
442 | | xps_impl_dnit_job(pl_interp_implementation_t *impl) |
443 | 90 | { |
444 | 90 | xps_interp_instance_t *instance = impl->interp_client_data; |
445 | 90 | xps_context_t *ctx = instance->ctx; |
446 | 90 | int i, code; |
447 | | |
448 | | /* return to original gstate */ |
449 | 90 | code = gs_grestore_only(ctx->pgs); /* destroys gs_save stack */ |
450 | | |
451 | 90 | if (gs_debug_c('|')) |
452 | 0 | xps_debug_fixdocseq(ctx); |
453 | | |
454 | 254k | for (i = 0; i < ctx->zip_count; i++) |
455 | 254k | xps_free(ctx, ctx->zip_table[i].name); |
456 | 90 | xps_free(ctx, ctx->zip_table); |
457 | | |
458 | | /* TODO: free resources too */ |
459 | 90 | xps_hash_free(ctx, ctx->font_table, xps_free_key_func, xps_free_font_func); |
460 | 90 | xps_hash_free(ctx, ctx->colorspace_table, xps_free_key_func, xps_free_hashed_colorspace); |
461 | | |
462 | 90 | if (ctx->page_range) |
463 | 0 | { |
464 | 0 | if (ctx->page_range->page_list) |
465 | 0 | xps_free(ctx, ctx->page_range->page_list); |
466 | 0 | xps_free(ctx, ctx->page_range); |
467 | 0 | ctx->page_range = NULL; |
468 | 0 | } |
469 | | |
470 | 90 | xps_free_fixed_pages(ctx); |
471 | 90 | xps_free_fixed_documents(ctx); |
472 | | |
473 | 90 | return code; |
474 | 90 | } |
475 | | |
476 | | /* Deallocate a interpreter instance */ |
477 | | static int |
478 | | xps_impl_deallocate_interp_instance(pl_interp_implementation_t *impl) |
479 | 8.09k | { |
480 | 8.09k | xps_interp_instance_t *instance = impl->interp_client_data; |
481 | 8.09k | xps_context_t *ctx = instance->ctx; |
482 | 8.09k | gs_memory_t *mem = ctx->memory; |
483 | | |
484 | | /* language clients don't free the font cache machinery */ |
485 | 8.09k | rc_decrement_cs(ctx->gray_lin, "xps_impl_deallocate_interp_instance"); |
486 | 8.09k | rc_decrement_cs(ctx->gray, "xps_impl_deallocate_interp_instance"); |
487 | 8.09k | rc_decrement_cs(ctx->cmyk, "xps_impl_deallocate_interp_instance"); |
488 | 8.09k | rc_decrement_cs(ctx->srgb, "xps_impl_deallocate_interp_instance"); |
489 | 8.09k | rc_decrement_cs(ctx->scrgb, "xps_impl_deallocate_interp_instance"); |
490 | | |
491 | 8.09k | gx_pattern_cache_free(ctx->pgs->pattern_cache); |
492 | 8.09k | gs_gstate_free(ctx->pgs); |
493 | | |
494 | 8.09k | gs_free_object(mem, ctx->start_part, "xps_impl_deallocate_interp_instance"); |
495 | 8.09k | gs_free_object(mem, ctx->fontdir, "xps_impl_deallocate_interp_instance"); |
496 | 8.09k | gs_free_object(mem, ctx, "xps_impl_deallocate_interp_instance"); |
497 | 8.09k | gs_free_object(mem, instance, "xps_impl_deallocate_interp_instance"); |
498 | | |
499 | 8.09k | return 0; |
500 | 8.09k | } |
501 | | |
502 | | /* Parser implementation descriptor */ |
503 | | pl_interp_implementation_t xps_implementation = |
504 | | { |
505 | | xps_impl_characteristics, |
506 | | xps_impl_allocate_interp_instance, |
507 | | NULL, /* get_device_memory */ |
508 | | NULL, /* set_param */ |
509 | | NULL, /* add_path */ |
510 | | NULL, /* post_args_init */ |
511 | | xps_impl_init_job, |
512 | | NULL, /* run_prefix_commands */ |
513 | | xps_impl_process_file, |
514 | | xps_impl_process_begin, |
515 | | xps_impl_process, |
516 | | xps_impl_process_end, |
517 | | xps_impl_flush_to_eoj, |
518 | | xps_impl_process_eof, |
519 | | xps_impl_report_errors, |
520 | | xps_impl_dnit_job, |
521 | | xps_impl_deallocate_interp_instance, |
522 | | NULL, |
523 | | }; |
524 | | |
525 | | /* |
526 | | * End-of-page function called by XPS parser. |
527 | | */ |
528 | | int |
529 | | xps_show_page(xps_context_t *ctx, int num_copies, int flush) |
530 | 3 | { |
531 | 3 | return pl_finish_page(ctx->memory->gs_lib_ctx->top_of_system, |
532 | 3 | ctx->pgs, num_copies, flush); |
533 | 3 | } |
534 | | |
535 | | /* |
536 | | * We need to install a halftone ourselves, this is not |
537 | | * done automatically. |
538 | | */ |
539 | | |
540 | | static float |
541 | | identity_transfer(double tint, const gx_transfer_map *ignore_map) |
542 | 23.0k | { |
543 | 23.0k | return tint; |
544 | 23.0k | } |
545 | | |
546 | | /* The following is a 45 degree spot screen with the spots enumerated |
547 | | * in a defined order. */ |
548 | | static byte order16x16[256] = { |
549 | | 38, 11, 14, 32, 165, 105, 90, 171, 38, 12, 14, 33, 161, 101, 88, 167, |
550 | | 30, 6, 0, 16, 61, 225, 231, 125, 30, 6, 1, 17, 63, 222, 227, 122, |
551 | | 27, 3, 8, 19, 71, 242, 205, 110, 28, 4, 9, 20, 74, 246, 208, 106, |
552 | | 35, 24, 22, 40, 182, 46, 56, 144, 36, 25, 22, 41, 186, 48, 58, 148, |
553 | | 152, 91, 81, 174, 39, 12, 15, 34, 156, 95, 84, 178, 40, 13, 16, 34, |
554 | | 69, 212, 235, 129, 31, 7, 2, 18, 66, 216, 239, 133, 32, 8, 2, 18, |
555 | | 79, 254, 203, 114, 28, 4, 10, 20, 76, 250, 199, 118, 29, 5, 10, 21, |
556 | | 193, 44, 54, 142, 36, 26, 23, 42, 189, 43, 52, 139, 37, 26, 24, 42, |
557 | | 39, 12, 15, 33, 159, 99, 87, 169, 38, 11, 14, 33, 163, 103, 89, 172, |
558 | | 31, 7, 1, 17, 65, 220, 229, 123, 30, 6, 1, 17, 62, 223, 233, 127, |
559 | | 28, 4, 9, 20, 75, 248, 210, 108, 27, 3, 9, 19, 72, 244, 206, 112, |
560 | | 36, 25, 23, 41, 188, 49, 60, 150, 35, 25, 22, 41, 184, 47, 57, 146, |
561 | | 157, 97, 85, 180, 40, 13, 16, 35, 154, 93, 83, 176, 39, 13, 15, 34, |
562 | | 67, 218, 240, 135, 32, 8, 3, 19, 70, 214, 237, 131, 31, 7, 2, 18, |
563 | | 78, 252, 197, 120, 29, 5, 11, 21, 80, 255, 201, 116, 29, 5, 10, 21, |
564 | | 191, 43, 51, 137, 37, 27, 24, 43, 195, 44, 53, 140, 37, 26, 23, 42 |
565 | | }; |
566 | | |
567 | | #define source_phase_x 4 |
568 | | #define source_phase_y 0 |
569 | | |
570 | | static int |
571 | | xps_install_halftone(xps_context_t *ctx, gx_device *pdevice) |
572 | 90 | { |
573 | 90 | gs_halftone ht; |
574 | 90 | gs_string thresh; |
575 | 90 | int code; |
576 | | |
577 | 90 | int width = 16; |
578 | 90 | int height = 16; |
579 | 90 | thresh.data = order16x16; |
580 | 90 | thresh.size = width * height; |
581 | | |
582 | 90 | if (gx_device_must_halftone(pdevice)) |
583 | 90 | { |
584 | 90 | memset(&ht.rc, 0x00, sizeof(ht.rc)); |
585 | 90 | ht.type = ht_type_threshold; |
586 | 90 | ht.objtype = HT_OBJTYPE_DEFAULT; |
587 | 90 | ht.params.threshold.width = width; |
588 | 90 | ht.params.threshold.height = height; |
589 | 90 | ht.params.threshold.thresholds.data = thresh.data; |
590 | 90 | ht.params.threshold.thresholds.size = thresh.size; |
591 | 90 | ht.params.threshold.transfer = 0; |
592 | 90 | ht.params.threshold.transfer_closure.proc = 0; |
593 | | |
594 | 90 | gs_settransfer(ctx->pgs, identity_transfer); |
595 | | |
596 | 90 | code = gs_sethalftone(ctx->pgs, &ht); |
597 | 90 | if (code < 0) |
598 | 0 | return gs_throw(code, "could not install halftone"); |
599 | | |
600 | 90 | code = gs_sethalftonephase(ctx->pgs, 0, 0); |
601 | 90 | if (code < 0) |
602 | 0 | return gs_throw(code, "could not set halftone phase"); |
603 | 90 | } |
604 | | |
605 | 90 | return 0; |
606 | 90 | } |