13ff48bf5SDavid du Colombier /* Copyright (C) 1990, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gdevprn.c,v 1.20 2005/05/27 05:43:24 dan Exp $ */
187dd7cddfSDavid du Colombier /* Generic printer driver support */
197dd7cddfSDavid du Colombier #include "ctype_.h"
207dd7cddfSDavid du Colombier #include "gdevprn.h"
217dd7cddfSDavid du Colombier #include "gp.h"
227dd7cddfSDavid du Colombier #include "gsdevice.h" /* for gs_deviceinitialmatrix */
237dd7cddfSDavid du Colombier #include "gsfname.h"
247dd7cddfSDavid du Colombier #include "gsparam.h"
257dd7cddfSDavid du Colombier #include "gxclio.h"
267dd7cddfSDavid du Colombier #include "gxgetbit.h"
277dd7cddfSDavid du Colombier #include "gdevplnx.h"
28*593dc095SDavid du Colombier #include "gstrans.h"
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier /*#define DEBUGGING_HACKS*/
317dd7cddfSDavid du Colombier
327dd7cddfSDavid du Colombier /* GC information */
337dd7cddfSDavid du Colombier #define PRINTER_IS_CLIST(pdev) ((pdev)->buffer_space != 0)
347dd7cddfSDavid du Colombier private
357dd7cddfSDavid du Colombier ENUM_PTRS_WITH(device_printer_enum_ptrs, gx_device_printer *pdev)
367dd7cddfSDavid du Colombier if (PRINTER_IS_CLIST(pdev))
377dd7cddfSDavid du Colombier ENUM_PREFIX(st_device_clist, 0);
387dd7cddfSDavid du Colombier else
397dd7cddfSDavid du Colombier ENUM_PREFIX(st_device_forward, 0);
407dd7cddfSDavid du Colombier ENUM_PTRS_END
417dd7cddfSDavid du Colombier private
RELOC_PTRS_WITH(device_printer_reloc_ptrs,gx_device_printer * pdev)427dd7cddfSDavid du Colombier RELOC_PTRS_WITH(device_printer_reloc_ptrs, gx_device_printer *pdev)
437dd7cddfSDavid du Colombier {
447dd7cddfSDavid du Colombier if (PRINTER_IS_CLIST(pdev))
457dd7cddfSDavid du Colombier RELOC_PREFIX(st_device_clist);
467dd7cddfSDavid du Colombier else
477dd7cddfSDavid du Colombier RELOC_PREFIX(st_device_forward);
487dd7cddfSDavid du Colombier } RELOC_PTRS_END
497dd7cddfSDavid du Colombier public_st_device_printer();
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier /* ---------------- Standard device procedures ---------------- */
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier /* Define the standard printer procedure vector. */
547dd7cddfSDavid du Colombier const gx_device_procs prn_std_procs =
557dd7cddfSDavid du Colombier prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close);
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier /* Forward references */
58*593dc095SDavid du Colombier int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
597dd7cddfSDavid du Colombier gdev_prn_space_params *old_space,
60*593dc095SDavid du Colombier int old_width, int old_height,
61*593dc095SDavid du Colombier bool old_page_uses_transparency);
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier /* ------ Open/close ------ */
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier /* Open a generic printer device. */
667dd7cddfSDavid du Colombier /* Specific devices may wish to extend this. */
677dd7cddfSDavid du Colombier int
gdev_prn_open(gx_device * pdev)687dd7cddfSDavid du Colombier gdev_prn_open(gx_device * pdev)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
717dd7cddfSDavid du Colombier int code;
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier ppdev->file = NULL;
747dd7cddfSDavid du Colombier code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
757dd7cddfSDavid du Colombier if (code < 0)
767dd7cddfSDavid du Colombier return code;
777dd7cddfSDavid du Colombier if (ppdev->OpenOutputFile)
787dd7cddfSDavid du Colombier code = gdev_prn_open_printer(pdev, 1);
797dd7cddfSDavid du Colombier return code;
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier
827dd7cddfSDavid du Colombier /* Generic closing for the printer device. */
837dd7cddfSDavid du Colombier /* Specific devices may wish to extend this. */
847dd7cddfSDavid du Colombier int
gdev_prn_close(gx_device * pdev)857dd7cddfSDavid du Colombier gdev_prn_close(gx_device * pdev)
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
887dd7cddfSDavid du Colombier int code = 0;
897dd7cddfSDavid du Colombier
907dd7cddfSDavid du Colombier gdev_prn_free_memory(pdev);
917dd7cddfSDavid du Colombier if (ppdev->file != NULL) {
927dd7cddfSDavid du Colombier code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
937dd7cddfSDavid du Colombier ppdev->file = NULL;
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier return code;
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier 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)997dd7cddfSDavid du Colombier gdev_prn_setup_as_command_list(gx_device *pdev, gs_memory_t *buffer_memory,
1007dd7cddfSDavid du Colombier byte **the_memory,
1017dd7cddfSDavid du Colombier const gdev_prn_space_params *space_params,
1027dd7cddfSDavid du Colombier bool bufferSpace_is_exact)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1057dd7cddfSDavid du Colombier uint space;
1067dd7cddfSDavid du Colombier int code;
1077dd7cddfSDavid du Colombier gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
1087dd7cddfSDavid du Colombier gx_device_clist_common * const pcldev = &pclist_dev->common;
1097dd7cddfSDavid du Colombier bool reallocate = *the_memory != 0;
1107dd7cddfSDavid du Colombier byte *base;
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier /* Try to allocate based simply on param-requested buffer size */
1137dd7cddfSDavid du Colombier #ifdef DEBUGGING_HACKS
1147dd7cddfSDavid du Colombier #define BACKTRACE(first_arg)\
1157dd7cddfSDavid du Colombier BEGIN\
1167dd7cddfSDavid du Colombier ulong *fp_ = (ulong *)&first_arg - 2;\
1177dd7cddfSDavid du Colombier for (; fp_ && (fp_[1] & 0xff000000) == 0x08000000; fp_ = (ulong *)*fp_)\
1187dd7cddfSDavid du Colombier dprintf2(" fp=0x%lx ip=0x%lx\n", (ulong)fp_, fp_[1]);\
1197dd7cddfSDavid du Colombier END
1207dd7cddfSDavid du Colombier dputs("alloc buffer:\n");
1217dd7cddfSDavid du Colombier BACKTRACE(pdev);
1227dd7cddfSDavid du Colombier #endif /*DEBUGGING_HACKS*/
1237dd7cddfSDavid du Colombier for ( space = space_params->BufferSpace; ; ) {
1247dd7cddfSDavid du Colombier base = (reallocate ?
1257dd7cddfSDavid du Colombier (byte *)gs_resize_object(buffer_memory, *the_memory, space,
1267dd7cddfSDavid du Colombier "cmd list buffer") :
1277dd7cddfSDavid du Colombier gs_alloc_bytes(buffer_memory, space,
1287dd7cddfSDavid du Colombier "cmd list buffer"));
1297dd7cddfSDavid du Colombier if (base != 0)
1307dd7cddfSDavid du Colombier break;
1317dd7cddfSDavid du Colombier if (bufferSpace_is_exact || (space >>= 1) < PRN_MIN_BUFFER_SPACE)
1327dd7cddfSDavid du Colombier break;
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier if (base == 0)
1357dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
1367dd7cddfSDavid du Colombier *the_memory = base;
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier /* Try opening the command list, to see if we allocated */
1397dd7cddfSDavid du Colombier /* enough buffer space. */
1407dd7cddfSDavid du Colombier open_c:
1417dd7cddfSDavid du Colombier ppdev->buf = base;
1427dd7cddfSDavid du Colombier ppdev->buffer_space = space;
1437dd7cddfSDavid du Colombier clist_init_params(pclist_dev, base, space, pdev,
1447dd7cddfSDavid du Colombier ppdev->printer_procs.buf_procs,
1457dd7cddfSDavid du Colombier space_params->band, ppdev->is_async_renderer,
146*593dc095SDavid du Colombier (ppdev->bandlist_memory == 0 ? pdev->memory->non_gc_memory:
1477dd7cddfSDavid du Colombier ppdev->bandlist_memory),
1487dd7cddfSDavid du Colombier ppdev->free_up_bandlist_memory,
149*593dc095SDavid du Colombier ppdev->clist_disable_mask,
150*593dc095SDavid du Colombier ppdev->page_uses_transparency);
1517dd7cddfSDavid du Colombier code = (*gs_clist_device_procs.open_device)( (gx_device *)pcldev );
1527dd7cddfSDavid du Colombier if (code < 0) {
1537dd7cddfSDavid du Colombier /* If there wasn't enough room, and we haven't */
1547dd7cddfSDavid du Colombier /* already shrunk the buffer, try enlarging it. */
1557dd7cddfSDavid du Colombier if ( code == gs_error_limitcheck &&
1567dd7cddfSDavid du Colombier space >= space_params->BufferSpace &&
1577dd7cddfSDavid du Colombier !bufferSpace_is_exact
1587dd7cddfSDavid du Colombier ) {
1597dd7cddfSDavid du Colombier space <<= 1;
1607dd7cddfSDavid du Colombier if (reallocate) {
1617dd7cddfSDavid du Colombier base = gs_resize_object(buffer_memory,
1627dd7cddfSDavid du Colombier *the_memory, space,
1637dd7cddfSDavid du Colombier "cmd list buf(retry open)");
1647dd7cddfSDavid du Colombier if (base != 0)
1657dd7cddfSDavid du Colombier *the_memory = base;
1667dd7cddfSDavid du Colombier } else {
1677dd7cddfSDavid du Colombier gs_free_object(buffer_memory, base,
1687dd7cddfSDavid du Colombier "cmd list buf(retry open)");
1697dd7cddfSDavid du Colombier *the_memory = base =
1707dd7cddfSDavid du Colombier gs_alloc_bytes(buffer_memory, space,
1717dd7cddfSDavid du Colombier "cmd list buf(retry open)");
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier ppdev->buf = *the_memory;
1747dd7cddfSDavid du Colombier if (base != 0)
1757dd7cddfSDavid du Colombier goto open_c;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier /* Failure. */
1787dd7cddfSDavid du Colombier if (!reallocate) {
1797dd7cddfSDavid du Colombier gs_free_object(buffer_memory, base, "cmd list buf");
1807dd7cddfSDavid du Colombier ppdev->buffer_space = 0;
1817dd7cddfSDavid du Colombier *the_memory = 0;
1827dd7cddfSDavid du Colombier }
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier return code;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier
1877dd7cddfSDavid du Colombier private bool /* ret true if device was cmd list, else false */
gdev_prn_tear_down(gx_device * pdev,byte ** the_memory)1887dd7cddfSDavid du Colombier gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
1897dd7cddfSDavid du Colombier {
1907dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1917dd7cddfSDavid du Colombier gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
1927dd7cddfSDavid du Colombier gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
1937dd7cddfSDavid du Colombier gx_device_clist_common * const pcldev = &pclist_dev->common;
1947dd7cddfSDavid du Colombier bool is_command_list;
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier if (ppdev->buffer_space != 0) {
1977dd7cddfSDavid du Colombier /* Close cmd list device & point to the storage */
1987dd7cddfSDavid du Colombier (*gs_clist_device_procs.close_device)( (gx_device *)pcldev );
1997dd7cddfSDavid du Colombier *the_memory = ppdev->buf;
2007dd7cddfSDavid du Colombier ppdev->buf = 0;
2017dd7cddfSDavid du Colombier ppdev->buffer_space = 0;
2027dd7cddfSDavid du Colombier is_command_list = true;
2037dd7cddfSDavid du Colombier } else {
2047dd7cddfSDavid du Colombier /* point at the device bitmap, no need to close mem dev */
2057dd7cddfSDavid du Colombier *the_memory = pmemdev->base;
2067dd7cddfSDavid du Colombier pmemdev->base = 0;
2077dd7cddfSDavid du Colombier is_command_list = false;
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier
2107dd7cddfSDavid du Colombier /* Reset device proc vector to default */
2117dd7cddfSDavid du Colombier if (ppdev->orig_procs.open_device != 0)
2127dd7cddfSDavid du Colombier pdev->procs = ppdev->orig_procs;
2137dd7cddfSDavid du Colombier ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier return is_command_list;
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier private int
gdev_prn_allocate(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height,bool reallocate)2197dd7cddfSDavid du Colombier gdev_prn_allocate(gx_device *pdev, gdev_prn_space_params *new_space_params,
2207dd7cddfSDavid du Colombier int new_width, int new_height, bool reallocate)
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
2237dd7cddfSDavid du Colombier gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
2247dd7cddfSDavid du Colombier byte *the_memory = 0;
2257dd7cddfSDavid du Colombier gdev_prn_space_params save_params;
226*593dc095SDavid du Colombier int save_width = 0x0badf00d; /* Quiet compiler */
227*593dc095SDavid du Colombier int save_height = 0x0badf00d; /* Quiet compiler */
228*593dc095SDavid du Colombier bool is_command_list = false; /* Quiet compiler */
229*593dc095SDavid du Colombier bool save_is_command_list = false; /* Quiet compiler */
2307dd7cddfSDavid du Colombier int ecode = 0;
2317dd7cddfSDavid du Colombier int pass;
2327dd7cddfSDavid du Colombier gs_memory_t *buffer_memory =
233*593dc095SDavid du Colombier (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
2347dd7cddfSDavid du Colombier ppdev->buffer_memory);
2357dd7cddfSDavid du Colombier
2367dd7cddfSDavid du Colombier /* If reallocate, find allocated memory & tear down buffer device */
2377dd7cddfSDavid du Colombier if (reallocate)
2387dd7cddfSDavid du Colombier save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
2397dd7cddfSDavid du Colombier
2407dd7cddfSDavid du Colombier /* Re/allocate memory */
2417dd7cddfSDavid du Colombier ppdev->orig_procs = pdev->procs;
2427dd7cddfSDavid du Colombier for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
2437dd7cddfSDavid du Colombier ulong mem_space;
244*593dc095SDavid du Colombier ulong pdf14_trans_buffer_size = 0;
2457dd7cddfSDavid du Colombier byte *base = 0;
2467dd7cddfSDavid du Colombier bool bufferSpace_is_default = false;
2477dd7cddfSDavid du Colombier gdev_prn_space_params space_params;
2487dd7cddfSDavid du Colombier gx_device_buf_space_t buf_space;
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier if (reallocate)
2517dd7cddfSDavid du Colombier switch (pass)
2527dd7cddfSDavid du Colombier {
2537dd7cddfSDavid du Colombier case 1:
2547dd7cddfSDavid du Colombier /* Setup device to get reallocated */
2557dd7cddfSDavid du Colombier save_params = ppdev->space_params;
2567dd7cddfSDavid du Colombier ppdev->space_params = *new_space_params;
2577dd7cddfSDavid du Colombier save_width = ppdev->width;
2587dd7cddfSDavid du Colombier ppdev->width = new_width;
2597dd7cddfSDavid du Colombier save_height = ppdev->height;
2607dd7cddfSDavid du Colombier ppdev->height = new_height;
2617dd7cddfSDavid du Colombier break;
2627dd7cddfSDavid du Colombier case 2: /* only comes here if reallocate */
2637dd7cddfSDavid du Colombier /* Restore device to previous contents */
2647dd7cddfSDavid du Colombier ppdev->space_params = save_params;
2657dd7cddfSDavid du Colombier ppdev->width = save_width;
2667dd7cddfSDavid du Colombier ppdev->height = save_height;
2677dd7cddfSDavid du Colombier break;
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier /* Init clist/mem device-specific fields */
2717dd7cddfSDavid du Colombier memset(ppdev->skip, 0, sizeof(ppdev->skip));
2727dd7cddfSDavid du Colombier ppdev->printer_procs.buf_procs.size_buf_device
2737dd7cddfSDavid du Colombier (&buf_space, pdev, NULL, pdev->height, false);
274*593dc095SDavid du Colombier if (ppdev->page_uses_transparency)
275*593dc095SDavid du Colombier pdf14_trans_buffer_size = new_height
276*593dc095SDavid du Colombier * (ESTIMATED_PDF14_ROW_SPACE(new_width) >> 3);
277*593dc095SDavid du Colombier mem_space = buf_space.bits + buf_space.line_ptrs
278*593dc095SDavid du Colombier + pdf14_trans_buffer_size;
2797dd7cddfSDavid du Colombier
2807dd7cddfSDavid du Colombier /* Compute desired space params: never use the space_params as-is. */
2817dd7cddfSDavid du Colombier /* Rather, give the dev-specific driver a chance to adjust them. */
2827dd7cddfSDavid du Colombier space_params = ppdev->space_params;
2837dd7cddfSDavid du Colombier space_params.BufferSpace = 0;
2847dd7cddfSDavid du Colombier (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
2857dd7cddfSDavid du Colombier if (ppdev->is_async_renderer && space_params.band.BandBufferSpace != 0)
2867dd7cddfSDavid du Colombier space_params.BufferSpace = space_params.band.BandBufferSpace;
2877dd7cddfSDavid du Colombier else if (space_params.BufferSpace == 0) {
2887dd7cddfSDavid du Colombier if (space_params.band.BandBufferSpace > 0)
2897dd7cddfSDavid du Colombier space_params.BufferSpace = space_params.band.BandBufferSpace;
2907dd7cddfSDavid du Colombier else {
2917dd7cddfSDavid du Colombier space_params.BufferSpace = ppdev->space_params.BufferSpace;
2927dd7cddfSDavid du Colombier bufferSpace_is_default = true;
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier /* Determine if we can use a full bitmap buffer, or have to use banding */
2977dd7cddfSDavid du Colombier if (pass > 1)
2987dd7cddfSDavid du Colombier is_command_list = save_is_command_list;
2997dd7cddfSDavid du Colombier else {
3007dd7cddfSDavid du Colombier is_command_list = space_params.banding_type == BandingAlways ||
3017dd7cddfSDavid du Colombier mem_space >= space_params.MaxBitmap ||
3027dd7cddfSDavid du Colombier mem_space != (uint)mem_space; /* too big to allocate */
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier if (!is_command_list) {
3057dd7cddfSDavid du Colombier /* Try to allocate memory for full memory buffer */
3067dd7cddfSDavid du Colombier base =
3077dd7cddfSDavid du Colombier (reallocate ?
3087dd7cddfSDavid du Colombier (byte *)gs_resize_object(buffer_memory, the_memory,
3097dd7cddfSDavid du Colombier (uint)mem_space, "printer buffer") :
3107dd7cddfSDavid du Colombier gs_alloc_bytes(buffer_memory, (uint)mem_space,
3117dd7cddfSDavid du Colombier "printer_buffer"));
3127dd7cddfSDavid du Colombier if (base == 0)
3137dd7cddfSDavid du Colombier is_command_list = true;
3147dd7cddfSDavid du Colombier else
3157dd7cddfSDavid du Colombier the_memory = base;
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
318*593dc095SDavid du Colombier && buffer_memory == pdev->memory->non_gc_memory) {
3197dd7cddfSDavid du Colombier /* before using full memory buffer, ensure enough working mem left */
3207dd7cddfSDavid du Colombier byte * left = gs_alloc_bytes( buffer_memory,
3217dd7cddfSDavid du Colombier PRN_MIN_MEMORY_LEFT, "printer mem left");
3227dd7cddfSDavid du Colombier if (left == 0)
3237dd7cddfSDavid du Colombier is_command_list = true;
3247dd7cddfSDavid du Colombier else
3257dd7cddfSDavid du Colombier gs_free_object(buffer_memory, left, "printer mem left");
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier
3287dd7cddfSDavid du Colombier if (is_command_list) {
3297dd7cddfSDavid du Colombier /* Buffer the image in a command list. */
3307dd7cddfSDavid du Colombier /* Release the buffer if we allocated it. */
3317dd7cddfSDavid du Colombier int code;
3327dd7cddfSDavid du Colombier if (!reallocate) {
3337dd7cddfSDavid du Colombier gs_free_object(buffer_memory, the_memory,
3347dd7cddfSDavid du Colombier "printer buffer(open)");
3357dd7cddfSDavid du Colombier the_memory = 0;
3367dd7cddfSDavid du Colombier }
3377dd7cddfSDavid du Colombier if (space_params.banding_type == BandingNever) {
3387dd7cddfSDavid du Colombier ecode = gs_note_error(gs_error_VMerror);
3397dd7cddfSDavid du Colombier continue;
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier code = gdev_prn_setup_as_command_list(pdev, buffer_memory,
3427dd7cddfSDavid du Colombier &the_memory, &space_params,
3437dd7cddfSDavid du Colombier !bufferSpace_is_default);
3447dd7cddfSDavid du Colombier if (ecode == 0)
3457dd7cddfSDavid du Colombier ecode = code;
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier if ( code >= 0 || (reallocate && pass > 1) )
3487dd7cddfSDavid du Colombier ppdev->procs = gs_clist_device_procs;
3497dd7cddfSDavid du Colombier } else {
3507dd7cddfSDavid du Colombier /* Render entirely in memory. */
3517dd7cddfSDavid du Colombier gx_device *bdev = (gx_device *)pmemdev;
3527dd7cddfSDavid du Colombier int code;
3537dd7cddfSDavid du Colombier
3547dd7cddfSDavid du Colombier ppdev->buffer_space = 0;
3557dd7cddfSDavid du Colombier if ((code = gdev_create_buf_device
3567dd7cddfSDavid du Colombier (ppdev->printer_procs.buf_procs.create_buf_device,
3577dd7cddfSDavid du Colombier &bdev, pdev, NULL, NULL, false)) < 0 ||
3587dd7cddfSDavid du Colombier (code = ppdev->printer_procs.buf_procs.setup_buf_device
3597dd7cddfSDavid du Colombier (bdev, base, buf_space.raster,
3607dd7cddfSDavid du Colombier (byte **)(base + buf_space.bits), 0, pdev->height,
3617dd7cddfSDavid du Colombier pdev->height)) < 0
3627dd7cddfSDavid du Colombier ) {
3637dd7cddfSDavid du Colombier /* Catastrophic. Shouldn't ever happen */
3647dd7cddfSDavid du Colombier gs_free_object(buffer_memory, base, "printer buffer");
3657dd7cddfSDavid du Colombier pdev->procs = ppdev->orig_procs;
3667dd7cddfSDavid du Colombier ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
3677dd7cddfSDavid du Colombier return_error(code);
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier pmemdev->base = base;
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier if (ecode == 0)
3727dd7cddfSDavid du Colombier break;
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier if (ecode >= 0 || reallocate) { /* even if realloc failed */
3767dd7cddfSDavid du Colombier /* Synthesize the procedure vector. */
3777dd7cddfSDavid du Colombier /* Rendering operations come from the memory or clist device, */
3787dd7cddfSDavid du Colombier /* non-rendering come from the printer device. */
3797dd7cddfSDavid du Colombier #define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
3807dd7cddfSDavid du Colombier COPY_PROC(get_initial_matrix);
3817dd7cddfSDavid du Colombier COPY_PROC(output_page);
3827dd7cddfSDavid du Colombier COPY_PROC(close_device);
3837dd7cddfSDavid du Colombier COPY_PROC(map_rgb_color);
3847dd7cddfSDavid du Colombier COPY_PROC(map_color_rgb);
3857dd7cddfSDavid du Colombier COPY_PROC(get_params);
3867dd7cddfSDavid du Colombier COPY_PROC(put_params);
3877dd7cddfSDavid du Colombier COPY_PROC(map_cmyk_color);
3887dd7cddfSDavid du Colombier COPY_PROC(get_xfont_procs);
3897dd7cddfSDavid du Colombier COPY_PROC(get_xfont_device);
3907dd7cddfSDavid du Colombier COPY_PROC(map_rgb_alpha_color);
3917dd7cddfSDavid du Colombier /* All printers are page devices, even if they didn't use the */
3927dd7cddfSDavid du Colombier /* standard macros for generating their procedure vectors. */
3937dd7cddfSDavid du Colombier set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
3947dd7cddfSDavid du Colombier COPY_PROC(get_clipping_box);
3957dd7cddfSDavid du Colombier COPY_PROC(map_color_rgb_alpha);
3967dd7cddfSDavid du Colombier COPY_PROC(get_hardware_params);
397*593dc095SDavid du Colombier COPY_PROC(get_color_mapping_procs);
398*593dc095SDavid du Colombier COPY_PROC(get_color_comp_index);
399*593dc095SDavid du Colombier COPY_PROC(encode_color);
400*593dc095SDavid du Colombier COPY_PROC(decode_color);
401*593dc095SDavid du Colombier COPY_PROC(begin_image);
402*593dc095SDavid du Colombier COPY_PROC(text_begin);
403*593dc095SDavid du Colombier COPY_PROC(fill_path);
404*593dc095SDavid du Colombier COPY_PROC(stroke_path);
405*593dc095SDavid du Colombier COPY_PROC(fill_rectangle_hl_color);
406*593dc095SDavid du Colombier COPY_PROC(update_spot_equivalent_colors);
4077dd7cddfSDavid du Colombier #undef COPY_PROC
4087dd7cddfSDavid du Colombier /* If using a command list, already opened the device. */
4097dd7cddfSDavid du Colombier if (is_command_list)
4107dd7cddfSDavid du Colombier return ecode;
4117dd7cddfSDavid du Colombier else
4127dd7cddfSDavid du Colombier return (*dev_proc(pdev, open_device))(pdev);
4137dd7cddfSDavid du Colombier } else {
4147dd7cddfSDavid du Colombier pdev->procs = ppdev->orig_procs;
4157dd7cddfSDavid du Colombier ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
4167dd7cddfSDavid du Colombier return ecode;
4177dd7cddfSDavid du Colombier }
4187dd7cddfSDavid du Colombier }
4197dd7cddfSDavid du Colombier
4207dd7cddfSDavid du Colombier int
gdev_prn_allocate_memory(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height)4217dd7cddfSDavid du Colombier gdev_prn_allocate_memory(gx_device *pdev,
4227dd7cddfSDavid du Colombier gdev_prn_space_params *new_space_params,
4237dd7cddfSDavid du Colombier int new_width, int new_height)
4247dd7cddfSDavid du Colombier {
4257dd7cddfSDavid du Colombier return gdev_prn_allocate(pdev, new_space_params,
4267dd7cddfSDavid du Colombier new_width, new_height, false);
4277dd7cddfSDavid du Colombier }
4287dd7cddfSDavid du Colombier
4297dd7cddfSDavid du Colombier int
gdev_prn_reallocate_memory(gx_device * pdev,gdev_prn_space_params * new_space_params,int new_width,int new_height)4307dd7cddfSDavid du Colombier gdev_prn_reallocate_memory(gx_device *pdev,
4317dd7cddfSDavid du Colombier gdev_prn_space_params *new_space_params,
4327dd7cddfSDavid du Colombier int new_width, int new_height)
4337dd7cddfSDavid du Colombier {
4347dd7cddfSDavid du Colombier return gdev_prn_allocate(pdev, new_space_params,
4357dd7cddfSDavid du Colombier new_width, new_height, true);
4367dd7cddfSDavid du Colombier }
4377dd7cddfSDavid du Colombier
4387dd7cddfSDavid du Colombier int
gdev_prn_free_memory(gx_device * pdev)4397dd7cddfSDavid du Colombier gdev_prn_free_memory(gx_device *pdev)
4407dd7cddfSDavid du Colombier {
4417dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
4427dd7cddfSDavid du Colombier byte *the_memory = 0;
4437dd7cddfSDavid du Colombier gs_memory_t *buffer_memory =
444*593dc095SDavid du Colombier (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
4457dd7cddfSDavid du Colombier ppdev->buffer_memory);
4467dd7cddfSDavid du Colombier
4477dd7cddfSDavid du Colombier gdev_prn_tear_down(pdev, &the_memory);
4487dd7cddfSDavid du Colombier gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory");
4497dd7cddfSDavid du Colombier return 0;
4507dd7cddfSDavid du Colombier }
4517dd7cddfSDavid du Colombier
4527dd7cddfSDavid du Colombier /* ------------- Stubs related only to async rendering ------- */
4537dd7cddfSDavid du Colombier
4547dd7cddfSDavid du Colombier int /* rets 0 ok, -ve error if couldn't start thread */
gx_default_start_render_thread(gdev_prn_start_render_params * params)4557dd7cddfSDavid du Colombier gx_default_start_render_thread(gdev_prn_start_render_params *params)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier return gs_error_unknownerror;
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier
4607dd7cddfSDavid du Colombier /* Open the renderer's copy of a device. */
4617dd7cddfSDavid du Colombier /* This is overriden in gdevprna.c */
4627dd7cddfSDavid du Colombier int
gx_default_open_render_device(gx_device_printer * pdev)4637dd7cddfSDavid du Colombier gx_default_open_render_device(gx_device_printer *pdev)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier return gs_error_unknownerror;
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier
4687dd7cddfSDavid du Colombier /* Close the renderer's copy of a device. */
4697dd7cddfSDavid du Colombier int
gx_default_close_render_device(gx_device_printer * pdev)4707dd7cddfSDavid du Colombier gx_default_close_render_device(gx_device_printer *pdev)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier return gdev_prn_close( (gx_device *)pdev );
4737dd7cddfSDavid du Colombier }
4747dd7cddfSDavid du Colombier
4757dd7cddfSDavid du Colombier /* ------ Get/put parameters ------ */
4767dd7cddfSDavid du Colombier
4777dd7cddfSDavid du Colombier /* Get parameters. Printer devices add several more parameters */
4787dd7cddfSDavid du Colombier /* to the default set. */
4797dd7cddfSDavid du Colombier int
gdev_prn_get_params(gx_device * pdev,gs_param_list * plist)4807dd7cddfSDavid du Colombier gdev_prn_get_params(gx_device * pdev, gs_param_list * plist)
4817dd7cddfSDavid du Colombier {
4827dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
4837dd7cddfSDavid du Colombier int code = gx_default_get_params(pdev, plist);
4847dd7cddfSDavid du Colombier gs_param_string ofns;
4857dd7cddfSDavid du Colombier
4867dd7cddfSDavid du Colombier if (code < 0 ||
4877dd7cddfSDavid du Colombier (code = param_write_long(plist, "MaxBitmap", &ppdev->space_params.MaxBitmap)) < 0 ||
4887dd7cddfSDavid du Colombier (code = param_write_long(plist, "BufferSpace", &ppdev->space_params.BufferSpace)) < 0 ||
4897dd7cddfSDavid du Colombier (code = param_write_int(plist, "BandWidth", &ppdev->space_params.band.BandWidth)) < 0 ||
4907dd7cddfSDavid du Colombier (code = param_write_int(plist, "BandHeight", &ppdev->space_params.band.BandHeight)) < 0 ||
4917dd7cddfSDavid du Colombier (code = param_write_long(plist, "BandBufferSpace", &ppdev->space_params.band.BandBufferSpace)) < 0 ||
4927dd7cddfSDavid du Colombier (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 ||
4937dd7cddfSDavid du Colombier (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 ||
494*593dc095SDavid du Colombier (code = param_write_bool(plist, "PageUsesTransparency",
495*593dc095SDavid du Colombier &ppdev->page_uses_transparency)) < 0 ||
4967dd7cddfSDavid du Colombier (ppdev->Duplex_set >= 0 &&
4977dd7cddfSDavid du Colombier (code = (ppdev->Duplex_set ?
4987dd7cddfSDavid du Colombier param_write_bool(plist, "Duplex", &ppdev->Duplex) :
4997dd7cddfSDavid du Colombier param_write_null(plist, "Duplex"))) < 0)
5007dd7cddfSDavid du Colombier )
5017dd7cddfSDavid du Colombier return code;
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier ofns.data = (const byte *)ppdev->fname,
5047dd7cddfSDavid du Colombier ofns.size = strlen(ppdev->fname),
5057dd7cddfSDavid du Colombier ofns.persistent = false;
5067dd7cddfSDavid du Colombier return param_write_string(plist, "OutputFile", &ofns);
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier
5097dd7cddfSDavid du Colombier /* Validate an OutputFile name by checking any %-formats. */
5107dd7cddfSDavid du Colombier private int
validate_output_file(const gs_param_string * ofs)5117dd7cddfSDavid du Colombier validate_output_file(const gs_param_string * ofs)
5127dd7cddfSDavid du Colombier {
5137dd7cddfSDavid du Colombier gs_parsed_file_name_t parsed;
5147dd7cddfSDavid du Colombier const char *fmt;
5157dd7cddfSDavid du Colombier
5167dd7cddfSDavid du Colombier return gx_parse_output_file_name(&parsed, &fmt, (const char *)ofs->data,
5177dd7cddfSDavid du Colombier ofs->size) >= 0;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier /* Put parameters. */
5217dd7cddfSDavid du Colombier int
gdev_prn_put_params(gx_device * pdev,gs_param_list * plist)5227dd7cddfSDavid du Colombier gdev_prn_put_params(gx_device * pdev, gs_param_list * plist)
5237dd7cddfSDavid du Colombier {
5247dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
5257dd7cddfSDavid du Colombier int ecode = 0;
5267dd7cddfSDavid du Colombier int code;
5277dd7cddfSDavid du Colombier const char *param_name;
5287dd7cddfSDavid du Colombier bool is_open = pdev->is_open;
5297dd7cddfSDavid du Colombier bool oof = ppdev->OpenOutputFile;
5307dd7cddfSDavid du Colombier bool rpp = ppdev->ReopenPerPage;
531*593dc095SDavid du Colombier bool page_uses_transparency = ppdev->page_uses_transparency;
532*593dc095SDavid du Colombier bool old_page_uses_transparency = ppdev->page_uses_transparency;
5337dd7cddfSDavid du Colombier bool duplex;
5347dd7cddfSDavid du Colombier int duplex_set = -1;
5357dd7cddfSDavid du Colombier int width = pdev->width;
5367dd7cddfSDavid du Colombier int height = pdev->height;
5377dd7cddfSDavid du Colombier gdev_prn_space_params sp, save_sp;
5387dd7cddfSDavid du Colombier gs_param_string ofs;
5397dd7cddfSDavid du Colombier gs_param_dict mdict;
5407dd7cddfSDavid du Colombier
5417dd7cddfSDavid du Colombier sp = ppdev->space_params;
5427dd7cddfSDavid du Colombier save_sp = sp;
5437dd7cddfSDavid du Colombier
5447dd7cddfSDavid du Colombier switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) {
5457dd7cddfSDavid du Colombier default:
5467dd7cddfSDavid du Colombier ecode = code;
5477dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);
5487dd7cddfSDavid du Colombier case 0:
5497dd7cddfSDavid du Colombier case 1:
5507dd7cddfSDavid du Colombier break;
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier
5537dd7cddfSDavid du Colombier switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) {
5547dd7cddfSDavid du Colombier default:
5557dd7cddfSDavid du Colombier ecode = code;
5567dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);
5577dd7cddfSDavid du Colombier case 0:
5587dd7cddfSDavid du Colombier case 1:
5597dd7cddfSDavid du Colombier break;
5607dd7cddfSDavid du Colombier }
5617dd7cddfSDavid du Colombier
562*593dc095SDavid du Colombier switch (code = param_read_bool(plist, (param_name = "PageUsesTransparency"),
563*593dc095SDavid du Colombier &page_uses_transparency)) {
564*593dc095SDavid du Colombier default:
565*593dc095SDavid du Colombier ecode = code;
566*593dc095SDavid du Colombier param_signal_error(plist, param_name, ecode);
567*593dc095SDavid du Colombier case 0:
568*593dc095SDavid du Colombier case 1:
569*593dc095SDavid du Colombier break;
570*593dc095SDavid du Colombier }
571*593dc095SDavid du Colombier
5727dd7cddfSDavid du Colombier if (ppdev->Duplex_set >= 0) /* i.e., Duplex is supported */
5737dd7cddfSDavid du Colombier switch (code = param_read_bool(plist, (param_name = "Duplex"),
5747dd7cddfSDavid du Colombier &duplex)) {
5757dd7cddfSDavid du Colombier case 0:
5767dd7cddfSDavid du Colombier duplex_set = 1;
5777dd7cddfSDavid du Colombier break;
5787dd7cddfSDavid du Colombier default:
5797dd7cddfSDavid du Colombier if ((code = param_read_null(plist, param_name)) == 0) {
5807dd7cddfSDavid du Colombier duplex_set = 0;
5817dd7cddfSDavid du Colombier break;
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier ecode = code;
5847dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);
5857dd7cddfSDavid du Colombier case 1:
5867dd7cddfSDavid du Colombier ;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier #define CHECK_PARAM_CASES(member, bad, label)\
5897dd7cddfSDavid du Colombier case 0:\
5907dd7cddfSDavid du Colombier if ((sp.params_are_read_only ? sp.member != save_sp.member : bad))\
5917dd7cddfSDavid du Colombier ecode = gs_error_rangecheck;\
5927dd7cddfSDavid du Colombier else\
5937dd7cddfSDavid du Colombier break;\
5947dd7cddfSDavid du Colombier goto label;\
5957dd7cddfSDavid du Colombier default:\
5967dd7cddfSDavid du Colombier ecode = code;\
5977dd7cddfSDavid du Colombier label:\
5987dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);\
5997dd7cddfSDavid du Colombier case 1:\
6007dd7cddfSDavid du Colombier break
6017dd7cddfSDavid du Colombier
6027dd7cddfSDavid du Colombier switch (code = param_read_long(plist, (param_name = "MaxBitmap"), &sp.MaxBitmap)) {
6037dd7cddfSDavid du Colombier CHECK_PARAM_CASES(MaxBitmap, sp.MaxBitmap < 10000, mbe);
6047dd7cddfSDavid du Colombier }
6057dd7cddfSDavid du Colombier
6067dd7cddfSDavid du Colombier switch (code = param_read_long(plist, (param_name = "BufferSpace"), &sp.BufferSpace)) {
6077dd7cddfSDavid du Colombier CHECK_PARAM_CASES(BufferSpace, sp.BufferSpace < 10000, bse);
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier
6107dd7cddfSDavid du Colombier switch (code = param_read_int(plist, (param_name = "BandWidth"), &sp.band.BandWidth)) {
6117dd7cddfSDavid du Colombier CHECK_PARAM_CASES(band.BandWidth, sp.band.BandWidth < 0, bwe);
6127dd7cddfSDavid du Colombier }
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier switch (code = param_read_int(plist, (param_name = "BandHeight"), &sp.band.BandHeight)) {
6157dd7cddfSDavid du Colombier CHECK_PARAM_CASES(band.BandHeight, sp.band.BandHeight < 0, bhe);
6167dd7cddfSDavid du Colombier }
6177dd7cddfSDavid du Colombier
6187dd7cddfSDavid du Colombier switch (code = param_read_long(plist, (param_name = "BandBufferSpace"), &sp.band.BandBufferSpace)) {
6197dd7cddfSDavid du Colombier CHECK_PARAM_CASES(band.BandBufferSpace, sp.band.BandBufferSpace < 0, bbse);
6207dd7cddfSDavid du Colombier }
6217dd7cddfSDavid du Colombier
6227dd7cddfSDavid du Colombier switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) {
6237dd7cddfSDavid du Colombier case 0:
624*593dc095SDavid du Colombier if (pdev->LockSafetyParams &&
625*593dc095SDavid du Colombier bytes_compare(ofs.data, ofs.size,
626*593dc095SDavid du Colombier (const byte *)ppdev->fname, strlen(ppdev->fname))) {
6273ff48bf5SDavid du Colombier code = gs_error_invalidaccess;
628*593dc095SDavid du Colombier }
6293ff48bf5SDavid du Colombier else
6307dd7cddfSDavid du Colombier code = validate_output_file(&ofs);
6317dd7cddfSDavid du Colombier if (code >= 0)
6327dd7cddfSDavid du Colombier break;
6337dd7cddfSDavid du Colombier /* falls through */
6347dd7cddfSDavid du Colombier default:
6357dd7cddfSDavid du Colombier ecode = code;
6367dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);
6377dd7cddfSDavid du Colombier case 1:
6387dd7cddfSDavid du Colombier ofs.data = 0;
6397dd7cddfSDavid du Colombier break;
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier /* Read InputAttributes and OutputAttributes just for the type */
6437dd7cddfSDavid du Colombier /* check and to indicate that they aren't undefined. */
6447dd7cddfSDavid du Colombier #define read_media(pname)\
6457dd7cddfSDavid du Colombier switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
6467dd7cddfSDavid du Colombier {\
6477dd7cddfSDavid du Colombier case 0:\
6487dd7cddfSDavid du Colombier param_end_read_dict(plist, pname, &mdict);\
6497dd7cddfSDavid du Colombier break;\
6507dd7cddfSDavid du Colombier default:\
6517dd7cddfSDavid du Colombier ecode = code;\
6527dd7cddfSDavid du Colombier param_signal_error(plist, param_name, ecode);\
6537dd7cddfSDavid du Colombier case 1:\
6547dd7cddfSDavid du Colombier ;\
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier
6577dd7cddfSDavid du Colombier read_media("InputAttributes");
6587dd7cddfSDavid du Colombier read_media("OutputAttributes");
6597dd7cddfSDavid du Colombier
6607dd7cddfSDavid du Colombier if (ecode < 0)
6617dd7cddfSDavid du Colombier return ecode;
6627dd7cddfSDavid du Colombier /* Prevent gx_default_put_params from closing the printer. */
6637dd7cddfSDavid du Colombier pdev->is_open = false;
6647dd7cddfSDavid du Colombier code = gx_default_put_params(pdev, plist);
6657dd7cddfSDavid du Colombier pdev->is_open = is_open;
6667dd7cddfSDavid du Colombier if (code < 0)
6677dd7cddfSDavid du Colombier return code;
6687dd7cddfSDavid du Colombier
6697dd7cddfSDavid du Colombier ppdev->OpenOutputFile = oof;
6707dd7cddfSDavid du Colombier ppdev->ReopenPerPage = rpp;
671*593dc095SDavid du Colombier ppdev->page_uses_transparency = page_uses_transparency;
6727dd7cddfSDavid du Colombier if (duplex_set >= 0) {
6737dd7cddfSDavid du Colombier ppdev->Duplex = duplex;
6747dd7cddfSDavid du Colombier ppdev->Duplex_set = duplex_set;
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier ppdev->space_params = sp;
6777dd7cddfSDavid du Colombier
6787dd7cddfSDavid du Colombier /* If necessary, free and reallocate the printer memory. */
6797dd7cddfSDavid du Colombier /* Formerly, would not reallocate if device is not open: */
6807dd7cddfSDavid du Colombier /* we had to patch this out (see News for 5.50). */
681*593dc095SDavid du Colombier code = gdev_prn_maybe_realloc_memory(ppdev, &save_sp, width, height,
682*593dc095SDavid du Colombier old_page_uses_transparency);
6837dd7cddfSDavid du Colombier if (code < 0)
6847dd7cddfSDavid du Colombier return code;
6857dd7cddfSDavid du Colombier
6867dd7cddfSDavid du Colombier /* If filename changed, close file. */
6877dd7cddfSDavid du Colombier if (ofs.data != 0 &&
6887dd7cddfSDavid du Colombier bytes_compare(ofs.data, ofs.size,
6897dd7cddfSDavid du Colombier (const byte *)ppdev->fname, strlen(ppdev->fname))
6907dd7cddfSDavid du Colombier ) {
6917dd7cddfSDavid du Colombier /* Close the file if it's open. */
6927dd7cddfSDavid du Colombier if (ppdev->file != NULL)
6937dd7cddfSDavid du Colombier gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
6947dd7cddfSDavid du Colombier ppdev->file = NULL;
6957dd7cddfSDavid du Colombier memcpy(ppdev->fname, ofs.data, ofs.size);
6967dd7cddfSDavid du Colombier ppdev->fname[ofs.size] = 0;
6977dd7cddfSDavid du Colombier }
6987dd7cddfSDavid du Colombier /* If the device is open and OpenOutputFile is true, */
6997dd7cddfSDavid du Colombier /* open the OutputFile now. (If the device isn't open, */
7007dd7cddfSDavid du Colombier /* this will happen when it is opened.) */
7017dd7cddfSDavid du Colombier if (pdev->is_open && oof) {
7027dd7cddfSDavid du Colombier code = gdev_prn_open_printer(pdev, 1);
7037dd7cddfSDavid du Colombier if (code < 0)
7047dd7cddfSDavid du Colombier return code;
7057dd7cddfSDavid du Colombier }
7067dd7cddfSDavid du Colombier return 0;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier
7097dd7cddfSDavid du Colombier /* ------ Others ------ */
7107dd7cddfSDavid du Colombier
7117dd7cddfSDavid du Colombier /* Default routine to (not) override current space_params. */
7127dd7cddfSDavid du Colombier void
gx_default_get_space_params(const gx_device_printer * printer_dev,gdev_prn_space_params * space_params)7137dd7cddfSDavid du Colombier gx_default_get_space_params(const gx_device_printer *printer_dev,
7147dd7cddfSDavid du Colombier gdev_prn_space_params *space_params)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier return;
7177dd7cddfSDavid du Colombier }
7187dd7cddfSDavid du Colombier
7197dd7cddfSDavid du Colombier /* Generic routine to send the page to the printer. */
7207dd7cddfSDavid du Colombier 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)7217dd7cddfSDavid du Colombier gdev_prn_output_page(gx_device * pdev, int num_copies, int flush)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
7247dd7cddfSDavid du Colombier int outcode = 0, closecode = 0, errcode = 0, endcode;
7257dd7cddfSDavid du Colombier bool upgraded_copypage = false;
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier if (num_copies > 0 || !flush) {
7287dd7cddfSDavid du Colombier int code = gdev_prn_open_printer(pdev, 1);
7297dd7cddfSDavid du Colombier
7307dd7cddfSDavid du Colombier if (code < 0)
7317dd7cddfSDavid du Colombier return code;
7327dd7cddfSDavid du Colombier
7337dd7cddfSDavid du Colombier /* If copypage request, try to do it using buffer_page */
7347dd7cddfSDavid du Colombier if ( !flush &&
7357dd7cddfSDavid du Colombier (*ppdev->printer_procs.buffer_page)
7367dd7cddfSDavid du Colombier (ppdev, ppdev->file, num_copies) >= 0
7377dd7cddfSDavid du Colombier ) {
7387dd7cddfSDavid du Colombier upgraded_copypage = true;
7397dd7cddfSDavid du Colombier flush = true;
7407dd7cddfSDavid du Colombier }
7417dd7cddfSDavid du Colombier else if (num_copies > 0)
7427dd7cddfSDavid du Colombier /* Print the accumulated page description. */
7437dd7cddfSDavid du Colombier outcode =
7447dd7cddfSDavid du Colombier (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
7457dd7cddfSDavid du Colombier num_copies);
7467dd7cddfSDavid du Colombier fflush(ppdev->file);
7477dd7cddfSDavid du Colombier errcode =
7487dd7cddfSDavid du Colombier (ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
7497dd7cddfSDavid du Colombier if (!upgraded_copypage)
7507dd7cddfSDavid du Colombier closecode = gdev_prn_close_printer(pdev);
7517dd7cddfSDavid du Colombier }
7527dd7cddfSDavid du Colombier endcode = (ppdev->buffer_space && !ppdev->is_async_renderer ?
7537dd7cddfSDavid du Colombier clist_finish_page(pdev, flush) : 0);
7547dd7cddfSDavid du Colombier
7557dd7cddfSDavid du Colombier if (outcode < 0)
7567dd7cddfSDavid du Colombier return outcode;
7577dd7cddfSDavid du Colombier if (errcode < 0)
7587dd7cddfSDavid du Colombier return errcode;
7597dd7cddfSDavid du Colombier if (closecode < 0)
7607dd7cddfSDavid du Colombier return closecode;
7617dd7cddfSDavid du Colombier if (endcode < 0)
7627dd7cddfSDavid du Colombier return endcode;
7637dd7cddfSDavid du Colombier endcode = gx_finish_output_page(pdev, num_copies, flush);
7647dd7cddfSDavid du Colombier return (endcode < 0 ? endcode : upgraded_copypage ? 1 : 0);
7657dd7cddfSDavid du Colombier }
7667dd7cddfSDavid du Colombier
7673ff48bf5SDavid du Colombier /* Print a single copy of a page by calling print_page_copies. */
7683ff48bf5SDavid du Colombier int
gx_print_page_single_copy(gx_device_printer * pdev,FILE * prn_stream)7693ff48bf5SDavid du Colombier gx_print_page_single_copy(gx_device_printer * pdev, FILE * prn_stream)
7703ff48bf5SDavid du Colombier {
7713ff48bf5SDavid du Colombier return pdev->printer_procs.print_page_copies(pdev, prn_stream, 1);
7723ff48bf5SDavid du Colombier }
7733ff48bf5SDavid du Colombier
7747dd7cddfSDavid du Colombier /* Print multiple copies of a page by calling print_page multiple times. */
7757dd7cddfSDavid du Colombier int
gx_default_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)7767dd7cddfSDavid du Colombier gx_default_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
7777dd7cddfSDavid du Colombier int num_copies)
7787dd7cddfSDavid du Colombier {
7793ff48bf5SDavid du Colombier int i = 1;
7807dd7cddfSDavid du Colombier int code = 0;
7817dd7cddfSDavid du Colombier
7823ff48bf5SDavid du Colombier for (; i < num_copies; ++i) {
7833ff48bf5SDavid du Colombier int errcode, closecode;
7843ff48bf5SDavid du Colombier
7857dd7cddfSDavid du Colombier code = (*pdev->printer_procs.print_page) (pdev, prn_stream);
7863ff48bf5SDavid du Colombier if (code < 0)
7877dd7cddfSDavid du Colombier return code;
7883ff48bf5SDavid du Colombier /*
7893ff48bf5SDavid du Colombier * Close and re-open the printer, to reset is_new and do the
7903ff48bf5SDavid du Colombier * right thing if we're producing multiple output files.
7913ff48bf5SDavid du Colombier * Code is mostly copied from gdev_prn_output_page.
7923ff48bf5SDavid du Colombier */
7933ff48bf5SDavid du Colombier fflush(pdev->file);
7943ff48bf5SDavid du Colombier errcode =
7953ff48bf5SDavid du Colombier (ferror(pdev->file) ? gs_note_error(gs_error_ioerror) : 0);
7963ff48bf5SDavid du Colombier closecode = gdev_prn_close_printer((gx_device *)pdev);
7973ff48bf5SDavid du Colombier pdev->PageCount++;
7983ff48bf5SDavid du Colombier code = (errcode < 0 ? errcode : closecode < 0 ? closecode :
7993ff48bf5SDavid du Colombier gdev_prn_open_printer((gx_device *)pdev, true));
8003ff48bf5SDavid du Colombier if (code < 0) {
8013ff48bf5SDavid du Colombier pdev->PageCount -= i;
8023ff48bf5SDavid du Colombier return code;
8033ff48bf5SDavid du Colombier }
8043ff48bf5SDavid du Colombier prn_stream = pdev->file;
8053ff48bf5SDavid du Colombier }
8063ff48bf5SDavid du Colombier /* Print the last (or only) page. */
8073ff48bf5SDavid du Colombier pdev->PageCount -= num_copies - 1;
8083ff48bf5SDavid du Colombier return (*pdev->printer_procs.print_page) (pdev, prn_stream);
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier
8117dd7cddfSDavid du Colombier /*
8127dd7cddfSDavid du Colombier * Buffer a (partial) rasterized page & optionally print result multiple times.
8137dd7cddfSDavid du Colombier * The default implementation returns error, since the driver needs to override
8147dd7cddfSDavid du Colombier * this (in procedure vector) in configurations where this call may occur.
8157dd7cddfSDavid du Colombier */
8167dd7cddfSDavid du Colombier int
gx_default_buffer_page(gx_device_printer * pdev,FILE * prn_stream,int num_copies)8177dd7cddfSDavid du Colombier gx_default_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
8187dd7cddfSDavid du Colombier int num_copies)
8197dd7cddfSDavid du Colombier {
8207dd7cddfSDavid du Colombier return gs_error_unknownerror;
8217dd7cddfSDavid du Colombier }
8227dd7cddfSDavid du Colombier
8237dd7cddfSDavid du Colombier /* ---------------- Driver services ---------------- */
8247dd7cddfSDavid du Colombier
8257dd7cddfSDavid du Colombier /* Initialize a rendering plane specification. */
8267dd7cddfSDavid du Colombier int
gx_render_plane_init(gx_render_plane_t * render_plane,const gx_device * dev,int index)8277dd7cddfSDavid du Colombier gx_render_plane_init(gx_render_plane_t *render_plane, const gx_device *dev,
8287dd7cddfSDavid du Colombier int index)
8297dd7cddfSDavid du Colombier {
8307dd7cddfSDavid du Colombier /*
8317dd7cddfSDavid du Colombier * Eventually the computation of shift and depth from dev and index
8327dd7cddfSDavid du Colombier * will be made device-dependent.
8337dd7cddfSDavid du Colombier */
8347dd7cddfSDavid du Colombier int num_planes = dev->color_info.num_components;
8357dd7cddfSDavid du Colombier int plane_depth = dev->color_info.depth / num_planes;
8367dd7cddfSDavid du Colombier
8377dd7cddfSDavid du Colombier if (index < 0 || index >= num_planes)
8387dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
8397dd7cddfSDavid du Colombier render_plane->index = index;
8407dd7cddfSDavid du Colombier render_plane->depth = plane_depth;
8417dd7cddfSDavid du Colombier render_plane->shift = plane_depth * (num_planes - 1 - index);
8427dd7cddfSDavid du Colombier return 0;
8437dd7cddfSDavid du Colombier }
8447dd7cddfSDavid du Colombier
8457dd7cddfSDavid du Colombier /* Clear trailing bits in the last byte of (a) scan line(s). */
8467dd7cddfSDavid du Colombier void
gdev_prn_clear_trailing_bits(byte * data,uint raster,int height,const gx_device * dev)8477dd7cddfSDavid du Colombier gdev_prn_clear_trailing_bits(byte *data, uint raster, int height,
8487dd7cddfSDavid du Colombier const gx_device *dev)
8497dd7cddfSDavid du Colombier {
8507dd7cddfSDavid du Colombier int first_bit = dev->width * dev->color_info.depth;
8517dd7cddfSDavid du Colombier
8527dd7cddfSDavid du Colombier if (first_bit & 7)
8537dd7cddfSDavid du Colombier bits_fill_rectangle(data, first_bit, raster, mono_fill_make_pattern(0),
8547dd7cddfSDavid du Colombier -first_bit & 7, height);
8557dd7cddfSDavid du Colombier }
8567dd7cddfSDavid du Colombier
8577dd7cddfSDavid du Colombier /* Return the number of scan lines that should actually be passed */
8587dd7cddfSDavid du Colombier /* to the device. */
8597dd7cddfSDavid du Colombier int
gdev_prn_print_scan_lines(gx_device * pdev)8607dd7cddfSDavid du Colombier gdev_prn_print_scan_lines(gx_device * pdev)
8617dd7cddfSDavid du Colombier {
8627dd7cddfSDavid du Colombier int height = pdev->height;
8637dd7cddfSDavid du Colombier gs_matrix imat;
8647dd7cddfSDavid du Colombier float yscale;
8657dd7cddfSDavid du Colombier int top, bottom, offset, end;
8667dd7cddfSDavid du Colombier
8677dd7cddfSDavid du Colombier (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
8687dd7cddfSDavid du Colombier yscale = imat.yy * 72.0; /* Y dpi, may be negative */
8697dd7cddfSDavid du Colombier top = (int)(dev_t_margin(pdev) * yscale);
8707dd7cddfSDavid du Colombier bottom = (int)(dev_b_margin(pdev) * yscale);
8717dd7cddfSDavid du Colombier offset = (int)(dev_y_offset(pdev) * yscale);
8727dd7cddfSDavid du Colombier if (yscale < 0) { /* Y=0 is top of page */
8737dd7cddfSDavid du Colombier end = -offset + height + bottom;
8747dd7cddfSDavid du Colombier } else { /* Y=0 is bottom of page */
8757dd7cddfSDavid du Colombier end = offset + height - top;
8767dd7cddfSDavid du Colombier }
8777dd7cddfSDavid du Colombier return min(height, end);
8787dd7cddfSDavid du Colombier }
8797dd7cddfSDavid du Colombier
8807dd7cddfSDavid du Colombier /* Open the current page for printing. */
8817dd7cddfSDavid du Colombier int
gdev_prn_open_printer_seekable(gx_device * pdev,bool binary_mode,bool seekable)8827dd7cddfSDavid du Colombier gdev_prn_open_printer_seekable(gx_device *pdev, bool binary_mode,
8837dd7cddfSDavid du Colombier bool seekable)
8847dd7cddfSDavid du Colombier {
8857dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
8867dd7cddfSDavid du Colombier
8877dd7cddfSDavid du Colombier if (ppdev->file != 0) {
8887dd7cddfSDavid du Colombier ppdev->file_is_new = false;
8897dd7cddfSDavid du Colombier return 0;
8907dd7cddfSDavid du Colombier }
8917dd7cddfSDavid du Colombier {
8927dd7cddfSDavid du Colombier int code = gx_device_open_output_file(pdev, ppdev->fname,
8937dd7cddfSDavid du Colombier binary_mode, seekable,
8947dd7cddfSDavid du Colombier &ppdev->file);
8957dd7cddfSDavid du Colombier if (code < 0)
8967dd7cddfSDavid du Colombier return code;
8977dd7cddfSDavid du Colombier }
8987dd7cddfSDavid du Colombier ppdev->file_is_new = true;
8997dd7cddfSDavid du Colombier return 0;
9007dd7cddfSDavid du Colombier }
9017dd7cddfSDavid du Colombier int
gdev_prn_open_printer(gx_device * pdev,bool binary_mode)9027dd7cddfSDavid du Colombier gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
9037dd7cddfSDavid du Colombier {
9047dd7cddfSDavid du Colombier return gdev_prn_open_printer_seekable(pdev, binary_mode, false);
9057dd7cddfSDavid du Colombier }
9067dd7cddfSDavid du Colombier
9073ff48bf5SDavid du Colombier /*
9083ff48bf5SDavid du Colombier * Test whether the printer's output file was just opened, i.e., whether
9093ff48bf5SDavid du Colombier * this is the first page being written to this file. This is only valid
9103ff48bf5SDavid du Colombier * at the entry to a driver's print_page procedure.
9113ff48bf5SDavid du Colombier */
9123ff48bf5SDavid du Colombier bool
gdev_prn_file_is_new(const gx_device_printer * pdev)9133ff48bf5SDavid du Colombier gdev_prn_file_is_new(const gx_device_printer *pdev)
9143ff48bf5SDavid du Colombier {
9153ff48bf5SDavid du Colombier return pdev->file_is_new;
9163ff48bf5SDavid du Colombier }
9173ff48bf5SDavid du Colombier
9187dd7cddfSDavid du Colombier /* Determine the colors used in a range of lines. */
9197dd7cddfSDavid du Colombier 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)9207dd7cddfSDavid du Colombier gx_page_info_colors_used(const gx_device *dev,
9217dd7cddfSDavid du Colombier const gx_band_page_info_t *page_info,
9227dd7cddfSDavid du Colombier int y, int height,
9237dd7cddfSDavid du Colombier gx_colors_used_t *colors_used, int *range_start)
9247dd7cddfSDavid du Colombier {
9257dd7cddfSDavid du Colombier int start, end, i;
9267dd7cddfSDavid du Colombier int num_lines = page_info->scan_lines_per_colors_used;
9277dd7cddfSDavid du Colombier gx_color_index or = 0;
9287dd7cddfSDavid du Colombier bool slow_rop = false;
9297dd7cddfSDavid du Colombier
9307dd7cddfSDavid du Colombier if (y < 0 || height < 0 || height > dev->height - y)
9317dd7cddfSDavid du Colombier return -1;
9327dd7cddfSDavid du Colombier start = y / num_lines;
9337dd7cddfSDavid du Colombier end = (y + height + num_lines - 1) / num_lines;
9347dd7cddfSDavid du Colombier for (i = start; i < end; ++i) {
9357dd7cddfSDavid du Colombier or |= page_info->band_colors_used[i].or;
9367dd7cddfSDavid du Colombier slow_rop |= page_info->band_colors_used[i].slow_rop;
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier colors_used->or = or;
9397dd7cddfSDavid du Colombier colors_used->slow_rop = slow_rop;
9407dd7cddfSDavid du Colombier *range_start = start * num_lines;
9417dd7cddfSDavid du Colombier return min(end * num_lines, dev->height) - *range_start;
9427dd7cddfSDavid du Colombier }
9437dd7cddfSDavid du Colombier int
gdev_prn_colors_used(gx_device * dev,int y,int height,gx_colors_used_t * colors_used,int * range_start)9447dd7cddfSDavid du Colombier gdev_prn_colors_used(gx_device *dev, int y, int height,
9457dd7cddfSDavid du Colombier gx_colors_used_t *colors_used, int *range_start)
9467dd7cddfSDavid du Colombier {
9477dd7cddfSDavid du Colombier gx_device_clist_writer *cldev;
9487dd7cddfSDavid du Colombier
9497dd7cddfSDavid du Colombier /* If this isn't a banded device, return default values. */
9507dd7cddfSDavid du Colombier if (dev_proc(dev, get_bits_rectangle) !=
9517dd7cddfSDavid du Colombier gs_clist_device_procs.get_bits_rectangle
9527dd7cddfSDavid du Colombier ) {
9537dd7cddfSDavid du Colombier *range_start = 0;
9547dd7cddfSDavid du Colombier colors_used->or = ((gx_color_index)1 << dev->color_info.depth) - 1;
9557dd7cddfSDavid du Colombier return dev->height;
9567dd7cddfSDavid du Colombier }
9577dd7cddfSDavid du Colombier cldev = (gx_device_clist_writer *)dev;
9587dd7cddfSDavid du Colombier if (cldev->page_info.scan_lines_per_colors_used == 0) /* not set yet */
9597dd7cddfSDavid du Colombier clist_compute_colors_used(cldev);
9607dd7cddfSDavid du Colombier return
9617dd7cddfSDavid du Colombier gx_page_info_colors_used(dev, &cldev->page_info,
9627dd7cddfSDavid du Colombier y, height, colors_used, range_start);
9637dd7cddfSDavid du Colombier }
9647dd7cddfSDavid du Colombier
9657dd7cddfSDavid du Colombier /*
9667dd7cddfSDavid du Colombier * Create the buffer device for a printer device. Clients should always
9677dd7cddfSDavid du Colombier * call this, and never call the device procedure directly.
9687dd7cddfSDavid du Colombier */
9697dd7cddfSDavid du Colombier 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)9707dd7cddfSDavid du Colombier gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev,
9717dd7cddfSDavid du Colombier gx_device *target,
9727dd7cddfSDavid du Colombier const gx_render_plane_t *render_plane,
9737dd7cddfSDavid du Colombier gs_memory_t *mem, bool for_band)
9747dd7cddfSDavid du Colombier {
9757dd7cddfSDavid du Colombier int code = cbd_proc(pbdev, target, render_plane, mem, for_band);
9767dd7cddfSDavid du Colombier
9777dd7cddfSDavid du Colombier if (code < 0)
9787dd7cddfSDavid du Colombier return code;
9797dd7cddfSDavid du Colombier /* Retain this device -- it will be freed explicitly. */
9807dd7cddfSDavid du Colombier gx_device_retain(*pbdev, true);
9817dd7cddfSDavid du Colombier return code;
9827dd7cddfSDavid du Colombier }
9837dd7cddfSDavid du Colombier
9847dd7cddfSDavid du Colombier /*
9857dd7cddfSDavid du Colombier * Create an ordinary memory device for page or band buffering,
9867dd7cddfSDavid du Colombier * possibly preceded by a plane extraction device.
9877dd7cddfSDavid du Colombier */
9887dd7cddfSDavid du Colombier 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)9897dd7cddfSDavid du Colombier gx_default_create_buf_device(gx_device **pbdev, gx_device *target,
9907dd7cddfSDavid du Colombier const gx_render_plane_t *render_plane, gs_memory_t *mem, bool for_band)
9917dd7cddfSDavid du Colombier {
9927dd7cddfSDavid du Colombier int plane_index = (render_plane ? render_plane->index : -1);
9937dd7cddfSDavid du Colombier int depth;
9947dd7cddfSDavid du Colombier const gx_device_memory *mdproto;
9957dd7cddfSDavid du Colombier gx_device_memory *mdev;
9967dd7cddfSDavid du Colombier gx_device *bdev;
9977dd7cddfSDavid du Colombier
9987dd7cddfSDavid du Colombier if (plane_index >= 0)
9997dd7cddfSDavid du Colombier depth = render_plane->depth;
10007dd7cddfSDavid du Colombier else
10017dd7cddfSDavid du Colombier depth = target->color_info.depth;
10027dd7cddfSDavid du Colombier mdproto = gdev_mem_device_for_bits(depth);
10037dd7cddfSDavid du Colombier if (mdproto == 0)
10047dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
10057dd7cddfSDavid du Colombier if (mem) {
10067dd7cddfSDavid du Colombier mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
10077dd7cddfSDavid du Colombier "create_buf_device");
10087dd7cddfSDavid du Colombier if (mdev == 0)
10097dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
10107dd7cddfSDavid du Colombier } else {
10117dd7cddfSDavid du Colombier mdev = (gx_device_memory *)*pbdev;
10127dd7cddfSDavid du Colombier }
10137dd7cddfSDavid du Colombier if (target == (gx_device *)mdev) {
10147dd7cddfSDavid du Colombier /* The following is a special hack for setting up printer devices. */
10157dd7cddfSDavid du Colombier assign_dev_procs(mdev, mdproto);
1016*593dc095SDavid du Colombier check_device_separable((gx_device *)mdev);
1017*593dc095SDavid du Colombier gx_device_fill_in_procs((gx_device *)mdev);
10187dd7cddfSDavid du Colombier } else
10197dd7cddfSDavid du Colombier gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0),
10207dd7cddfSDavid du Colombier (target == (gx_device *)mdev ? NULL : target));
10217dd7cddfSDavid du Colombier mdev->width = target->width;
10227dd7cddfSDavid du Colombier /*
10237dd7cddfSDavid du Colombier * The matrix in the memory device is irrelevant,
10247dd7cddfSDavid du Colombier * because all we do with the device is call the device-level
10257dd7cddfSDavid du Colombier * output procedures, but we may as well set it to
10267dd7cddfSDavid du Colombier * something halfway reasonable.
10277dd7cddfSDavid du Colombier */
10287dd7cddfSDavid du Colombier gs_deviceinitialmatrix(target, &mdev->initial_matrix);
10297dd7cddfSDavid du Colombier if (plane_index >= 0) {
10307dd7cddfSDavid du Colombier gx_device_plane_extract *edev =
10317dd7cddfSDavid du Colombier gs_alloc_struct(mem, gx_device_plane_extract,
10327dd7cddfSDavid du Colombier &st_device_plane_extract, "create_buf_device");
10337dd7cddfSDavid du Colombier
10347dd7cddfSDavid du Colombier if (edev == 0) {
10357dd7cddfSDavid du Colombier gx_default_destroy_buf_device((gx_device *)mdev);
10367dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
10377dd7cddfSDavid du Colombier }
10387dd7cddfSDavid du Colombier edev->memory = mem;
10397dd7cddfSDavid du Colombier plane_device_init(edev, target, (gx_device *)mdev, render_plane,
10407dd7cddfSDavid du Colombier false);
10417dd7cddfSDavid du Colombier bdev = (gx_device *)edev;
10427dd7cddfSDavid du Colombier } else
10437dd7cddfSDavid du Colombier bdev = (gx_device *)mdev;
10447dd7cddfSDavid du Colombier /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
10457dd7cddfSDavid du Colombier bdev->color_info = target->color_info;
10467dd7cddfSDavid du Colombier *pbdev = bdev;
10477dd7cddfSDavid du Colombier return 0;
10487dd7cddfSDavid du Colombier }
10497dd7cddfSDavid du Colombier
10507dd7cddfSDavid du Colombier /* Determine the space needed by the buffer device. */
10517dd7cddfSDavid du Colombier 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)10527dd7cddfSDavid du Colombier gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
10537dd7cddfSDavid du Colombier const gx_render_plane_t *render_plane,
10547dd7cddfSDavid du Colombier int height, bool for_band)
10557dd7cddfSDavid du Colombier {
10567dd7cddfSDavid du Colombier gx_device_memory mdev;
10577dd7cddfSDavid du Colombier
10587dd7cddfSDavid du Colombier mdev.color_info.depth =
10597dd7cddfSDavid du Colombier (render_plane && render_plane->index >= 0 ? render_plane->depth :
10607dd7cddfSDavid du Colombier target->color_info.depth);
10617dd7cddfSDavid du Colombier mdev.width = target->width;
10627dd7cddfSDavid du Colombier mdev.num_planes = 0;
10637dd7cddfSDavid du Colombier space->bits = gdev_mem_bits_size(&mdev, target->width, height);
10647dd7cddfSDavid du Colombier space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
10657dd7cddfSDavid du Colombier space->raster = gdev_mem_raster(&mdev);
10667dd7cddfSDavid du Colombier return 0;
10677dd7cddfSDavid du Colombier }
10687dd7cddfSDavid du Colombier
10697dd7cddfSDavid du Colombier /* Set up the buffer device. */
10707dd7cddfSDavid du Colombier 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)10717dd7cddfSDavid du Colombier gx_default_setup_buf_device(gx_device *bdev, byte *buffer, int bytes_per_line,
10727dd7cddfSDavid du Colombier byte **line_ptrs, int y, int setup_height,
10737dd7cddfSDavid du Colombier int full_height)
10747dd7cddfSDavid du Colombier {
10757dd7cddfSDavid du Colombier gx_device_memory *mdev =
10767dd7cddfSDavid du Colombier (gs_device_is_memory(bdev) ? (gx_device_memory *)bdev :
10777dd7cddfSDavid du Colombier (gx_device_memory *)(((gx_device_plane_extract *)bdev)->plane_dev));
10787dd7cddfSDavid du Colombier byte **ptrs = line_ptrs;
10797dd7cddfSDavid du Colombier int raster = bytes_per_line;
10807dd7cddfSDavid du Colombier int code;
10817dd7cddfSDavid du Colombier
10827dd7cddfSDavid du Colombier /****** HACK ******/
10837dd7cddfSDavid du Colombier if ((gx_device *)mdev == bdev && mdev->num_planes)
10847dd7cddfSDavid du Colombier raster = bitmap_raster(mdev->planes[0].depth * mdev->width);
10857dd7cddfSDavid du Colombier if (ptrs == 0) {
10867dd7cddfSDavid du Colombier /*
10877dd7cddfSDavid du Colombier * Allocate line pointers now; free them when we close the device.
10887dd7cddfSDavid du Colombier * Note that for multi-planar devices, we have to allocate using
10897dd7cddfSDavid du Colombier * full_height rather than setup_height.
10907dd7cddfSDavid du Colombier */
10917dd7cddfSDavid du Colombier ptrs = (byte **)
10927dd7cddfSDavid du Colombier gs_alloc_byte_array(mdev->memory,
10937dd7cddfSDavid du Colombier (mdev->num_planes ?
10947dd7cddfSDavid du Colombier full_height * mdev->num_planes :
10957dd7cddfSDavid du Colombier setup_height),
10967dd7cddfSDavid du Colombier sizeof(byte *), "setup_buf_device");
10977dd7cddfSDavid du Colombier if (ptrs == 0)
10987dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
10997dd7cddfSDavid du Colombier mdev->line_pointer_memory = mdev->memory;
11007dd7cddfSDavid du Colombier mdev->foreign_line_pointers = false;
11017dd7cddfSDavid du Colombier }
11027dd7cddfSDavid du Colombier mdev->height = full_height;
11037dd7cddfSDavid du Colombier code = gdev_mem_set_line_ptrs(mdev, buffer + raster * y, bytes_per_line,
11047dd7cddfSDavid du Colombier ptrs, setup_height);
11057dd7cddfSDavid du Colombier mdev->height = setup_height;
11067dd7cddfSDavid du Colombier bdev->height = setup_height; /* do here in case mdev == bdev */
11077dd7cddfSDavid du Colombier return code;
11087dd7cddfSDavid du Colombier }
11097dd7cddfSDavid du Colombier
11107dd7cddfSDavid du Colombier /* Destroy the buffer device. */
11117dd7cddfSDavid du Colombier void
gx_default_destroy_buf_device(gx_device * bdev)11127dd7cddfSDavid du Colombier gx_default_destroy_buf_device(gx_device *bdev)
11137dd7cddfSDavid du Colombier {
11147dd7cddfSDavid du Colombier gx_device *mdev = bdev;
11157dd7cddfSDavid du Colombier
11167dd7cddfSDavid du Colombier if (!gs_device_is_memory(bdev)) {
11177dd7cddfSDavid du Colombier /* bdev must be a plane extraction device. */
11187dd7cddfSDavid du Colombier mdev = ((gx_device_plane_extract *)bdev)->plane_dev;
11197dd7cddfSDavid du Colombier gs_free_object(bdev->memory, bdev, "destroy_buf_device");
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier dev_proc(mdev, close_device)(mdev);
11227dd7cddfSDavid du Colombier gs_free_object(mdev->memory, mdev, "destroy_buf_device");
11237dd7cddfSDavid du Colombier }
11247dd7cddfSDavid du Colombier
11257dd7cddfSDavid du Colombier /*
11267dd7cddfSDavid du Colombier * Copy one or more rasterized scan lines to a buffer, or return a pointer
11277dd7cddfSDavid du Colombier * to them. See gdevprn.h for detailed specifications.
11287dd7cddfSDavid du Colombier */
11297dd7cddfSDavid du Colombier 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)11307dd7cddfSDavid du Colombier gdev_prn_get_lines(gx_device_printer *pdev, int y, int height,
11317dd7cddfSDavid du Colombier byte *buffer, uint bytes_per_line,
11327dd7cddfSDavid du Colombier byte **actual_buffer, uint *actual_bytes_per_line,
11337dd7cddfSDavid du Colombier const gx_render_plane_t *render_plane)
11347dd7cddfSDavid du Colombier {
11357dd7cddfSDavid du Colombier int code;
11367dd7cddfSDavid du Colombier gs_int_rect rect;
11377dd7cddfSDavid du Colombier gs_get_bits_params_t params;
11387dd7cddfSDavid du Colombier int plane;
11397dd7cddfSDavid du Colombier
11407dd7cddfSDavid du Colombier if (y < 0 || height < 0 || y + height > pdev->height)
11417dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
11427dd7cddfSDavid du Colombier rect.p.x = 0, rect.p.y = y;
11437dd7cddfSDavid du Colombier rect.q.x = pdev->width, rect.q.y = y + height;
11447dd7cddfSDavid du Colombier params.options =
11457dd7cddfSDavid du Colombier GB_RETURN_POINTER | GB_ALIGN_STANDARD | GB_OFFSET_0 |
11467dd7cddfSDavid du Colombier GB_RASTER_ANY |
11477dd7cddfSDavid du Colombier /* No depth specified, we always use native colors. */
11487dd7cddfSDavid du Colombier GB_COLORS_NATIVE | GB_ALPHA_NONE;
11497dd7cddfSDavid du Colombier if (render_plane) {
11507dd7cddfSDavid du Colombier params.options |= GB_PACKING_PLANAR | GB_SELECT_PLANES;
11517dd7cddfSDavid du Colombier memset(params.data, 0,
11527dd7cddfSDavid du Colombier sizeof(params.data[0]) * pdev->color_info.num_components);
11537dd7cddfSDavid du Colombier plane = render_plane->index;
11547dd7cddfSDavid du Colombier params.data[plane] = buffer;
11557dd7cddfSDavid du Colombier } else {
11567dd7cddfSDavid du Colombier params.options |= GB_PACKING_CHUNKY;
11577dd7cddfSDavid du Colombier params.data[0] = buffer;
11587dd7cddfSDavid du Colombier plane = 0;
11597dd7cddfSDavid du Colombier }
11607dd7cddfSDavid du Colombier params.x_offset = 0;
11617dd7cddfSDavid du Colombier params.raster = bytes_per_line;
11627dd7cddfSDavid du Colombier code = dev_proc(pdev, get_bits_rectangle)
11637dd7cddfSDavid du Colombier ((gx_device *)pdev, &rect, ¶ms, NULL);
11647dd7cddfSDavid du Colombier if (code < 0 && actual_buffer) {
11657dd7cddfSDavid du Colombier /*
11667dd7cddfSDavid du Colombier * RETURN_POINTER might not be implemented for this
11677dd7cddfSDavid du Colombier * combination of parameters: try RETURN_COPY.
11687dd7cddfSDavid du Colombier */
11697dd7cddfSDavid du Colombier params.options &= ~(GB_RETURN_POINTER | GB_RASTER_ALL);
11707dd7cddfSDavid du Colombier params.options |= GB_RETURN_COPY | GB_RASTER_SPECIFIED;
11717dd7cddfSDavid du Colombier code = dev_proc(pdev, get_bits_rectangle)
11727dd7cddfSDavid du Colombier ((gx_device *)pdev, &rect, ¶ms, NULL);
11737dd7cddfSDavid du Colombier }
11747dd7cddfSDavid du Colombier if (code < 0)
11757dd7cddfSDavid du Colombier return code;
11767dd7cddfSDavid du Colombier if (actual_buffer)
11777dd7cddfSDavid du Colombier *actual_buffer = params.data[plane];
11787dd7cddfSDavid du Colombier if (actual_bytes_per_line)
11797dd7cddfSDavid du Colombier *actual_bytes_per_line = params.raster;
11807dd7cddfSDavid du Colombier return code;
11817dd7cddfSDavid du Colombier }
11827dd7cddfSDavid du Colombier
11837dd7cddfSDavid du Colombier
11847dd7cddfSDavid du Colombier /* Copy a scan line from the buffer to the printer. */
11857dd7cddfSDavid du Colombier int
gdev_prn_get_bits(gx_device_printer * pdev,int y,byte * str,byte ** actual_data)11867dd7cddfSDavid du Colombier gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
11877dd7cddfSDavid du Colombier {
11887dd7cddfSDavid du Colombier int code = (*dev_proc(pdev, get_bits)) ((gx_device *) pdev, y, str, actual_data);
11897dd7cddfSDavid du Colombier uint line_size = gdev_prn_raster(pdev);
11907dd7cddfSDavid du Colombier int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
11917dd7cddfSDavid du Colombier
11927dd7cddfSDavid du Colombier if (code < 0)
11937dd7cddfSDavid du Colombier return code;
11947dd7cddfSDavid du Colombier if (last_bits != 0) {
11957dd7cddfSDavid du Colombier byte *dest = (actual_data != 0 ? *actual_data : str);
11967dd7cddfSDavid du Colombier
11977dd7cddfSDavid du Colombier dest[line_size - 1] &= 0xff << last_bits;
11987dd7cddfSDavid du Colombier }
11997dd7cddfSDavid du Colombier return 0;
12007dd7cddfSDavid du Colombier }
12017dd7cddfSDavid du Colombier /* Copy scan lines to a buffer. Return the number of scan lines, */
12027dd7cddfSDavid du Colombier /* or <0 if error. This procedure is DEPRECATED. */
12037dd7cddfSDavid du Colombier int
gdev_prn_copy_scan_lines(gx_device_printer * pdev,int y,byte * str,uint size)12047dd7cddfSDavid du Colombier gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size)
12057dd7cddfSDavid du Colombier {
12067dd7cddfSDavid du Colombier uint line_size = gdev_prn_raster(pdev);
12077dd7cddfSDavid du Colombier int count = size / line_size;
12087dd7cddfSDavid du Colombier int i;
12097dd7cddfSDavid du Colombier byte *dest = str;
12107dd7cddfSDavid du Colombier
12117dd7cddfSDavid du Colombier count = min(count, pdev->height - y);
12127dd7cddfSDavid du Colombier for (i = 0; i < count; i++, dest += line_size) {
12137dd7cddfSDavid du Colombier int code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
12147dd7cddfSDavid du Colombier
12157dd7cddfSDavid du Colombier if (code < 0)
12167dd7cddfSDavid du Colombier return code;
12177dd7cddfSDavid du Colombier }
12187dd7cddfSDavid du Colombier return count;
12197dd7cddfSDavid du Colombier }
12207dd7cddfSDavid du Colombier
12217dd7cddfSDavid du Colombier /* Close the current page. */
12227dd7cddfSDavid du Colombier int
gdev_prn_close_printer(gx_device * pdev)12237dd7cddfSDavid du Colombier gdev_prn_close_printer(gx_device * pdev)
12247dd7cddfSDavid du Colombier {
12257dd7cddfSDavid du Colombier gx_device_printer * const ppdev = (gx_device_printer *)pdev;
12267dd7cddfSDavid du Colombier gs_parsed_file_name_t parsed;
12277dd7cddfSDavid du Colombier const char *fmt;
12287dd7cddfSDavid du Colombier int code = gx_parse_output_file_name(&parsed, &fmt, ppdev->fname,
12297dd7cddfSDavid du Colombier strlen(ppdev->fname));
12307dd7cddfSDavid du Colombier
12317dd7cddfSDavid du Colombier if ((code >= 0 && fmt) /* file per page */ ||
12327dd7cddfSDavid du Colombier ppdev->ReopenPerPage /* close and reopen for each page */
12337dd7cddfSDavid du Colombier ) {
12347dd7cddfSDavid du Colombier gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
12357dd7cddfSDavid du Colombier ppdev->file = NULL;
12367dd7cddfSDavid du Colombier }
12377dd7cddfSDavid du Colombier return 0;
12387dd7cddfSDavid du Colombier }
12397dd7cddfSDavid du Colombier
12407dd7cddfSDavid du Colombier /* If necessary, free and reallocate the printer memory after changing params */
12417dd7cddfSDavid du Colombier 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)12427dd7cddfSDavid du Colombier gdev_prn_maybe_realloc_memory(gx_device_printer *prdev,
12437dd7cddfSDavid du Colombier gdev_prn_space_params *old_sp,
1244*593dc095SDavid du Colombier int old_width, int old_height,
1245*593dc095SDavid du Colombier bool old_page_uses_transparency)
12467dd7cddfSDavid du Colombier {
12477dd7cddfSDavid du Colombier int code = 0;
12487dd7cddfSDavid du Colombier gx_device *const pdev = (gx_device *)prdev;
12497dd7cddfSDavid du Colombier /*gx_device_memory * const mdev = (gx_device_memory *)prdev;*/
12507dd7cddfSDavid du Colombier
12517dd7cddfSDavid du Colombier /*
12527dd7cddfSDavid du Colombier * The first test was changed to mdev->base != 0 in 5.50 (per Artifex).
12537dd7cddfSDavid du Colombier * Not only was this test wrong logically, it was incorrect in that
12547dd7cddfSDavid du Colombier * casting pdev to a (gx_device_memory *) is only meaningful if banding
12557dd7cddfSDavid du Colombier * is not being used. The test was changed back to prdev->is_open in
12567dd7cddfSDavid du Colombier * 5.67 (also per Artifex). For more information, see the News items
12577dd7cddfSDavid du Colombier * for these filesets.
12587dd7cddfSDavid du Colombier */
12597dd7cddfSDavid du Colombier if (prdev->is_open &&
12607dd7cddfSDavid du Colombier (memcmp(&prdev->space_params, old_sp, sizeof(*old_sp)) != 0 ||
1261*593dc095SDavid du Colombier prdev->width != old_width || prdev->height != old_height ||
1262*593dc095SDavid du Colombier prdev->page_uses_transparency != old_page_uses_transparency)
12637dd7cddfSDavid du Colombier ) {
12647dd7cddfSDavid du Colombier int new_width = prdev->width;
12657dd7cddfSDavid du Colombier int new_height = prdev->height;
12667dd7cddfSDavid du Colombier gdev_prn_space_params new_sp;
12677dd7cddfSDavid du Colombier
12687dd7cddfSDavid du Colombier #ifdef DEBUGGING_HACKS
12697dd7cddfSDavid du Colombier debug_dump_bytes((const byte *)old_sp, (const byte *)(old_sp + 1), "old");
12707dd7cddfSDavid du Colombier debug_dump_bytes((const byte *)&prdev->space_params,
12717dd7cddfSDavid du Colombier (const byte *)(&prdev->space_params + 1), "new");
12727dd7cddfSDavid du Colombier dprintf4("w=%d/%d, h=%d/%d\n", old_width, new_width, old_height, new_height);
12737dd7cddfSDavid du Colombier #endif /*DEBUGGING_HACKS*/
12747dd7cddfSDavid du Colombier new_sp = prdev->space_params;
12757dd7cddfSDavid du Colombier prdev->width = old_width;
12767dd7cddfSDavid du Colombier prdev->height = old_height;
12777dd7cddfSDavid du Colombier prdev->space_params = *old_sp;
12787dd7cddfSDavid du Colombier code = gdev_prn_reallocate_memory(pdev, &new_sp,
12797dd7cddfSDavid du Colombier new_width, new_height);
12807dd7cddfSDavid du Colombier /* If this fails, device should be usable w/old params, but */
12817dd7cddfSDavid du Colombier /* band files may not be open. */
12827dd7cddfSDavid du Colombier }
12837dd7cddfSDavid du Colombier return code;
12847dd7cddfSDavid du Colombier }
1285