Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/gs/src/gdevprn.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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 */
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 */
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
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
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
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
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 */
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
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
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
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
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
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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}