Coverage Report

Created: 2025-06-10 06:58

/src/ghostpdl/base/gdevprn.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Generic printer driver support */
18
#include "ctype_.h"
19
#include "gdevprn.h"
20
#include "gp.h"
21
#include "gdevdevn.h"           /* for gs_devn_params_s */
22
#include "gsdevice.h"   /* for gs_deviceinitialmatrix */
23
#include "gxdevsop.h"   /* for gxdso_* */
24
#include "gsfname.h"
25
#include "gsparam.h"
26
#include "gxclio.h"
27
#include "gxgetbit.h"
28
#include "gdevplnx.h"
29
#include "gstrans.h"
30
#include "gxdownscale.h"
31
#include "gsbitops.h"
32
33
#include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */
34
35
/*#define DEBUGGING_HACKS*/
36
37
/* GC information */
38
static
39
0
ENUM_PTRS_WITH(device_printer_enum_ptrs, gx_device_printer *pdev);
40
0
    ENUM_PREFIX(st_device_clist_mutatable, 2);
41
0
    break;
42
0
case 0:ENUM_RETURN(gx_device_enum_ptr(pdev->parent));
43
0
case 1:ENUM_RETURN(gx_device_enum_ptr(pdev->child));
44
0
ENUM_PTRS_END
45
static
46
0
RELOC_PTRS_WITH(device_printer_reloc_ptrs, gx_device_printer *pdev)
47
0
{
48
0
    pdev->parent = gx_device_reloc_ptr(pdev->parent, gcst);
49
0
    pdev->child = gx_device_reloc_ptr(pdev->child, gcst);
50
0
    RELOC_PREFIX(st_device_clist_mutatable);
51
0
} RELOC_PTRS_END
52
public_st_device_printer();
53
54
/* ---------------- Standard device procedures ---------------- */
55
56
/* Forward references */
57
int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
58
                                  gdev_space_params *old_space,
59
                                  int old_width, int old_height,
60
                                  bool old_page_uses_transparency);
61
62
static int
63
gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok);
64
65
extern dev_proc_open_device(pattern_clist_open_device);
66
extern dev_proc_open_device(clist_open);
67
extern dev_proc_close_device(clist_close);
68
69
/* The function run in a background thread */
70
static void prn_print_page_in_background(void *data);
71
72
/* wait for a background thread to finish and clean up background printing */
73
static void prn_finish_bg_print(gx_device_printer *ppdev);
74
75
/* ------ Open/close ------ */
76
/* Open a generic printer device. */
77
/* Specific devices may wish to extend this. */
78
int
79
gdev_prn_open(gx_device * pdev)
80
0
{
81
0
    gx_device_printer * ppdev;
82
0
    int code;
83
0
    bool update_procs = false;
84
85
0
    code = install_internal_subclass_devices(&pdev, &update_procs);
86
0
    if (code < 0)
87
0
        return code;
88
89
0
    ppdev = (gx_device_printer *)pdev;
90
91
0
    ppdev->file = NULL;
92
0
    code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
93
0
    if (update_procs) {
94
0
        if (pdev->ObjectHandlerPushed) {
95
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_obj_filter_device);
96
0
            pdev = pdev->parent;
97
0
        }
98
0
        if (pdev->PageHandlerPushed) {
99
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_flp_device);
100
0
            pdev = pdev->parent;
101
0
        }
102
0
        if (pdev->NupHandlerPushed)
103
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_nup_device);
104
0
    }
105
0
    if (code < 0)
106
0
        return code;
107
0
    if (ppdev->OpenOutputFile)
108
0
        code = gdev_prn_open_printer(pdev, 1);
109
0
    return code;
110
0
}
111
112
/* This is called various places to wait for any pending bg print thread and */
113
/* perform its cleanup                                                       */
114
static void
115
prn_finish_bg_print(gx_device_printer *ppdev)
116
0
{
117
    /* if we have a a bg printing device that was created, then wait for its  */
118
    /* semaphore (it may already have been signalled, but that's OK.) then  */
119
    /* close and unlink the files and free the device and its private allocator */
120
0
    if (ppdev->bg_print && (ppdev->bg_print->device != NULL)) {
121
0
        int closecode;
122
0
        gx_device_printer *bgppdev = (gx_device_printer *)ppdev->bg_print->device;
123
124
0
        gx_semaphore_wait(ppdev->bg_print->sema);
125
        /* If numcopies > 1, then the bg_print->device will have closed and reopened
126
         * the output file, so the pointer in the original device is now stale,
127
         * so copy it back.
128
         * If numcopies == 1, this is pointless, but benign.
129
         */
130
0
        ppdev->file = bgppdev->file;
131
0
        closecode = gdev_prn_close_printer((gx_device *)ppdev);
132
0
        if (ppdev->bg_print->return_code == 0)
133
0
            ppdev->bg_print->return_code = closecode; /* return code here iff there wasn't another error */
134
0
        teardown_device_and_mem_for_thread(ppdev->bg_print->device,
135
0
                                           ppdev->bg_print->thread_id, true);
136
0
        ppdev->bg_print->device = NULL;
137
0
        if (ppdev->bg_print->ocfile) {
138
0
            closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->ocfile, ppdev->bg_print->ocfname, true);
139
0
            if (ppdev->bg_print->return_code == 0)
140
0
               ppdev->bg_print->return_code = closecode;
141
0
        }
142
0
        if (ppdev->bg_print->ocfname) {
143
0
            gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "prn_finish_bg_print(ocfname)");
144
0
        }
145
0
        if (ppdev->bg_print->obfile) {
146
0
            closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->obfile, ppdev->bg_print->obfname, true);
147
0
            if (ppdev->bg_print->return_code == 0)
148
0
               ppdev->bg_print->return_code = closecode;
149
0
        }
150
0
        if (ppdev->bg_print->obfname) {
151
0
            gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "prn_finish_bg_print(obfname)");
152
0
        }
153
0
        ppdev->bg_print->ocfile = ppdev->bg_print->obfile =
154
0
          ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL;
155
0
    }
156
0
}
157
/* Generic closing for the printer device. */
158
/* Specific devices may wish to extend this. */
159
int
160
gdev_prn_close(gx_device * pdev)
161
0
{
162
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
163
0
    int code = 0;
164
165
0
    prn_finish_bg_print(ppdev);
166
0
    if (ppdev->bg_print != NULL && ppdev->bg_print->sema != NULL) {
167
0
        gx_semaphore_free(ppdev->bg_print->sema);
168
0
        ppdev->bg_print->sema = NULL;   /* prevent double free */
169
0
    }
170
0
    gdev_prn_free_memory(pdev);
171
0
    if (ppdev->file != NULL) {
172
0
        code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
173
0
        ppdev->file = NULL;
174
0
    }
175
0
    return code;
176
0
}
177
178
int
179
gdev_prn_forwarding_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
180
0
{
181
0
    gx_device_printer *ppdev = (gx_device_printer *)pdev;
182
0
    int code;
183
184
    /* if the device is a printer device, we will get here, but allow for a printer device */
185
    /* that has a non-default dev_spec_op that may want to not support saved_pages, if so  */
186
    /* that device can return an error from the supports_saved_pages spec_op.              */
187
0
    code = ppdev->orig_procs.dev_spec_op(pdev, dev_spec_op, data, size);
188
0
    if (dev_spec_op == gxdso_supports_saved_pages) /* printer devices support saved pages */
189
0
        return code == 0 ? 1: code; /*default returns 0, but we still want saved-page support */
190
0
    return code;
191
0
}
192
193
int
194
gdev_prn_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
195
0
{
196
0
    if (dev_spec_op == gxdso_supports_saved_pages)
197
0
        return 1;
198
199
0
    if (dev_spec_op == gxdso_get_dev_param) {
200
0
        int code;
201
0
        dev_param_req_t *request = (dev_param_req_t *)data;
202
203
0
        code = gdev_prn_get_param(pdev, request->Param, request->list);
204
0
        if (code != gs_error_undefined)
205
0
            return code;
206
0
    }
207
208
#ifdef DEBUG
209
    if (dev_spec_op == gxdso_debug_printer_check)
210
        return 1;
211
#endif
212
213
0
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
214
0
}
215
216
static bool /* ret true if device was cmd list, else false */
217
gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
218
0
{
219
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
220
0
    gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
221
0
    gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
222
0
    gx_device_clist_common * const pcldev = &pclist_dev->common;
223
0
    gx_device_clist_reader * const pcrdev = &pclist_dev->reader;
224
0
    bool was_command_list;
225
226
0
    if (PRINTER_IS_CLIST(ppdev)) {
227
        /* Close cmd list device & point to the storage */
228
0
        clist_close( (gx_device *)pcldev );
229
0
        *the_memory = ppdev->buf;
230
0
        ppdev->buf = 0;
231
0
        ppdev->buffer_space = 0;
232
0
        pmemdev->base = 0;    /* in case finalize tries to free this */
233
0
        was_command_list = true;
234
235
0
        prn_finish_bg_print(ppdev);
236
237
0
        gs_free_object(pcldev->memory->non_gc_memory, pcldev->cache_chunk, "free tile cache for clist");
238
0
        pcldev->cache_chunk = 0;
239
240
0
        rc_decrement(pcldev->icc_cache_cl, "gdev_prn_tear_down");
241
0
        pcldev->icc_cache_cl = NULL;
242
243
0
        clist_free_icc_table(pcldev->icc_table, pcldev->memory);
244
0
        pcldev->icc_table = NULL;
245
246
        /* If the clist is a reader clist, free any color_usage_array
247
         * memory used by same.
248
         */
249
0
        if (!CLIST_IS_WRITER(pclist_dev))
250
0
            gs_free_object(pcrdev->memory, pcrdev->color_usage_array, "clist_color_usage_array");
251
252
0
    } else {
253
        /* point at the device bitmap, no need to close mem dev */
254
0
        *the_memory = pmemdev->base;
255
0
        pmemdev->base = 0;
256
0
        was_command_list = false;
257
0
    }
258
259
    /* Reset device proc vector to default */
260
0
    if (ppdev->orig_procs.open_device != NULL)
261
0
        pdev->procs = ppdev->orig_procs;
262
0
    ppdev->orig_procs.open_device = NULL; /* prevent uninit'd restore of procs */
263
264
0
    return was_command_list;
265
0
}
266
267
static int
268
gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
269
                  int new_width, int new_height, bool reallocate)
270
0
{
271
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
272
0
    gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
273
0
    byte *the_memory = 0;
274
0
    gdev_space_params save_params = ppdev->space_params;
275
0
    int save_width = 0x0badf00d; /* Quiet compiler */
276
0
    int save_height = 0x0badf00d; /* Quiet compiler */
277
0
    bool is_command_list = false; /* Quiet compiler */
278
0
    bool save_is_command_list = false; /* Quiet compiler */
279
0
    bool size_ok = 0;
280
0
    int ecode = 0;
281
0
    int code;
282
0
    int pass;
283
0
    gs_memory_t *buffer_memory =
284
0
        (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
285
0
         ppdev->buffer_memory);
286
0
    bool deep = device_is_deep(pdev);
287
288
    /* If reallocate, find allocated memory & tear down buffer device */
289
0
    if (reallocate)
290
0
        save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
291
292
293
    /* bg_print allocation is not fatal, we just continue (as far as possible) without BGPrint */
294
0
    if (ppdev->bg_print == NULL)
295
0
        ppdev->bg_print = (bg_print_t *)gs_alloc_bytes(pdev->memory->non_gc_memory, sizeof(bg_print_t), "prn bg_print");
296
0
    if (ppdev->bg_print == NULL) {
297
0
        emprintf(pdev->memory, "Failed to allocate memory for BGPrint, attempting to continue without BGPrint\n");
298
0
    } else {
299
0
        memset(ppdev->bg_print, 0, sizeof(bg_print_t));
300
0
    }
301
302
    /* Re/allocate memory */
303
0
    ppdev->orig_procs = pdev->procs;
304
0
    for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
305
0
        size_t mem_space;
306
0
        size_t pdf14_trans_buffer_size = 0;
307
0
        byte *base = 0;
308
0
        bool bufferSpace_is_default = false;
309
0
        gdev_space_params space_params;
310
0
        gx_device_buf_space_t buf_space;
311
312
0
        if (reallocate)
313
0
            switch (pass)
314
0
                {
315
0
                case 1:
316
                    /* Setup device to get reallocated */
317
0
                    ppdev->space_params = *new_space_params;
318
0
                    save_width = ppdev->width;
319
0
                    ppdev->width = new_width;
320
0
                    save_height = ppdev->height;
321
0
                    ppdev->height = new_height;
322
0
                    break;
323
0
                case 2: /* only comes here if reallocate */
324
                    /* Restore device to previous contents */
325
0
                    ppdev->space_params = save_params;
326
0
                    ppdev->width = save_width;
327
0
                    ppdev->height = save_height;
328
0
                    break;
329
0
                }
330
331
        /* Init clist/mem device-specific fields */
332
0
        memset(ppdev->skip, 0, sizeof(ppdev->skip));
333
0
        size_ok = ppdev->printer_procs.buf_procs.size_buf_device
334
0
            (&buf_space, pdev, NULL, pdev->height, false) >= 0;
335
336
        /* Make sure we won't overflow a size_t, if we do then we'll use a clist below */
337
0
        if (ARCH_MAX_SIZE_T - buf_space.bits < buf_space.line_ptrs)
338
0
            size_ok = 0;
339
340
0
        mem_space = buf_space.bits + buf_space.line_ptrs;
341
0
        if (ppdev->page_uses_transparency) {
342
0
            pdf14_trans_buffer_size = (ESTIMATED_PDF14_ROW_SPACE(max(1, pdev->width), pdev->color_info.num_components, deep ? 16 : 8) >> 3);
343
0
            if (new_height < (max_size_t - mem_space) / pdf14_trans_buffer_size) {
344
0
                pdf14_trans_buffer_size *= pdev->height;
345
0
            } else {
346
0
                size_ok = 0;
347
0
            }
348
0
        }
349
350
        /* Compute desired space params: never use the space_params as-is. */
351
        /* Rather, give the dev-specific driver a chance to adjust them. */
352
0
        space_params = ppdev->space_params;
353
0
        space_params.BufferSpace = 0;
354
0
        (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
355
0
        if (space_params.BufferSpace == 0) {
356
0
            if (space_params.band.BandBufferSpace > 0)
357
0
                space_params.BufferSpace = space_params.band.BandBufferSpace;
358
0
            else {
359
0
                space_params.BufferSpace = ppdev->space_params.BufferSpace;
360
0
                bufferSpace_is_default = true;
361
0
            }
362
0
        }
363
364
        /* Determine if we can use a full bitmap buffer, or have to use banding */
365
0
        if (pass > 1)
366
0
            is_command_list = save_is_command_list;
367
0
        else {
368
0
            is_command_list = space_params.banding_type == BandingAlways ||
369
0
                ppdev->saved_pages_list != NULL ||
370
0
                mem_space + pdf14_trans_buffer_size >= space_params.MaxBitmap ||
371
0
                !size_ok;     /* too big to allocate */
372
0
        }
373
0
        if (!is_command_list) {
374
0
            byte *trans_buffer_reserve_space = NULL;
375
376
            /* Try to allocate memory for full memory buffer, then allocate the
377
               pdf14_trans_buffer_size to make sure we have enough space for that */
378
            /* NOTE: Assumes that caller won't normally call this function if page
379
               size didn't actually change, so we can free/alloc without checking
380
               that the new size is different than old size.
381
            */
382
0
            if (reallocate) {
383
0
                gs_free_object(buffer_memory, the_memory, "printer_buffer");
384
0
                the_memory = NULL;
385
0
            }
386
0
            base = gs_alloc_bytes(buffer_memory, mem_space, "printer_buffer");
387
0
            if (base == 0)
388
0
                is_command_list = true;
389
0
            else
390
0
                the_memory = base;
391
0
            trans_buffer_reserve_space = gs_alloc_bytes(buffer_memory, (uint)pdf14_trans_buffer_size,
392
0
                                                        "pdf14_trans_buffer_reserve test");
393
0
            if (trans_buffer_reserve_space == NULL) {
394
                /* the pdf14 reserve test failed, switch to clist mode, the 'base' memory freed below */
395
0
                is_command_list = true;
396
0
            } else {
397
0
                gs_free_object(buffer_memory, trans_buffer_reserve_space, "pdf14_trans_buffer_reserve OK");
398
0
            }
399
0
        }
400
0
        if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
401
0
            && buffer_memory == pdev->memory->non_gc_memory) {
402
            /* before using full memory buffer, ensure enough working mem left */
403
0
            byte * left = gs_alloc_bytes( buffer_memory,
404
0
                                          PRN_MIN_MEMORY_LEFT, "printer mem left");
405
0
            if (left == 0)
406
0
                is_command_list = true;
407
0
            else
408
0
                gs_free_object(buffer_memory, left, "printer mem left");
409
0
        }
410
411
0
        if (is_command_list) {
412
            /* Buffer the image in a command list. */
413
            /* Release the buffer if we allocated it. */
414
0
            int code;
415
0
            gx_device_printer * const ppdev = (gx_device_printer *)pdev;
416
417
0
            if (!reallocate) {
418
0
                gs_free_object(buffer_memory, the_memory,
419
0
                               "printer buffer(open)");
420
0
                the_memory = 0;
421
0
            }
422
0
            if (space_params.banding_type == BandingNever) {
423
0
                ecode = gs_note_error(gs_error_VMerror);
424
0
                continue;
425
0
            }
426
0
            if (ppdev->bg_print) {
427
0
                ppdev->bg_print->ocfname = ppdev->bg_print->obfname =
428
0
                    ppdev->bg_print->obfile = ppdev->bg_print->ocfile = NULL;
429
0
            }
430
431
0
            code = clist_mutate_to_clist((gx_device_clist_mutatable *)pdev,
432
0
                                         buffer_memory,
433
0
                                         &the_memory, &space_params,
434
0
                                         !bufferSpace_is_default,
435
0
                                         &ppdev->printer_procs.buf_procs,
436
0
                                         gdev_prn_forwarding_dev_spec_op,
437
0
                                         PRN_MIN_BUFFER_SPACE);
438
0
            if (ecode == 0)
439
0
                ecode = code;
440
441
0
            if (code >= 0 || (reallocate && pass > 1)) {
442
0
                ppdev->initialize_device_procs = clist_initialize_device_procs;
443
                /* Hacky - we know this can't fail. */
444
0
                (void)ppdev->initialize_device_procs((gx_device *)ppdev);
445
0
                gx_device_fill_in_procs((gx_device *)ppdev);
446
0
            }
447
0
        } else {
448
            /* Render entirely in memory. */
449
0
            gx_device *bdev = (gx_device *)pmemdev;
450
0
            int code;
451
452
0
            ppdev->buffer_space = 0;
453
0
            if ((code = gdev_create_buf_device
454
0
                 (ppdev->printer_procs.buf_procs.create_buf_device,
455
0
                  &bdev, pdev, 0, NULL, NULL, NULL)) < 0 ||
456
0
                (code = ppdev->printer_procs.buf_procs.setup_buf_device
457
0
                 (bdev, base, buf_space.raster,
458
0
                  (byte **)(base + buf_space.bits), 0, pdev->height,
459
0
                  pdev->height)) < 0
460
0
                ) {
461
                /* Catastrophic. Shouldn't ever happen */
462
0
                gs_free_object(buffer_memory, base, "printer buffer");
463
0
                pdev->procs = ppdev->orig_procs;
464
0
                ppdev->orig_procs.open_device = 0;  /* prevent uninit'd restore of procs */
465
0
                gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
466
0
                ppdev->bg_print = NULL;
467
0
                return_error(code);
468
0
            }
469
0
        }
470
0
        if (ecode == 0)
471
0
            break;
472
0
    }
473
474
0
    if (ecode >= 0 || reallocate) { /* even if realloc failed */
475
        /* Synthesize the procedure vector. */
476
        /* Rendering operations come from the memory or clist device, */
477
        /* non-rendering come from the printer device. */
478
0
#define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
479
0
        COPY_PROC(get_initial_matrix);
480
0
        COPY_PROC(output_page);
481
0
        COPY_PROC(close_device);
482
0
        COPY_PROC(map_rgb_color);
483
0
        COPY_PROC(map_color_rgb);
484
0
        COPY_PROC(get_params);
485
0
        COPY_PROC(put_params);
486
0
        COPY_PROC(map_cmyk_color);
487
        /* All printers are page devices, even if they didn't use the */
488
        /* standard macros for generating their procedure vectors. */
489
0
        set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
490
0
        COPY_PROC(get_clipping_box);
491
0
        COPY_PROC(get_hardware_params);
492
0
        COPY_PROC(get_color_mapping_procs);
493
0
        COPY_PROC(get_color_comp_index);
494
0
        COPY_PROC(encode_color);
495
0
        COPY_PROC(decode_color);
496
0
        COPY_PROC(update_spot_equivalent_colors);
497
0
        COPY_PROC(ret_devn_params);
498
        /* This can be set from the memory device (planar) or target */
499
0
        if ( dev_proc(ppdev, put_image) == gx_default_put_image )
500
0
            set_dev_proc(ppdev, put_image, ppdev->orig_procs.put_image);
501
0
#undef COPY_PROC
502
        /* If using a command list, already opened the device. */
503
0
        if (is_command_list)
504
0
            code = ecode;
505
0
        else
506
            /* If this open_device fails, do we need to free everything? */
507
0
            code = (*dev_proc(pdev, open_device))(pdev);
508
0
    } else {
509
0
        pdev->procs = ppdev->orig_procs;
510
0
        ppdev->orig_procs.open_device = 0;  /* prevent uninit'd restore of procs */
511
0
        code = ecode;
512
0
    }
513
0
    if (code < 0) {
514
0
          gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
515
0
          ppdev->bg_print = NULL;
516
0
    }
517
0
    return code;
518
0
}
519
520
int
521
gdev_prn_allocate_memory(gx_device *pdev,
522
                         gdev_space_params *new_space_params,
523
                         int new_width, int new_height)
524
0
{
525
0
    return gdev_prn_allocate(pdev, new_space_params,
526
0
                             new_width, new_height, false);
527
0
}
528
529
int
530
gdev_prn_reallocate_memory(gx_device *pdev,
531
                         gdev_space_params *new_space_params,
532
                         int new_width, int new_height)
533
0
{
534
0
    return gdev_prn_allocate(pdev, new_space_params,
535
0
                             new_width, new_height, true);
536
0
}
537
538
int
539
gdev_prn_free_memory(gx_device *pdev)
540
0
{
541
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
542
0
    byte *the_memory = 0;
543
0
    gs_memory_t *buffer_memory =
544
0
        (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
545
0
         ppdev->buffer_memory);
546
547
0
    gdev_prn_tear_down(pdev, &the_memory);
548
0
    gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "gdev_prn_free_memory");
549
0
    ppdev->bg_print = NULL;
550
0
    gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory");
551
0
    return 0;
552
0
}
553
554
/* for saved pages, we need to make sure and free up the saved_pages_list */
555
void
556
gdev_prn_finalize(gx_device *pdev)
557
0
{
558
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
559
560
0
    if (ppdev->saved_pages_list != NULL) {
561
0
        gx_saved_pages_list_free(ppdev->saved_pages_list);
562
0
        ppdev->saved_pages_list = NULL;
563
0
    }
564
0
}
565
566
567
/* ------ Get/put parameters ------ */
568
569
int
570
gdev_prn_get_param(gx_device *dev, char *Param, void *list)
571
0
{
572
0
    gx_device_printer * const ppdev = (gx_device_printer *)dev;
573
0
    gs_param_list * plist = (gs_param_list *)list;
574
0
    bool pageneutralcolor = false;
575
576
0
    if (strcmp(Param, "Duplex") == 0) {
577
0
        if (ppdev->Duplex_set >= 0) {
578
0
            if (ppdev->Duplex_set)
579
0
                return param_write_bool(plist, "Duplex", &ppdev->Duplex);
580
0
            else
581
0
                return param_write_null(plist, "Duplex");
582
0
        }
583
0
    }
584
0
    if (strcmp(Param, "NumRenderingThreads") == 0) {
585
0
        return param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested);
586
0
    }
587
0
    if (strcmp(Param, "OpenOutputFile") == 0) {
588
0
        return param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile);
589
0
    }
590
0
    if (strcmp(Param, "BGPrint") == 0) {
591
0
        return param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested);
592
0
    }
593
0
    if (strcmp(Param, "ReopenPerPage") == 0) {
594
0
        return param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage);
595
0
    }
596
0
    if (strcmp(Param, "BandListStorage") == 0) {
597
0
        gs_param_string bls;
598
0
        gs_lib_ctx_core_t *core = dev->memory->gs_lib_ctx->core;
599
        /* Force the default to 'memory' if clist file I/O is not included in this build */
600
0
        if (core->clist_io_procs_file == NULL)
601
0
            ppdev->BLS_force_memory = true;
602
0
        if (ppdev->BLS_force_memory) {
603
0
            bls.data = (byte *)"memory";
604
0
            bls.size = 6;
605
0
            bls.persistent = false;
606
0
        } else {
607
0
            bls.data = (byte *)"file";
608
0
            bls.size = 4;
609
0
            bls.persistent = false;
610
0
        }
611
0
        return param_write_string(plist, "BandListStorage", &bls);
612
0
    }
613
0
    if (strcmp(Param, "OutputFile") == 0) {
614
0
        gs_param_string ofns;
615
616
0
        ofns.data = (const byte *)ppdev->fname,
617
0
        ofns.size = strlen(ppdev->fname),
618
0
        ofns.persistent = false;
619
0
        return param_write_string(plist, "OutputFile", &ofns);
620
0
    }
621
0
    if (strcmp(Param, "saved-pages") == 0) {
622
0
        gs_param_string saved_pages;
623
        /* Always return an empty string for saved-pages */
624
0
        saved_pages.data = (const byte *)"";
625
0
        saved_pages.size = 0;
626
0
        saved_pages.persistent = false;
627
0
        return param_write_string(plist, "saved-pages", &saved_pages);
628
0
    }
629
0
    if (dev->icc_struct != NULL)
630
0
        pageneutralcolor = dev->icc_struct->pageneutralcolor;
631
0
    if (strcmp(Param, "pageneutralcolor") == 0) {
632
0
        return param_write_bool(plist, "pageneutralcolor", &pageneutralcolor);
633
0
    }
634
0
    return gx_default_get_param(dev, Param, list);
635
0
}
636
637
/* Get parameters.  Printer devices add several more parameters */
638
/* to the default set. */
639
int
640
gdev_prn_get_params(gx_device * pdev, gs_param_list * plist)
641
0
{
642
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
643
0
    int code = gx_default_get_params(pdev, plist);
644
0
    gs_param_string ofns;
645
0
    gs_param_string bls;
646
0
    gs_param_string saved_pages;
647
0
    bool pageneutralcolor = false;
648
0
    gs_lib_ctx_core_t *core = pdev->memory->gs_lib_ctx->core;
649
650
0
    if (pdev->icc_struct != NULL)
651
0
        pageneutralcolor = pdev->icc_struct->pageneutralcolor;
652
0
    if (code < 0 ||
653
0
        (ppdev->Duplex_set >= 0 &&
654
0
        (code = (ppdev->Duplex_set ?
655
0
                  param_write_bool(plist, "Duplex", &ppdev->Duplex) :
656
0
                  param_write_null(plist, "Duplex"))) < 0) ||
657
0
        (code = param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested)) < 0 ||
658
0
        (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 ||
659
0
        (code = param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested)) < 0 ||
660
0
        (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 ||
661
0
        (code = param_write_bool(plist, "pageneutralcolor", &pageneutralcolor)) < 0
662
0
        )
663
0
        return code;
664
665
    /* Force the default to 'memory' if clist file I/O is not included in this build */
666
0
    if (core->clist_io_procs_file == NULL)
667
0
        ppdev->BLS_force_memory = true;
668
0
    if (ppdev->BLS_force_memory) {
669
0
        bls.data = (byte *)"memory";
670
0
        bls.size = 6;
671
0
        bls.persistent = false;
672
0
    } else {
673
0
        bls.data = (byte *)"file";
674
0
        bls.size = 4;
675
0
        bls.persistent = false;
676
0
    }
677
0
    if( (code = param_write_string(plist, "BandListStorage", &bls)) < 0 )
678
0
        return code;
679
680
0
    ofns.data = (const byte *)ppdev->fname,
681
0
        ofns.size = strlen(ppdev->fname),
682
0
        ofns.persistent = false;
683
0
    if ((code = param_write_string(plist, "OutputFile", &ofns)) < 0)
684
0
        return code;
685
686
    /* Always return an empty string for saved-pages so that get_params followed */
687
    /* by put_params will have no effect.                                       */
688
0
    saved_pages.data = (const byte *)"";
689
0
    saved_pages.size = 0;
690
0
    saved_pages.persistent = false;
691
0
    return param_write_string(plist, "saved-pages", &saved_pages);
692
0
}
693
694
/* Validate an OutputFile name by checking any %-formats. */
695
static int
696
validate_output_file(const gs_param_string * ofs, gs_memory_t *memory)
697
0
{
698
0
    gs_parsed_file_name_t parsed;
699
0
    const char *fmt;
700
701
0
    return gx_parse_output_file_name(&parsed, &fmt, (const char *)ofs->data,
702
0
                                     ofs->size, memory) >= 0;
703
0
}
704
705
/* Put parameters. */
706
int
707
gdev_prn_put_params(gx_device * pdev, gs_param_list * plist)
708
0
{
709
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
710
0
    int ecode = 0;
711
0
    int code;
712
0
    const char *param_name;
713
0
    bool is_open = pdev->is_open;
714
0
    bool oof = ppdev->OpenOutputFile;
715
0
    bool rpp = ppdev->ReopenPerPage;
716
0
    bool old_page_uses_transparency = ppdev->page_uses_transparency;
717
0
    bool bg_print_requested = ppdev->bg_print_requested;
718
0
    bool duplex;
719
0
    int duplex_set = -1;
720
0
    int width = pdev->width;
721
0
    int height = pdev->height;
722
0
    int nthreads = ppdev->num_render_threads_requested;
723
0
    gdev_space_params save_sp;
724
0
    gs_param_string ofs;
725
0
    gs_param_string bls;
726
0
    gs_param_dict mdict;
727
0
    gs_param_string saved_pages;
728
0
    bool pageneutralcolor = false;
729
0
    gs_lib_ctx_core_t *core = ppdev->memory->gs_lib_ctx->core;
730
731
0
    memset(&saved_pages, 0, sizeof(gs_param_string));
732
0
    save_sp = ppdev->space_params;
733
734
0
    switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) {
735
0
        default:
736
0
            ecode = code;
737
0
            param_signal_error(plist, param_name, ecode);
738
0
        case 0:
739
0
        case 1:
740
0
            break;
741
0
    }
742
743
0
    switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) {
744
0
        default:
745
0
            ecode = code;
746
0
            param_signal_error(plist, param_name, ecode);
747
0
        case 0:
748
0
        case 1:
749
0
            break;
750
0
    }
751
752
0
    if (ppdev->Duplex_set >= 0) /* i.e., Duplex is supported */
753
0
        switch (code = param_read_bool(plist, (param_name = "Duplex"),
754
0
                                       &duplex)) {
755
0
            case 0:
756
0
                duplex_set = 1;
757
0
                break;
758
0
            default:
759
0
                if ((code = param_read_null(plist, param_name)) == 0) {
760
0
                    duplex_set = 0;
761
0
                    break;
762
0
                }
763
0
                ecode = code;
764
0
                param_signal_error(plist, param_name, ecode);
765
0
            case 1:
766
0
                ;
767
0
        }
768
0
    switch (code = param_read_string(plist, (param_name = "BandListStorage"), &bls)) {
769
0
        case 0:
770
            /* Only accept 'file' if the file procs are include in the build */
771
0
            if ((bls.size > 1) && (bls.data[0] == 'm' ||
772
0
                 (core->clist_io_procs_file != NULL && bls.data[0] == 'f')))
773
0
                break;
774
            /* fall through */
775
0
        default:
776
0
            ecode = code;
777
0
            param_signal_error(plist, param_name, ecode);
778
            /* fall through */
779
0
        case 1:
780
0
            bls.data = 0;
781
0
            break;
782
0
    }
783
784
0
    switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) {
785
0
        case 0:
786
0
            if (pdev->LockSafetyParams &&
787
0
                    bytes_compare(ofs.data, ofs.size,
788
0
                        (const byte *)ppdev->fname, strlen(ppdev->fname))) {
789
0
                code = gs_error_invalidaccess;
790
0
            }
791
0
            else
792
0
                code = validate_output_file(&ofs, pdev->memory);
793
0
            if (code >= 0)
794
0
                break;
795
            /* fall through */
796
0
        default:
797
0
            ecode = code;
798
0
            param_signal_error(plist, param_name, ecode);
799
            /* fall through */
800
0
        case 1:
801
0
            ofs.data = 0;
802
0
            break;
803
0
    }
804
805
    /* Read InputAttributes and OutputAttributes just for the type */
806
    /* check and to indicate that they aren't undefined. */
807
0
#define read_media(pname)\
808
0
        switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
809
0
          {\
810
0
          case 0:\
811
0
                param_end_read_dict(plist, pname, &mdict);\
812
0
                break;\
813
0
          default:\
814
0
                ecode = code;\
815
0
                param_signal_error(plist, param_name, ecode);\
816
0
          case 1:\
817
0
                ;\
818
0
          }
819
820
0
    read_media("InputAttributes");
821
0
    read_media("OutputAttributes");
822
823
0
    switch (code = param_read_int(plist, (param_name = "NumRenderingThreads"), &nthreads)) {
824
0
        case 0:
825
0
            break;
826
0
        default:
827
0
            ecode = code;
828
0
            param_signal_error(plist, param_name, ecode);
829
0
        case 1:
830
0
            ;
831
0
    }
832
0
    switch (code = param_read_bool(plist, (param_name = "BGPrint"),
833
0
                                                        &bg_print_requested)) {
834
0
        default:
835
0
            ecode = code;
836
0
            param_signal_error(plist, param_name, ecode);
837
0
        case 0:
838
0
        case 1:
839
0
            break;
840
0
    }
841
842
0
    switch (code = param_read_string(plist, (param_name = "saved-pages"),
843
0
                                                        &saved_pages)) {
844
0
        default:
845
0
            ecode = code;
846
0
            param_signal_error(plist, param_name, ecode);
847
0
        case 0:
848
0
        case 1:
849
0
            break;
850
0
    }
851
852
    /* NB: put_params to change pageneutralcolor is allowed, but has no effect */
853
    /*     It will be set according the GrayDetection. Allowing it prevents errors */
854
0
    if (pdev->icc_struct != NULL)
855
0
        pageneutralcolor = pdev->icc_struct->pageneutralcolor;
856
0
    if ((code = param_read_bool(plist, (param_name = "pageneutralcolor"),
857
0
                                                        &pageneutralcolor)) < 0) {
858
0
        ecode = code;
859
0
        param_signal_error(plist, param_name, ecode);
860
0
    }
861
862
0
    if (ecode < 0)
863
0
        return ecode;
864
    /* Prevent gx_default_put_params from closing the printer. */
865
0
    pdev->is_open = false;
866
0
    code = gx_default_put_params(pdev, plist);
867
0
    pdev->is_open = is_open;
868
0
    if (code < 0)
869
0
        return code;
870
871
0
    ppdev->OpenOutputFile = oof;
872
0
    ppdev->ReopenPerPage = rpp;
873
874
    /* If BGPrint was previously true and it is being turned off, wait for the BG thread */
875
0
    if (ppdev->bg_print_requested && !bg_print_requested) {
876
0
        prn_finish_bg_print(ppdev);
877
0
    }
878
879
0
    ppdev->bg_print_requested = bg_print_requested;
880
0
    if (duplex_set >= 0) {
881
0
        ppdev->Duplex = duplex;
882
0
        ppdev->Duplex_set = duplex_set;
883
0
    }
884
0
    ppdev->num_render_threads_requested = nthreads;
885
0
    if (bls.data != 0) {
886
0
        ppdev->BLS_force_memory = (bls.data[0] == 'm');
887
0
    }
888
889
    /* If necessary, free and reallocate the printer memory. */
890
    /* Formerly, would not reallocate if device is not open: */
891
    /* we had to patch this out (see News for 5.50). */
892
0
    code = gdev_prn_maybe_realloc_memory(ppdev, &save_sp, width, height,
893
0
                                         old_page_uses_transparency);
894
0
    if (code < 0)
895
0
        return code;
896
897
    /* If filename changed, close file. */
898
0
    if (ofs.data != 0 &&
899
0
        bytes_compare(ofs.data, ofs.size,
900
0
                      (const byte *)ppdev->fname, strlen(ppdev->fname))
901
0
        ) {
902
        /* Close the file if it's open. */
903
0
        if (ppdev->file != NULL) {
904
0
            gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
905
0
        }
906
0
        ppdev->file = NULL;
907
0
        if (sizeof(ppdev->fname) <= ofs.size)
908
0
            return_error(gs_error_limitcheck);
909
0
        memcpy(ppdev->fname, ofs.data, ofs.size);
910
0
        ppdev->fname[ofs.size] = 0;
911
0
    }
912
    /* If the device is open and OpenOutputFile is true, */
913
    /* open the OutputFile now.  (If the device isn't open, */
914
    /* this will happen when it is opened.) */
915
0
    if (pdev->is_open && oof) {
916
0
        code = gdev_prn_open_printer(pdev, 1);
917
0
        if (code < 0)
918
0
            return code;
919
0
    }
920
921
    /* Processing the saved_pages string MAY have side effects, such as printing, */
922
    /* allocating or freeing a list. This is (sort of) a write-only parameter, so */
923
    /* the get_params will always return an empty string (a no-op action).        */
924
0
    if (saved_pages.data != 0 && saved_pages.size != 0) {
925
0
        return gx_saved_pages_param_process(ppdev, (byte *)saved_pages.data, saved_pages.size);
926
0
    }
927
0
    return 0;
928
0
}
929
930
/* ------ Others ------ */
931
932
/* Default routine to (not) override current space_params. */
933
void
934
gx_default_get_space_params(const gx_device_printer *printer_dev,
935
                            gdev_space_params *space_params)
936
0
{
937
0
    return;
938
0
}
939
940
/* Common routine to send the page to the printer.                               */
941
/* If seekable is true, then the printer outputfile must be seekable.            */
942
/* If bg_print_ok is true, the device print_page_copies is compatible with the   */
943
/* background printing, i.e., thread safe and does not change the device.        */
944
/* If the printer device is in 'saved_pages' mode, then background printing is   */
945
/* irrelevant and is ignored. In this case, pages are saved to the list.         */
946
static int  /* 0 ok, -ve error                                               */
947
gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok)
948
0
{
949
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
950
0
    gs_devn_params *pdevn_params;
951
0
    int outcode = 0, errcode = 0, endcode, closecode = 0;
952
0
    int code;
953
954
0
    prn_finish_bg_print(ppdev);   /* finish any previous background printing */
955
956
0
    if (num_copies > 0 && ppdev->saved_pages_list != NULL) {
957
        /* We are putting pages on a list */
958
0
        if ((code = gx_saved_pages_list_add(ppdev)) < 0)
959
0
            return code;
960
961
0
    } else if (num_copies > 0 || !flush) {
962
0
        if ((code = gdev_prn_open_printer_seekable(pdev, 1, seekable)) < 0)
963
0
            return code;
964
965
0
        if (num_copies > 0) {
966
0
            int threads_enabled = 0;
967
0
            int print_foreground = 1;   /* default to foreground printing */
968
969
0
            if (bg_print_ok && PRINTER_IS_CLIST(ppdev) && ppdev->bg_print &&
970
0
                (ppdev->bg_print_requested || ppdev->num_render_threads_requested > 0)) {
971
0
                threads_enabled = clist_enable_multi_thread_render(pdev);
972
0
            }
973
            /* NB: we leave the semaphore allocated until foreground printing or close */
974
            /* If there was an error, abort on this page -- no good way to handle this */
975
            /* but it means that the error will be reported AFTER another page was     */
976
            /* interpreted and written to clist files. FIXME: ???                      */
977
0
            if (ppdev->bg_print && (ppdev->bg_print->return_code < 0)) {
978
0
                outcode = ppdev->bg_print->return_code;
979
0
                threads_enabled = 0;  /* and allow current page to try foreground */
980
0
            }
981
            /* Use 'while' instead of 'if' to avoid nesting */
982
0
            while (ppdev->bg_print_requested && ppdev->bg_print && threads_enabled) {
983
0
                gx_device *ndev;
984
0
                gx_device_printer *npdev;
985
0
                gx_device_clist_reader *crdev = (gx_device_clist_reader *)ppdev;
986
987
0
                if ((code = clist_close_writer_and_init_reader((gx_device_clist *)ppdev)) < 0)
988
                    /* should not happen -- do foreground print */
989
0
                    break;
990
991
                /* We need to hang onto references to these files, so we can ensure the main file data
992
                 * gets freed with the correct allocator.
993
                 */
994
0
                ppdev->bg_print->ocfname =
995
0
                     (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory,
996
0
                           strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1, "gdev_prn_output_page_aux(ocfname)");
997
0
                ppdev->bg_print->obfname =
998
0
                     (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory,
999
0
                           strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1,"gdev_prn_output_page_aux(ocfname)");
1000
1001
0
                if (!ppdev->bg_print->ocfname || !ppdev->bg_print->obfname)
1002
0
                    break;
1003
1004
0
                strncpy(ppdev->bg_print->ocfname, crdev->page_info.cfname, strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1);
1005
0
                strncpy(ppdev->bg_print->obfname, crdev->page_info.bfname, strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1);
1006
0
                ppdev->bg_print->obfile = crdev->page_info.bfile;
1007
0
                ppdev->bg_print->ocfile = crdev->page_info.cfile;
1008
0
                ppdev->bg_print->oio_procs = crdev->page_info.io_procs;
1009
0
                crdev->page_info.cfile = crdev->page_info.bfile = NULL;
1010
1011
0
                if (ppdev->bg_print->sema == NULL)
1012
0
                {
1013
0
                    ppdev->bg_print->sema = gx_semaphore_label(gx_semaphore_alloc(ppdev->memory->non_gc_memory), "BGPrint");
1014
0
                    if (ppdev->bg_print->sema == NULL)
1015
0
                        break;     /* couldn't create the semaphore */
1016
0
                }
1017
1018
0
                ndev = setup_device_and_mem_for_thread(pdev->memory->thread_safe_memory, pdev, true, NULL);
1019
0
                if (ndev == NULL) {
1020
0
                    break;
1021
0
                }
1022
0
                ppdev->bg_print->device = ndev;
1023
0
                ppdev->bg_print->num_copies = num_copies;
1024
0
                npdev = (gx_device_printer *)ndev;
1025
0
                npdev->bg_print_requested = 0;
1026
0
                npdev->num_render_threads_requested = ppdev->num_render_threads_requested;
1027
                /* The bgprint's device was created with normal procs, so multi-threaded */
1028
                /* rendering was turned off. Re-enable it now if it is needed.           */
1029
0
                if (npdev->num_render_threads_requested > 0) {
1030
                    /* ignore return code - even if it fails, we'll output the page */
1031
0
                    (void)clist_enable_multi_thread_render(ndev);
1032
0
                }
1033
1034
                /* Now start the thread to print the page */
1035
0
                if ((code = gp_thread_start(prn_print_page_in_background,
1036
0
                                            (void *)(ppdev->bg_print),
1037
0
                                            &(ppdev->bg_print->thread_id))) < 0) {
1038
                    /* Did not start cleanly - clean up is in print_foreground block below */
1039
0
                    break;
1040
0
                }
1041
0
                gp_thread_label(ppdev->bg_print->thread_id, "BG print thread");
1042
                /* Page was succesfully started in bg_print mode */
1043
0
                print_foreground = 0;
1044
                /* Now we need to set up the next page so it will use new clist files */
1045
0
                if ((code = clist_open(pdev)) < 0)   /* this should do it */
1046
                    /* OOPS! can't proceed with the next page */
1047
0
                    return code; /* probably ioerror */
1048
0
                break;       /* exit the while loop */
1049
0
            }
1050
0
            if (print_foreground) {
1051
0
                if (ppdev->bg_print) {
1052
0
                     gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "gdev_prn_output_page_aux(ocfname)");
1053
0
                     gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "gdev_prn_output_page_aux(obfname)");
1054
0
                     ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL;
1055
1056
                    /* either bg_print was not requested or was not able to start */
1057
0
                    if (ppdev->bg_print->sema != NULL && ppdev->bg_print->device != NULL) {
1058
                        /* There was a problem. Teardown the device and its allocator, but */
1059
                        /* leave the semaphore for possible later use.                     */
1060
0
                        teardown_device_and_mem_for_thread(ppdev->bg_print->device,
1061
0
                                                           ppdev->bg_print->thread_id, true);
1062
0
                        ppdev->bg_print->device = NULL;
1063
0
                    }
1064
0
                }
1065
                /* Here's where we actually let the device's print_page_copies work */
1066
                /* Print the accumulated page description. */
1067
0
                outcode = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
1068
0
                                                          num_copies);
1069
0
                gp_fflush(ppdev->file);
1070
0
                errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1071
                /* NB: background printing does this differently in its thread */
1072
0
                closecode = gdev_prn_close_printer(pdev);
1073
1074
0
            }
1075
0
        }
1076
0
    }
1077
    /* In the case of a separation device, we need to make sure we */
1078
    /* clear the separation info before the next page starts.      */
1079
0
    pdevn_params = dev_proc(pdev, ret_devn_params)(pdev);
1080
0
    if (pdevn_params != NULL) {
1081
        /* Free up the list of spot names as they were only relevent to that page */
1082
0
        free_separation_names(pdev->memory, &(pdevn_params->separations));
1083
0
        pdevn_params->num_separation_order_names = 0;
1084
0
    }
1085
0
    endcode = (PRINTER_IS_CLIST(ppdev) &&
1086
0
              !((gx_device_clist_common *)ppdev)->do_not_open_or_close_bandfiles ?
1087
0
              clist_finish_page(pdev, flush) : 0);
1088
1089
0
    if (outcode < 0)
1090
0
        return outcode;
1091
0
    if (errcode < 0)
1092
0
        return errcode;
1093
0
    if (endcode < 0)
1094
0
        return endcode;
1095
0
    endcode = gx_finish_output_page(pdev, num_copies, flush);
1096
0
    code = (endcode < 0 ? endcode : closecode < 0 ? closecode : 0);
1097
0
    return code;
1098
0
}
1099
1100
int
1101
gdev_prn_output_page(gx_device * pdev, int num_copies, int flush)
1102
0
{
1103
0
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, false));
1104
0
}
1105
1106
int
1107
gdev_prn_output_page_seekable(gx_device * pdev, int num_copies, int flush)
1108
0
{
1109
0
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, false));
1110
0
}
1111
1112
int
1113
gdev_prn_bg_output_page(gx_device * pdev, int num_copies, int flush)
1114
0
{
1115
0
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, true));
1116
0
}
1117
1118
int
1119
gdev_prn_bg_output_page_seekable(gx_device * pdev, int num_copies, int flush)
1120
0
{
1121
0
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, true));
1122
0
}
1123
1124
/* Print a single copy of a page by calling print_page_copies. */
1125
int
1126
gx_print_page_single_copy(gx_device_printer * pdev, gp_file * prn_stream)
1127
0
{
1128
0
    return pdev->printer_procs.print_page_copies(pdev, prn_stream, 1);
1129
0
}
1130
1131
/* Print multiple copies of a page by calling print_page multiple times. */
1132
int
1133
gx_default_print_page_copies(gx_device_printer * pdev, gp_file * prn_stream,
1134
                             int num_copies)
1135
0
{
1136
0
    int i = 1;
1137
0
    int code = 0;
1138
1139
0
    for (; i < num_copies; ++i) {
1140
0
        int errcode, closecode;
1141
1142
0
        code = (*pdev->printer_procs.print_page) (pdev, prn_stream);
1143
0
        if (code < 0)
1144
0
            return code;
1145
        /*
1146
         * Close and re-open the printer, to reset is_new and do the
1147
         * right thing if we're producing multiple output files.
1148
         * Code is mostly copied from gdev_prn_output_page.
1149
         */
1150
0
        gp_fflush(pdev->file);
1151
0
        errcode =
1152
0
            (gp_ferror(pdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1153
0
        closecode = gdev_prn_close_printer((gx_device *)pdev);
1154
0
        pdev->PageCount++;
1155
0
        code = (errcode < 0 ? errcode : closecode < 0 ? closecode :
1156
0
                gdev_prn_open_printer((gx_device *)pdev, true));
1157
0
        if (code < 0) {
1158
0
            pdev->PageCount -= i;
1159
0
            return code;
1160
0
        }
1161
0
        prn_stream = pdev->file;
1162
0
    }
1163
    /* Print the last (or only) page. */
1164
0
    pdev->PageCount -= num_copies - 1;
1165
0
    return (*pdev->printer_procs.print_page) (pdev, prn_stream);
1166
0
}
1167
1168
/*
1169
 * Print a page in the background. When printing is complete,
1170
 * post the return code and signal the foreground (semaphore).
1171
 * This is the procedure that is run in the background thread.
1172
 */
1173
static void
1174
prn_print_page_in_background(void *data)
1175
0
{
1176
0
    bg_print_t *bg_print = (bg_print_t *)data;
1177
0
    int code, errcode = 0;
1178
0
    int num_copies = bg_print->num_copies;
1179
0
    gx_device_printer *ppdev = (gx_device_printer *)bg_print->device;
1180
1181
0
    code = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
1182
0
                                                          num_copies);
1183
0
    gp_fflush(ppdev->file);
1184
1185
0
    errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1186
0
    bg_print->return_code = code < 0 ? code : errcode;
1187
1188
    /* Finally, release the foreground that may be waiting */
1189
0
    gx_semaphore_signal(bg_print->sema);
1190
0
}
1191
/* ---------------- Driver services ---------------- */
1192
1193
/* Initialize a rendering plane specification. */
1194
int
1195
gx_render_plane_init(gx_render_plane_t *render_plane, const gx_device *dev,
1196
                     int index)
1197
0
{
1198
    /*
1199
     * Eventually the computation of shift and depth from dev and index
1200
     * will be made device-dependent.
1201
     */
1202
0
    int num_planes = dev->color_info.num_components;
1203
0
    int plane_depth = dev->color_info.depth / num_planes;
1204
1205
0
    if (index < -1 || index >= num_planes)
1206
0
        return_error(gs_error_rangecheck);
1207
0
    render_plane->index = index;
1208
0
    if (index == -1) {
1209
        /* No plane, chunky results required. */
1210
0
        render_plane->depth = dev->color_info.depth;
1211
0
        render_plane->shift = 0;
1212
0
    } else {
1213
        /* A single plane */
1214
0
        render_plane->depth = plane_depth;
1215
0
        render_plane->shift = plane_depth * (num_planes - 1 - index);
1216
0
    }
1217
0
    return 0;
1218
0
}
1219
1220
/* Clear trailing bits in the last byte of (a) scan line(s). */
1221
void
1222
gdev_prn_clear_trailing_bits(byte *data, uint raster, int height,
1223
                             const gx_device *dev)
1224
0
{
1225
0
    int first_bit = dev->width * dev->color_info.depth;
1226
1227
0
    if (first_bit & 7)
1228
0
        bits_fill_rectangle(data, first_bit, raster, mono_fill_make_pattern(0),
1229
0
                            -first_bit & 7, height);
1230
0
}
1231
1232
/* Return the number of scan lines that should actually be passed */
1233
/* to the device. */
1234
int
1235
gdev_prn_print_scan_lines(gx_device * pdev)
1236
0
{
1237
0
    int height = pdev->height;
1238
0
    gs_matrix imat;
1239
0
    float yscale;
1240
0
    int top, bottom, offset, end;
1241
1242
0
    (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
1243
0
    yscale = imat.yy * 72.0;  /* Y dpi, may be negative */
1244
0
    top = (int)(dev_t_margin(pdev) * yscale);
1245
0
    bottom = (int)(dev_b_margin(pdev) * yscale);
1246
0
    offset = (int)(dev_y_offset(pdev) * yscale);
1247
0
    if (yscale < 0) {   /* Y=0 is top of page */
1248
0
        end = -offset + height + bottom;
1249
0
    } else {     /* Y=0 is bottom of page */
1250
0
        end = offset + height - top;
1251
0
    }
1252
0
    return min(height, end);
1253
0
}
1254
1255
/* Open the current page for printing. */
1256
int
1257
gdev_prn_open_printer_seekable(gx_device *pdev, bool binary_mode,
1258
                               bool seekable)
1259
0
{
1260
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1261
1262
0
    if (ppdev->file != 0) {
1263
0
        ppdev->file_is_new = false;
1264
0
        return 0;
1265
0
    }
1266
0
    {
1267
0
        int code = gx_device_open_output_file(pdev, ppdev->fname,
1268
0
                                              binary_mode, seekable,
1269
0
                                              &ppdev->file);
1270
0
        if (code < 0)
1271
0
            return code;
1272
1273
0
        if (seekable && !gp_fseekable(ppdev->file)) {
1274
0
            errprintf(pdev->memory, "I/O Error: Output File \"%s\" must be seekable\n", ppdev->fname);
1275
0
            if (!IS_LIBCTX_STDOUT(pdev->memory, gp_get_file(ppdev->file))
1276
0
              && !IS_LIBCTX_STDERR(pdev->memory, gp_get_file(ppdev->file))) {
1277
1278
0
                code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
1279
0
                ppdev->file = NULL;
1280
0
                if (code < 0)
1281
0
                    return code;
1282
0
            }
1283
0
            ppdev->file = NULL;
1284
1285
0
            return_error(gs_error_ioerror);
1286
0
        }
1287
0
    }
1288
0
    ppdev->file_is_new = true;
1289
1290
0
    return 0;
1291
0
}
1292
int
1293
gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
1294
0
{
1295
0
    return gdev_prn_open_printer_seekable(pdev, binary_mode, false);
1296
0
}
1297
1298
/*
1299
 * Test whether the printer's output file was just opened, i.e., whether
1300
 * this is the first page being written to this file.  This is only valid
1301
 * at the entry to a driver's print_page procedure.
1302
 */
1303
bool
1304
gdev_prn_file_is_new(const gx_device_printer *pdev)
1305
0
{
1306
0
    return pdev->file_is_new;
1307
0
}
1308
1309
/* Determine the colors used in a range of lines. */
1310
/* FIXME: Currently, the page_info is ignored and the page_info from
1311
 * the 'dev' parameter is used. For saved pages, the 'dev' may not
1312
 * be a clist and the page_info should be used for clist file info
1313
 * which may require a dummy gx_device_printer with the page_info
1314
 * copied from the caller's data.
1315
 */
1316
int
1317
gx_page_info_color_usage(const gx_device *dev,
1318
                         const gx_band_page_info_t *page_info,
1319
                         int y, int height,
1320
                         gx_color_usage_t *color_usage, int *range_start)
1321
0
{
1322
0
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)dev;
1323
0
    int start, end, i;
1324
0
    int band_height = page_info->band_params.BandHeight;
1325
0
    gx_color_usage_bits or = 0;
1326
0
    bool slow_rop = false;
1327
1328
0
    if (y < 0 || height < 0 || height > dev->height - y)
1329
0
        return -1;
1330
0
    start = y / band_height;
1331
0
    end = (y + height + band_height - 1) / band_height;
1332
0
    if (crdev->color_usage_array == NULL) {
1333
0
        return -1;
1334
0
    }
1335
0
    for (i = start; i < end; ++i) {
1336
0
        or |= crdev->color_usage_array[i].or;
1337
0
        slow_rop |= crdev->color_usage_array[i].slow_rop;
1338
0
    }
1339
0
    color_usage->or = or;
1340
0
    color_usage->slow_rop = slow_rop;
1341
0
    *range_start = start * band_height;
1342
0
    return min(end * band_height, dev->height) - *range_start;
1343
0
}
1344
int
1345
gdev_prn_color_usage(gx_device *dev, int y, int height,
1346
                     gx_color_usage_t *color_usage, int *range_start)
1347
0
{
1348
0
    gx_device_printer *pdev = (gx_device_printer *)dev;
1349
0
    gx_device_clist *cdev = (gx_device_clist *)dev;
1350
0
    gx_device_clist_writer *cldev = (gx_device_clist_writer *)dev;
1351
1352
    /* If this isn't a banded device, return default values. */
1353
0
    if (!PRINTER_IS_CLIST(pdev)) {
1354
0
        *range_start = 0;
1355
0
        color_usage->or = gx_color_usage_all(dev);
1356
0
        return dev->height;
1357
0
    }
1358
0
    if (y < 0 || height < 0 || height > dev->height - y)
1359
0
        return -1;
1360
0
    if (CLIST_IS_WRITER(cdev)) {
1361
        /* Not expected to be used since usually this is called during reading */
1362
0
        return clist_writer_color_usage(cldev, y, height, color_usage, range_start);
1363
0
    } else
1364
0
        return gx_page_info_color_usage(dev, &cldev->page_info,
1365
0
                                 y, height, color_usage, range_start);
1366
0
}
1367
1368
/*
1369
 * Create the buffer device for a printer device.  Clients should always
1370
 * call this, and never call the device procedure directly.
1371
 */
1372
int
1373
gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev,
1374
                       gx_device *target, int y,
1375
                       const gx_render_plane_t *render_plane,
1376
                       gs_memory_t *mem, gx_color_usage_t *color_usage)
1377
0
{
1378
0
    int code = cbd_proc(pbdev, target, y, render_plane, mem, color_usage);
1379
1380
0
    if (code < 0)
1381
0
        return code;
1382
    /* Retain this device -- it will be freed explicitly. */
1383
0
    gx_device_retain(*pbdev, true);
1384
0
    return code;
1385
0
}
1386
1387
/*
1388
 * Create an ordinary memory device for page or band buffering,
1389
 * possibly preceded by a plane extraction device.
1390
 */
1391
int
1392
gx_default_create_buf_device(gx_device **pbdev, gx_device *target, int y,
1393
    const gx_render_plane_t *render_plane, gs_memory_t *mem, gx_color_usage_t *color_usage)
1394
0
{
1395
0
    int plane_index = (render_plane ? render_plane->index : -1);
1396
0
    int depth;
1397
0
    const gx_device_memory *mdproto;
1398
0
    gx_device_memory *mdev;
1399
0
    gx_device *bdev;
1400
1401
0
    if (plane_index >= 0)
1402
0
        depth = render_plane->depth;
1403
0
    else {
1404
0
        depth = target->color_info.depth;
1405
0
        if (target->num_planar_planes)
1406
0
            depth /= target->num_planar_planes;
1407
0
    }
1408
1409
0
    mdproto = gdev_mem_device_for_bits(depth);
1410
0
    if (mdproto == 0)
1411
0
        return_error(gs_error_rangecheck);
1412
0
    if (mem) {
1413
0
        mdev = gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1414
0
                               "create_buf_device");
1415
0
        if (mdev == 0)
1416
0
            return_error(gs_error_VMerror);
1417
0
    } else {
1418
0
        mdev = (gx_device_memory *)*pbdev;
1419
0
    }
1420
0
    if (target == (gx_device *)mdev) {
1421
0
        dev_t_proc_dev_spec_op((*orig_dso), gx_device) = dev_proc(mdev, dev_spec_op);
1422
        /* The following is a special hack for setting up printer devices. */
1423
0
        assign_dev_procs(mdev, mdproto);
1424
0
        mdev->initialize_device_procs = mdproto->initialize_device_procs;
1425
0
        mdev->initialize_device_procs((gx_device *)mdev);
1426
        /* We know mdev->procs.initialize_device is NULL! */
1427
        /* Do not override the dev_spec_op! */
1428
0
        dev_proc(mdev, dev_spec_op) = orig_dso;
1429
0
        check_device_separable((gx_device *)mdev);
1430
        /* In order for saved-pages to work, we need to hook the dev_spec_op */
1431
0
        if (mdev->procs.dev_spec_op == NULL || mdev->procs.dev_spec_op == gx_default_dev_spec_op)
1432
0
            set_dev_proc(mdev, dev_spec_op, gdev_prn_dev_spec_op);
1433
#ifdef DEBUG
1434
        /* scanning sources didn't show anything, but if a device gets changed or added */
1435
        /* that has its own dev_spec_op, it should call the gdev_prn_spec_op as well    */
1436
        else {
1437
            if (dev_proc(mdev, dev_spec_op)((gx_device *)mdev, gxdso_debug_printer_check, NULL, 0) < 0)
1438
                errprintf(mdev->memory, "Warning: printer device has private dev_spec_op\n");
1439
        }
1440
#endif
1441
0
        gx_device_fill_in_procs((gx_device *)mdev);
1442
0
    } else {
1443
0
        gs_devn_params* pdevn_params;
1444
1445
0
        gs_make_mem_device(mdev, mdproto, mem, (color_usage == NULL ? 1 : 0), target);
1446
        /* mem devices may need to refer to the target's devn_params struct */
1447
        /* if the device has separations already defined (by SeparationOrderNames), we   */
1448
        /* need to use them so the colorants are in the same order as the target device. */
1449
0
        pdevn_params = dev_proc(target, ret_devn_params)(target);
1450
0
        if (pdevn_params != NULL) {
1451
0
            mdev->procs.ret_devn_params = gx_forward_ret_devn_params;
1452
0
        }
1453
0
    }
1454
0
    mdev->width = target->width;
1455
0
    mdev->band_y = y;
1456
0
    mdev->log2_align_mod = target->log2_align_mod;
1457
0
    mdev->pad = target->pad;
1458
0
    mdev->num_planar_planes = target->num_planar_planes;
1459
    /*
1460
     * The matrix in the memory device is irrelevant,
1461
     * because all we do with the device is call the device-level
1462
     * output procedures, but we may as well set it to
1463
     * something halfway reasonable.
1464
     */
1465
0
    gs_deviceinitialmatrix(target, &mdev->initial_matrix);
1466
0
    if (plane_index >= 0) {
1467
0
        gx_device_plane_extract *edev;
1468
1469
        /* Guard against potential NULL dereference in gs_alloc_struct */
1470
0
        if (!mem)
1471
0
            return_error(gs_error_undefined);
1472
1473
0
        edev = gs_alloc_struct(mem, gx_device_plane_extract,
1474
0
                            &st_device_plane_extract, "create_buf_device");
1475
1476
0
        if (edev == 0) {
1477
0
            gx_default_destroy_buf_device((gx_device *)mdev);
1478
0
            return_error(gs_error_VMerror);
1479
0
        }
1480
0
        edev->memory = mem;
1481
0
        plane_device_init(edev, target, (gx_device *)mdev, render_plane,
1482
0
                          false);
1483
0
        bdev = (gx_device *)edev;
1484
0
    } else
1485
0
        bdev = (gx_device *)mdev;
1486
    /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
1487
0
    if (&bdev->color_info != &target->color_info) /* Pacify Valgrind */
1488
0
        bdev->color_info = target->color_info;
1489
0
    *pbdev = bdev;
1490
0
    return 0;
1491
0
}
1492
1493
/* Determine the space needed by the buffer device. */
1494
int
1495
gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
1496
                           const gx_render_plane_t *render_plane,
1497
                           int height, bool not_used)
1498
0
{
1499
0
    gx_device_memory mdev;
1500
1501
0
    space->line_ptrs = 0; /*        */
1502
0
    space->bits = 0;    /* clear in case of failure */
1503
0
    space->raster = 0;    /*        */
1504
0
    mdev.color_info.depth =
1505
0
        (render_plane && render_plane->index >= 0 ? render_plane->depth :
1506
0
         target->color_info.depth);
1507
0
    mdev.color_info.num_components = target->color_info.num_components;
1508
0
    mdev.width = target->width;
1509
0
    mdev.num_planar_planes = target->num_planar_planes;
1510
0
    mdev.pad = target->pad;
1511
0
    mdev.log2_align_mod = target->log2_align_mod;
1512
0
    if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0)
1513
0
        return_error(gs_error_VMerror);
1514
0
    space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
1515
0
    space->raster = gdev_mem_raster(&mdev);
1516
0
    return 0;
1517
0
}
1518
1519
/* Set up the buffer device. */
1520
int
1521
gx_default_setup_buf_device(gx_device *bdev, byte *buffer, int raster,
1522
                            byte **line_ptrs, int y, int setup_height,
1523
                            int full_height)
1524
0
{
1525
0
    gx_device_memory *mdev =
1526
0
        (gs_device_is_memory(bdev) ? (gx_device_memory *)bdev :
1527
0
         (gx_device_memory *)(((gx_device_plane_extract *)bdev)->plane_dev));
1528
0
    byte **ptrs = line_ptrs;
1529
0
    int code;
1530
1531
0
    if (ptrs == 0) {
1532
        /*
1533
         * Before allocating a new line pointer array, if there is a previous
1534
         * array, free it to prevent leaks.
1535
         */
1536
0
        if (mdev->line_ptrs != NULL)
1537
0
            gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs,
1538
0
                       "mem_close");
1539
        /*
1540
         * Allocate line pointers now; free them when we close the device.
1541
         * Note that for multi-planar devices, we have to allocate using
1542
         * full_height rather than setup_height.
1543
         */
1544
0
        ptrs = (byte **)
1545
0
            gs_alloc_byte_array(mdev->memory,
1546
0
                                (mdev->num_planar_planes ?
1547
0
                                 full_height * mdev->num_planar_planes :
1548
0
                                 setup_height),
1549
0
                                sizeof(byte *), "setup_buf_device");
1550
0
        if (ptrs == 0)
1551
0
            return_error(gs_error_VMerror);
1552
0
        mdev->line_pointer_memory = mdev->memory;
1553
0
        mdev->foreign_line_pointers = false;
1554
0
    }
1555
0
    mdev->height = full_height;
1556
0
    code = gdev_mem_set_line_ptrs(mdev, buffer + raster * y, raster,
1557
0
                                  ptrs, setup_height);
1558
0
    mdev->height = setup_height;
1559
0
    bdev->height = setup_height; /* do here in case mdev == bdev */
1560
0
    return code;
1561
0
}
1562
1563
/* Destroy the buffer device. */
1564
void
1565
gx_default_destroy_buf_device(gx_device *bdev)
1566
0
{
1567
0
    gx_device *mdev = bdev;
1568
1569
0
    if (!gs_device_is_memory(bdev)) {
1570
        /* bdev must be a plane extraction device. */
1571
0
        mdev = ((gx_device_plane_extract *)bdev)->plane_dev;
1572
0
        gs_free_object(bdev->memory, bdev, "destroy_buf_device");
1573
0
    }
1574
    /* gs_free_object will do finalize which will decrement icc profile */
1575
0
    dev_proc(mdev, close_device)(mdev);
1576
0
    gs_free_object(mdev->memory, mdev, "destroy_buf_device");
1577
0
}
1578
1579
/*
1580
 * Copy one or more rasterized scan lines to a buffer, or return a pointer
1581
 * to them.  See gdevprn.h for detailed specifications.
1582
 */
1583
int
1584
gdev_prn_get_lines(gx_device_printer *pdev, int y, int height,
1585
                   byte *buffer, uint bytes_per_line,
1586
                   byte **actual_buffer, uint *actual_bytes_per_line,
1587
                   const gx_render_plane_t *render_plane)
1588
0
{
1589
0
    int code;
1590
0
    gs_int_rect rect;
1591
0
    gs_get_bits_params_t params;
1592
0
    int plane;
1593
1594
0
    if (y < 0 || height < 0 || y + height > pdev->height)
1595
0
        return_error(gs_error_rangecheck);
1596
0
    rect.p.x = 0, rect.p.y = y;
1597
0
    rect.q.x = pdev->width, rect.q.y = y + height;
1598
0
    params.options =
1599
0
        GB_RETURN_POINTER | GB_ALIGN_STANDARD | GB_OFFSET_0 |
1600
0
        GB_RASTER_ANY |
1601
        /* No depth specified, we always use native colors. */
1602
0
        GB_COLORS_NATIVE | GB_ALPHA_NONE;
1603
0
    if (render_plane) {
1604
0
        params.options |= GB_PACKING_PLANAR | GB_SELECT_PLANES;
1605
0
        memset(params.data, 0,
1606
0
               sizeof(params.data[0]) * pdev->color_info.num_components);
1607
0
        plane = render_plane->index;
1608
0
        params.data[plane] = buffer;
1609
0
    } else {
1610
0
        params.options |= GB_PACKING_CHUNKY;
1611
0
        params.data[0] = buffer;
1612
0
        plane = 0;
1613
0
    }
1614
0
    params.x_offset = 0;
1615
0
    params.raster = bytes_per_line;
1616
0
    code = dev_proc(pdev, get_bits_rectangle)
1617
0
        ((gx_device *)pdev, &rect, &params);
1618
0
    if (code < 0 && actual_buffer) {
1619
        /*
1620
         * RETURN_POINTER might not be implemented for this
1621
         * combination of parameters: try RETURN_COPY.
1622
         */
1623
0
        params.options &= ~(GB_RETURN_POINTER | GB_RASTER_ALL);
1624
0
        params.options |= GB_RETURN_COPY | GB_RASTER_SPECIFIED;
1625
0
        code = dev_proc(pdev, get_bits_rectangle)
1626
0
            ((gx_device *)pdev, &rect, &params);
1627
0
    }
1628
0
    if (code < 0)
1629
0
        return code;
1630
0
    if (actual_buffer)
1631
0
        *actual_buffer = params.data[plane];
1632
0
    if (actual_bytes_per_line)
1633
0
        *actual_bytes_per_line = params.raster;
1634
0
    return code;
1635
0
}
1636
1637
/* Copy a scan line from the buffer to the printer. */
1638
int
1639
gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
1640
0
{
1641
0
    int code;
1642
0
    uint line_size = gdev_prn_raster(pdev);
1643
0
    int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
1644
0
    gs_int_rect rect;
1645
0
    gs_get_bits_params_t params;
1646
1647
0
    rect.p.x = 0;
1648
0
    rect.p.y = y;
1649
0
    rect.q.x = pdev->width;
1650
0
    rect.q.y = y+1;
1651
1652
0
    params.options = (GB_ALIGN_ANY |
1653
0
                      GB_RETURN_COPY |
1654
0
                      GB_OFFSET_0 |
1655
0
                      GB_RASTER_STANDARD | GB_PACKING_CHUNKY |
1656
0
                      GB_COLORS_NATIVE | GB_ALPHA_NONE);
1657
0
    if (actual_data)
1658
0
        params.options |=  GB_RETURN_POINTER;
1659
0
    params.x_offset = 0;
1660
0
    params.raster = bitmap_raster(pdev->width * pdev->color_info.depth);
1661
0
    params.data[0] = str;
1662
0
    code = (*dev_proc(pdev, get_bits_rectangle))((gx_device *)pdev, &rect,
1663
0
                                                 &params);
1664
0
    if (code < 0)
1665
0
        return code;
1666
0
    if (actual_data)
1667
0
        *actual_data = params.data[0];
1668
0
    if (last_bits != 0) {
1669
0
        byte *dest = (actual_data != NULL ? *actual_data : str);
1670
1671
0
        dest[line_size - 1] &= 0xff << last_bits;
1672
0
    }
1673
0
    return 0;
1674
0
}
1675
/* Copy scan lines to a buffer.  Return the number of scan lines, */
1676
/* or <0 if error.  This procedure is DEPRECATED. */
1677
/* Some old and contrib drivers ignore error codes, so make sure and fill */
1678
/* remaining lines if we get an error (and for lines past end of page).   */
1679
int
1680
gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size)
1681
0
{
1682
0
    uint line_size = gdev_prn_raster(pdev);
1683
0
    int requested_count = 0;
1684
0
    int i, count;
1685
0
    int code = 0;
1686
0
    byte *dest = str;
1687
1688
0
    if (line_size != 0)
1689
0
        requested_count = size / line_size;
1690
1691
    /* Clamp count between 0 and remaining lines on page so we don't return < 0 */
1692
    /* unless gdev_prn_get_bits returns an error */
1693
0
    count = max(0, min(requested_count, pdev->height - y));
1694
0
    for (i = 0; i < count; i++, dest += line_size) {
1695
0
        code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
1696
0
        if (code < 0)
1697
0
            break; /* will fill remaining lines and return code outside the loop */
1698
0
    }
1699
    /* fill remaining lines with 0's to prevent printing garbage */
1700
0
    memset(dest, 0, (size_t)line_size * (requested_count - i));
1701
0
    return (code < 0 ) ? code : count;
1702
0
}
1703
1704
/* Close the current page. */
1705
int
1706
gdev_prn_close_printer(gx_device * pdev)
1707
0
{
1708
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1709
0
    gs_parsed_file_name_t parsed;
1710
0
    const char *fmt;
1711
0
    int code = gx_parse_output_file_name(&parsed, &fmt, ppdev->fname,
1712
0
                                         strlen(ppdev->fname), pdev->memory);
1713
1714
0
    if ((code >= 0 && fmt) /* file per page */ ||
1715
0
        ppdev->ReopenPerPage  /* close and reopen for each page */
1716
0
        ) {
1717
0
        gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
1718
0
        ppdev->file = NULL;
1719
0
    }
1720
0
    return 0;
1721
0
}
1722
1723
/* If necessary, free and reallocate the printer memory after changing params */
1724
int
1725
gdev_prn_maybe_realloc_memory(gx_device_printer *prdev,
1726
                              gdev_space_params *old_sp,
1727
                              int old_width, int old_height,
1728
                              bool old_page_uses_transparency)
1729
0
{
1730
0
    int code = 0;
1731
0
    gx_device *const pdev = (gx_device *)prdev;
1732
    /*gx_device_memory * const mdev = (gx_device_memory *)prdev;*/
1733
1734
    /*
1735
     * The first test was changed to mdev->base != 0 in 5.50 (per Artifex).
1736
     * Not only was this test wrong logically, it was incorrect in that
1737
     * casting pdev to a (gx_device_memory *) is only meaningful if banding
1738
     * is not being used.  The test was changed back to prdev->is_open in
1739
     * 5.67 (also per Artifex).  For more information, see the News items
1740
     * for these filesets.
1741
     */
1742
0
    if (prdev->is_open &&
1743
0
        (gdev_space_params_cmp(prdev->space_params, *old_sp) != 0 ||
1744
0
         prdev->width != old_width || prdev->height != old_height ||
1745
0
         prdev->page_uses_transparency != old_page_uses_transparency)
1746
0
        ) {
1747
0
        int new_width = prdev->width;
1748
0
        int new_height = prdev->height;
1749
0
        gdev_space_params new_sp;
1750
1751
#ifdef DEBUGGING_HACKS
1752
debug_dump_bytes(pdev->memory, (const byte *)old_sp, (const byte *)(old_sp + 1), "old");
1753
debug_dump_bytes(pddev->memory, (const byte *)&prdev->space_params,
1754
                 (const byte *)(&prdev->space_params + 1), "new");
1755
dmprintf4(pdev->memory, "w=%d/%d, h=%d/%d\n", old_width, new_width, old_height, new_height);
1756
#endif /*DEBUGGING_HACKS*/
1757
0
        new_sp = prdev->space_params;
1758
0
        prdev->width = old_width;
1759
0
        prdev->height = old_height;
1760
0
        prdev->space_params = *old_sp;
1761
0
        code = gdev_prn_reallocate_memory(pdev, &new_sp,
1762
0
                                          new_width, new_height);
1763
        /* If this fails, device should be usable w/old params, but */
1764
        /* band files may not be open. */
1765
0
    }
1766
0
    return code;
1767
0
}
1768
1769
void
1770
gdev_prn_initialize_device_procs(gx_device *dev)
1771
0
{
1772
0
    set_dev_proc(dev, open_device, gdev_prn_open);
1773
0
    set_dev_proc(dev, close_device, gdev_prn_close);
1774
0
    set_dev_proc(dev, output_page, gdev_prn_output_page);
1775
0
    set_dev_proc(dev, get_params, gdev_prn_get_params);
1776
0
    set_dev_proc(dev, put_params, gdev_prn_put_params);
1777
0
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
1778
0
    set_dev_proc(dev, dev_spec_op, gdev_prn_dev_spec_op);
1779
0
    set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color);
1780
0
    set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb);
1781
0
    set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color);
1782
0
    set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb);
1783
0
}
1784
1785
void gdev_prn_initialize_device_procs_bg(gx_device *dev)
1786
0
{
1787
0
    gdev_prn_initialize_device_procs(dev);
1788
1789
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1790
0
}
1791
1792
void
1793
gdev_prn_initialize_device_procs_mono(gx_device *dev)
1794
0
{
1795
0
    gdev_prn_initialize_device_procs(dev);
1796
1797
0
    set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color);
1798
0
    set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb);
1799
0
    set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color);
1800
0
    set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb);
1801
0
}
1802
1803
void gdev_prn_initialize_device_procs_mono_bg(gx_device *dev)
1804
0
{
1805
0
    gdev_prn_initialize_device_procs_mono(dev);
1806
1807
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1808
0
}
1809
1810
void
1811
gdev_prn_initialize_device_procs_gray(gx_device *dev)
1812
0
{
1813
0
    gdev_prn_initialize_device_procs(dev);
1814
1815
0
    set_dev_proc(dev, map_rgb_color, gx_default_gray_map_rgb_color);
1816
0
    set_dev_proc(dev, map_color_rgb, gx_default_gray_map_color_rgb);
1817
0
    set_dev_proc(dev, encode_color, gx_default_gray_encode_color);
1818
0
    set_dev_proc(dev, decode_color, gx_default_gray_decode_color);
1819
0
}
1820
1821
void gdev_prn_initialize_device_procs_gray_bg(gx_device *dev)
1822
0
{
1823
0
    gdev_prn_initialize_device_procs_gray(dev);
1824
1825
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1826
0
}
1827
1828
void gdev_prn_initialize_device_procs_rgb(gx_device *dev)
1829
0
{
1830
0
    gdev_prn_initialize_device_procs(dev);
1831
1832
0
    set_dev_proc(dev, map_rgb_color, gx_default_rgb_map_rgb_color);
1833
0
    set_dev_proc(dev, map_color_rgb, gx_default_rgb_map_color_rgb);
1834
0
    set_dev_proc(dev, encode_color, gx_default_rgb_map_rgb_color);
1835
0
    set_dev_proc(dev, decode_color, gx_default_rgb_map_color_rgb);
1836
0
}
1837
1838
void gdev_prn_initialize_device_procs_rgb_bg(gx_device *dev)
1839
0
{
1840
0
    gdev_prn_initialize_device_procs_rgb(dev);
1841
1842
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1843
0
}
1844
1845
void
1846
gdev_prn_initialize_device_procs_gray8(gx_device *dev)
1847
0
{
1848
0
    gdev_prn_initialize_device_procs(dev);
1849
1850
0
    set_dev_proc(dev, map_rgb_color, gx_default_8bit_map_gray_color);
1851
0
    set_dev_proc(dev, map_color_rgb, gx_default_8bit_map_color_gray);
1852
0
    set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color);
1853
0
    set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray);
1854
0
}
1855
1856
void gdev_prn_initialize_device_procs_gray8_bg(gx_device *dev)
1857
0
{
1858
0
    gdev_prn_initialize_device_procs_gray8(dev);
1859
1860
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1861
0
}
1862
1863
void gdev_prn_initialize_device_procs_cmyk1(gx_device *dev)
1864
0
{
1865
0
    gdev_prn_initialize_device_procs(dev);
1866
1867
0
    set_dev_proc(dev, map_cmyk_color, cmyk_1bit_map_cmyk_color);
1868
0
    set_dev_proc(dev, map_color_rgb, cmyk_1bit_map_color_rgb);
1869
0
    set_dev_proc(dev, encode_color, cmyk_1bit_map_cmyk_color);
1870
0
    set_dev_proc(dev, decode_color, cmyk_1bit_map_color_cmyk);
1871
0
}
1872
1873
void gdev_prn_initialize_device_procs_cmyk1_bg(gx_device *dev)
1874
0
{
1875
0
    gdev_prn_initialize_device_procs_cmyk1(dev);
1876
1877
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1878
0
}
1879
1880
void gdev_prn_initialize_device_procs_cmyk8(gx_device *dev)
1881
0
{
1882
0
    gdev_prn_initialize_device_procs(dev);
1883
1884
0
    set_dev_proc(dev, map_cmyk_color, cmyk_8bit_map_cmyk_color);
1885
0
    set_dev_proc(dev, map_color_rgb, cmyk_8bit_map_color_rgb);
1886
0
    set_dev_proc(dev, encode_color, cmyk_8bit_map_cmyk_color);
1887
0
    set_dev_proc(dev, decode_color, cmyk_8bit_map_color_cmyk);
1888
0
}
1889
1890
void gdev_prn_initialize_device_procs_cmyk8_bg(gx_device *dev)
1891
0
{
1892
0
    gdev_prn_initialize_device_procs_cmyk8(dev);
1893
1894
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1895
0
}
1896
1897
void gdev_prn_initialize_device_procs_cmyk16(gx_device *dev)
1898
0
{
1899
0
    gdev_prn_initialize_device_procs(dev);
1900
1901
0
    set_dev_proc(dev, map_cmyk_color, cmyk_16bit_map_cmyk_color);
1902
0
    set_dev_proc(dev, map_color_rgb, cmyk_16bit_map_color_rgb);
1903
0
    set_dev_proc(dev, encode_color, cmyk_16bit_map_cmyk_color);
1904
0
    set_dev_proc(dev, decode_color, cmyk_16bit_map_color_cmyk);
1905
0
}
1906
1907
void gdev_prn_initialize_device_procs_cmyk16_bg(gx_device *dev)
1908
0
{
1909
0
    gdev_prn_initialize_device_procs_cmyk16(dev);
1910
1911
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1912
0
}