]> git.ipfire.org Git - thirdparty/cups.git/blob - pstoraster/gdevprn.c
63718242a1d879b7b8fa7be6bdf13765fd7a8672
[thirdparty/cups.git] / pstoraster / gdevprn.c
1 /*
2 Copyright 1993-2001 by Easy Software Products.
3 Copyright 1990, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
4
5 This file is part of GNU Ghostscript.
6
7 GNU Ghostscript is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
9 to anyone for the consequences of using it or for whether it serves any
10 particular purpose or works at all, unless he says so in writing. Refer
11 to the GNU General Public License for full details.
12
13 Everyone is granted permission to copy, modify and redistribute GNU
14 Ghostscript, but only under the conditions described in the GNU General
15 Public License. A copy of this license is supposed to have been given
16 to you along with GNU Ghostscript so you can know your rights and
17 responsibilities. It should be in a file named COPYING. Among other
18 things, the copyright notice and this notice must be preserved on all
19 copies.
20
21 Aladdin Enterprises supports the work of the GNU Project, but is not
22 affiliated with the Free Software Foundation or the GNU Project. GNU
23 Ghostscript, as distributed by Aladdin Enterprises, does not require any
24 GNU software to build or run it.
25 */
26
27 /*$Id: gdevprn.c,v 1.13 2001/03/27 15:45:20 mike Exp $ */
28 /* Generic printer driver support */
29 #include "ctype_.h"
30 #include "gdevprn.h"
31 #include "gp.h"
32 #include "gsparam.h"
33 #include "gxclio.h"
34 #include <stdlib.h>
35
36 /* ---------------- Standard device procedures ---------------- */
37
38 /* Define the standard printer procedure vector. */
39 const gx_device_procs prn_std_procs =
40 prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close);
41
42 /* Forward references */
43 int gdev_prn_maybe_reallocate_memory(P4(gx_device_printer *pdev,
44 gdev_prn_space_params *old_space,
45 int old_width, int old_height));
46
47 /* ------ Open/close ------ */
48
49 /* Open a generic printer device. */
50 /* Specific devices may wish to extend this. */
51 int
52 gdev_prn_open(gx_device * pdev)
53 {
54 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
55 int code;
56
57 ppdev->file = NULL;
58 code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
59 if (code < 0)
60 return code;
61 if (ppdev->OpenOutputFile)
62 code = gdev_prn_open_printer(pdev, 1);
63 return code;
64 }
65
66 /* Generic closing for the printer device. */
67 /* Specific devices may wish to extend this. */
68 int
69 gdev_prn_close(gx_device * pdev)
70 {
71 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
72
73 gdev_prn_free_memory(pdev);
74 if (ppdev->file != NULL) {
75 if (ppdev->file != stdout)
76 gp_close_printer(ppdev->file, ppdev->fname);
77 ppdev->file = NULL;
78 }
79 return 0;
80 }
81
82 private int /* returns 0 ok, else -ve error cde */
83 gdev_prn_setup_as_command_list(gx_device *pdev, gs_memory_t *buffer_memory,
84 byte **the_memory,
85 const gdev_prn_space_params *space_params,
86 bool bufferSpace_is_exact)
87 {
88 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
89 uint space;
90 int code;
91 gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
92 gx_device_clist_common * const pcldev = &pclist_dev->common;
93 bool reallocate = *the_memory != 0;
94 byte *base;
95
96 /* Try to allocate based simply on param-requested buffer size */
97 for ( space = space_params->BufferSpace; ; ) {
98 base = (reallocate ?
99 gs_resize_object(buffer_memory, *the_memory, space,
100 "cmd list buffer") :
101 gs_alloc_bytes(buffer_memory, space,
102 "cmd list buffer"));
103 if (base != 0)
104 break;
105 if (bufferSpace_is_exact || (space >>= 1) < PRN_MIN_BUFFER_SPACE)
106 break;
107 }
108 if (base == 0)
109 return_error(gs_error_VMerror);
110 *the_memory = base;
111
112 /* Try opening the command list, to see if we allocated */
113 /* enough buffer space. */
114 open_c:
115 ppdev->buf = base;
116 ppdev->buffer_space = space;
117 clist_init_params(pclist_dev, base, space, pdev,
118 ppdev->printer_procs.make_buffer_device,
119 space_params->band, ppdev->is_async_renderer,
120 (ppdev->bandlist_memory == 0 ? &gs_memory_default :
121 ppdev->bandlist_memory),
122 ppdev->free_up_bandlist_memory,
123 ppdev->clist_disable_mask);
124 code = (*gs_clist_device_procs.open_device)( (gx_device *)pcldev );
125 if (code < 0) {
126 /* If there wasn't enough room, and we haven't */
127 /* already shrunk the buffer, try enlarging it. */
128 if ( code == gs_error_limitcheck &&
129 space >= space_params->BufferSpace &&
130 !bufferSpace_is_exact
131 ) {
132 space <<= 1;
133 if (reallocate) {
134 base = gs_resize_object(buffer_memory,
135 *the_memory, space,
136 "cmd list buf(retry open)");
137 if (base != 0)
138 *the_memory = base;
139 } else {
140 gs_free_object(buffer_memory, base,
141 "cmd list buf(retry open)");
142 *the_memory = base =
143 gs_alloc_bytes(buffer_memory, space,
144 "cmd list buf(retry open)");
145 }
146 ppdev->buf = *the_memory;
147 if (base != 0)
148 goto open_c;
149 }
150 /* Failure. */
151 if (!reallocate) {
152 gs_free_object(buffer_memory, base, "cmd list buf");
153 ppdev->buffer_space = 0;
154 *the_memory = 0;
155 }
156 }
157 return code;
158 }
159
160 private bool /* ret true if device was cmd list, else false */
161 gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
162 {
163 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
164 gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
165 gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
166 gx_device_clist_common * const pcldev = &pclist_dev->common;
167 bool is_command_list;
168
169 if (ppdev->buffer_space != 0) {
170 /* Close cmd list device & point to the storage */
171 (*gs_clist_device_procs.close_device)( (gx_device *)pcldev );
172 *the_memory = ppdev->buf;
173 ppdev->buf = 0;
174 ppdev->buffer_space = 0;
175 is_command_list = true;
176 } else {
177 /* point at the device bitmap, no need to close mem dev */
178 *the_memory = pmemdev->base;
179 pmemdev->base = 0;
180 is_command_list = false;
181 }
182
183 /* Reset device proc vector to default */
184 if (ppdev->orig_procs.open_device != 0)
185 pdev->procs = ppdev->orig_procs;
186 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
187
188 return is_command_list;
189 }
190
191 private int
192 gdev_prn_allocate(gx_device *pdev, gdev_prn_space_params *new_space_params,
193 int new_width, int new_height, bool reallocate)
194 {
195 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
196 gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
197 byte *the_memory = 0;
198 gdev_prn_space_params save_params;
199 int save_width, save_height;
200 bool is_command_list = false;
201 bool save_is_command_list;
202 int ecode = 0;
203 int pass;
204 gs_memory_t *buffer_memory =
205 (ppdev->buffer_memory == 0 ? &gs_memory_default :
206 ppdev->buffer_memory);
207
208 /* If reallocate, find allocated memory & tear down buffer device */
209 if (reallocate)
210 save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
211
212 /* Re/allocate memory */
213 ppdev->orig_procs = pdev->procs;
214 for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
215 ulong mem_space;
216 byte *base = 0;
217 bool bufferSpace_is_default = false;
218 gdev_prn_space_params space_params;
219
220 if (reallocate)
221 switch (pass)
222 {
223 case 1:
224 /* Setup device to get reallocated */
225 save_params = ppdev->space_params;
226 ppdev->space_params = *new_space_params;
227 save_width = ppdev->width;
228 ppdev->width = new_width;
229 save_height = ppdev->height;
230 ppdev->height = new_height;
231 break;
232 case 2: /* only comes here if reallocate */
233 /* Restore device to previous contents */
234 ppdev->space_params = save_params;
235 ppdev->width = save_width;
236 ppdev->height = save_height;
237 break;
238 }
239
240 /* Init clist/mem device-specific fields */
241 memset(ppdev->skip, 0, sizeof(ppdev->skip));
242 mem_space = gdev_mem_bitmap_size(pmemdev);
243
244 /* Compute desired space params: never use the space_params as-is. */
245 /* Rather, give the dev-specific driver a chance to adjust them. */
246 space_params = ppdev->space_params;
247 space_params.BufferSpace = 0;
248 (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
249 if (ppdev->is_async_renderer && space_params.band.BandBufferSpace != 0)
250 space_params.BufferSpace = space_params.band.BandBufferSpace;
251 else if (space_params.BufferSpace == 0) {
252 if (space_params.band.BandBufferSpace > 0)
253 space_params.BufferSpace = space_params.band.BandBufferSpace;
254 else {
255 space_params.BufferSpace = ppdev->space_params.BufferSpace;
256 bufferSpace_is_default = true;
257 }
258 }
259
260 /* Determine if we can use a full bitmap buffer, or have to use banding */
261 if (pass > 1)
262 is_command_list = save_is_command_list;
263 else {
264 is_command_list = space_params.banding_type == BandingAlways ||
265 mem_space >= space_params.MaxBitmap ||
266 mem_space != (uint)mem_space; /* too big to allocate */
267 }
268 if (!is_command_list) {
269 /* Try to allocate memory for full memory buffer */
270 base = reallocate
271 ? gs_resize_object( buffer_memory, the_memory,
272 (uint)mem_space, "printer buffer" )
273 : gs_alloc_bytes( buffer_memory, (uint)mem_space,
274 "printer_buffer" );
275 if (base == 0)
276 is_command_list = true;
277 else
278 the_memory = base;
279 }
280 if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
281 && buffer_memory == &gs_memory_default) {
282 /* before using full memory buffer, ensure enough working mem left */
283 byte * left = gs_alloc_bytes( buffer_memory,
284 PRN_MIN_MEMORY_LEFT, "printer mem left");
285 if (left == 0)
286 is_command_list = true;
287 else
288 gs_free_object(buffer_memory, left, "printer mem left");
289 }
290
291 if (is_command_list) {
292 /* Buffer the image in a command list. */
293 /* Release the buffer if we allocated it. */
294 int code;
295 if (!reallocate) {
296 gs_free_object(buffer_memory, the_memory,
297 "printer buffer(open)");
298 the_memory = 0;
299 }
300 if (space_params.banding_type == BandingNever) {
301 ecode = gs_note_error(gs_error_VMerror);
302 continue;
303 }
304 code = gdev_prn_setup_as_command_list(pdev, buffer_memory,
305 &the_memory, &space_params,
306 !bufferSpace_is_default);
307 if (ecode == 0)
308 ecode = code;
309
310 if ( code >= 0 || (reallocate && pass > 1) )
311 ppdev->procs = gs_clist_device_procs;
312 } else {
313 /* Render entirely in memory. */
314 int code;
315
316 ppdev->buffer_space = 0;
317 code = (*ppdev->printer_procs.make_buffer_device)
318 (pmemdev, pdev, buffer_memory, false);
319 if (code < 0) { /* Catastrophic. Shouldn't ever happen */
320 gs_free_object(buffer_memory, base, "printer buffer");
321 pdev->procs = ppdev->orig_procs;
322 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
323 return_error(code);
324 }
325 pmemdev->base = base;
326 }
327 if (ecode == 0)
328 break;
329 }
330
331 if (ecode >= 0 || reallocate) { /* even if realloc failed */
332 /* Synthesize the procedure vector. */
333 /* Rendering operations come from the memory or clist device, */
334 /* non-rendering come from the printer device. */
335 #define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
336 COPY_PROC(get_initial_matrix);
337 COPY_PROC(output_page);
338 COPY_PROC(close_device);
339 COPY_PROC(map_rgb_color);
340 COPY_PROC(map_color_rgb);
341 COPY_PROC(get_params);
342 COPY_PROC(put_params);
343 COPY_PROC(map_cmyk_color);
344 COPY_PROC(get_xfont_procs);
345 COPY_PROC(get_xfont_device);
346 COPY_PROC(map_rgb_alpha_color);
347 /* All printers are page devices, even if they didn't use the */
348 /* standard macros for generating their procedure vectors. */
349 set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
350 COPY_PROC(get_alpha_bits);
351 COPY_PROC(get_clipping_box);
352 COPY_PROC(map_color_rgb_alpha);
353 COPY_PROC(get_hardware_params);
354 #undef COPY_PROC
355 /* If using a command list, already opened the device. */
356 if (is_command_list)
357 return ecode;
358 else
359 return (*dev_proc(pdev, open_device))(pdev);
360 } else {
361 pdev->procs = ppdev->orig_procs;
362 ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
363 return ecode;
364 }
365 }
366
367 int
368 gdev_prn_allocate_memory(gx_device *pdev,
369 gdev_prn_space_params *new_space_params,
370 int new_width, int new_height)
371 {
372 return gdev_prn_allocate(pdev, new_space_params,
373 new_width, new_height, false);
374 }
375
376 int
377 gdev_prn_reallocate_memory(gx_device *pdev,
378 gdev_prn_space_params *new_space_params,
379 int new_width, int new_height)
380 {
381 return gdev_prn_allocate(pdev, new_space_params,
382 new_width, new_height, true);
383 }
384
385 int
386 gdev_prn_free_memory(gx_device *pdev)
387 {
388 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
389 byte *the_memory = 0;
390 gs_memory_t *buffer_memory =
391 (ppdev->buffer_memory == 0 ? &gs_memory_default :
392 ppdev->buffer_memory);
393
394 gdev_prn_tear_down(pdev, &the_memory);
395 gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory");
396 return 0;
397 }
398
399 /* ------------- Stubs related only to async rendering ------- */
400
401 int /* rets 0 ok, -ve error if couldn't start thread */
402 gx_default_start_render_thread(gdev_prn_start_render_params *params)
403 {
404 return gs_error_unknownerror;
405 }
406
407 /* Open the renderer's copy of a device. */
408 /* This is overriden in gdevprna.c */
409 int
410 gx_default_open_render_device(gx_device_printer *pdev)
411 {
412 return gs_error_unknownerror;
413 }
414
415 /* Close the renderer's copy of a device. */
416 int
417 gx_default_close_render_device(gx_device_printer *pdev)
418 {
419 return gdev_prn_close( (gx_device *)pdev );
420 }
421
422 /* ------ Get/put parameters ------ */
423
424 /* Get parameters. Printer devices add several more parameters */
425 /* to the default set. */
426 int
427 gdev_prn_get_params(gx_device * pdev, gs_param_list * plist)
428 {
429 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
430 int code = gx_default_get_params(pdev, plist);
431
432 if (code < 0 ||
433 (ppdev->Duplex_set >= 0 &&
434 (code = (ppdev->Duplex_set ?
435 param_write_bool(plist, "Duplex", &ppdev->Duplex) :
436 param_write_null(plist, "Duplex"))) < 0)
437 )
438 return code;
439
440 return 0;
441 }
442
443 /* Put parameters. */
444 int
445 gdev_prn_put_params(gx_device * pdev, gs_param_list * plist)
446 {
447 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
448 int ecode = 0;
449 int code;
450 const char *param_name;
451 bool is_open = pdev->is_open;
452 bool oof = ppdev->OpenOutputFile;
453 bool rpp = ppdev->ReopenPerPage;
454 bool duplex;
455 int duplex_set = -1;
456 int width = pdev->width;
457 int height = pdev->height;
458 gdev_prn_space_params sp, save_sp;
459 gs_param_dict mdict;
460
461 sp = ppdev->space_params;
462 save_sp = sp;
463
464 switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) {
465 default:
466 ecode = code;
467 param_signal_error(plist, param_name, ecode);
468 case 0:
469 case 1:
470 break;
471 }
472
473 switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) {
474 default:
475 ecode = code;
476 param_signal_error(plist, param_name, ecode);
477 case 0:
478 case 1:
479 break;
480 }
481
482 if (ppdev->Duplex_set >= 0) /* i.e., Duplex is supported */
483 switch (code = param_read_bool(plist, (param_name = "Duplex"),
484 &duplex)) {
485 case 0:
486 duplex_set = 1;
487 break;
488 default:
489 if ((code = param_read_null(plist, param_name)) == 0) {
490 duplex_set = 0;
491 break;
492 }
493 ecode = code;
494 param_signal_error(plist, param_name, ecode);
495 case 1:
496 ;
497 }
498 #define CHECK_PARAM_CASES(member, bad, label)\
499 case 0:\
500 if ((sp.params_are_read_only ? sp.member != save_sp.member : bad))\
501 ecode = gs_error_rangecheck;\
502 else\
503 break;\
504 goto label;\
505 default:\
506 ecode = code;\
507 label:\
508 param_signal_error(plist, param_name, ecode);\
509 case 1:\
510 break
511
512 /* Read InputAttributes and OutputAttributes just for the type */
513 /* check and to indicate that they aren't undefined. */
514 #define read_media(pname)\
515 switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
516 {\
517 case 0:\
518 param_end_read_dict(plist, pname, &mdict);\
519 break;\
520 default:\
521 ecode = code;\
522 param_signal_error(plist, param_name, ecode);\
523 case 1:\
524 ;\
525 }
526
527 read_media("InputAttributes");
528 read_media("OutputAttributes");
529
530 if (ecode < 0)
531 return ecode;
532 /* Prevent gx_default_put_params from closing the printer. */
533 pdev->is_open = false;
534 code = gx_default_put_params(pdev, plist);
535 pdev->is_open = is_open;
536 if (code < 0)
537 return code;
538
539 ppdev->OpenOutputFile = oof;
540 ppdev->ReopenPerPage = rpp;
541 if (duplex_set >= 0) {
542 ppdev->Duplex = duplex;
543 ppdev->Duplex_set = duplex_set;
544 }
545 ppdev->space_params = sp;
546
547 /* If necessary, free and reallocate the printer memory. */
548 /* Formerly, would not reallocate if device is not open: */
549 /* we had to patch this out (see News for 5.50). */
550 code = gdev_prn_maybe_reallocate_memory(ppdev, &save_sp, width, height);
551 if (code < 0)
552 return code;
553
554 return 0;
555 }
556
557 /* ------ Others ------ */
558
559 #define TILE_SIZE 256
560
561 /* Default routine to override current space_params. */
562 void
563 gdev_prn_default_get_space_params(const gx_device_printer *printer_dev,
564 gdev_prn_space_params *space_params)
565 {
566 int cache_size; /* Size of tile cache in bytes */
567 char *cache_env, /* Cache size environment variable */
568 cache_units[255]; /* Cache size units */
569
570
571 if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
572 {
573 switch (sscanf(cache_env, "%d%254s", &cache_size, cache_units))
574 {
575 case 0 :
576 cache_size = 8 * 1024 * 1024;
577 break;
578 case 1 :
579 cache_size *= 4 * TILE_SIZE * TILE_SIZE;
580 break;
581 case 2 :
582 if (tolower(cache_units[0]) == 'g')
583 cache_size *= 1024 * 1024 * 1024;
584 else if (tolower(cache_units[0]) == 'm')
585 cache_size *= 1024 * 1024;
586 else if (tolower(cache_units[0]) == 'k')
587 cache_size *= 1024;
588 else if (tolower(cache_units[0]) == 't')
589 cache_size *= 4 * TILE_SIZE * TILE_SIZE;
590 break;
591 }
592 }
593 else
594 cache_size = 8 * 1024 * 1024;
595
596 space_params->MaxBitmap = cache_size;
597 space_params->BufferSpace = cache_size / 10;
598 }
599
600 /* Generic routine to send the page to the printer. */
601 int /* 0 ok, -ve error, or 1 if successfully upgraded to buffer_page */
602 gdev_prn_output_page(gx_device * pdev, int num_copies, int flush)
603 {
604 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
605 int outcode = 0, closecode = 0, errcode = 0, endcode;
606 bool upgraded_copypage = false;
607
608 if (num_copies > 0 || !flush) {
609 int code = gdev_prn_open_printer(pdev, 1);
610
611 if (code < 0)
612 return code;
613
614 /* If copypage request, try to do it using buffer_page */
615 if ( !flush &&
616 (*ppdev->printer_procs.buffer_page)
617 (ppdev, ppdev->file, num_copies) >= 0
618 ) {
619 upgraded_copypage = true;
620 flush = true;
621 }
622 else if (num_copies > 0)
623 /* Print the accumulated page description. */
624 outcode =
625 (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
626 num_copies);
627 if (ppdev->file)
628 {
629 fflush(ppdev->file);
630 errcode =
631 (ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
632 }
633 else
634 errcode = 0;
635
636 if (!upgraded_copypage)
637 closecode = gdev_prn_close_printer(pdev);
638 }
639 endcode = (ppdev->buffer_space ? clist_finish_page(pdev, flush) : 0);
640
641 if (outcode < 0)
642 return outcode;
643 if (errcode < 0)
644 return errcode;
645 if (closecode < 0)
646 return closecode;
647 if (endcode < 0)
648 return endcode;
649 return (upgraded_copypage ? 1 : 0);
650 }
651
652 /* Print multiple copies of a page by calling print_page multiple times. */
653 int
654 gx_default_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
655 int num_copies)
656 {
657 int i = num_copies;
658 int code = 0;
659
660 while (code >= 0 && i-- > 0)
661 code = (*pdev->printer_procs.print_page) (pdev, prn_stream);
662 return code;
663 }
664
665 /*
666 * Buffer a (partial) rasterized page & optionally print result multiple times.
667 * The default implementation returns error, since the driver needs to override
668 * this (in procedure vector) in configurations where this call may occur.
669 */
670 int
671 gx_default_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
672 int num_copies)
673 {
674 return gs_error_unknownerror;
675 }
676
677 /* ---------------- Driver services ---------------- */
678
679 /* Return the number of scan lines that should actually be passed */
680 /* to the device. */
681 int
682 gdev_prn_print_scan_lines(gx_device * pdev)
683 {
684 int height = pdev->height;
685 gs_matrix imat;
686 float yscale;
687 int top, bottom, offset, end;
688
689 (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
690 yscale = imat.yy * 72.0; /* Y dpi, may be negative */
691 top = (int)(dev_t_margin(pdev) * yscale);
692 bottom = (int)(dev_b_margin(pdev) * yscale);
693 offset = (int)(dev_y_offset(pdev) * yscale);
694 if (yscale < 0) { /* Y=0 is top of page */
695 end = -offset + height + bottom;
696 } else { /* Y=0 is bottom of page */
697 end = offset + height - top;
698 }
699 return min(height, end);
700 }
701
702 /* Open the current page for printing. */
703 int
704 gdev_prn_open_printer_positionable(gx_device *pdev, bool binary_mode,
705 bool positionable)
706 {
707 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
708
709 if (ppdev->file != 0) {
710 ppdev->file_is_new = false;
711 return 0;
712 }
713 {
714 int code = gx_device_open_output_file(pdev, ppdev->fname,
715 binary_mode, positionable,
716 &ppdev->file);
717 if (code < 0)
718 return code;
719 }
720 ppdev->file_is_new = true;
721 return 0;
722 }
723 int
724 gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
725 {
726 return gdev_prn_open_printer_positionable(pdev, binary_mode, false);
727 }
728
729 /* Copy a scan line from the buffer to the printer. */
730 int
731 gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
732 {
733 int code = (*dev_proc(pdev, get_bits)) ((gx_device *) pdev, y, str, actual_data);
734 uint line_size = gdev_prn_raster(pdev);
735 int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
736
737 if (code < 0)
738 return code;
739 if (last_bits != 0) {
740 byte *dest = (actual_data != 0 ? *actual_data : str);
741
742 dest[line_size - 1] &= 0xff << last_bits;
743 }
744 return 0;
745 }
746 /* Copy scan lines to a buffer. Return the number of scan lines, */
747 /* or <0 if error. */
748 int
749 gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size)
750 {
751 uint line_size = gdev_prn_raster(pdev);
752 int count = size / line_size;
753 int i;
754 byte *dest = str;
755
756 count = min(count, pdev->height - y);
757 for (i = 0; i < count; i++, dest += line_size) {
758 int code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
759
760 if (code < 0)
761 return code;
762 }
763 return count;
764 }
765
766 /* Like get_bits, but accepts initial raster contents */
767 int
768 gdev_prn_get_overlay_bits(gx_device_printer *pdev, int y, int lineCount,
769 byte *data)
770 {
771 if (pdev->buffer_space) {
772 /* Command lists have built-in support for this function */
773 return clist_get_overlay_bits(pdev, y, lineCount, data);
774 } else {
775 /* Memory devices cannot support this function. */
776 return_error(gs_error_unknownerror);
777 }
778 }
779
780 /* Find out where the band buffer for a given line is going to fall on the */
781 /* next call to get_bits. */
782 int /* rets # lines from y till end of buffer, or -ve error code */
783 gdev_prn_locate_overlay_buffer(gx_device_printer *pdev, int y, byte **data)
784 {
785 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
786
787 if (ppdev->buffer_space) {
788 /* Command lists have built-in support for this function */
789 return clist_locate_overlay_buffer(pdev, y, data);
790 } else {
791 /* Memory devices cannot support this function. */
792 return_error(gs_error_unknownerror);
793 }
794 }
795
796 /* Close the current page. */
797 int
798 gdev_prn_close_printer(gx_device * pdev)
799 {
800 gx_device_printer * const ppdev = (gx_device_printer *)pdev;
801
802 if (strchr(ppdev->fname, '%') /* file per page */ ||
803 ppdev->ReopenPerPage /* close and reopen for each page */
804 ) {
805 gp_close_printer(ppdev->file, ppdev->fname);
806 ppdev->file = NULL;
807 }
808 return 0;
809 }
810
811 /* If necessary, free and reallocate the printer memory after changing params */
812 int
813 gdev_prn_maybe_reallocate_memory(gx_device_printer *prdev,
814 gdev_prn_space_params *old_sp,
815 int old_width, int old_height)
816 {
817 int code = 0;
818 gx_device *const pdev = (gx_device *)prdev;
819
820 if (prdev->is_open &&
821 (memcmp(&prdev->space_params, old_sp, sizeof(*old_sp)) != 0 ||
822 prdev->width != old_width || prdev->height != old_height )
823 ) {
824 int new_width = prdev->width;
825 int new_height = prdev->height;
826 gdev_prn_space_params new_sp = prdev->space_params;
827
828 prdev->width = old_width;
829 prdev->height = old_height;
830 prdev->space_params = *old_sp;
831 code = gdev_prn_reallocate_memory(pdev, &new_sp,
832 new_width, new_height);
833 /* If this fails, device should be usable w/old params, but */
834 /* band files may not be open. */
835 }
836 return code;
837 }