1 /* Copyright (C) 1990, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevprn.c,v 1.20 2005/05/27 05:43:24 dan Exp $ */
18 /* Generic printer driver support */
19 #include "ctype_.h"
20 #include "gdevprn.h"
21 #include "gp.h"
22 #include "gsdevice.h" /* for gs_deviceinitialmatrix */
23 #include "gsfname.h"
24 #include "gsparam.h"
25 #include "gxclio.h"
26 #include "gxgetbit.h"
27 #include "gdevplnx.h"
28 #include "gstrans.h"
29
30 /*#define DEBUGGING_HACKS*/
31
32 /* GC information */
33 #define PRINTER_IS_CLIST(pdev) ((pdev)->buffer_space != 0)
34 private
35 ENUM_PTRS_WITH(device_printer_enum_ptrs, gx_device_printer *pdev)
36 if (PRINTER_IS_CLIST(pdev))
37 ENUM_PREFIX(st_device_clist, 0);
38 else
39 ENUM_PREFIX(st_device_forward, 0);
40 ENUM_PTRS_END
41 private
RELOC_PTRS_WITH(device_printer_reloc_ptrs,gx_device_printer * pdev)42 RELOC_PTRS_WITH(device_printer_reloc_ptrs, gx_device_printer *pdev)
43 {
44 if (PRINTER_IS_CLIST(pdev))
45 RELOC_PREFIX(st_device_clist);
46 else
47 RELOC_PREFIX(st_device_forward);
48 } RELOC_PTRS_END
49 public_st_device_printer();
50
51 /* ---------------- Standard device procedures ---------------- */
52
53 /* Define the standard printer procedure vector. */
54 const gx_device_procs prn_std_procs =
55 prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close);
56
57 /* Forward references */
58 int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
59 gdev_prn_space_params *old_space,
60 int old_width, int old_height,
61 bool old_page_uses_transparency);
62
63 /* ------ Open/close ------ */
64
65 /* Open a generic printer device. */
66 /* Specific devices may wish to extend this. */
67 int
gdev_prn_open(gx_device * pdev)68 gdev_prn_open(gx_device * pdev)
69 {
70 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
71 int code;
72
73 ppdev->file = NULL;
74 code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
75 if (code < 0)
76 return code;
77 if (ppdev->OpenOutputFile)
78 code = gdev_prn_open_printer(pdev, 1);
79 return code;
80 }
81
82 /* Generic closing for the printer device. */
83 /* Specific devices may wish to extend this. */
84 int
gdev_prn_close(gx_device * pdev)85 gdev_prn_close(gx_device * pdev)
86 {
87 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
88 int code = 0;
89
90 gdev_prn_free_memory(pdev);
91 if (ppdev->file != NULL) {
92 code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
93 ppdev->file = NULL;
94 }
95 return code;
96 }
97
98 private int /* returns 0 ok, else -ve error cde */
gdev_prn_setup_as_command_list(gx_device * pdev,gs_memory_t * buffer_memory,byte ** the_memory,const gdev_prn_space_params * space_params,bool bufferSpace_is_exact)99 gdev_prn_setup_as_command_list(gx_device *pdev, gs_memory_t *buffer_memory,
100 byte **the_memory,
101 const gdev_prn_space_params *space_params,
102 bool bufferSpace_is_exact)
103 {
104 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
105 uint space;
106 int code;
107 gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
108 gx_device_clist_common * const pcldev = &pclist_dev->common;
109 bool reallocate = *the_memory != 0;
110 byte *base;
111
112 /* Try to allocate based simply on param-requested buffer size */
113 #ifdef DEBUGGING_HACKS
114 #define BACKTRACE(first_arg)\
115 BEGIN\
116 ulong *fp_ = (ulong *)&first_arg - 2;\
117 for (; fp_ && (fp_[1] & 0xff000000) == 0x08000000; fp_ = (ulong *)*fp_)\
118 dprintf2(" fp=0x%lx ip=0x%lx\n", (ulong)fp_, fp_[1]);\
119 END
120 dputs("alloc buffer:\n");
121 BACKTRACE(pdev);
122 #endif /*DEBUGGING_HACKS*/
123 for ( space = space_params->BufferSpace; ; ) {
124 base = (reallocate ?
125 (byte *)gs_resize_object(buffer_memory, *the_memory, space,
126 "cmd list buffer") :
127 gs_alloc_bytes(buffer_memory, space,
128 "cmd list buffer"));
129 if (base != 0)
130 break;
131 if (bufferSpace_is_exact || (space >>= 1) < PRN_MIN_BUFFER_SPACE)
132 break;
133 }
134 if (base == 0)
135 return_error(gs_error_VMerror);
136 *the_memory = base;
137
138 /* Try opening the command list, to see if we allocated */
139 /* enough buffer space. */
140 open_c:
141 ppdev->buf = base;
142 ppdev->buffer_space = space;
143 clist_init_params(pclist_dev, base, space, pdev,
144 ppdev->printer_procs.buf_procs,
145 space_params->band, ppdev->is_async_renderer,
146 (ppdev->bandlist_memory == 0 ? pdev->memory->non_gc_memory:
147 ppdev->bandlist_memory),
148 ppdev->free_up_bandlist_memory,
149 ppdev->clist_disable_mask,
150 ppdev->page_uses_transparency);
151 code = (*gs_clist_device_procs.open_device)( (gx_device *)pcldev );
152 if (code < 0) {
153 /* If there wasn't enough room, and we haven't */
154 /* already shrunk the buffer, try enlarging it. */
155 if ( code == gs_error_limitcheck &&
156 space >= space_params->BufferSpace &&
157 !bufferSpace_is_exact
158 ) {
159 space <<= 1;
160 if (reallocate) {
161 base = gs_resize_object(buffer_memory,
162 *the_memory, space,
163 "cmd list buf(retry open)");
164 if (base != 0)
165 *the_memory = base;
166 } else {
167 gs_free_object(buffer_memory, base,
168 "cmd list buf(retry open)");
169 *the_memory = base =
170 gs_alloc_bytes(buffer_memory, space,
171 "cmd list buf(retry open)");
172 }
173 ppdev->buf = *the_memory;
174 if (base != 0)
175 goto open_c;
176 }
177 /* Failure. */
178 if (!reallocate) {
179 gs_free_object(buffer_memory, base, "cmd list buf");
180 ppdev->buffer_space = 0;
181 *the_memory = 0;
182 }
183 }
184 return code;
185 }
186
187 private bool /* ret true if device was cmd list, else false */
gdev_prn_tear_down(gx_device * pdev,byte ** the_memory)188 gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
189 {
190 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
191 gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
192 gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
193 gx_device_clist_common * const pcldev = &pclist_dev->common;
194 bool is_command_list;
195
196 if (ppdev->buffer_space != 0) {
197 /* Close cmd list device & point to the storage */
198 (*gs_clist_device_procs.close_device)( (gx_device *)pcldev );
199 *the_memory = ppdev->buf;
200 ppdev->buf = 0;
201 ppdev->buffer_space = 0;
202 is_command_list = true;
203 } else {
204 /* point at the device bitmap, no need to close mem dev */
205 *the_memory = pmemdev->base;
206 pmemdev->base = 0;
207 is_command_list = false;
208 }
209
210 /* Reset device proc vector to default */
211 if (ppdev->orig_procs.open_device != 0)
212 pdev->procs = ppdev->orig_procs;
213 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
214
215 return is_command_list;
216 }
217
218 private int
gdev_prn_allocate(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height,bool reallocate)219 gdev_prn_allocate(gx_device *pdev, gdev_prn_space_params *new_space_params,
220 int new_width, int new_height, bool reallocate)
221 {
222 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
223 gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
224 byte *the_memory = 0;
225 gdev_prn_space_params save_params;
226 int save_width = 0x0badf00d; /* Quiet compiler */
227 int save_height = 0x0badf00d; /* Quiet compiler */
228 bool is_command_list = false; /* Quiet compiler */
229 bool save_is_command_list = false; /* Quiet compiler */
230 int ecode = 0;
231 int pass;
232 gs_memory_t *buffer_memory =
233 (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
234 ppdev->buffer_memory);
235
236 /* If reallocate, find allocated memory & tear down buffer device */
237 if (reallocate)
238 save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
239
240 /* Re/allocate memory */
241 ppdev->orig_procs = pdev->procs;
242 for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
243 ulong mem_space;
244 ulong pdf14_trans_buffer_size = 0;
245 byte *base = 0;
246 bool bufferSpace_is_default = false;
247 gdev_prn_space_params space_params;
248 gx_device_buf_space_t buf_space;
249
250 if (reallocate)
251 switch (pass)
252 {
253 case 1:
254 /* Setup device to get reallocated */
255 save_params = ppdev->space_params;
256 ppdev->space_params = *new_space_params;
257 save_width = ppdev->width;
258 ppdev->width = new_width;
259 save_height = ppdev->height;
260 ppdev->height = new_height;
261 break;
262 case 2: /* only comes here if reallocate */
263 /* Restore device to previous contents */
264 ppdev->space_params = save_params;
265 ppdev->width = save_width;
266 ppdev->height = save_height;
267 break;
268 }
269
270 /* Init clist/mem device-specific fields */
271 memset(ppdev->skip, 0, sizeof(ppdev->skip));
272 ppdev->printer_procs.buf_procs.size_buf_device
273 (&buf_space, pdev, NULL, pdev->height, false);
274 if (ppdev->page_uses_transparency)
275 pdf14_trans_buffer_size = new_height
276 * (ESTIMATED_PDF14_ROW_SPACE(new_width) >> 3);
277 mem_space = buf_space.bits + buf_space.line_ptrs
278 + pdf14_trans_buffer_size;
279
280 /* Compute desired space params: never use the space_params as-is. */
281 /* Rather, give the dev-specific driver a chance to adjust them. */
282 space_params = ppdev->space_params;
283 space_params.BufferSpace = 0;
284 (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
285 if (ppdev->is_async_renderer && space_params.band.BandBufferSpace != 0)
286 space_params.BufferSpace = space_params.band.BandBufferSpace;
287 else if (space_params.BufferSpace == 0) {
288 if (space_params.band.BandBufferSpace > 0)
289 space_params.BufferSpace = space_params.band.BandBufferSpace;
290 else {
291 space_params.BufferSpace = ppdev->space_params.BufferSpace;
292 bufferSpace_is_default = true;
293 }
294 }
295
296 /* Determine if we can use a full bitmap buffer, or have to use banding */
297 if (pass > 1)
298 is_command_list = save_is_command_list;
299 else {
300 is_command_list = space_params.banding_type == BandingAlways ||
301 mem_space >= space_params.MaxBitmap ||
302 mem_space != (uint)mem_space; /* too big to allocate */
303 }
304 if (!is_command_list) {
305 /* Try to allocate memory for full memory buffer */
306 base =
307 (reallocate ?
308 (byte *)gs_resize_object(buffer_memory, the_memory,
309 (uint)mem_space, "printer buffer") :
310 gs_alloc_bytes(buffer_memory, (uint)mem_space,
311 "printer_buffer"));
312 if (base == 0)
313 is_command_list = true;
314 else
315 the_memory = base;
316 }
317 if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
318 && buffer_memory == pdev->memory->non_gc_memory) {
319 /* before using full memory buffer, ensure enough working mem left */
320 byte * left = gs_alloc_bytes( buffer_memory,
321 PRN_MIN_MEMORY_LEFT, "printer mem left");
322 if (left == 0)
323 is_command_list = true;
324 else
325 gs_free_object(buffer_memory, left, "printer mem left");
326 }
327
328 if (is_command_list) {
329 /* Buffer the image in a command list. */
330 /* Release the buffer if we allocated it. */
331 int code;
332 if (!reallocate) {
333 gs_free_object(buffer_memory, the_memory,
334 "printer buffer(open)");
335 the_memory = 0;
336 }
337 if (space_params.banding_type == BandingNever) {
338 ecode = gs_note_error(gs_error_VMerror);
339 continue;
340 }
341 code = gdev_prn_setup_as_command_list(pdev, buffer_memory,
342 &the_memory, &space_params,
343 !bufferSpace_is_default);
344 if (ecode == 0)
345 ecode = code;
346
347 if ( code >= 0 || (reallocate && pass > 1) )
348 ppdev->procs = gs_clist_device_procs;
349 } else {
350 /* Render entirely in memory. */
351 gx_device *bdev = (gx_device *)pmemdev;
352 int code;
353
354 ppdev->buffer_space = 0;
355 if ((code = gdev_create_buf_device
356 (ppdev->printer_procs.buf_procs.create_buf_device,
357 &bdev, pdev, NULL, NULL, false)) < 0 ||
358 (code = ppdev->printer_procs.buf_procs.setup_buf_device
359 (bdev, base, buf_space.raster,
360 (byte **)(base + buf_space.bits), 0, pdev->height,
361 pdev->height)) < 0
362 ) {
363 /* Catastrophic. Shouldn't ever happen */
364 gs_free_object(buffer_memory, base, "printer buffer");
365 pdev->procs = ppdev->orig_procs;
366 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
367 return_error(code);
368 }
369 pmemdev->base = base;
370 }
371 if (ecode == 0)
372 break;
373 }
374
375 if (ecode >= 0 || reallocate) { /* even if realloc failed */
376 /* Synthesize the procedure vector. */
377 /* Rendering operations come from the memory or clist device, */
378 /* non-rendering come from the printer device. */
379 #define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
380 COPY_PROC(get_initial_matrix);
381 COPY_PROC(output_page);
382 COPY_PROC(close_device);
383 COPY_PROC(map_rgb_color);
384 COPY_PROC(map_color_rgb);
385 COPY_PROC(get_params);
386 COPY_PROC(put_params);
387 COPY_PROC(map_cmyk_color);
388 COPY_PROC(get_xfont_procs);
389 COPY_PROC(get_xfont_device);
390 COPY_PROC(map_rgb_alpha_color);
391 /* All printers are page devices, even if they didn't use the */
392 /* standard macros for generating their procedure vectors. */
393 set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
394 COPY_PROC(get_clipping_box);
395 COPY_PROC(map_color_rgb_alpha);
396 COPY_PROC(get_hardware_params);
397 COPY_PROC(get_color_mapping_procs);
398 COPY_PROC(get_color_comp_index);
399 COPY_PROC(encode_color);
400 COPY_PROC(decode_color);
401 COPY_PROC(begin_image);
402 COPY_PROC(text_begin);
403 COPY_PROC(fill_path);
404 COPY_PROC(stroke_path);
405 COPY_PROC(fill_rectangle_hl_color);
406 COPY_PROC(update_spot_equivalent_colors);
407 #undef COPY_PROC
408 /* If using a command list, already opened the device. */
409 if (is_command_list)
410 return ecode;
411 else
412 return (*dev_proc(pdev, open_device))(pdev);
413 } else {
414 pdev->procs = ppdev->orig_procs;
415 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
416 return ecode;
417 }
418 }
419
420 int
gdev_prn_allocate_memory(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height)421 gdev_prn_allocate_memory(gx_device *pdev,
422 gdev_prn_space_params *new_space_params,
423 int new_width, int new_height)
424 {
425 return gdev_prn_allocate(pdev, new_space_params,
426 new_width, new_height, false);
427 }
428
429 int
gdev_prn_reallocate_memory(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height)430 gdev_prn_reallocate_memory(gx_device *pdev,
431 gdev_prn_space_params *new_space_params,
432 int new_width, int new_height)
433 {
434 return gdev_prn_allocate(pdev, new_space_params,
435 new_width, new_height, true);
436 }
437
438 int
gdev_prn_free_memory(gx_device * pdev)439 gdev_prn_free_memory(gx_device *pdev)
440 {
441 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
442 byte *the_memory = 0;
443 gs_memory_t *buffer_memory =
444 (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
445 ppdev->buffer_memory);
446
447 gdev_prn_tear_down(pdev, &the_memory);
448 gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory");
449 return 0;
450 }
451
452 /* ------------- Stubs related only to async rendering ------- */
453
454 int /* rets 0 ok, -ve error if couldn't start thread */
gx_default_start_render_thread(gdev_prn_start_render_params * params)455 gx_default_start_render_thread(gdev_prn_start_render_params *params)
456 {
457 return gs_error_unknownerror;
458 }
459
460 /* Open the renderer's copy of a device. */
461 /* This is overriden in gdevprna.c */
462 int
gx_default_open_render_device(gx_device_printer * pdev)463 gx_default_open_render_device(gx_device_printer *pdev)
464 {
465 return gs_error_unknownerror;
466 }
467
468 /* Close the renderer's copy of a device. */
469 int
gx_default_close_render_device(gx_device_printer * pdev)470 gx_default_close_render_device(gx_device_printer *pdev)
471 {
472 return gdev_prn_close( (gx_device *)pdev );
473 }
474
475 /* ------ Get/put parameters ------ */
476
477 /* Get parameters. Printer devices add several more parameters */
478 /* to the default set. */
479 int
gdev_prn_get_params(gx_device * pdev,gs_param_list * plist)480 gdev_prn_get_params(gx_device * pdev, gs_param_list * plist)
481 {
482 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
483 int code = gx_default_get_params(pdev, plist);
484 gs_param_string ofns;
485
486 if (code < 0 ||
487 (code = param_write_long(plist, "MaxBitmap", &ppdev->space_params.MaxBitmap)) < 0 ||
488 (code = param_write_long(plist, "BufferSpace", &ppdev->space_params.BufferSpace)) < 0 ||
489 (code = param_write_int(plist, "BandWidth", &ppdev->space_params.band.BandWidth)) < 0 ||
490 (code = param_write_int(plist, "BandHeight", &ppdev->space_params.band.BandHeight)) < 0 ||
491 (code = param_write_long(plist, "BandBufferSpace", &ppdev->space_params.band.BandBufferSpace)) < 0 ||
492 (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 ||
493 (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 ||
494 (code = param_write_bool(plist, "PageUsesTransparency",
495 &ppdev->page_uses_transparency)) < 0 ||
496 (ppdev->Duplex_set >= 0 &&
497 (code = (ppdev->Duplex_set ?
498 param_write_bool(plist, "Duplex", &ppdev->Duplex) :
499 param_write_null(plist, "Duplex"))) < 0)
500 )
501 return code;
502
503 ofns.data = (const byte *)ppdev->fname,
504 ofns.size = strlen(ppdev->fname),
505 ofns.persistent = false;
506 return param_write_string(plist, "OutputFile", &ofns);
507 }
508
509 /* Validate an OutputFile name by checking any %-formats. */
510 private int
validate_output_file(const gs_param_string * ofs)511 validate_output_file(const gs_param_string * ofs)
512 {
513 gs_parsed_file_name_t parsed;
514 const char *fmt;
515
516 return gx_parse_output_file_name(&parsed, &fmt, (const char *)ofs->data,
517 ofs->size) >= 0;
518 }
519
520 /* Put parameters. */
521 int
gdev_prn_put_params(gx_device * pdev,gs_param_list * plist)522 gdev_prn_put_params(gx_device * pdev, gs_param_list * plist)
523 {
524 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
525 int ecode = 0;
526 int code;
527 const char *param_name;
528 bool is_open = pdev->is_open;
529 bool oof = ppdev->OpenOutputFile;
530 bool rpp = ppdev->ReopenPerPage;
531 bool page_uses_transparency = ppdev->page_uses_transparency;
532 bool old_page_uses_transparency = ppdev->page_uses_transparency;
533 bool duplex;
534 int duplex_set = -1;
535 int width = pdev->width;
536 int height = pdev->height;
537 gdev_prn_space_params sp, save_sp;
538 gs_param_string ofs;
539 gs_param_dict mdict;
540
541 sp = ppdev->space_params;
542 save_sp = sp;
543
544 switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) {
545 default:
546 ecode = code;
547 param_signal_error(plist, param_name, ecode);
548 case 0:
549 case 1:
550 break;
551 }
552
553 switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) {
554 default:
555 ecode = code;
556 param_signal_error(plist, param_name, ecode);
557 case 0:
558 case 1:
559 break;
560 }
561
562 switch (code = param_read_bool(plist, (param_name = "PageUsesTransparency"),
563 &page_uses_transparency)) {
564 default:
565 ecode = code;
566 param_signal_error(plist, param_name, ecode);
567 case 0:
568 case 1:
569 break;
570 }
571
572 if (ppdev->Duplex_set >= 0) /* i.e., Duplex is supported */
573 switch (code = param_read_bool(plist, (param_name = "Duplex"),
574 &duplex)) {
575 case 0:
576 duplex_set = 1;
577 break;
578 default:
579 if ((code = param_read_null(plist, param_name)) == 0) {
580 duplex_set = 0;
581 break;
582 }
583 ecode = code;
584 param_signal_error(plist, param_name, ecode);
585 case 1:
586 ;
587 }
588 #define CHECK_PARAM_CASES(member, bad, label)\
589 case 0:\
590 if ((sp.params_are_read_only ? sp.member != save_sp.member : bad))\
591 ecode = gs_error_rangecheck;\
592 else\
593 break;\
594 goto label;\
595 default:\
596 ecode = code;\
597 label:\
598 param_signal_error(plist, param_name, ecode);\
599 case 1:\
600 break
601
602 switch (code = param_read_long(plist, (param_name = "MaxBitmap"), &sp.MaxBitmap)) {
603 CHECK_PARAM_CASES(MaxBitmap, sp.MaxBitmap < 10000, mbe);
604 }
605
606 switch (code = param_read_long(plist, (param_name = "BufferSpace"), &sp.BufferSpace)) {
607 CHECK_PARAM_CASES(BufferSpace, sp.BufferSpace < 10000, bse);
608 }
609
610 switch (code = param_read_int(plist, (param_name = "BandWidth"), &sp.band.BandWidth)) {
611 CHECK_PARAM_CASES(band.BandWidth, sp.band.BandWidth < 0, bwe);
612 }
613
614 switch (code = param_read_int(plist, (param_name = "BandHeight"), &sp.band.BandHeight)) {
615 CHECK_PARAM_CASES(band.BandHeight, sp.band.BandHeight < 0, bhe);
616 }
617
618 switch (code = param_read_long(plist, (param_name = "BandBufferSpace"), &sp.band.BandBufferSpace)) {
619 CHECK_PARAM_CASES(band.BandBufferSpace, sp.band.BandBufferSpace < 0, bbse);
620 }
621
622 switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) {
623 case 0:
624 if (pdev->LockSafetyParams &&
625 bytes_compare(ofs.data, ofs.size,
626 (const byte *)ppdev->fname, strlen(ppdev->fname))) {
627 code = gs_error_invalidaccess;
628 }
629 else
630 code = validate_output_file(&ofs);
631 if (code >= 0)
632 break;
633 /* falls through */
634 default:
635 ecode = code;
636 param_signal_error(plist, param_name, ecode);
637 case 1:
638 ofs.data = 0;
639 break;
640 }
641
642 /* Read InputAttributes and OutputAttributes just for the type */
643 /* check and to indicate that they aren't undefined. */
644 #define read_media(pname)\
645 switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
646 {\
647 case 0:\
648 param_end_read_dict(plist, pname, &mdict);\
649 break;\
650 default:\
651 ecode = code;\
652 param_signal_error(plist, param_name, ecode);\
653 case 1:\
654 ;\
655 }
656
657 read_media("InputAttributes");
658 read_media("OutputAttributes");
659
660 if (ecode < 0)
661 return ecode;
662 /* Prevent gx_default_put_params from closing the printer. */
663 pdev->is_open = false;
664 code = gx_default_put_params(pdev, plist);
665 pdev->is_open = is_open;
666 if (code < 0)
667 return code;
668
669 ppdev->OpenOutputFile = oof;
670 ppdev->ReopenPerPage = rpp;
671 ppdev->page_uses_transparency = page_uses_transparency;
672 if (duplex_set >= 0) {
673 ppdev->Duplex = duplex;
674 ppdev->Duplex_set = duplex_set;
675 }
676 ppdev->space_params = sp;
677
678 /* If necessary, free and reallocate the printer memory. */
679 /* Formerly, would not reallocate if device is not open: */
680 /* we had to patch this out (see News for 5.50). */
681 code = gdev_prn_maybe_realloc_memory(ppdev, &save_sp, width, height,
682 old_page_uses_transparency);
683 if (code < 0)
684 return code;
685
686 /* If filename changed, close file. */
687 if (ofs.data != 0 &&
688 bytes_compare(ofs.data, ofs.size,
689 (const byte *)ppdev->fname, strlen(ppdev->fname))
690 ) {
691 /* Close the file if it's open. */
692 if (ppdev->file != NULL)
693 gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
694 ppdev->file = NULL;
695 memcpy(ppdev->fname, ofs.data, ofs.size);
696 ppdev->fname[ofs.size] = 0;
697 }
698 /* If the device is open and OpenOutputFile is true, */
699 /* open the OutputFile now. (If the device isn't open, */
700 /* this will happen when it is opened.) */
701 if (pdev->is_open && oof) {
702 code = gdev_prn_open_printer(pdev, 1);
703 if (code < 0)
704 return code;
705 }
706 return 0;
707 }
708
709 /* ------ Others ------ */
710
711 /* Default routine to (not) override current space_params. */
712 void
gx_default_get_space_params(const gx_device_printer * printer_dev,gdev_prn_space_params * space_params)713 gx_default_get_space_params(const gx_device_printer *printer_dev,
714 gdev_prn_space_params *space_params)
715 {
716 return;
717 }
718
719 /* Generic routine to send the page to the printer. */
720 int /* 0 ok, -ve error, or 1 if successfully upgraded to buffer_page */
gdev_prn_output_page(gx_device * pdev,int num_copies,int flush)721 gdev_prn_output_page(gx_device * pdev, int num_copies, int flush)
722 {
723 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
724 int outcode = 0, closecode = 0, errcode = 0, endcode;
725 bool upgraded_copypage = false;
726
727 if (num_copies > 0 || !flush) {
728 int code = gdev_prn_open_printer(pdev, 1);
729
730 if (code < 0)
731 return code;
732
733 /* If copypage request, try to do it using buffer_page */
734 if ( !flush &&
735 (*ppdev->printer_procs.buffer_page)
736 (ppdev, ppdev->file, num_copies) >= 0
737 ) {
738 upgraded_copypage = true;
739 flush = true;
740 }
741 else if (num_copies > 0)
742 /* Print the accumulated page description. */
743 outcode =
744 (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
745 num_copies);
746 fflush(ppdev->file);
747 errcode =
748 (ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
749 if (!upgraded_copypage)
750 closecode = gdev_prn_close_printer(pdev);
751 }
752 endcode = (ppdev->buffer_space && !ppdev->is_async_renderer ?
753 clist_finish_page(pdev, flush) : 0);
754
755 if (outcode < 0)
756 return outcode;
757 if (errcode < 0)
758 return errcode;
759 if (closecode < 0)
760 return closecode;
761 if (endcode < 0)
762 return endcode;
763 endcode = gx_finish_output_page(pdev, num_copies, flush);
764 return (endcode < 0 ? endcode : upgraded_copypage ? 1 : 0);
765 }
766
767 /* Print a single copy of a page by calling print_page_copies. */
768 int
gx_print_page_single_copy(gx_device_printer * pdev,FILE * prn_stream)769 gx_print_page_single_copy(gx_device_printer * pdev, FILE * prn_stream)
770 {
771 return pdev->printer_procs.print_page_copies(pdev, prn_stream, 1);
772 }
773
774 /* Print multiple copies of a page by calling print_page multiple times. */
775 int
gx_default_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)776 gx_default_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
777 int num_copies)
778 {
779 int i = 1;
780 int code = 0;
781
782 for (; i < num_copies; ++i) {
783 int errcode, closecode;
784
785 code = (*pdev->printer_procs.print_page) (pdev, prn_stream);
786 if (code < 0)
787 return code;
788 /*
789 * Close and re-open the printer, to reset is_new and do the
790 * right thing if we're producing multiple output files.
791 * Code is mostly copied from gdev_prn_output_page.
792 */
793 fflush(pdev->file);
794 errcode =
795 (ferror(pdev->file) ? gs_note_error(gs_error_ioerror) : 0);
796 closecode = gdev_prn_close_printer((gx_device *)pdev);
797 pdev->PageCount++;
798 code = (errcode < 0 ? errcode : closecode < 0 ? closecode :
799 gdev_prn_open_printer((gx_device *)pdev, true));
800 if (code < 0) {
801 pdev->PageCount -= i;
802 return code;
803 }
804 prn_stream = pdev->file;
805 }
806 /* Print the last (or only) page. */
807 pdev->PageCount -= num_copies - 1;
808 return (*pdev->printer_procs.print_page) (pdev, prn_stream);
809 }
810
811 /*
812 * Buffer a (partial) rasterized page & optionally print result multiple times.
813 * The default implementation returns error, since the driver needs to override
814 * this (in procedure vector) in configurations where this call may occur.
815 */
816 int
gx_default_buffer_page(gx_device_printer * pdev,FILE * prn_stream,int num_copies)817 gx_default_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
818 int num_copies)
819 {
820 return gs_error_unknownerror;
821 }
822
823 /* ---------------- Driver services ---------------- */
824
825 /* Initialize a rendering plane specification. */
826 int
gx_render_plane_init(gx_render_plane_t * render_plane,const gx_device * dev,int index)827 gx_render_plane_init(gx_render_plane_t *render_plane, const gx_device *dev,
828 int index)
829 {
830 /*
831 * Eventually the computation of shift and depth from dev and index
832 * will be made device-dependent.
833 */
834 int num_planes = dev->color_info.num_components;
835 int plane_depth = dev->color_info.depth / num_planes;
836
837 if (index < 0 || index >= num_planes)
838 return_error(gs_error_rangecheck);
839 render_plane->index = index;
840 render_plane->depth = plane_depth;
841 render_plane->shift = plane_depth * (num_planes - 1 - index);
842 return 0;
843 }
844
845 /* Clear trailing bits in the last byte of (a) scan line(s). */
846 void
gdev_prn_clear_trailing_bits(byte * data,uint raster,int height,const gx_device * dev)847 gdev_prn_clear_trailing_bits(byte *data, uint raster, int height,
848 const gx_device *dev)
849 {
850 int first_bit = dev->width * dev->color_info.depth;
851
852 if (first_bit & 7)
853 bits_fill_rectangle(data, first_bit, raster, mono_fill_make_pattern(0),
854 -first_bit & 7, height);
855 }
856
857 /* Return the number of scan lines that should actually be passed */
858 /* to the device. */
859 int
gdev_prn_print_scan_lines(gx_device * pdev)860 gdev_prn_print_scan_lines(gx_device * pdev)
861 {
862 int height = pdev->height;
863 gs_matrix imat;
864 float yscale;
865 int top, bottom, offset, end;
866
867 (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
868 yscale = imat.yy * 72.0; /* Y dpi, may be negative */
869 top = (int)(dev_t_margin(pdev) * yscale);
870 bottom = (int)(dev_b_margin(pdev) * yscale);
871 offset = (int)(dev_y_offset(pdev) * yscale);
872 if (yscale < 0) { /* Y=0 is top of page */
873 end = -offset + height + bottom;
874 } else { /* Y=0 is bottom of page */
875 end = offset + height - top;
876 }
877 return min(height, end);
878 }
879
880 /* Open the current page for printing. */
881 int
gdev_prn_open_printer_seekable(gx_device * pdev,bool binary_mode,bool seekable)882 gdev_prn_open_printer_seekable(gx_device *pdev, bool binary_mode,
883 bool seekable)
884 {
885 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
886
887 if (ppdev->file != 0) {
888 ppdev->file_is_new = false;
889 return 0;
890 }
891 {
892 int code = gx_device_open_output_file(pdev, ppdev->fname,
893 binary_mode, seekable,
894 &ppdev->file);
895 if (code < 0)
896 return code;
897 }
898 ppdev->file_is_new = true;
899 return 0;
900 }
901 int
gdev_prn_open_printer(gx_device * pdev,bool binary_mode)902 gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
903 {
904 return gdev_prn_open_printer_seekable(pdev, binary_mode, false);
905 }
906
907 /*
908 * Test whether the printer's output file was just opened, i.e., whether
909 * this is the first page being written to this file. This is only valid
910 * at the entry to a driver's print_page procedure.
911 */
912 bool
gdev_prn_file_is_new(const gx_device_printer * pdev)913 gdev_prn_file_is_new(const gx_device_printer *pdev)
914 {
915 return pdev->file_is_new;
916 }
917
918 /* Determine the colors used in a range of lines. */
919 int
gx_page_info_colors_used(const gx_device * dev,const gx_band_page_info_t * page_info,int y,int height,gx_colors_used_t * colors_used,int * range_start)920 gx_page_info_colors_used(const gx_device *dev,
921 const gx_band_page_info_t *page_info,
922 int y, int height,
923 gx_colors_used_t *colors_used, int *range_start)
924 {
925 int start, end, i;
926 int num_lines = page_info->scan_lines_per_colors_used;
927 gx_color_index or = 0;
928 bool slow_rop = false;
929
930 if (y < 0 || height < 0 || height > dev->height - y)
931 return -1;
932 start = y / num_lines;
933 end = (y + height + num_lines - 1) / num_lines;
934 for (i = start; i < end; ++i) {
935 or |= page_info->band_colors_used[i].or;
936 slow_rop |= page_info->band_colors_used[i].slow_rop;
937 }
938 colors_used->or = or;
939 colors_used->slow_rop = slow_rop;
940 *range_start = start * num_lines;
941 return min(end * num_lines, dev->height) - *range_start;
942 }
943 int
gdev_prn_colors_used(gx_device * dev,int y,int height,gx_colors_used_t * colors_used,int * range_start)944 gdev_prn_colors_used(gx_device *dev, int y, int height,
945 gx_colors_used_t *colors_used, int *range_start)
946 {
947 gx_device_clist_writer *cldev;
948
949 /* If this isn't a banded device, return default values. */
950 if (dev_proc(dev, get_bits_rectangle) !=
951 gs_clist_device_procs.get_bits_rectangle
952 ) {
953 *range_start = 0;
954 colors_used->or = ((gx_color_index)1 << dev->color_info.depth) - 1;
955 return dev->height;
956 }
957 cldev = (gx_device_clist_writer *)dev;
958 if (cldev->page_info.scan_lines_per_colors_used == 0) /* not set yet */
959 clist_compute_colors_used(cldev);
960 return
961 gx_page_info_colors_used(dev, &cldev->page_info,
962 y, height, colors_used, range_start);
963 }
964
965 /*
966 * Create the buffer device for a printer device. Clients should always
967 * call this, and never call the device procedure directly.
968 */
969 int
gdev_create_buf_device(create_buf_device_proc_t cbd_proc,gx_device ** pbdev,gx_device * target,const gx_render_plane_t * render_plane,gs_memory_t * mem,bool for_band)970 gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev,
971 gx_device *target,
972 const gx_render_plane_t *render_plane,
973 gs_memory_t *mem, bool for_band)
974 {
975 int code = cbd_proc(pbdev, target, render_plane, mem, for_band);
976
977 if (code < 0)
978 return code;
979 /* Retain this device -- it will be freed explicitly. */
980 gx_device_retain(*pbdev, true);
981 return code;
982 }
983
984 /*
985 * Create an ordinary memory device for page or band buffering,
986 * possibly preceded by a plane extraction device.
987 */
988 int
gx_default_create_buf_device(gx_device ** pbdev,gx_device * target,const gx_render_plane_t * render_plane,gs_memory_t * mem,bool for_band)989 gx_default_create_buf_device(gx_device **pbdev, gx_device *target,
990 const gx_render_plane_t *render_plane, gs_memory_t *mem, bool for_band)
991 {
992 int plane_index = (render_plane ? render_plane->index : -1);
993 int depth;
994 const gx_device_memory *mdproto;
995 gx_device_memory *mdev;
996 gx_device *bdev;
997
998 if (plane_index >= 0)
999 depth = render_plane->depth;
1000 else
1001 depth = target->color_info.depth;
1002 mdproto = gdev_mem_device_for_bits(depth);
1003 if (mdproto == 0)
1004 return_error(gs_error_rangecheck);
1005 if (mem) {
1006 mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
1007 "create_buf_device");
1008 if (mdev == 0)
1009 return_error(gs_error_VMerror);
1010 } else {
1011 mdev = (gx_device_memory *)*pbdev;
1012 }
1013 if (target == (gx_device *)mdev) {
1014 /* The following is a special hack for setting up printer devices. */
1015 assign_dev_procs(mdev, mdproto);
1016 check_device_separable((gx_device *)mdev);
1017 gx_device_fill_in_procs((gx_device *)mdev);
1018 } else
1019 gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0),
1020 (target == (gx_device *)mdev ? NULL : target));
1021 mdev->width = target->width;
1022 /*
1023 * The matrix in the memory device is irrelevant,
1024 * because all we do with the device is call the device-level
1025 * output procedures, but we may as well set it to
1026 * something halfway reasonable.
1027 */
1028 gs_deviceinitialmatrix(target, &mdev->initial_matrix);
1029 if (plane_index >= 0) {
1030 gx_device_plane_extract *edev =
1031 gs_alloc_struct(mem, gx_device_plane_extract,
1032 &st_device_plane_extract, "create_buf_device");
1033
1034 if (edev == 0) {
1035 gx_default_destroy_buf_device((gx_device *)mdev);
1036 return_error(gs_error_VMerror);
1037 }
1038 edev->memory = mem;
1039 plane_device_init(edev, target, (gx_device *)mdev, render_plane,
1040 false);
1041 bdev = (gx_device *)edev;
1042 } else
1043 bdev = (gx_device *)mdev;
1044 /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
1045 bdev->color_info = target->color_info;
1046 *pbdev = bdev;
1047 return 0;
1048 }
1049
1050 /* Determine the space needed by the buffer device. */
1051 int
gx_default_size_buf_device(gx_device_buf_space_t * space,gx_device * target,const gx_render_plane_t * render_plane,int height,bool for_band)1052 gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
1053 const gx_render_plane_t *render_plane,
1054 int height, bool for_band)
1055 {
1056 gx_device_memory mdev;
1057
1058 mdev.color_info.depth =
1059 (render_plane && render_plane->index >= 0 ? render_plane->depth :
1060 target->color_info.depth);
1061 mdev.width = target->width;
1062 mdev.num_planes = 0;
1063 space->bits = gdev_mem_bits_size(&mdev, target->width, height);
1064 space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
1065 space->raster = gdev_mem_raster(&mdev);
1066 return 0;
1067 }
1068
1069 /* Set up the buffer device. */
1070 int
gx_default_setup_buf_device(gx_device * bdev,byte * buffer,int bytes_per_line,byte ** line_ptrs,int y,int setup_height,int full_height)1071 gx_default_setup_buf_device(gx_device *bdev, byte *buffer, int bytes_per_line,
1072 byte **line_ptrs, int y, int setup_height,
1073 int full_height)
1074 {
1075 gx_device_memory *mdev =
1076 (gs_device_is_memory(bdev) ? (gx_device_memory *)bdev :
1077 (gx_device_memory *)(((gx_device_plane_extract *)bdev)->plane_dev));
1078 byte **ptrs = line_ptrs;
1079 int raster = bytes_per_line;
1080 int code;
1081
1082 /****** HACK ******/
1083 if ((gx_device *)mdev == bdev && mdev->num_planes)
1084 raster = bitmap_raster(mdev->planes[0].depth * mdev->width);
1085 if (ptrs == 0) {
1086 /*
1087 * Allocate line pointers now; free them when we close the device.
1088 * Note that for multi-planar devices, we have to allocate using
1089 * full_height rather than setup_height.
1090 */
1091 ptrs = (byte **)
1092 gs_alloc_byte_array(mdev->memory,
1093 (mdev->num_planes ?
1094 full_height * mdev->num_planes :
1095 setup_height),
1096 sizeof(byte *), "setup_buf_device");
1097 if (ptrs == 0)
1098 return_error(gs_error_VMerror);
1099 mdev->line_pointer_memory = mdev->memory;
1100 mdev->foreign_line_pointers = false;
1101 }
1102 mdev->height = full_height;
1103 code = gdev_mem_set_line_ptrs(mdev, buffer + raster * y, bytes_per_line,
1104 ptrs, setup_height);
1105 mdev->height = setup_height;
1106 bdev->height = setup_height; /* do here in case mdev == bdev */
1107 return code;
1108 }
1109
1110 /* Destroy the buffer device. */
1111 void
gx_default_destroy_buf_device(gx_device * bdev)1112 gx_default_destroy_buf_device(gx_device *bdev)
1113 {
1114 gx_device *mdev = bdev;
1115
1116 if (!gs_device_is_memory(bdev)) {
1117 /* bdev must be a plane extraction device. */
1118 mdev = ((gx_device_plane_extract *)bdev)->plane_dev;
1119 gs_free_object(bdev->memory, bdev, "destroy_buf_device");
1120 }
1121 dev_proc(mdev, close_device)(mdev);
1122 gs_free_object(mdev->memory, mdev, "destroy_buf_device");
1123 }
1124
1125 /*
1126 * Copy one or more rasterized scan lines to a buffer, or return a pointer
1127 * to them. See gdevprn.h for detailed specifications.
1128 */
1129 int
gdev_prn_get_lines(gx_device_printer * pdev,int y,int height,byte * buffer,uint bytes_per_line,byte ** actual_buffer,uint * actual_bytes_per_line,const gx_render_plane_t * render_plane)1130 gdev_prn_get_lines(gx_device_printer *pdev, int y, int height,
1131 byte *buffer, uint bytes_per_line,
1132 byte **actual_buffer, uint *actual_bytes_per_line,
1133 const gx_render_plane_t *render_plane)
1134 {
1135 int code;
1136 gs_int_rect rect;
1137 gs_get_bits_params_t params;
1138 int plane;
1139
1140 if (y < 0 || height < 0 || y + height > pdev->height)
1141 return_error(gs_error_rangecheck);
1142 rect.p.x = 0, rect.p.y = y;
1143 rect.q.x = pdev->width, rect.q.y = y + height;
1144 params.options =
1145 GB_RETURN_POINTER | GB_ALIGN_STANDARD | GB_OFFSET_0 |
1146 GB_RASTER_ANY |
1147 /* No depth specified, we always use native colors. */
1148 GB_COLORS_NATIVE | GB_ALPHA_NONE;
1149 if (render_plane) {
1150 params.options |= GB_PACKING_PLANAR | GB_SELECT_PLANES;
1151 memset(params.data, 0,
1152 sizeof(params.data[0]) * pdev->color_info.num_components);
1153 plane = render_plane->index;
1154 params.data[plane] = buffer;
1155 } else {
1156 params.options |= GB_PACKING_CHUNKY;
1157 params.data[0] = buffer;
1158 plane = 0;
1159 }
1160 params.x_offset = 0;
1161 params.raster = bytes_per_line;
1162 code = dev_proc(pdev, get_bits_rectangle)
1163 ((gx_device *)pdev, &rect, ¶ms, NULL);
1164 if (code < 0 && actual_buffer) {
1165 /*
1166 * RETURN_POINTER might not be implemented for this
1167 * combination of parameters: try RETURN_COPY.
1168 */
1169 params.options &= ~(GB_RETURN_POINTER | GB_RASTER_ALL);
1170 params.options |= GB_RETURN_COPY | GB_RASTER_SPECIFIED;
1171 code = dev_proc(pdev, get_bits_rectangle)
1172 ((gx_device *)pdev, &rect, ¶ms, NULL);
1173 }
1174 if (code < 0)
1175 return code;
1176 if (actual_buffer)
1177 *actual_buffer = params.data[plane];
1178 if (actual_bytes_per_line)
1179 *actual_bytes_per_line = params.raster;
1180 return code;
1181 }
1182
1183
1184 /* Copy a scan line from the buffer to the printer. */
1185 int
gdev_prn_get_bits(gx_device_printer * pdev,int y,byte * str,byte ** actual_data)1186 gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
1187 {
1188 int code = (*dev_proc(pdev, get_bits)) ((gx_device *) pdev, y, str, actual_data);
1189 uint line_size = gdev_prn_raster(pdev);
1190 int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
1191
1192 if (code < 0)
1193 return code;
1194 if (last_bits != 0) {
1195 byte *dest = (actual_data != 0 ? *actual_data : str);
1196
1197 dest[line_size - 1] &= 0xff << last_bits;
1198 }
1199 return 0;
1200 }
1201 /* Copy scan lines to a buffer. Return the number of scan lines, */
1202 /* or <0 if error. This procedure is DEPRECATED. */
1203 int
gdev_prn_copy_scan_lines(gx_device_printer * pdev,int y,byte * str,uint size)1204 gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size)
1205 {
1206 uint line_size = gdev_prn_raster(pdev);
1207 int count = size / line_size;
1208 int i;
1209 byte *dest = str;
1210
1211 count = min(count, pdev->height - y);
1212 for (i = 0; i < count; i++, dest += line_size) {
1213 int code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
1214
1215 if (code < 0)
1216 return code;
1217 }
1218 return count;
1219 }
1220
1221 /* Close the current page. */
1222 int
gdev_prn_close_printer(gx_device * pdev)1223 gdev_prn_close_printer(gx_device * pdev)
1224 {
1225 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1226 gs_parsed_file_name_t parsed;
1227 const char *fmt;
1228 int code = gx_parse_output_file_name(&parsed, &fmt, ppdev->fname,
1229 strlen(ppdev->fname));
1230
1231 if ((code >= 0 && fmt) /* file per page */ ||
1232 ppdev->ReopenPerPage /* close and reopen for each page */
1233 ) {
1234 gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
1235 ppdev->file = NULL;
1236 }
1237 return 0;
1238 }
1239
1240 /* If necessary, free and reallocate the printer memory after changing params */
1241 int
gdev_prn_maybe_realloc_memory(gx_device_printer * prdev,gdev_prn_space_params * old_sp,int old_width,int old_height,bool old_page_uses_transparency)1242 gdev_prn_maybe_realloc_memory(gx_device_printer *prdev,
1243 gdev_prn_space_params *old_sp,
1244 int old_width, int old_height,
1245 bool old_page_uses_transparency)
1246 {
1247 int code = 0;
1248 gx_device *const pdev = (gx_device *)prdev;
1249 /*gx_device_memory * const mdev = (gx_device_memory *)prdev;*/
1250
1251 /*
1252 * The first test was changed to mdev->base != 0 in 5.50 (per Artifex).
1253 * Not only was this test wrong logically, it was incorrect in that
1254 * casting pdev to a (gx_device_memory *) is only meaningful if banding
1255 * is not being used. The test was changed back to prdev->is_open in
1256 * 5.67 (also per Artifex). For more information, see the News items
1257 * for these filesets.
1258 */
1259 if (prdev->is_open &&
1260 (memcmp(&prdev->space_params, old_sp, sizeof(*old_sp)) != 0 ||
1261 prdev->width != old_width || prdev->height != old_height ||
1262 prdev->page_uses_transparency != old_page_uses_transparency)
1263 ) {
1264 int new_width = prdev->width;
1265 int new_height = prdev->height;
1266 gdev_prn_space_params new_sp;
1267
1268 #ifdef DEBUGGING_HACKS
1269 debug_dump_bytes((const byte *)old_sp, (const byte *)(old_sp + 1), "old");
1270 debug_dump_bytes((const byte *)&prdev->space_params,
1271 (const byte *)(&prdev->space_params + 1), "new");
1272 dprintf4("w=%d/%d, h=%d/%d\n", old_width, new_width, old_height, new_height);
1273 #endif /*DEBUGGING_HACKS*/
1274 new_sp = prdev->space_params;
1275 prdev->width = old_width;
1276 prdev->height = old_height;
1277 prdev->space_params = *old_sp;
1278 code = gdev_prn_reallocate_memory(pdev, &new_sp,
1279 new_width, new_height);
1280 /* If this fails, device should be usable w/old params, but */
1281 /* band files may not be open. */
1282 }
1283 return code;
1284 }
1285