/src/ghostpdl/base/gdevprn.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 | | |
17 | | /* Generic printer driver support */ |
18 | | #include "ctype_.h" |
19 | | #include "gdevprn.h" |
20 | | #include "gp.h" |
21 | | #include "gdevdevn.h" /* for gs_devn_params_s */ |
22 | | #include "gsdevice.h" /* for gs_deviceinitialmatrix */ |
23 | | #include "gxdevsop.h" /* for gxdso_* */ |
24 | | #include "gsfname.h" |
25 | | #include "gsparam.h" |
26 | | #include "gxclio.h" |
27 | | #include "gxgetbit.h" |
28 | | #include "gdevplnx.h" |
29 | | #include "gstrans.h" |
30 | | #include "gxdownscale.h" |
31 | | #include "gsbitops.h" |
32 | | |
33 | | #include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */ |
34 | | |
35 | | /*#define DEBUGGING_HACKS*/ |
36 | | |
37 | | /* GC information */ |
38 | | static |
39 | 10.3M | ENUM_PTRS_WITH(device_printer_enum_ptrs, gx_device_printer *pdev); |
40 | 9.90M | ENUM_PREFIX(st_device_clist_mutatable, 2); |
41 | 0 | break; |
42 | 202k | case 0:ENUM_RETURN(gx_device_enum_ptr(pdev->parent)); |
43 | 202k | case 1:ENUM_RETURN(gx_device_enum_ptr(pdev->child)); |
44 | 10.3M | ENUM_PTRS_END |
45 | | static |
46 | 202k | RELOC_PTRS_WITH(device_printer_reloc_ptrs, gx_device_printer *pdev) |
47 | 202k | { |
48 | 202k | pdev->parent = gx_device_reloc_ptr(pdev->parent, gcst); |
49 | 202k | pdev->child = gx_device_reloc_ptr(pdev->child, gcst); |
50 | 202k | RELOC_PREFIX(st_device_clist_mutatable); |
51 | 202k | } RELOC_PTRS_END |
52 | | public_st_device_printer(); |
53 | | |
54 | | /* ---------------- Standard device procedures ---------------- */ |
55 | | |
56 | | /* Forward references */ |
57 | | int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev, |
58 | | gdev_space_params *old_space, |
59 | | int old_width, int old_height, |
60 | | bool old_page_uses_transparency); |
61 | | |
62 | | static int |
63 | | gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok); |
64 | | |
65 | | extern dev_proc_open_device(pattern_clist_open_device); |
66 | | extern dev_proc_open_device(clist_open); |
67 | | extern dev_proc_close_device(clist_close); |
68 | | |
69 | | /* The function run in a background thread */ |
70 | | static void prn_print_page_in_background(void *data); |
71 | | |
72 | | /* wait for a background thread to finish and clean up background printing */ |
73 | | static void prn_finish_bg_print(gx_device_printer *ppdev); |
74 | | |
75 | | /* ------ Open/close ------ */ |
76 | | /* Open a generic printer device. */ |
77 | | /* Specific devices may wish to extend this. */ |
78 | | int |
79 | | gdev_prn_open(gx_device * pdev) |
80 | 120k | { |
81 | 120k | gx_device_printer * ppdev; |
82 | 120k | int code; |
83 | 120k | bool update_procs = false; |
84 | | |
85 | 120k | code = install_internal_subclass_devices(&pdev, &update_procs); |
86 | 120k | if (code < 0) |
87 | 0 | return code; |
88 | | |
89 | 120k | ppdev = (gx_device_printer *)pdev; |
90 | | |
91 | 120k | ppdev->file = NULL; |
92 | 120k | code = gdev_prn_allocate_memory(pdev, NULL, 0, 0); |
93 | 120k | if (update_procs) { |
94 | 0 | if (pdev->ObjectHandlerPushed) { |
95 | 0 | gx_copy_device_procs(pdev->parent, pdev, &gs_obj_filter_device); |
96 | 0 | pdev = pdev->parent; |
97 | 0 | } |
98 | 0 | if (pdev->PageHandlerPushed) { |
99 | 0 | gx_copy_device_procs(pdev->parent, pdev, &gs_flp_device); |
100 | 0 | pdev = pdev->parent; |
101 | 0 | } |
102 | 0 | if (pdev->NupHandlerPushed) |
103 | 0 | gx_copy_device_procs(pdev->parent, pdev, &gs_nup_device); |
104 | 0 | } |
105 | 120k | if (code < 0) |
106 | 0 | return code; |
107 | 120k | if (ppdev->OpenOutputFile) |
108 | 0 | code = gdev_prn_open_printer(pdev, 1); |
109 | 120k | return code; |
110 | 120k | } |
111 | | |
112 | | /* This is called various places to wait for any pending bg print thread and */ |
113 | | /* perform its cleanup */ |
114 | | static void |
115 | | prn_finish_bg_print(gx_device_printer *ppdev) |
116 | 446k | { |
117 | | /* if we have a a bg printing device that was created, then wait for its */ |
118 | | /* semaphore (it may already have been signalled, but that's OK.) then */ |
119 | | /* close and unlink the files and free the device and its private allocator */ |
120 | 446k | if (ppdev->bg_print && (ppdev->bg_print->device != NULL)) { |
121 | 0 | int closecode; |
122 | 0 | gx_device_printer *bgppdev = (gx_device_printer *)ppdev->bg_print->device; |
123 | |
|
124 | 0 | gx_semaphore_wait(ppdev->bg_print->sema); |
125 | | /* If numcopies > 1, then the bg_print->device will have closed and reopened |
126 | | * the output file, so the pointer in the original device is now stale, |
127 | | * so copy it back. |
128 | | * If numcopies == 1, this is pointless, but benign. |
129 | | */ |
130 | 0 | ppdev->file = bgppdev->file; |
131 | 0 | closecode = gdev_prn_close_printer((gx_device *)ppdev); |
132 | 0 | if (ppdev->bg_print->return_code == 0) |
133 | 0 | ppdev->bg_print->return_code = closecode; /* return code here iff there wasn't another error */ |
134 | 0 | teardown_device_and_mem_for_thread(ppdev->bg_print->device, |
135 | 0 | ppdev->bg_print->thread_id, true); |
136 | 0 | ppdev->bg_print->device = NULL; |
137 | 0 | if (ppdev->bg_print->ocfile) { |
138 | 0 | closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->ocfile, ppdev->bg_print->ocfname, true); |
139 | 0 | if (ppdev->bg_print->return_code == 0) |
140 | 0 | ppdev->bg_print->return_code = closecode; |
141 | 0 | } |
142 | 0 | if (ppdev->bg_print->ocfname) { |
143 | 0 | gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "prn_finish_bg_print(ocfname)"); |
144 | 0 | } |
145 | 0 | if (ppdev->bg_print->obfile) { |
146 | 0 | closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->obfile, ppdev->bg_print->obfname, true); |
147 | 0 | if (ppdev->bg_print->return_code == 0) |
148 | 0 | ppdev->bg_print->return_code = closecode; |
149 | 0 | } |
150 | 0 | if (ppdev->bg_print->obfname) { |
151 | 0 | gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "prn_finish_bg_print(obfname)"); |
152 | 0 | } |
153 | 0 | ppdev->bg_print->ocfile = ppdev->bg_print->obfile = |
154 | 0 | ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL; |
155 | 0 | } |
156 | 446k | } |
157 | | /* Generic closing for the printer device. */ |
158 | | /* Specific devices may wish to extend this. */ |
159 | | int |
160 | | gdev_prn_close(gx_device * pdev) |
161 | 120k | { |
162 | 120k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
163 | 120k | int code = 0; |
164 | | |
165 | 120k | prn_finish_bg_print(ppdev); |
166 | 120k | if (ppdev->bg_print != NULL && ppdev->bg_print->sema != NULL) { |
167 | 0 | gx_semaphore_free(ppdev->bg_print->sema); |
168 | 0 | ppdev->bg_print->sema = NULL; /* prevent double free */ |
169 | 0 | } |
170 | 120k | gdev_prn_free_memory(pdev); |
171 | 120k | if (ppdev->file != NULL) { |
172 | 44.7k | code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file); |
173 | 44.7k | ppdev->file = NULL; |
174 | 44.7k | } |
175 | 120k | return code; |
176 | 120k | } |
177 | | |
178 | | int |
179 | | gdev_prn_forwarding_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size) |
180 | 160M | { |
181 | 160M | gx_device_printer *ppdev = (gx_device_printer *)pdev; |
182 | 160M | int code; |
183 | | |
184 | | /* if the device is a printer device, we will get here, but allow for a printer device */ |
185 | | /* that has a non-default dev_spec_op that may want to not support saved_pages, if so */ |
186 | | /* that device can return an error from the supports_saved_pages spec_op. */ |
187 | 160M | code = ppdev->orig_procs.dev_spec_op(pdev, dev_spec_op, data, size); |
188 | 160M | if (dev_spec_op == gxdso_supports_saved_pages) /* printer devices support saved pages */ |
189 | 932k | return code == 0 ? 1: code; /*default returns 0, but we still want saved-page support */ |
190 | 159M | return code; |
191 | 160M | } |
192 | | |
193 | | int |
194 | | gdev_prn_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size) |
195 | 98.6M | { |
196 | 98.6M | if (dev_spec_op == gxdso_supports_saved_pages) |
197 | 1.21M | return 1; |
198 | | |
199 | 97.4M | if (dev_spec_op == gxdso_get_dev_param) { |
200 | 2.51M | int code; |
201 | 2.51M | dev_param_req_t *request = (dev_param_req_t *)data; |
202 | | |
203 | 2.51M | code = gdev_prn_get_param(pdev, request->Param, request->list); |
204 | 2.51M | if (code != gs_error_undefined) |
205 | 172k | return code; |
206 | 2.51M | } |
207 | | |
208 | | #ifdef DEBUG |
209 | | if (dev_spec_op == gxdso_debug_printer_check) |
210 | | return 1; |
211 | | #endif |
212 | | |
213 | 97.3M | return gx_default_dev_spec_op(pdev, dev_spec_op, data, size); |
214 | 97.4M | } |
215 | | |
216 | | static bool /* ret true if device was cmd list, else false */ |
217 | | gdev_prn_tear_down(gx_device *pdev, byte **the_memory) |
218 | 250k | { |
219 | 250k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
220 | 250k | gx_device_memory * const pmemdev = (gx_device_memory *)pdev; |
221 | 250k | gx_device_clist *const pclist_dev = (gx_device_clist *)pdev; |
222 | 250k | gx_device_clist_common * const pcldev = &pclist_dev->common; |
223 | 250k | gx_device_clist_reader * const pcrdev = &pclist_dev->reader; |
224 | 250k | bool was_command_list; |
225 | | |
226 | 250k | if (PRINTER_IS_CLIST(ppdev)) { |
227 | | /* Close cmd list device & point to the storage */ |
228 | 250k | clist_close( (gx_device *)pcldev ); |
229 | 250k | *the_memory = ppdev->buf; |
230 | 250k | ppdev->buf = 0; |
231 | 250k | ppdev->buffer_space = 0; |
232 | 250k | pmemdev->base = 0; /* in case finalize tries to free this */ |
233 | 250k | was_command_list = true; |
234 | | |
235 | 250k | prn_finish_bg_print(ppdev); |
236 | | |
237 | 250k | gs_free_object(pcldev->memory->non_gc_memory, pcldev->cache_chunk, "free tile cache for clist"); |
238 | 250k | pcldev->cache_chunk = 0; |
239 | | |
240 | 250k | rc_decrement(pcldev->icc_cache_cl, "gdev_prn_tear_down"); |
241 | 250k | pcldev->icc_cache_cl = NULL; |
242 | | |
243 | 250k | clist_free_icc_table(pcldev->icc_table, pcldev->memory); |
244 | 250k | pcldev->icc_table = NULL; |
245 | | |
246 | | /* If the clist is a reader clist, free any color_usage_array |
247 | | * memory used by same. |
248 | | */ |
249 | 250k | if (!CLIST_IS_WRITER(pclist_dev)) |
250 | 6.17k | gs_free_object(pcrdev->memory, pcrdev->color_usage_array, "clist_color_usage_array"); |
251 | | |
252 | 250k | } else { |
253 | | /* point at the device bitmap, no need to close mem dev */ |
254 | 0 | *the_memory = pmemdev->base; |
255 | 0 | pmemdev->base = 0; |
256 | 0 | was_command_list = false; |
257 | 0 | } |
258 | | |
259 | | /* Reset device proc vector to default */ |
260 | 250k | if (ppdev->orig_procs.open_device != NULL) |
261 | 250k | pdev->procs = ppdev->orig_procs; |
262 | 250k | ppdev->orig_procs.open_device = NULL; /* prevent uninit'd restore of procs */ |
263 | | |
264 | 250k | return was_command_list; |
265 | 250k | } |
266 | | |
267 | | static int |
268 | | gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params, |
269 | | int new_width, int new_height, bool reallocate) |
270 | 250k | { |
271 | 250k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
272 | 250k | gx_device_memory * const pmemdev = (gx_device_memory *)pdev; |
273 | 250k | byte *the_memory = 0; |
274 | 250k | gdev_space_params save_params = ppdev->space_params; |
275 | 250k | int save_width = 0x0badf00d; /* Quiet compiler */ |
276 | 250k | int save_height = 0x0badf00d; /* Quiet compiler */ |
277 | 250k | bool is_command_list = false; /* Quiet compiler */ |
278 | 250k | bool save_is_command_list = false; /* Quiet compiler */ |
279 | 250k | bool size_ok = 0; |
280 | 250k | int ecode = 0; |
281 | 250k | int code; |
282 | 250k | int pass; |
283 | 250k | gs_memory_t *buffer_memory = |
284 | 250k | (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory : |
285 | 250k | ppdev->buffer_memory); |
286 | 250k | bool deep = device_is_deep(pdev); |
287 | | |
288 | | /* If reallocate, find allocated memory & tear down buffer device */ |
289 | 250k | if (reallocate) |
290 | 130k | save_is_command_list = gdev_prn_tear_down(pdev, &the_memory); |
291 | | |
292 | | |
293 | | /* bg_print allocation is not fatal, we just continue (as far as possible) without BGPrint */ |
294 | 250k | if (ppdev->bg_print == NULL) |
295 | 120k | ppdev->bg_print = (bg_print_t *)gs_alloc_bytes(pdev->memory->non_gc_memory, sizeof(bg_print_t), "prn bg_print"); |
296 | 250k | if (ppdev->bg_print == NULL) { |
297 | 0 | emprintf(pdev->memory, "Failed to allocate memory for BGPrint, attempting to continue without BGPrint\n"); |
298 | 250k | } else { |
299 | 250k | memset(ppdev->bg_print, 0, sizeof(bg_print_t)); |
300 | 250k | } |
301 | | |
302 | | /* Re/allocate memory */ |
303 | 250k | ppdev->orig_procs = pdev->procs; |
304 | 250k | for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) { |
305 | 250k | size_t mem_space; |
306 | 250k | size_t pdf14_trans_buffer_size = 0; |
307 | 250k | byte *base = 0; |
308 | 250k | bool bufferSpace_is_default = false; |
309 | 250k | gdev_space_params space_params; |
310 | 250k | gx_device_buf_space_t buf_space; |
311 | | |
312 | 250k | if (reallocate) |
313 | 130k | switch (pass) |
314 | 130k | { |
315 | 130k | case 1: |
316 | | /* Setup device to get reallocated */ |
317 | 130k | ppdev->space_params = *new_space_params; |
318 | 130k | save_width = ppdev->width; |
319 | 130k | ppdev->width = new_width; |
320 | 130k | save_height = ppdev->height; |
321 | 130k | ppdev->height = new_height; |
322 | 130k | break; |
323 | 0 | case 2: /* only comes here if reallocate */ |
324 | | /* Restore device to previous contents */ |
325 | 0 | ppdev->space_params = save_params; |
326 | 0 | ppdev->width = save_width; |
327 | 0 | ppdev->height = save_height; |
328 | 0 | break; |
329 | 130k | } |
330 | | |
331 | | /* Init clist/mem device-specific fields */ |
332 | 250k | memset(ppdev->skip, 0, sizeof(ppdev->skip)); |
333 | 250k | size_ok = ppdev->printer_procs.buf_procs.size_buf_device |
334 | 250k | (&buf_space, pdev, NULL, pdev->height, false) >= 0; |
335 | | |
336 | | /* Make sure we won't overflow a size_t, if we do then we'll use a clist below */ |
337 | 250k | if (ARCH_MAX_SIZE_T - buf_space.bits < buf_space.line_ptrs) |
338 | 0 | size_ok = 0; |
339 | | |
340 | 250k | mem_space = buf_space.bits + buf_space.line_ptrs; |
341 | 250k | if (ppdev->page_uses_transparency) { |
342 | 20.6k | pdf14_trans_buffer_size = (ESTIMATED_PDF14_ROW_SPACE(max(1, pdev->width), pdev->color_info.num_components, deep ? 16 : 8) >> 3); |
343 | 20.6k | if (new_height < (max_size_t - mem_space) / pdf14_trans_buffer_size) { |
344 | 20.6k | pdf14_trans_buffer_size *= pdev->height; |
345 | 20.6k | } else { |
346 | 0 | size_ok = 0; |
347 | 0 | } |
348 | 20.6k | } |
349 | | |
350 | | /* Compute desired space params: never use the space_params as-is. */ |
351 | | /* Rather, give the dev-specific driver a chance to adjust them. */ |
352 | 250k | space_params = ppdev->space_params; |
353 | 250k | space_params.BufferSpace = 0; |
354 | 250k | (*ppdev->printer_procs.get_space_params)(ppdev, &space_params); |
355 | 250k | if (space_params.BufferSpace == 0) { |
356 | 250k | if (space_params.band.BandBufferSpace > 0) |
357 | 0 | space_params.BufferSpace = space_params.band.BandBufferSpace; |
358 | 250k | else { |
359 | 250k | space_params.BufferSpace = ppdev->space_params.BufferSpace; |
360 | 250k | bufferSpace_is_default = true; |
361 | 250k | } |
362 | 250k | } |
363 | | |
364 | | /* Determine if we can use a full bitmap buffer, or have to use banding */ |
365 | 250k | if (pass > 1) |
366 | 0 | is_command_list = save_is_command_list; |
367 | 250k | else { |
368 | 250k | is_command_list = space_params.banding_type == BandingAlways || |
369 | 250k | ppdev->saved_pages_list != NULL || |
370 | 250k | mem_space + pdf14_trans_buffer_size >= space_params.MaxBitmap || |
371 | 250k | !size_ok; /* too big to allocate */ |
372 | 250k | } |
373 | 250k | if (!is_command_list) { |
374 | 0 | byte *trans_buffer_reserve_space = NULL; |
375 | | |
376 | | /* Try to allocate memory for full memory buffer, then allocate the |
377 | | pdf14_trans_buffer_size to make sure we have enough space for that */ |
378 | | /* NOTE: Assumes that caller won't normally call this function if page |
379 | | size didn't actually change, so we can free/alloc without checking |
380 | | that the new size is different than old size. |
381 | | */ |
382 | 0 | if (reallocate) { |
383 | 0 | gs_free_object(buffer_memory, the_memory, "printer_buffer"); |
384 | 0 | the_memory = NULL; |
385 | 0 | } |
386 | 0 | base = gs_alloc_bytes(buffer_memory, mem_space, "printer_buffer"); |
387 | 0 | if (base == 0) |
388 | 0 | is_command_list = true; |
389 | 0 | else |
390 | 0 | the_memory = base; |
391 | 0 | trans_buffer_reserve_space = gs_alloc_bytes(buffer_memory, (uint)pdf14_trans_buffer_size, |
392 | 0 | "pdf14_trans_buffer_reserve test"); |
393 | 0 | if (trans_buffer_reserve_space == NULL) { |
394 | | /* the pdf14 reserve test failed, switch to clist mode, the 'base' memory freed below */ |
395 | 0 | is_command_list = true; |
396 | 0 | } else { |
397 | 0 | gs_free_object(buffer_memory, trans_buffer_reserve_space, "pdf14_trans_buffer_reserve OK"); |
398 | 0 | } |
399 | 0 | } |
400 | 250k | if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0 |
401 | 250k | && buffer_memory == pdev->memory->non_gc_memory) { |
402 | | /* before using full memory buffer, ensure enough working mem left */ |
403 | 0 | byte * left = gs_alloc_bytes( buffer_memory, |
404 | 0 | PRN_MIN_MEMORY_LEFT, "printer mem left"); |
405 | 0 | if (left == 0) |
406 | 0 | is_command_list = true; |
407 | 0 | else |
408 | 0 | gs_free_object(buffer_memory, left, "printer mem left"); |
409 | 0 | } |
410 | | |
411 | 250k | if (is_command_list) { |
412 | | /* Buffer the image in a command list. */ |
413 | | /* Release the buffer if we allocated it. */ |
414 | 250k | int code; |
415 | 250k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
416 | | |
417 | 250k | if (!reallocate) { |
418 | 120k | gs_free_object(buffer_memory, the_memory, |
419 | 120k | "printer buffer(open)"); |
420 | 120k | the_memory = 0; |
421 | 120k | } |
422 | 250k | if (space_params.banding_type == BandingNever) { |
423 | 0 | ecode = gs_note_error(gs_error_VMerror); |
424 | 0 | continue; |
425 | 0 | } |
426 | 250k | if (ppdev->bg_print) { |
427 | 250k | ppdev->bg_print->ocfname = ppdev->bg_print->obfname = |
428 | 250k | ppdev->bg_print->obfile = ppdev->bg_print->ocfile = NULL; |
429 | 250k | } |
430 | | |
431 | 250k | code = clist_mutate_to_clist((gx_device_clist_mutatable *)pdev, |
432 | 250k | buffer_memory, |
433 | 250k | &the_memory, &space_params, |
434 | 250k | !bufferSpace_is_default, |
435 | 250k | &ppdev->printer_procs.buf_procs, |
436 | 250k | gdev_prn_forwarding_dev_spec_op, |
437 | 250k | PRN_MIN_BUFFER_SPACE); |
438 | 250k | if (ecode == 0) |
439 | 250k | ecode = code; |
440 | | |
441 | 250k | if (code >= 0 || (reallocate && pass > 1)) { |
442 | 250k | ppdev->initialize_device_procs = clist_initialize_device_procs; |
443 | | /* Hacky - we know this can't fail. */ |
444 | 250k | (void)ppdev->initialize_device_procs((gx_device *)ppdev); |
445 | 250k | gx_device_fill_in_procs((gx_device *)ppdev); |
446 | 250k | } |
447 | 250k | } else { |
448 | | /* Render entirely in memory. */ |
449 | 0 | gx_device *bdev = (gx_device *)pmemdev; |
450 | 0 | int code; |
451 | |
|
452 | 0 | ppdev->buffer_space = 0; |
453 | 0 | if ((code = gdev_create_buf_device |
454 | 0 | (ppdev->printer_procs.buf_procs.create_buf_device, |
455 | 0 | &bdev, pdev, 0, NULL, NULL, NULL)) < 0 || |
456 | 0 | (code = ppdev->printer_procs.buf_procs.setup_buf_device |
457 | 0 | (bdev, base, buf_space.raster, |
458 | 0 | (byte **)(base + buf_space.bits), 0, pdev->height, |
459 | 0 | pdev->height)) < 0 |
460 | 0 | ) { |
461 | | /* Catastrophic. Shouldn't ever happen */ |
462 | 0 | gs_free_object(buffer_memory, base, "printer buffer"); |
463 | 0 | pdev->procs = ppdev->orig_procs; |
464 | 0 | ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */ |
465 | 0 | gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print"); |
466 | 0 | ppdev->bg_print = NULL; |
467 | 0 | return_error(code); |
468 | 0 | } |
469 | 0 | } |
470 | 250k | if (ecode == 0) |
471 | 250k | break; |
472 | 250k | } |
473 | | |
474 | 250k | if (ecode >= 0 || reallocate) { /* even if realloc failed */ |
475 | | /* Synthesize the procedure vector. */ |
476 | | /* Rendering operations come from the memory or clist device, */ |
477 | | /* non-rendering come from the printer device. */ |
478 | 4.01M | #define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p) |
479 | 250k | COPY_PROC(get_initial_matrix); |
480 | 250k | COPY_PROC(output_page); |
481 | 250k | COPY_PROC(close_device); |
482 | 250k | COPY_PROC(map_rgb_color); |
483 | 250k | COPY_PROC(map_color_rgb); |
484 | 250k | COPY_PROC(get_params); |
485 | 250k | COPY_PROC(put_params); |
486 | 250k | COPY_PROC(map_cmyk_color); |
487 | | /* All printers are page devices, even if they didn't use the */ |
488 | | /* standard macros for generating their procedure vectors. */ |
489 | 250k | set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device); |
490 | 250k | COPY_PROC(get_clipping_box); |
491 | 250k | COPY_PROC(get_hardware_params); |
492 | 250k | COPY_PROC(get_color_mapping_procs); |
493 | 250k | COPY_PROC(get_color_comp_index); |
494 | 250k | COPY_PROC(encode_color); |
495 | 250k | COPY_PROC(decode_color); |
496 | 250k | COPY_PROC(update_spot_equivalent_colors); |
497 | 250k | COPY_PROC(ret_devn_params); |
498 | | /* This can be set from the memory device (planar) or target */ |
499 | 250k | if ( dev_proc(ppdev, put_image) == gx_default_put_image ) |
500 | 250k | set_dev_proc(ppdev, put_image, ppdev->orig_procs.put_image); |
501 | 250k | #undef COPY_PROC |
502 | | /* If using a command list, already opened the device. */ |
503 | 250k | if (is_command_list) |
504 | 250k | code = ecode; |
505 | 0 | else |
506 | | /* If this open_device fails, do we need to free everything? */ |
507 | 0 | code = (*dev_proc(pdev, open_device))(pdev); |
508 | 250k | } else { |
509 | 0 | pdev->procs = ppdev->orig_procs; |
510 | 0 | ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */ |
511 | 0 | code = ecode; |
512 | 0 | } |
513 | 250k | if (code < 0) { |
514 | 0 | gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print"); |
515 | 0 | ppdev->bg_print = NULL; |
516 | 0 | } |
517 | 250k | return code; |
518 | 250k | } |
519 | | |
520 | | int |
521 | | gdev_prn_allocate_memory(gx_device *pdev, |
522 | | gdev_space_params *new_space_params, |
523 | | int new_width, int new_height) |
524 | 120k | { |
525 | 120k | return gdev_prn_allocate(pdev, new_space_params, |
526 | 120k | new_width, new_height, false); |
527 | 120k | } |
528 | | |
529 | | int |
530 | | gdev_prn_reallocate_memory(gx_device *pdev, |
531 | | gdev_space_params *new_space_params, |
532 | | int new_width, int new_height) |
533 | 130k | { |
534 | 130k | return gdev_prn_allocate(pdev, new_space_params, |
535 | 130k | new_width, new_height, true); |
536 | 130k | } |
537 | | |
538 | | int |
539 | | gdev_prn_free_memory(gx_device *pdev) |
540 | 120k | { |
541 | 120k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
542 | 120k | byte *the_memory = 0; |
543 | 120k | gs_memory_t *buffer_memory = |
544 | 120k | (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory : |
545 | 120k | ppdev->buffer_memory); |
546 | | |
547 | 120k | gdev_prn_tear_down(pdev, &the_memory); |
548 | 120k | gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "gdev_prn_free_memory"); |
549 | 120k | ppdev->bg_print = NULL; |
550 | 120k | gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory"); |
551 | 120k | return 0; |
552 | 120k | } |
553 | | |
554 | | /* for saved pages, we need to make sure and free up the saved_pages_list */ |
555 | | void |
556 | | gdev_prn_finalize(gx_device *pdev) |
557 | 0 | { |
558 | 0 | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
559 | |
|
560 | 0 | if (ppdev->saved_pages_list != NULL) { |
561 | 0 | gx_saved_pages_list_free(ppdev->saved_pages_list); |
562 | 0 | ppdev->saved_pages_list = NULL; |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | | |
567 | | /* ------ Get/put parameters ------ */ |
568 | | |
569 | | int |
570 | | gdev_prn_get_param(gx_device *dev, char *Param, void *list) |
571 | 2.51M | { |
572 | 2.51M | gx_device_printer * const ppdev = (gx_device_printer *)dev; |
573 | 2.51M | gs_param_list * plist = (gs_param_list *)list; |
574 | 2.51M | bool pageneutralcolor = false; |
575 | | |
576 | 2.51M | if (strcmp(Param, "Duplex") == 0) { |
577 | 0 | if (ppdev->Duplex_set >= 0) { |
578 | 0 | if (ppdev->Duplex_set) |
579 | 0 | return param_write_bool(plist, "Duplex", &ppdev->Duplex); |
580 | 0 | else |
581 | 0 | return param_write_null(plist, "Duplex"); |
582 | 0 | } |
583 | 0 | } |
584 | 2.51M | if (strcmp(Param, "NumRenderingThreads") == 0) { |
585 | 0 | return param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested); |
586 | 0 | } |
587 | 2.51M | if (strcmp(Param, "OpenOutputFile") == 0) { |
588 | 0 | return param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile); |
589 | 0 | } |
590 | 2.51M | if (strcmp(Param, "BGPrint") == 0) { |
591 | 57.5k | return param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested); |
592 | 57.5k | } |
593 | 2.45M | if (strcmp(Param, "ReopenPerPage") == 0) { |
594 | 0 | return param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage); |
595 | 0 | } |
596 | 2.45M | if (strcmp(Param, "BandListStorage") == 0) { |
597 | 0 | gs_param_string bls; |
598 | 0 | gs_lib_ctx_core_t *core = dev->memory->gs_lib_ctx->core; |
599 | | /* Force the default to 'memory' if clist file I/O is not included in this build */ |
600 | 0 | if (core->clist_io_procs_file == NULL) |
601 | 0 | ppdev->BLS_force_memory = true; |
602 | 0 | if (ppdev->BLS_force_memory) { |
603 | 0 | bls.data = (byte *)"memory"; |
604 | 0 | bls.size = 6; |
605 | 0 | bls.persistent = false; |
606 | 0 | } else { |
607 | 0 | bls.data = (byte *)"file"; |
608 | 0 | bls.size = 4; |
609 | 0 | bls.persistent = false; |
610 | 0 | } |
611 | 0 | return param_write_string(plist, "BandListStorage", &bls); |
612 | 0 | } |
613 | 2.45M | if (strcmp(Param, "OutputFile") == 0) { |
614 | 0 | gs_param_string ofns; |
615 | |
|
616 | 0 | ofns.data = (const byte *)ppdev->fname, |
617 | 0 | ofns.size = strlen(ppdev->fname), |
618 | 0 | ofns.persistent = false; |
619 | 0 | return param_write_string(plist, "OutputFile", &ofns); |
620 | 0 | } |
621 | 2.45M | if (strcmp(Param, "saved-pages") == 0) { |
622 | 0 | gs_param_string saved_pages; |
623 | | /* Always return an empty string for saved-pages */ |
624 | 0 | saved_pages.data = (const byte *)""; |
625 | 0 | saved_pages.size = 0; |
626 | 0 | saved_pages.persistent = false; |
627 | 0 | return param_write_string(plist, "saved-pages", &saved_pages); |
628 | 0 | } |
629 | 2.45M | if (dev->icc_struct != NULL) |
630 | 2.45M | pageneutralcolor = dev->icc_struct->pageneutralcolor; |
631 | 2.45M | if (strcmp(Param, "pageneutralcolor") == 0) { |
632 | 0 | return param_write_bool(plist, "pageneutralcolor", &pageneutralcolor); |
633 | 0 | } |
634 | 2.45M | return gx_default_get_param(dev, Param, list); |
635 | 2.45M | } |
636 | | |
637 | | /* Get parameters. Printer devices add several more parameters */ |
638 | | /* to the default set. */ |
639 | | int |
640 | | gdev_prn_get_params(gx_device * pdev, gs_param_list * plist) |
641 | 2.57M | { |
642 | 2.57M | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
643 | 2.57M | int code = gx_default_get_params(pdev, plist); |
644 | 2.57M | gs_param_string ofns; |
645 | 2.57M | gs_param_string bls; |
646 | 2.57M | gs_param_string saved_pages; |
647 | 2.57M | bool pageneutralcolor = false; |
648 | 2.57M | gs_lib_ctx_core_t *core = pdev->memory->gs_lib_ctx->core; |
649 | | |
650 | 2.57M | if (pdev->icc_struct != NULL) |
651 | 2.47M | pageneutralcolor = pdev->icc_struct->pageneutralcolor; |
652 | 2.57M | if (code < 0 || |
653 | 2.57M | (ppdev->Duplex_set >= 0 && |
654 | 2.57M | (code = (ppdev->Duplex_set ? |
655 | 0 | param_write_bool(plist, "Duplex", &ppdev->Duplex) : |
656 | 0 | param_write_null(plist, "Duplex"))) < 0) || |
657 | 2.57M | (code = param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested)) < 0 || |
658 | 2.57M | (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 || |
659 | 2.57M | (code = param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested)) < 0 || |
660 | 2.57M | (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 || |
661 | 2.57M | (code = param_write_bool(plist, "pageneutralcolor", &pageneutralcolor)) < 0 |
662 | 2.57M | ) |
663 | 0 | return code; |
664 | | |
665 | | /* Force the default to 'memory' if clist file I/O is not included in this build */ |
666 | 2.57M | if (core->clist_io_procs_file == NULL) |
667 | 0 | ppdev->BLS_force_memory = true; |
668 | 2.57M | if (ppdev->BLS_force_memory) { |
669 | 2.37M | bls.data = (byte *)"memory"; |
670 | 2.37M | bls.size = 6; |
671 | 2.37M | bls.persistent = false; |
672 | 2.37M | } else { |
673 | 193k | bls.data = (byte *)"file"; |
674 | 193k | bls.size = 4; |
675 | 193k | bls.persistent = false; |
676 | 193k | } |
677 | 2.57M | if( (code = param_write_string(plist, "BandListStorage", &bls)) < 0 ) |
678 | 0 | return code; |
679 | | |
680 | 2.57M | ofns.data = (const byte *)ppdev->fname, |
681 | 2.57M | ofns.size = strlen(ppdev->fname), |
682 | 2.57M | ofns.persistent = false; |
683 | 2.57M | if ((code = param_write_string(plist, "OutputFile", &ofns)) < 0) |
684 | 0 | return code; |
685 | | |
686 | | /* Always return an empty string for saved-pages so that get_params followed */ |
687 | | /* by put_params will have no effect. */ |
688 | 2.57M | saved_pages.data = (const byte *)""; |
689 | 2.57M | saved_pages.size = 0; |
690 | 2.57M | saved_pages.persistent = false; |
691 | 2.57M | return param_write_string(plist, "saved-pages", &saved_pages); |
692 | 2.57M | } |
693 | | |
694 | | /* Validate an OutputFile name by checking any %-formats. */ |
695 | | static int |
696 | | validate_output_file(const gs_param_string * ofs, gs_memory_t *memory) |
697 | 150k | { |
698 | 150k | gs_parsed_file_name_t parsed; |
699 | 150k | const char *fmt; |
700 | | |
701 | 150k | return gx_parse_output_file_name(&parsed, &fmt, (const char *)ofs->data, |
702 | 150k | ofs->size, memory) >= 0; |
703 | 150k | } |
704 | | |
705 | | /* Put parameters. */ |
706 | | int |
707 | | gdev_prn_put_params(gx_device * pdev, gs_param_list * plist) |
708 | 758k | { |
709 | 758k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
710 | 758k | int ecode = 0; |
711 | 758k | int code; |
712 | 758k | const char *param_name; |
713 | 758k | bool is_open = pdev->is_open; |
714 | 758k | bool oof = ppdev->OpenOutputFile; |
715 | 758k | bool rpp = ppdev->ReopenPerPage; |
716 | 758k | bool old_page_uses_transparency = ppdev->page_uses_transparency; |
717 | 758k | bool bg_print_requested = ppdev->bg_print_requested; |
718 | 758k | bool duplex; |
719 | 758k | int duplex_set = -1; |
720 | 758k | int width = pdev->width; |
721 | 758k | int height = pdev->height; |
722 | 758k | int nthreads = ppdev->num_render_threads_requested; |
723 | 758k | gdev_space_params save_sp; |
724 | 758k | gs_param_string ofs; |
725 | 758k | gs_param_string bls; |
726 | 758k | gs_param_dict mdict; |
727 | 758k | gs_param_string saved_pages; |
728 | 758k | bool pageneutralcolor = false; |
729 | 758k | gs_lib_ctx_core_t *core = ppdev->memory->gs_lib_ctx->core; |
730 | | |
731 | 758k | memset(&saved_pages, 0, sizeof(gs_param_string)); |
732 | 758k | save_sp = ppdev->space_params; |
733 | | |
734 | 758k | switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) { |
735 | 0 | default: |
736 | 0 | ecode = code; |
737 | 0 | param_signal_error(plist, param_name, ecode); |
738 | 53.7k | case 0: |
739 | 758k | case 1: |
740 | 758k | break; |
741 | 758k | } |
742 | | |
743 | 758k | switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) { |
744 | 0 | default: |
745 | 0 | ecode = code; |
746 | 0 | param_signal_error(plist, param_name, ecode); |
747 | 53.7k | case 0: |
748 | 758k | case 1: |
749 | 758k | break; |
750 | 758k | } |
751 | | |
752 | 758k | if (ppdev->Duplex_set >= 0) /* i.e., Duplex is supported */ |
753 | 0 | switch (code = param_read_bool(plist, (param_name = "Duplex"), |
754 | 0 | &duplex)) { |
755 | 0 | case 0: |
756 | 0 | duplex_set = 1; |
757 | 0 | break; |
758 | 0 | default: |
759 | 0 | if ((code = param_read_null(plist, param_name)) == 0) { |
760 | 0 | duplex_set = 0; |
761 | 0 | break; |
762 | 0 | } |
763 | 0 | ecode = code; |
764 | 0 | param_signal_error(plist, param_name, ecode); |
765 | 0 | case 1: |
766 | 0 | ; |
767 | 0 | } |
768 | 758k | switch (code = param_read_string(plist, (param_name = "BandListStorage"), &bls)) { |
769 | 150k | case 0: |
770 | | /* Only accept 'file' if the file procs are include in the build */ |
771 | 150k | if ((bls.size > 1) && (bls.data[0] == 'm' || |
772 | 150k | (core->clist_io_procs_file != NULL && bls.data[0] == 'f'))) |
773 | 150k | break; |
774 | | /* fall through */ |
775 | 0 | default: |
776 | 0 | ecode = code; |
777 | 0 | param_signal_error(plist, param_name, ecode); |
778 | | /* fall through */ |
779 | 607k | case 1: |
780 | 607k | bls.data = 0; |
781 | 607k | break; |
782 | 758k | } |
783 | | |
784 | 758k | switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) { |
785 | 150k | case 0: |
786 | 150k | if (pdev->LockSafetyParams && |
787 | 150k | bytes_compare(ofs.data, ofs.size, |
788 | 0 | (const byte *)ppdev->fname, strlen(ppdev->fname))) { |
789 | 0 | code = gs_error_invalidaccess; |
790 | 0 | } |
791 | 150k | else |
792 | 150k | code = validate_output_file(&ofs, pdev->memory); |
793 | 150k | if (code >= 0) |
794 | 150k | break; |
795 | | /* fall through */ |
796 | 0 | default: |
797 | 0 | ecode = code; |
798 | 0 | param_signal_error(plist, param_name, ecode); |
799 | | /* fall through */ |
800 | 607k | case 1: |
801 | 607k | ofs.data = 0; |
802 | 607k | break; |
803 | 758k | } |
804 | | |
805 | | /* Read InputAttributes and OutputAttributes just for the type */ |
806 | | /* check and to indicate that they aren't undefined. */ |
807 | 758k | #define read_media(pname)\ |
808 | 1.51M | switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\ |
809 | 1.51M | {\ |
810 | 0 | case 0:\ |
811 | 0 | param_end_read_dict(plist, pname, &mdict);\ |
812 | 0 | break;\ |
813 | 0 | default:\ |
814 | 0 | ecode = code;\ |
815 | 0 | param_signal_error(plist, param_name, ecode);\ |
816 | 1.51M | case 1:\ |
817 | 1.51M | ;\ |
818 | 1.51M | } |
819 | | |
820 | 758k | read_media("InputAttributes"); |
821 | 758k | read_media("OutputAttributes"); |
822 | | |
823 | 758k | switch (code = param_read_int(plist, (param_name = "NumRenderingThreads"), &nthreads)) { |
824 | 53.7k | case 0: |
825 | 53.7k | break; |
826 | 0 | default: |
827 | 0 | ecode = code; |
828 | 0 | param_signal_error(plist, param_name, ecode); |
829 | 704k | case 1: |
830 | 704k | ; |
831 | 758k | } |
832 | 758k | switch (code = param_read_bool(plist, (param_name = "BGPrint"), |
833 | 758k | &bg_print_requested)) { |
834 | 0 | default: |
835 | 0 | ecode = code; |
836 | 0 | param_signal_error(plist, param_name, ecode); |
837 | 53.7k | case 0: |
838 | 758k | case 1: |
839 | 758k | break; |
840 | 758k | } |
841 | | |
842 | 758k | switch (code = param_read_string(plist, (param_name = "saved-pages"), |
843 | 758k | &saved_pages)) { |
844 | 0 | default: |
845 | 0 | ecode = code; |
846 | 0 | param_signal_error(plist, param_name, ecode); |
847 | 53.7k | case 0: |
848 | 758k | case 1: |
849 | 758k | break; |
850 | 758k | } |
851 | | |
852 | | /* NB: put_params to change pageneutralcolor is allowed, but has no effect */ |
853 | | /* It will be set according the GrayDetection. Allowing it prevents errors */ |
854 | 758k | if (pdev->icc_struct != NULL) |
855 | 700k | pageneutralcolor = pdev->icc_struct->pageneutralcolor; |
856 | 758k | if ((code = param_read_bool(plist, (param_name = "pageneutralcolor"), |
857 | 758k | &pageneutralcolor)) < 0) { |
858 | 0 | ecode = code; |
859 | 0 | param_signal_error(plist, param_name, ecode); |
860 | 0 | } |
861 | | |
862 | 758k | if (ecode < 0) |
863 | 0 | return ecode; |
864 | | /* Prevent gx_default_put_params from closing the printer. */ |
865 | 758k | pdev->is_open = false; |
866 | 758k | code = gx_default_put_params(pdev, plist); |
867 | 758k | pdev->is_open = is_open; |
868 | 758k | if (code < 0) |
869 | 347 | return code; |
870 | | |
871 | 758k | ppdev->OpenOutputFile = oof; |
872 | 758k | ppdev->ReopenPerPage = rpp; |
873 | | |
874 | | /* If BGPrint was previously true and it is being turned off, wait for the BG thread */ |
875 | 758k | if (ppdev->bg_print_requested && !bg_print_requested) { |
876 | 0 | prn_finish_bg_print(ppdev); |
877 | 0 | } |
878 | | |
879 | 758k | ppdev->bg_print_requested = bg_print_requested; |
880 | 758k | if (duplex_set >= 0) { |
881 | 0 | ppdev->Duplex = duplex; |
882 | 0 | ppdev->Duplex_set = duplex_set; |
883 | 0 | } |
884 | 758k | ppdev->num_render_threads_requested = nthreads; |
885 | 758k | if (bls.data != 0) { |
886 | 150k | ppdev->BLS_force_memory = (bls.data[0] == 'm'); |
887 | 150k | } |
888 | | |
889 | | /* If necessary, free and reallocate the printer memory. */ |
890 | | /* Formerly, would not reallocate if device is not open: */ |
891 | | /* we had to patch this out (see News for 5.50). */ |
892 | 758k | code = gdev_prn_maybe_realloc_memory(ppdev, &save_sp, width, height, |
893 | 758k | old_page_uses_transparency); |
894 | 758k | if (code < 0) |
895 | 0 | return code; |
896 | | |
897 | | /* If filename changed, close file. */ |
898 | 758k | if (ofs.data != 0 && |
899 | 758k | bytes_compare(ofs.data, ofs.size, |
900 | 150k | (const byte *)ppdev->fname, strlen(ppdev->fname)) |
901 | 758k | ) { |
902 | | /* Close the file if it's open. */ |
903 | 96.8k | if (ppdev->file != NULL) { |
904 | 0 | gx_device_close_output_file(pdev, ppdev->fname, ppdev->file); |
905 | 0 | } |
906 | 96.8k | ppdev->file = NULL; |
907 | 96.8k | if (sizeof(ppdev->fname) <= ofs.size) |
908 | 0 | return_error(gs_error_limitcheck); |
909 | 96.8k | memcpy(ppdev->fname, ofs.data, ofs.size); |
910 | 96.8k | ppdev->fname[ofs.size] = 0; |
911 | 96.8k | } |
912 | | /* If the device is open and OpenOutputFile is true, */ |
913 | | /* open the OutputFile now. (If the device isn't open, */ |
914 | | /* this will happen when it is opened.) */ |
915 | 758k | if (pdev->is_open && oof) { |
916 | 0 | code = gdev_prn_open_printer(pdev, 1); |
917 | 0 | if (code < 0) |
918 | 0 | return code; |
919 | 0 | } |
920 | | |
921 | | /* Processing the saved_pages string MAY have side effects, such as printing, */ |
922 | | /* allocating or freeing a list. This is (sort of) a write-only parameter, so */ |
923 | | /* the get_params will always return an empty string (a no-op action). */ |
924 | 758k | if (saved_pages.data != 0 && saved_pages.size != 0) { |
925 | 0 | return gx_saved_pages_param_process(ppdev, (byte *)saved_pages.data, saved_pages.size); |
926 | 0 | } |
927 | 758k | return 0; |
928 | 758k | } |
929 | | |
930 | | /* ------ Others ------ */ |
931 | | |
932 | | /* Default routine to (not) override current space_params. */ |
933 | | void |
934 | | gx_default_get_space_params(const gx_device_printer *printer_dev, |
935 | | gdev_space_params *space_params) |
936 | 155k | { |
937 | 155k | return; |
938 | 155k | } |
939 | | |
940 | | /* Common routine to send the page to the printer. */ |
941 | | /* If seekable is true, then the printer outputfile must be seekable. */ |
942 | | /* If bg_print_ok is true, the device print_page_copies is compatible with the */ |
943 | | /* background printing, i.e., thread safe and does not change the device. */ |
944 | | /* If the printer device is in 'saved_pages' mode, then background printing is */ |
945 | | /* irrelevant and is ignored. In this case, pages are saved to the list. */ |
946 | | static int /* 0 ok, -ve error */ |
947 | | gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok) |
948 | 75.2k | { |
949 | 75.2k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
950 | 75.2k | gs_devn_params *pdevn_params; |
951 | 75.2k | int outcode = 0, errcode = 0, endcode, closecode = 0; |
952 | 75.2k | int code; |
953 | | |
954 | 75.2k | prn_finish_bg_print(ppdev); /* finish any previous background printing */ |
955 | | |
956 | 75.2k | if (num_copies > 0 && ppdev->saved_pages_list != NULL) { |
957 | | /* We are putting pages on a list */ |
958 | 0 | if ((code = gx_saved_pages_list_add(ppdev)) < 0) |
959 | 0 | return code; |
960 | |
|
961 | 75.2k | } else if (num_copies > 0 || !flush) { |
962 | 75.2k | if ((code = gdev_prn_open_printer_seekable(pdev, 1, seekable)) < 0) |
963 | 0 | return code; |
964 | | |
965 | 75.2k | if (num_copies > 0) { |
966 | 75.2k | int threads_enabled = 0; |
967 | 75.2k | int print_foreground = 1; /* default to foreground printing */ |
968 | | |
969 | 75.2k | if (bg_print_ok && PRINTER_IS_CLIST(ppdev) && ppdev->bg_print && |
970 | 75.2k | (ppdev->bg_print_requested || ppdev->num_render_threads_requested > 0)) { |
971 | 0 | threads_enabled = clist_enable_multi_thread_render(pdev); |
972 | 0 | } |
973 | | /* NB: we leave the semaphore allocated until foreground printing or close */ |
974 | | /* If there was an error, abort on this page -- no good way to handle this */ |
975 | | /* but it means that the error will be reported AFTER another page was */ |
976 | | /* interpreted and written to clist files. FIXME: ??? */ |
977 | 75.2k | if (ppdev->bg_print && (ppdev->bg_print->return_code < 0)) { |
978 | 0 | outcode = ppdev->bg_print->return_code; |
979 | 0 | threads_enabled = 0; /* and allow current page to try foreground */ |
980 | 0 | } |
981 | | /* Use 'while' instead of 'if' to avoid nesting */ |
982 | 75.2k | while (ppdev->bg_print_requested && ppdev->bg_print && threads_enabled) { |
983 | 0 | gx_device *ndev; |
984 | 0 | gx_device_printer *npdev; |
985 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)ppdev; |
986 | |
|
987 | 0 | if ((code = clist_close_writer_and_init_reader((gx_device_clist *)ppdev)) < 0) |
988 | | /* should not happen -- do foreground print */ |
989 | 0 | break; |
990 | | |
991 | | /* We need to hang onto references to these files, so we can ensure the main file data |
992 | | * gets freed with the correct allocator. |
993 | | */ |
994 | 0 | ppdev->bg_print->ocfname = |
995 | 0 | (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory, |
996 | 0 | strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1, "gdev_prn_output_page_aux(ocfname)"); |
997 | 0 | ppdev->bg_print->obfname = |
998 | 0 | (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory, |
999 | 0 | strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1,"gdev_prn_output_page_aux(ocfname)"); |
1000 | |
|
1001 | 0 | if (!ppdev->bg_print->ocfname || !ppdev->bg_print->obfname) |
1002 | 0 | break; |
1003 | | |
1004 | 0 | strncpy(ppdev->bg_print->ocfname, crdev->page_info.cfname, strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1); |
1005 | 0 | strncpy(ppdev->bg_print->obfname, crdev->page_info.bfname, strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1); |
1006 | 0 | ppdev->bg_print->obfile = crdev->page_info.bfile; |
1007 | 0 | ppdev->bg_print->ocfile = crdev->page_info.cfile; |
1008 | 0 | ppdev->bg_print->oio_procs = crdev->page_info.io_procs; |
1009 | 0 | crdev->page_info.cfile = crdev->page_info.bfile = NULL; |
1010 | |
|
1011 | 0 | if (ppdev->bg_print->sema == NULL) |
1012 | 0 | { |
1013 | 0 | ppdev->bg_print->sema = gx_semaphore_label(gx_semaphore_alloc(ppdev->memory->non_gc_memory), "BGPrint"); |
1014 | 0 | if (ppdev->bg_print->sema == NULL) |
1015 | 0 | break; /* couldn't create the semaphore */ |
1016 | 0 | } |
1017 | | |
1018 | 0 | ndev = setup_device_and_mem_for_thread(pdev->memory->thread_safe_memory, pdev, true, NULL); |
1019 | 0 | if (ndev == NULL) { |
1020 | 0 | break; |
1021 | 0 | } |
1022 | 0 | ppdev->bg_print->device = ndev; |
1023 | 0 | ppdev->bg_print->num_copies = num_copies; |
1024 | 0 | npdev = (gx_device_printer *)ndev; |
1025 | 0 | npdev->bg_print_requested = 0; |
1026 | 0 | npdev->num_render_threads_requested = ppdev->num_render_threads_requested; |
1027 | | /* The bgprint's device was created with normal procs, so multi-threaded */ |
1028 | | /* rendering was turned off. Re-enable it now if it is needed. */ |
1029 | 0 | if (npdev->num_render_threads_requested > 0) { |
1030 | | /* ignore return code - even if it fails, we'll output the page */ |
1031 | 0 | (void)clist_enable_multi_thread_render(ndev); |
1032 | 0 | } |
1033 | | |
1034 | | /* Now start the thread to print the page */ |
1035 | 0 | if ((code = gp_thread_start(prn_print_page_in_background, |
1036 | 0 | (void *)(ppdev->bg_print), |
1037 | 0 | &(ppdev->bg_print->thread_id))) < 0) { |
1038 | | /* Did not start cleanly - clean up is in print_foreground block below */ |
1039 | 0 | break; |
1040 | 0 | } |
1041 | 0 | gp_thread_label(ppdev->bg_print->thread_id, "BG print thread"); |
1042 | | /* Page was succesfully started in bg_print mode */ |
1043 | 0 | print_foreground = 0; |
1044 | | /* Now we need to set up the next page so it will use new clist files */ |
1045 | 0 | if ((code = clist_open(pdev)) < 0) /* this should do it */ |
1046 | | /* OOPS! can't proceed with the next page */ |
1047 | 0 | return code; /* probably ioerror */ |
1048 | 0 | break; /* exit the while loop */ |
1049 | 0 | } |
1050 | 75.2k | if (print_foreground) { |
1051 | 75.2k | if (ppdev->bg_print) { |
1052 | 75.2k | gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "gdev_prn_output_page_aux(ocfname)"); |
1053 | 75.2k | gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "gdev_prn_output_page_aux(obfname)"); |
1054 | 75.2k | ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL; |
1055 | | |
1056 | | /* either bg_print was not requested or was not able to start */ |
1057 | 75.2k | if (ppdev->bg_print->sema != NULL && ppdev->bg_print->device != NULL) { |
1058 | | /* There was a problem. Teardown the device and its allocator, but */ |
1059 | | /* leave the semaphore for possible later use. */ |
1060 | 0 | teardown_device_and_mem_for_thread(ppdev->bg_print->device, |
1061 | 0 | ppdev->bg_print->thread_id, true); |
1062 | 0 | ppdev->bg_print->device = NULL; |
1063 | 0 | } |
1064 | 75.2k | } |
1065 | | /* Here's where we actually let the device's print_page_copies work */ |
1066 | | /* Print the accumulated page description. */ |
1067 | 75.2k | outcode = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file, |
1068 | 75.2k | num_copies); |
1069 | 75.2k | gp_fflush(ppdev->file); |
1070 | 75.2k | errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0); |
1071 | | /* NB: background printing does this differently in its thread */ |
1072 | 75.2k | closecode = gdev_prn_close_printer(pdev); |
1073 | | |
1074 | 75.2k | } |
1075 | 75.2k | } |
1076 | 75.2k | } |
1077 | | /* In the case of a separation device, we need to make sure we */ |
1078 | | /* clear the separation info before the next page starts. */ |
1079 | 75.2k | pdevn_params = dev_proc(pdev, ret_devn_params)(pdev); |
1080 | 75.2k | if (pdevn_params != NULL) { |
1081 | | /* Free up the list of spot names as they were only relevent to that page */ |
1082 | 13.4k | free_separation_names(pdev->memory, &(pdevn_params->separations)); |
1083 | 13.4k | pdevn_params->num_separation_order_names = 0; |
1084 | 13.4k | } |
1085 | 75.2k | endcode = (PRINTER_IS_CLIST(ppdev) && |
1086 | 75.2k | !((gx_device_clist_common *)ppdev)->do_not_open_or_close_bandfiles ? |
1087 | 75.2k | clist_finish_page(pdev, flush) : 0); |
1088 | | |
1089 | 75.2k | if (outcode < 0) |
1090 | 9.28k | return outcode; |
1091 | 65.9k | if (errcode < 0) |
1092 | 0 | return errcode; |
1093 | 65.9k | if (endcode < 0) |
1094 | 0 | return endcode; |
1095 | 65.9k | endcode = gx_finish_output_page(pdev, num_copies, flush); |
1096 | 65.9k | code = (endcode < 0 ? endcode : closecode < 0 ? closecode : 0); |
1097 | 65.9k | return code; |
1098 | 65.9k | } |
1099 | | |
1100 | | int |
1101 | | gdev_prn_output_page(gx_device * pdev, int num_copies, int flush) |
1102 | 33.2k | { |
1103 | 33.2k | return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, false)); |
1104 | 33.2k | } |
1105 | | |
1106 | | int |
1107 | | gdev_prn_output_page_seekable(gx_device * pdev, int num_copies, int flush) |
1108 | 6.13k | { |
1109 | 6.13k | return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, false)); |
1110 | 6.13k | } |
1111 | | |
1112 | | int |
1113 | | gdev_prn_bg_output_page(gx_device * pdev, int num_copies, int flush) |
1114 | 35.8k | { |
1115 | 35.8k | return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, true)); |
1116 | 35.8k | } |
1117 | | |
1118 | | int |
1119 | | gdev_prn_bg_output_page_seekable(gx_device * pdev, int num_copies, int flush) |
1120 | 0 | { |
1121 | 0 | return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, true)); |
1122 | 0 | } |
1123 | | |
1124 | | /* Print a single copy of a page by calling print_page_copies. */ |
1125 | | int |
1126 | | gx_print_page_single_copy(gx_device_printer * pdev, gp_file * prn_stream) |
1127 | 0 | { |
1128 | 0 | return pdev->printer_procs.print_page_copies(pdev, prn_stream, 1); |
1129 | 0 | } |
1130 | | |
1131 | | /* Print multiple copies of a page by calling print_page multiple times. */ |
1132 | | int |
1133 | | gx_default_print_page_copies(gx_device_printer * pdev, gp_file * prn_stream, |
1134 | | int num_copies) |
1135 | 41.9k | { |
1136 | 41.9k | int i = 1; |
1137 | 41.9k | int code = 0; |
1138 | | |
1139 | 41.9k | for (; i < num_copies; ++i) { |
1140 | 0 | int errcode, closecode; |
1141 | |
|
1142 | 0 | code = (*pdev->printer_procs.print_page) (pdev, prn_stream); |
1143 | 0 | if (code < 0) |
1144 | 0 | return code; |
1145 | | /* |
1146 | | * Close and re-open the printer, to reset is_new and do the |
1147 | | * right thing if we're producing multiple output files. |
1148 | | * Code is mostly copied from gdev_prn_output_page. |
1149 | | */ |
1150 | 0 | gp_fflush(pdev->file); |
1151 | 0 | errcode = |
1152 | 0 | (gp_ferror(pdev->file) ? gs_note_error(gs_error_ioerror) : 0); |
1153 | 0 | closecode = gdev_prn_close_printer((gx_device *)pdev); |
1154 | 0 | pdev->PageCount++; |
1155 | 0 | code = (errcode < 0 ? errcode : closecode < 0 ? closecode : |
1156 | 0 | gdev_prn_open_printer((gx_device *)pdev, true)); |
1157 | 0 | if (code < 0) { |
1158 | 0 | pdev->PageCount -= i; |
1159 | 0 | return code; |
1160 | 0 | } |
1161 | 0 | prn_stream = pdev->file; |
1162 | 0 | } |
1163 | | /* Print the last (or only) page. */ |
1164 | 41.9k | pdev->PageCount -= num_copies - 1; |
1165 | 41.9k | return (*pdev->printer_procs.print_page) (pdev, prn_stream); |
1166 | 41.9k | } |
1167 | | |
1168 | | /* |
1169 | | * Print a page in the background. When printing is complete, |
1170 | | * post the return code and signal the foreground (semaphore). |
1171 | | * This is the procedure that is run in the background thread. |
1172 | | */ |
1173 | | static void |
1174 | | prn_print_page_in_background(void *data) |
1175 | 0 | { |
1176 | 0 | bg_print_t *bg_print = (bg_print_t *)data; |
1177 | 0 | int code, errcode = 0; |
1178 | 0 | int num_copies = bg_print->num_copies; |
1179 | 0 | gx_device_printer *ppdev = (gx_device_printer *)bg_print->device; |
1180 | |
|
1181 | 0 | code = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file, |
1182 | 0 | num_copies); |
1183 | 0 | gp_fflush(ppdev->file); |
1184 | |
|
1185 | 0 | errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0); |
1186 | 0 | bg_print->return_code = code < 0 ? code : errcode; |
1187 | | |
1188 | | /* Finally, release the foreground that may be waiting */ |
1189 | 0 | gx_semaphore_signal(bg_print->sema); |
1190 | 0 | } |
1191 | | /* ---------------- Driver services ---------------- */ |
1192 | | |
1193 | | /* Initialize a rendering plane specification. */ |
1194 | | int |
1195 | | gx_render_plane_init(gx_render_plane_t *render_plane, const gx_device *dev, |
1196 | | int index) |
1197 | 0 | { |
1198 | | /* |
1199 | | * Eventually the computation of shift and depth from dev and index |
1200 | | * will be made device-dependent. |
1201 | | */ |
1202 | 0 | int num_planes = dev->color_info.num_components; |
1203 | 0 | int plane_depth = dev->color_info.depth / num_planes; |
1204 | |
|
1205 | 0 | if (index < -1 || index >= num_planes) |
1206 | 0 | return_error(gs_error_rangecheck); |
1207 | 0 | render_plane->index = index; |
1208 | 0 | if (index == -1) { |
1209 | | /* No plane, chunky results required. */ |
1210 | 0 | render_plane->depth = dev->color_info.depth; |
1211 | 0 | render_plane->shift = 0; |
1212 | 0 | } else { |
1213 | | /* A single plane */ |
1214 | 0 | render_plane->depth = plane_depth; |
1215 | 0 | render_plane->shift = plane_depth * (num_planes - 1 - index); |
1216 | 0 | } |
1217 | 0 | return 0; |
1218 | 0 | } |
1219 | | |
1220 | | /* Clear trailing bits in the last byte of (a) scan line(s). */ |
1221 | | void |
1222 | | gdev_prn_clear_trailing_bits(byte *data, uint raster, int height, |
1223 | | const gx_device *dev) |
1224 | 0 | { |
1225 | 0 | int first_bit = dev->width * dev->color_info.depth; |
1226 | |
|
1227 | 0 | if (first_bit & 7) |
1228 | 0 | bits_fill_rectangle(data, first_bit, raster, mono_fill_make_pattern(0), |
1229 | 0 | -first_bit & 7, height); |
1230 | 0 | } |
1231 | | |
1232 | | /* Return the number of scan lines that should actually be passed */ |
1233 | | /* to the device. */ |
1234 | | int |
1235 | | gdev_prn_print_scan_lines(gx_device * pdev) |
1236 | 0 | { |
1237 | 0 | int height = pdev->height; |
1238 | 0 | gs_matrix imat; |
1239 | 0 | float yscale; |
1240 | 0 | int top, bottom, offset, end; |
1241 | |
|
1242 | 0 | (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat); |
1243 | 0 | yscale = imat.yy * 72.0; /* Y dpi, may be negative */ |
1244 | 0 | top = (int)(dev_t_margin(pdev) * yscale); |
1245 | 0 | bottom = (int)(dev_b_margin(pdev) * yscale); |
1246 | 0 | offset = (int)(dev_y_offset(pdev) * yscale); |
1247 | 0 | if (yscale < 0) { /* Y=0 is top of page */ |
1248 | 0 | end = -offset + height + bottom; |
1249 | 0 | } else { /* Y=0 is bottom of page */ |
1250 | 0 | end = offset + height - top; |
1251 | 0 | } |
1252 | 0 | return min(height, end); |
1253 | 0 | } |
1254 | | |
1255 | | /* Open the current page for printing. */ |
1256 | | int |
1257 | | gdev_prn_open_printer_seekable(gx_device *pdev, bool binary_mode, |
1258 | | bool seekable) |
1259 | 75.2k | { |
1260 | 75.2k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
1261 | | |
1262 | 75.2k | if (ppdev->file != 0) { |
1263 | 30.4k | ppdev->file_is_new = false; |
1264 | 30.4k | return 0; |
1265 | 30.4k | } |
1266 | 44.7k | { |
1267 | 44.7k | int code = gx_device_open_output_file(pdev, ppdev->fname, |
1268 | 44.7k | binary_mode, seekable, |
1269 | 44.7k | &ppdev->file); |
1270 | 44.7k | if (code < 0) |
1271 | 0 | return code; |
1272 | | |
1273 | 44.7k | if (seekable && !gp_fseekable(ppdev->file)) { |
1274 | 0 | errprintf(pdev->memory, "I/O Error: Output File \"%s\" must be seekable\n", ppdev->fname); |
1275 | 0 | if (!IS_LIBCTX_STDOUT(pdev->memory, gp_get_file(ppdev->file)) |
1276 | 0 | && !IS_LIBCTX_STDERR(pdev->memory, gp_get_file(ppdev->file))) { |
1277 | |
|
1278 | 0 | code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file); |
1279 | 0 | ppdev->file = NULL; |
1280 | 0 | if (code < 0) |
1281 | 0 | return code; |
1282 | 0 | } |
1283 | 0 | ppdev->file = NULL; |
1284 | |
|
1285 | 0 | return_error(gs_error_ioerror); |
1286 | 0 | } |
1287 | 44.7k | } |
1288 | 44.7k | ppdev->file_is_new = true; |
1289 | | |
1290 | 44.7k | return 0; |
1291 | 44.7k | } |
1292 | | int |
1293 | | gdev_prn_open_printer(gx_device *pdev, bool binary_mode) |
1294 | 0 | { |
1295 | 0 | return gdev_prn_open_printer_seekable(pdev, binary_mode, false); |
1296 | 0 | } |
1297 | | |
1298 | | /* |
1299 | | * Test whether the printer's output file was just opened, i.e., whether |
1300 | | * this is the first page being written to this file. This is only valid |
1301 | | * at the entry to a driver's print_page procedure. |
1302 | | */ |
1303 | | bool |
1304 | | gdev_prn_file_is_new(const gx_device_printer *pdev) |
1305 | 0 | { |
1306 | 0 | return pdev->file_is_new; |
1307 | 0 | } |
1308 | | |
1309 | | /* Determine the colors used in a range of lines. */ |
1310 | | /* FIXME: Currently, the page_info is ignored and the page_info from |
1311 | | * the 'dev' parameter is used. For saved pages, the 'dev' may not |
1312 | | * be a clist and the page_info should be used for clist file info |
1313 | | * which may require a dummy gx_device_printer with the page_info |
1314 | | * copied from the caller's data. |
1315 | | */ |
1316 | | int |
1317 | | gx_page_info_color_usage(const gx_device *dev, |
1318 | | const gx_band_page_info_t *page_info, |
1319 | | int y, int height, |
1320 | | gx_color_usage_t *color_usage, int *range_start) |
1321 | 0 | { |
1322 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)dev; |
1323 | 0 | int start, end, i; |
1324 | 0 | int band_height = page_info->band_params.BandHeight; |
1325 | 0 | gx_color_usage_bits or = 0; |
1326 | 0 | bool slow_rop = false; |
1327 | |
|
1328 | 0 | if (y < 0 || height < 0 || height > dev->height - y) |
1329 | 0 | return -1; |
1330 | 0 | start = y / band_height; |
1331 | 0 | end = (y + height + band_height - 1) / band_height; |
1332 | 0 | if (crdev->color_usage_array == NULL) { |
1333 | 0 | return -1; |
1334 | 0 | } |
1335 | 0 | for (i = start; i < end; ++i) { |
1336 | 0 | or |= crdev->color_usage_array[i].or; |
1337 | 0 | slow_rop |= crdev->color_usage_array[i].slow_rop; |
1338 | 0 | } |
1339 | 0 | color_usage->or = or; |
1340 | 0 | color_usage->slow_rop = slow_rop; |
1341 | 0 | *range_start = start * band_height; |
1342 | 0 | return min(end * band_height, dev->height) - *range_start; |
1343 | 0 | } |
1344 | | int |
1345 | | gdev_prn_color_usage(gx_device *dev, int y, int height, |
1346 | | gx_color_usage_t *color_usage, int *range_start) |
1347 | 0 | { |
1348 | 0 | gx_device_printer *pdev = (gx_device_printer *)dev; |
1349 | 0 | gx_device_clist *cdev = (gx_device_clist *)dev; |
1350 | 0 | gx_device_clist_writer *cldev = (gx_device_clist_writer *)dev; |
1351 | | |
1352 | | /* If this isn't a banded device, return default values. */ |
1353 | 0 | if (!PRINTER_IS_CLIST(pdev)) { |
1354 | 0 | *range_start = 0; |
1355 | 0 | color_usage->or = gx_color_usage_all(dev); |
1356 | 0 | return dev->height; |
1357 | 0 | } |
1358 | 0 | if (y < 0 || height < 0 || height > dev->height - y) |
1359 | 0 | return -1; |
1360 | 0 | if (CLIST_IS_WRITER(cdev)) { |
1361 | | /* Not expected to be used since usually this is called during reading */ |
1362 | 0 | return clist_writer_color_usage(cldev, y, height, color_usage, range_start); |
1363 | 0 | } else |
1364 | 0 | return gx_page_info_color_usage(dev, &cldev->page_info, |
1365 | 0 | y, height, color_usage, range_start); |
1366 | 0 | } |
1367 | | |
1368 | | /* |
1369 | | * Create the buffer device for a printer device. Clients should always |
1370 | | * call this, and never call the device procedure directly. |
1371 | | */ |
1372 | | int |
1373 | | gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev, |
1374 | | gx_device *target, int y, |
1375 | | const gx_render_plane_t *render_plane, |
1376 | | gs_memory_t *mem, gx_color_usage_t *color_usage) |
1377 | 160M | { |
1378 | 160M | int code = cbd_proc(pbdev, target, y, render_plane, mem, color_usage); |
1379 | | |
1380 | 160M | if (code < 0) |
1381 | 0 | return code; |
1382 | | /* Retain this device -- it will be freed explicitly. */ |
1383 | 160M | gx_device_retain(*pbdev, true); |
1384 | 160M | return code; |
1385 | 160M | } |
1386 | | |
1387 | | /* |
1388 | | * Create an ordinary memory device for page or band buffering, |
1389 | | * possibly preceded by a plane extraction device. |
1390 | | */ |
1391 | | int |
1392 | | gx_default_create_buf_device(gx_device **pbdev, gx_device *target, int y, |
1393 | | const gx_render_plane_t *render_plane, gs_memory_t *mem, gx_color_usage_t *color_usage) |
1394 | 161M | { |
1395 | 161M | int plane_index = (render_plane ? render_plane->index : -1); |
1396 | 161M | int depth; |
1397 | 161M | const gx_device_memory *mdproto; |
1398 | 161M | gx_device_memory *mdev; |
1399 | 161M | gx_device *bdev; |
1400 | | |
1401 | 161M | if (plane_index >= 0) |
1402 | 0 | depth = render_plane->depth; |
1403 | 161M | else { |
1404 | 161M | depth = target->color_info.depth; |
1405 | 161M | if (target->num_planar_planes) |
1406 | 7.65M | depth /= target->num_planar_planes; |
1407 | 161M | } |
1408 | | |
1409 | 161M | mdproto = gdev_mem_device_for_bits(depth); |
1410 | 161M | if (mdproto == 0) |
1411 | 0 | return_error(gs_error_rangecheck); |
1412 | 161M | if (mem) { |
1413 | 160M | mdev = gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory, |
1414 | 160M | "create_buf_device"); |
1415 | 160M | if (mdev == 0) |
1416 | 0 | return_error(gs_error_VMerror); |
1417 | 160M | } else { |
1418 | 1.35M | mdev = (gx_device_memory *)*pbdev; |
1419 | 1.35M | } |
1420 | 161M | if (target == (gx_device *)mdev) { |
1421 | 0 | dev_t_proc_dev_spec_op((*orig_dso), gx_device) = dev_proc(mdev, dev_spec_op); |
1422 | | /* The following is a special hack for setting up printer devices. */ |
1423 | 0 | assign_dev_procs(mdev, mdproto); |
1424 | 0 | mdev->initialize_device_procs = mdproto->initialize_device_procs; |
1425 | 0 | mdev->initialize_device_procs((gx_device *)mdev); |
1426 | | /* We know mdev->procs.initialize_device is NULL! */ |
1427 | | /* Do not override the dev_spec_op! */ |
1428 | 0 | dev_proc(mdev, dev_spec_op) = orig_dso; |
1429 | 0 | check_device_separable((gx_device *)mdev); |
1430 | | /* In order for saved-pages to work, we need to hook the dev_spec_op */ |
1431 | 0 | if (mdev->procs.dev_spec_op == NULL || mdev->procs.dev_spec_op == gx_default_dev_spec_op) |
1432 | 0 | set_dev_proc(mdev, dev_spec_op, gdev_prn_dev_spec_op); |
1433 | | #ifdef DEBUG |
1434 | | /* scanning sources didn't show anything, but if a device gets changed or added */ |
1435 | | /* that has its own dev_spec_op, it should call the gdev_prn_spec_op as well */ |
1436 | | else { |
1437 | | if (dev_proc(mdev, dev_spec_op)((gx_device *)mdev, gxdso_debug_printer_check, NULL, 0) < 0) |
1438 | | errprintf(mdev->memory, "Warning: printer device has private dev_spec_op\n"); |
1439 | | } |
1440 | | #endif |
1441 | 0 | gx_device_fill_in_procs((gx_device *)mdev); |
1442 | 161M | } else { |
1443 | 161M | gs_devn_params* pdevn_params; |
1444 | | |
1445 | 161M | gs_make_mem_device(mdev, mdproto, mem, (color_usage == NULL ? 1 : 0), target); |
1446 | | /* mem devices may need to refer to the target's devn_params struct */ |
1447 | | /* if the device has separations already defined (by SeparationOrderNames), we */ |
1448 | | /* need to use them so the colorants are in the same order as the target device. */ |
1449 | 161M | pdevn_params = dev_proc(target, ret_devn_params)(target); |
1450 | 161M | if (pdevn_params != NULL) { |
1451 | 7.65M | mdev->procs.ret_devn_params = gx_forward_ret_devn_params; |
1452 | 7.65M | } |
1453 | 161M | } |
1454 | 161M | mdev->width = target->width; |
1455 | 161M | mdev->band_y = y; |
1456 | 161M | mdev->log2_align_mod = target->log2_align_mod; |
1457 | 161M | mdev->pad = target->pad; |
1458 | 161M | mdev->num_planar_planes = target->num_planar_planes; |
1459 | | /* |
1460 | | * The matrix in the memory device is irrelevant, |
1461 | | * because all we do with the device is call the device-level |
1462 | | * output procedures, but we may as well set it to |
1463 | | * something halfway reasonable. |
1464 | | */ |
1465 | 161M | gs_deviceinitialmatrix(target, &mdev->initial_matrix); |
1466 | 161M | if (plane_index >= 0) { |
1467 | 0 | gx_device_plane_extract *edev; |
1468 | | |
1469 | | /* Guard against potential NULL dereference in gs_alloc_struct */ |
1470 | 0 | if (!mem) |
1471 | 0 | return_error(gs_error_undefined); |
1472 | | |
1473 | 0 | edev = gs_alloc_struct(mem, gx_device_plane_extract, |
1474 | 0 | &st_device_plane_extract, "create_buf_device"); |
1475 | |
|
1476 | 0 | if (edev == 0) { |
1477 | 0 | gx_default_destroy_buf_device((gx_device *)mdev); |
1478 | 0 | return_error(gs_error_VMerror); |
1479 | 0 | } |
1480 | 0 | edev->memory = mem; |
1481 | 0 | plane_device_init(edev, target, (gx_device *)mdev, render_plane, |
1482 | 0 | false); |
1483 | 0 | bdev = (gx_device *)edev; |
1484 | 0 | } else |
1485 | 161M | bdev = (gx_device *)mdev; |
1486 | | /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/ |
1487 | 161M | if (&bdev->color_info != &target->color_info) /* Pacify Valgrind */ |
1488 | 161M | bdev->color_info = target->color_info; |
1489 | 161M | *pbdev = bdev; |
1490 | 161M | return 0; |
1491 | 161M | } |
1492 | | |
1493 | | /* Determine the space needed by the buffer device. */ |
1494 | | int |
1495 | | gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target, |
1496 | | const gx_render_plane_t *render_plane, |
1497 | | int height, bool not_used) |
1498 | 195k | { |
1499 | 195k | gx_device_memory mdev; |
1500 | | |
1501 | 195k | space->line_ptrs = 0; /* */ |
1502 | 195k | space->bits = 0; /* clear in case of failure */ |
1503 | 195k | space->raster = 0; /* */ |
1504 | 195k | mdev.color_info.depth = |
1505 | 195k | (render_plane && render_plane->index >= 0 ? render_plane->depth : |
1506 | 195k | target->color_info.depth); |
1507 | 195k | mdev.color_info.num_components = target->color_info.num_components; |
1508 | 195k | mdev.width = target->width; |
1509 | 195k | mdev.num_planar_planes = target->num_planar_planes; |
1510 | 195k | mdev.pad = target->pad; |
1511 | 195k | mdev.log2_align_mod = target->log2_align_mod; |
1512 | 195k | if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0) |
1513 | 0 | return_error(gs_error_VMerror); |
1514 | 195k | space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height); |
1515 | 195k | space->raster = gdev_mem_raster(&mdev); |
1516 | 195k | return 0; |
1517 | 195k | } |
1518 | | |
1519 | | /* Set up the buffer device. */ |
1520 | | int |
1521 | | gx_default_setup_buf_device(gx_device *bdev, byte *buffer, int raster, |
1522 | | byte **line_ptrs, int y, int setup_height, |
1523 | | int full_height) |
1524 | 163M | { |
1525 | 163M | gx_device_memory *mdev = |
1526 | 163M | (gs_device_is_memory(bdev) ? (gx_device_memory *)bdev : |
1527 | 163M | (gx_device_memory *)(((gx_device_plane_extract *)bdev)->plane_dev)); |
1528 | 163M | byte **ptrs = line_ptrs; |
1529 | 163M | int code; |
1530 | | |
1531 | 163M | if (ptrs == 0) { |
1532 | | /* |
1533 | | * Before allocating a new line pointer array, if there is a previous |
1534 | | * array, free it to prevent leaks. |
1535 | | */ |
1536 | 0 | if (mdev->line_ptrs != NULL) |
1537 | 0 | gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs, |
1538 | 0 | "mem_close"); |
1539 | | /* |
1540 | | * Allocate line pointers now; free them when we close the device. |
1541 | | * Note that for multi-planar devices, we have to allocate using |
1542 | | * full_height rather than setup_height. |
1543 | | */ |
1544 | 0 | ptrs = (byte **) |
1545 | 0 | gs_alloc_byte_array(mdev->memory, |
1546 | 0 | (mdev->num_planar_planes ? |
1547 | 0 | full_height * mdev->num_planar_planes : |
1548 | 0 | setup_height), |
1549 | 0 | sizeof(byte *), "setup_buf_device"); |
1550 | 0 | if (ptrs == 0) |
1551 | 0 | return_error(gs_error_VMerror); |
1552 | 0 | mdev->line_pointer_memory = mdev->memory; |
1553 | 0 | mdev->foreign_line_pointers = false; |
1554 | 0 | } |
1555 | 163M | mdev->height = full_height; |
1556 | 163M | code = gdev_mem_set_line_ptrs(mdev, buffer + raster * y, raster, |
1557 | 163M | ptrs, setup_height); |
1558 | 163M | mdev->height = setup_height; |
1559 | 163M | bdev->height = setup_height; /* do here in case mdev == bdev */ |
1560 | 163M | return code; |
1561 | 163M | } |
1562 | | |
1563 | | /* Destroy the buffer device. */ |
1564 | | void |
1565 | | gx_default_destroy_buf_device(gx_device *bdev) |
1566 | 160M | { |
1567 | 160M | gx_device *mdev = bdev; |
1568 | | |
1569 | 160M | if (!gs_device_is_memory(bdev)) { |
1570 | | /* bdev must be a plane extraction device. */ |
1571 | 0 | mdev = ((gx_device_plane_extract *)bdev)->plane_dev; |
1572 | 0 | gs_free_object(bdev->memory, bdev, "destroy_buf_device"); |
1573 | 0 | } |
1574 | | /* gs_free_object will do finalize which will decrement icc profile */ |
1575 | 160M | dev_proc(mdev, close_device)(mdev); |
1576 | 160M | gs_free_object(mdev->memory, mdev, "destroy_buf_device"); |
1577 | 160M | } |
1578 | | |
1579 | | /* |
1580 | | * Copy one or more rasterized scan lines to a buffer, or return a pointer |
1581 | | * to them. See gdevprn.h for detailed specifications. |
1582 | | */ |
1583 | | int |
1584 | | gdev_prn_get_lines(gx_device_printer *pdev, int y, int height, |
1585 | | byte *buffer, uint bytes_per_line, |
1586 | | byte **actual_buffer, uint *actual_bytes_per_line, |
1587 | | const gx_render_plane_t *render_plane) |
1588 | 0 | { |
1589 | 0 | int code; |
1590 | 0 | gs_int_rect rect; |
1591 | 0 | gs_get_bits_params_t params; |
1592 | 0 | int plane; |
1593 | |
|
1594 | 0 | if (y < 0 || height < 0 || y + height > pdev->height) |
1595 | 0 | return_error(gs_error_rangecheck); |
1596 | 0 | rect.p.x = 0, rect.p.y = y; |
1597 | 0 | rect.q.x = pdev->width, rect.q.y = y + height; |
1598 | 0 | params.options = |
1599 | 0 | GB_RETURN_POINTER | GB_ALIGN_STANDARD | GB_OFFSET_0 | |
1600 | 0 | GB_RASTER_ANY | |
1601 | | /* No depth specified, we always use native colors. */ |
1602 | 0 | GB_COLORS_NATIVE | GB_ALPHA_NONE; |
1603 | 0 | if (render_plane) { |
1604 | 0 | params.options |= GB_PACKING_PLANAR | GB_SELECT_PLANES; |
1605 | 0 | memset(params.data, 0, |
1606 | 0 | sizeof(params.data[0]) * pdev->color_info.num_components); |
1607 | 0 | plane = render_plane->index; |
1608 | 0 | params.data[plane] = buffer; |
1609 | 0 | } else { |
1610 | 0 | params.options |= GB_PACKING_CHUNKY; |
1611 | 0 | params.data[0] = buffer; |
1612 | 0 | plane = 0; |
1613 | 0 | } |
1614 | 0 | params.x_offset = 0; |
1615 | 0 | params.raster = bytes_per_line; |
1616 | 0 | code = dev_proc(pdev, get_bits_rectangle) |
1617 | 0 | ((gx_device *)pdev, &rect, ¶ms); |
1618 | 0 | if (code < 0 && actual_buffer) { |
1619 | | /* |
1620 | | * RETURN_POINTER might not be implemented for this |
1621 | | * combination of parameters: try RETURN_COPY. |
1622 | | */ |
1623 | 0 | params.options &= ~(GB_RETURN_POINTER | GB_RASTER_ALL); |
1624 | 0 | params.options |= GB_RETURN_COPY | GB_RASTER_SPECIFIED; |
1625 | 0 | code = dev_proc(pdev, get_bits_rectangle) |
1626 | 0 | ((gx_device *)pdev, &rect, ¶ms); |
1627 | 0 | } |
1628 | 0 | if (code < 0) |
1629 | 0 | return code; |
1630 | 0 | if (actual_buffer) |
1631 | 0 | *actual_buffer = params.data[plane]; |
1632 | 0 | if (actual_bytes_per_line) |
1633 | 0 | *actual_bytes_per_line = params.raster; |
1634 | 0 | return code; |
1635 | 0 | } |
1636 | | |
1637 | | /* Copy a scan line from the buffer to the printer. */ |
1638 | | int |
1639 | | gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data) |
1640 | 130M | { |
1641 | 130M | int code; |
1642 | 130M | uint line_size = gdev_prn_raster(pdev); |
1643 | 130M | int last_bits = -(pdev->width * pdev->color_info.depth) & 7; |
1644 | 130M | gs_int_rect rect; |
1645 | 130M | gs_get_bits_params_t params; |
1646 | | |
1647 | 130M | rect.p.x = 0; |
1648 | 130M | rect.p.y = y; |
1649 | 130M | rect.q.x = pdev->width; |
1650 | 130M | rect.q.y = y+1; |
1651 | | |
1652 | 130M | params.options = (GB_ALIGN_ANY | |
1653 | 130M | GB_RETURN_COPY | |
1654 | 130M | GB_OFFSET_0 | |
1655 | 130M | GB_RASTER_STANDARD | GB_PACKING_CHUNKY | |
1656 | 130M | GB_COLORS_NATIVE | GB_ALPHA_NONE); |
1657 | 130M | if (actual_data) |
1658 | 97.8M | params.options |= GB_RETURN_POINTER; |
1659 | 130M | params.x_offset = 0; |
1660 | 130M | params.raster = bitmap_raster(pdev->width * pdev->color_info.depth); |
1661 | 130M | params.data[0] = str; |
1662 | 130M | code = (*dev_proc(pdev, get_bits_rectangle))((gx_device *)pdev, &rect, |
1663 | 130M | ¶ms); |
1664 | 130M | if (code < 0) |
1665 | 6 | return code; |
1666 | 130M | if (actual_data) |
1667 | 97.8M | *actual_data = params.data[0]; |
1668 | 130M | if (last_bits != 0) { |
1669 | 56.1M | byte *dest = (actual_data != NULL ? *actual_data : str); |
1670 | | |
1671 | 56.1M | dest[line_size - 1] &= 0xff << last_bits; |
1672 | 56.1M | } |
1673 | 130M | return 0; |
1674 | 130M | } |
1675 | | /* Copy scan lines to a buffer. Return the number of scan lines, */ |
1676 | | /* or <0 if error. This procedure is DEPRECATED. */ |
1677 | | /* Some old and contrib drivers ignore error codes, so make sure and fill */ |
1678 | | /* remaining lines if we get an error (and for lines past end of page). */ |
1679 | | int |
1680 | | gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size) |
1681 | 33.1M | { |
1682 | 33.1M | uint line_size = gdev_prn_raster(pdev); |
1683 | 33.1M | int requested_count = 0; |
1684 | 33.1M | int i, count; |
1685 | 33.1M | int code = 0; |
1686 | 33.1M | byte *dest = str; |
1687 | | |
1688 | 33.1M | if (line_size != 0) |
1689 | 33.1M | requested_count = size / line_size; |
1690 | | |
1691 | | /* Clamp count between 0 and remaining lines on page so we don't return < 0 */ |
1692 | | /* unless gdev_prn_get_bits returns an error */ |
1693 | 33.1M | count = max(0, min(requested_count, pdev->height - y)); |
1694 | 66.3M | for (i = 0; i < count; i++, dest += line_size) { |
1695 | 33.1M | code = gdev_prn_get_bits(pdev, y + i, dest, NULL); |
1696 | 33.1M | if (code < 0) |
1697 | 4 | break; /* will fill remaining lines and return code outside the loop */ |
1698 | 33.1M | } |
1699 | | /* fill remaining lines with 0's to prevent printing garbage */ |
1700 | 33.1M | memset(dest, 0, (size_t)line_size * (requested_count - i)); |
1701 | 33.1M | return (code < 0 ) ? code : count; |
1702 | 33.1M | } |
1703 | | |
1704 | | /* Close the current page. */ |
1705 | | int |
1706 | | gdev_prn_close_printer(gx_device * pdev) |
1707 | 75.2k | { |
1708 | 75.2k | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
1709 | 75.2k | gs_parsed_file_name_t parsed; |
1710 | 75.2k | const char *fmt; |
1711 | 75.2k | int code = gx_parse_output_file_name(&parsed, &fmt, ppdev->fname, |
1712 | 75.2k | strlen(ppdev->fname), pdev->memory); |
1713 | | |
1714 | 75.2k | if ((code >= 0 && fmt) /* file per page */ || |
1715 | 75.2k | ppdev->ReopenPerPage /* close and reopen for each page */ |
1716 | 75.2k | ) { |
1717 | 0 | gx_device_close_output_file(pdev, ppdev->fname, ppdev->file); |
1718 | 0 | ppdev->file = NULL; |
1719 | 0 | } |
1720 | 75.2k | return 0; |
1721 | 75.2k | } |
1722 | | |
1723 | | /* If necessary, free and reallocate the printer memory after changing params */ |
1724 | | int |
1725 | | gdev_prn_maybe_realloc_memory(gx_device_printer *prdev, |
1726 | | gdev_space_params *old_sp, |
1727 | | int old_width, int old_height, |
1728 | | bool old_page_uses_transparency) |
1729 | 1.00M | { |
1730 | 1.00M | int code = 0; |
1731 | 1.00M | gx_device *const pdev = (gx_device *)prdev; |
1732 | | /*gx_device_memory * const mdev = (gx_device_memory *)prdev;*/ |
1733 | | |
1734 | | /* |
1735 | | * The first test was changed to mdev->base != 0 in 5.50 (per Artifex). |
1736 | | * Not only was this test wrong logically, it was incorrect in that |
1737 | | * casting pdev to a (gx_device_memory *) is only meaningful if banding |
1738 | | * is not being used. The test was changed back to prdev->is_open in |
1739 | | * 5.67 (also per Artifex). For more information, see the News items |
1740 | | * for these filesets. |
1741 | | */ |
1742 | 1.00M | if (prdev->is_open && |
1743 | 1.00M | (gdev_space_params_cmp(prdev->space_params, *old_sp) != 0 || |
1744 | 815k | prdev->width != old_width || prdev->height != old_height || |
1745 | 815k | prdev->page_uses_transparency != old_page_uses_transparency) |
1746 | 1.00M | ) { |
1747 | 130k | int new_width = prdev->width; |
1748 | 130k | int new_height = prdev->height; |
1749 | 130k | gdev_space_params new_sp; |
1750 | | |
1751 | | #ifdef DEBUGGING_HACKS |
1752 | | debug_dump_bytes(pdev->memory, (const byte *)old_sp, (const byte *)(old_sp + 1), "old"); |
1753 | | debug_dump_bytes(pddev->memory, (const byte *)&prdev->space_params, |
1754 | | (const byte *)(&prdev->space_params + 1), "new"); |
1755 | | dmprintf4(pdev->memory, "w=%d/%d, h=%d/%d\n", old_width, new_width, old_height, new_height); |
1756 | | #endif /*DEBUGGING_HACKS*/ |
1757 | 130k | new_sp = prdev->space_params; |
1758 | 130k | prdev->width = old_width; |
1759 | 130k | prdev->height = old_height; |
1760 | 130k | prdev->space_params = *old_sp; |
1761 | 130k | code = gdev_prn_reallocate_memory(pdev, &new_sp, |
1762 | 130k | new_width, new_height); |
1763 | | /* If this fails, device should be usable w/old params, but */ |
1764 | | /* band files may not be open. */ |
1765 | 130k | } |
1766 | 1.00M | return code; |
1767 | 1.00M | } |
1768 | | |
1769 | | void |
1770 | | gdev_prn_initialize_device_procs(gx_device *dev) |
1771 | 63.7k | { |
1772 | 63.7k | set_dev_proc(dev, open_device, gdev_prn_open); |
1773 | 63.7k | set_dev_proc(dev, close_device, gdev_prn_close); |
1774 | 63.7k | set_dev_proc(dev, output_page, gdev_prn_output_page); |
1775 | 63.7k | set_dev_proc(dev, get_params, gdev_prn_get_params); |
1776 | 63.7k | set_dev_proc(dev, put_params, gdev_prn_put_params); |
1777 | 63.7k | set_dev_proc(dev, get_page_device, gx_page_device_get_page_device); |
1778 | 63.7k | set_dev_proc(dev, dev_spec_op, gdev_prn_dev_spec_op); |
1779 | 63.7k | set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color); |
1780 | 63.7k | set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb); |
1781 | 63.7k | set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color); |
1782 | 63.7k | set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb); |
1783 | 63.7k | } |
1784 | | |
1785 | | void gdev_prn_initialize_device_procs_bg(gx_device *dev) |
1786 | 10.5k | { |
1787 | 10.5k | gdev_prn_initialize_device_procs(dev); |
1788 | | |
1789 | 10.5k | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1790 | 10.5k | } |
1791 | | |
1792 | | void |
1793 | | gdev_prn_initialize_device_procs_mono(gx_device *dev) |
1794 | 28.9k | { |
1795 | 28.9k | gdev_prn_initialize_device_procs(dev); |
1796 | | |
1797 | 28.9k | set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color); |
1798 | 28.9k | set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb); |
1799 | 28.9k | set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color); |
1800 | 28.9k | set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb); |
1801 | 28.9k | } |
1802 | | |
1803 | | void gdev_prn_initialize_device_procs_mono_bg(gx_device *dev) |
1804 | 19.1k | { |
1805 | 19.1k | gdev_prn_initialize_device_procs_mono(dev); |
1806 | | |
1807 | 19.1k | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1808 | 19.1k | } |
1809 | | |
1810 | | void |
1811 | | gdev_prn_initialize_device_procs_gray(gx_device *dev) |
1812 | 0 | { |
1813 | 0 | gdev_prn_initialize_device_procs(dev); |
1814 | |
|
1815 | 0 | set_dev_proc(dev, map_rgb_color, gx_default_gray_map_rgb_color); |
1816 | 0 | set_dev_proc(dev, map_color_rgb, gx_default_gray_map_color_rgb); |
1817 | 0 | set_dev_proc(dev, encode_color, gx_default_gray_encode_color); |
1818 | 0 | set_dev_proc(dev, decode_color, gx_default_gray_decode_color); |
1819 | 0 | } |
1820 | | |
1821 | | void gdev_prn_initialize_device_procs_gray_bg(gx_device *dev) |
1822 | 0 | { |
1823 | 0 | gdev_prn_initialize_device_procs_gray(dev); |
1824 | |
|
1825 | 0 | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1826 | 0 | } |
1827 | | |
1828 | | void gdev_prn_initialize_device_procs_rgb(gx_device *dev) |
1829 | 14.3k | { |
1830 | 14.3k | gdev_prn_initialize_device_procs(dev); |
1831 | | |
1832 | 14.3k | set_dev_proc(dev, map_rgb_color, gx_default_rgb_map_rgb_color); |
1833 | 14.3k | set_dev_proc(dev, map_color_rgb, gx_default_rgb_map_color_rgb); |
1834 | 14.3k | set_dev_proc(dev, encode_color, gx_default_rgb_map_rgb_color); |
1835 | 14.3k | set_dev_proc(dev, decode_color, gx_default_rgb_map_color_rgb); |
1836 | 14.3k | } |
1837 | | |
1838 | | void gdev_prn_initialize_device_procs_rgb_bg(gx_device *dev) |
1839 | 9.20k | { |
1840 | 9.20k | gdev_prn_initialize_device_procs_rgb(dev); |
1841 | | |
1842 | 9.20k | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1843 | 9.20k | } |
1844 | | |
1845 | | void |
1846 | | gdev_prn_initialize_device_procs_gray8(gx_device *dev) |
1847 | 1.04k | { |
1848 | 1.04k | gdev_prn_initialize_device_procs(dev); |
1849 | | |
1850 | 1.04k | set_dev_proc(dev, map_rgb_color, gx_default_8bit_map_gray_color); |
1851 | 1.04k | set_dev_proc(dev, map_color_rgb, gx_default_8bit_map_color_gray); |
1852 | 1.04k | set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color); |
1853 | 1.04k | set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray); |
1854 | 1.04k | } |
1855 | | |
1856 | | void gdev_prn_initialize_device_procs_gray8_bg(gx_device *dev) |
1857 | 0 | { |
1858 | 0 | gdev_prn_initialize_device_procs_gray8(dev); |
1859 | |
|
1860 | 0 | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1861 | 0 | } |
1862 | | |
1863 | | void gdev_prn_initialize_device_procs_cmyk1(gx_device *dev) |
1864 | 0 | { |
1865 | 0 | gdev_prn_initialize_device_procs(dev); |
1866 | |
|
1867 | 0 | set_dev_proc(dev, map_cmyk_color, cmyk_1bit_map_cmyk_color); |
1868 | 0 | set_dev_proc(dev, map_color_rgb, cmyk_1bit_map_color_rgb); |
1869 | 0 | set_dev_proc(dev, encode_color, cmyk_1bit_map_cmyk_color); |
1870 | 0 | set_dev_proc(dev, decode_color, cmyk_1bit_map_color_cmyk); |
1871 | 0 | } |
1872 | | |
1873 | | void gdev_prn_initialize_device_procs_cmyk1_bg(gx_device *dev) |
1874 | 0 | { |
1875 | 0 | gdev_prn_initialize_device_procs_cmyk1(dev); |
1876 | |
|
1877 | 0 | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1878 | 0 | } |
1879 | | |
1880 | | void gdev_prn_initialize_device_procs_cmyk8(gx_device *dev) |
1881 | 0 | { |
1882 | 0 | gdev_prn_initialize_device_procs(dev); |
1883 | |
|
1884 | 0 | set_dev_proc(dev, map_cmyk_color, cmyk_8bit_map_cmyk_color); |
1885 | 0 | set_dev_proc(dev, map_color_rgb, cmyk_8bit_map_color_rgb); |
1886 | 0 | set_dev_proc(dev, encode_color, cmyk_8bit_map_cmyk_color); |
1887 | 0 | set_dev_proc(dev, decode_color, cmyk_8bit_map_color_cmyk); |
1888 | 0 | } |
1889 | | |
1890 | | void gdev_prn_initialize_device_procs_cmyk8_bg(gx_device *dev) |
1891 | 0 | { |
1892 | 0 | gdev_prn_initialize_device_procs_cmyk8(dev); |
1893 | |
|
1894 | 0 | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1895 | 0 | } |
1896 | | |
1897 | | void gdev_prn_initialize_device_procs_cmyk16(gx_device *dev) |
1898 | 0 | { |
1899 | 0 | gdev_prn_initialize_device_procs(dev); |
1900 | |
|
1901 | 0 | set_dev_proc(dev, map_cmyk_color, cmyk_16bit_map_cmyk_color); |
1902 | 0 | set_dev_proc(dev, map_color_rgb, cmyk_16bit_map_color_rgb); |
1903 | 0 | set_dev_proc(dev, encode_color, cmyk_16bit_map_cmyk_color); |
1904 | 0 | set_dev_proc(dev, decode_color, cmyk_16bit_map_color_cmyk); |
1905 | 0 | } |
1906 | | |
1907 | | void gdev_prn_initialize_device_procs_cmyk16_bg(gx_device *dev) |
1908 | 0 | { |
1909 | 0 | gdev_prn_initialize_device_procs_cmyk16(dev); |
1910 | |
|
1911 | 0 | set_dev_proc(dev, output_page, gdev_prn_bg_output_page); |
1912 | 0 | } |