Coverage Report

Created: 2022-04-16 11:23

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