xref: /plan9/sys/src/cmd/gs/src/gdevprn.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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, &params, 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, &params, 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