Coverage Report

Created: 2025-11-16 07:40

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