Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/pdf/pdf_device.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-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
/* Routines for dealing with devices */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "pdf_device.h"
21
#include "gsdevice.h"       /* For gs_setdevice_no_erase */
22
#include "gspaint.h"        /* For gs_erasepage */
23
#include "gdevvec.h"        /* for gs_device_vector */
24
#include "gxdevsop.h"       /* For special ops : dev_param_req_t */
25
26
int pdfi_device_check_param(gx_device *dev, const char *param, gs_c_param_list *list)
27
1.05M
{
28
1.05M
    dev_param_req_t request;
29
1.05M
    int code;
30
31
1.05M
    gs_c_param_list_write(list, dev->memory);
32
    /* Stuff the data into a structure for passing to the spec_op */
33
1.05M
    request.Param = (char *)param;
34
1.05M
    request.list = list;
35
1.05M
    code = dev_proc(dev, dev_spec_op)(dev, gxdso_get_dev_param, &request, sizeof(dev_param_req_t));
36
1.05M
    if (code < 0) {
37
809k
        gs_c_param_list_release(list);
38
809k
        return code;
39
809k
    }
40
241k
    return 0;
41
1.05M
}
42
43
/* Check value of boolean device parameter */
44
bool pdfi_device_check_param_bool(gx_device *dev, const char *param)
45
965k
{
46
965k
    int code;
47
965k
    gs_c_param_list list;
48
965k
    bool value;
49
50
965k
    code = pdfi_device_check_param(dev, param, &list);
51
965k
    if (code < 0)
52
727k
        return false;
53
237k
    gs_c_param_list_read(&list);
54
237k
    code = param_read_bool((gs_param_list *)&list,
55
237k
                           param,
56
237k
                           &value);
57
237k
    if (code < 0)
58
0
        value = false;
59
237k
    gs_c_param_list_release(&list);
60
237k
    return value;
61
965k
}
62
63
/* Set value of string device parameter */
64
int pdfi_device_set_param_string(gx_device *dev, const char *paramname, const char *value)
65
0
{
66
0
    int code;
67
0
    gs_c_param_list list;
68
0
    gs_param_string paramstring;
69
70
0
    paramstring.data = (byte *)value;
71
0
    paramstring.size = strlen(value);
72
0
    paramstring.persistent = 0;
73
74
0
    gs_c_param_list_write(&list, dev->memory);
75
76
0
    gs_param_list_set_persistent_keys((gs_param_list *) &list, false);
77
0
    code = param_write_string((gs_param_list *)&list, paramname, &paramstring);
78
0
    if (code < 0) goto exit;
79
0
    gs_c_param_list_read(&list);
80
0
    code = gs_putdeviceparams(dev, (gs_param_list *)&list);
81
82
0
 exit:
83
0
    gs_c_param_list_release(&list);
84
0
    return code;
85
0
}
86
87
/* Set value of boolean device parameter */
88
int pdfi_device_set_param_bool(gx_device *dev, const char *param, bool value)
89
0
{
90
0
    int code;
91
0
    gs_c_param_list list;
92
0
    bool paramval = value;
93
94
0
    gs_c_param_list_write(&list, dev->memory);
95
96
0
    code = param_write_bool((gs_param_list *)&list, param, &paramval);
97
0
    if (code < 0) goto exit;
98
0
    gs_c_param_list_read(&list);
99
0
    code = gs_putdeviceparams(dev, (gs_param_list *)&list);
100
101
0
 exit:
102
0
    gs_c_param_list_release(&list);
103
0
    return code;
104
0
}
105
106
int pdfi_device_set_param_float(gx_device *dev, const char *param, float value)
107
0
{
108
0
    int code;
109
0
    gs_c_param_list list;
110
0
    float paramval = value;
111
112
0
    gs_c_param_list_write(&list, dev->memory);
113
114
0
    code = param_write_float((gs_param_list *)&list, param, &paramval);
115
0
    if (code < 0) goto exit;
116
0
    gs_c_param_list_read(&list);
117
0
    code = gs_putdeviceparams(dev, (gs_param_list *)&list);
118
119
0
 exit:
120
0
    gs_c_param_list_release(&list);
121
0
    return code;
122
0
}
123
124
/* Checks whether a parameter exists for the device */
125
bool pdfi_device_check_param_exists(gx_device *dev, const char *param)
126
86.0k
{
127
86.0k
    int code;
128
86.0k
    gs_c_param_list list;
129
130
86.0k
    code = pdfi_device_check_param(dev, param, &list);
131
86.0k
    if (code < 0)
132
82.0k
        return false;
133
4.00k
    gs_c_param_list_release(&list);
134
4.00k
    return true;
135
86.0k
}
136
137
/* Config some device-related variables */
138
void pdfi_device_set_flags(pdf_context *ctx)
139
86.0k
{
140
86.0k
    bool has_pdfmark;
141
86.0k
    bool has_ForOPDFRead;
142
86.0k
    gx_device *dev = ctx->pgs->device;
143
144
86.0k
    has_pdfmark = pdfi_device_check_param_exists(dev, "pdfmark");
145
86.0k
    has_ForOPDFRead = pdfi_device_check_param_bool(dev, "ForOPDFRead");
146
147
    /* Cache these so they don't have to constantly be calculated */
148
86.0k
    ctx->device_state.writepdfmarks = has_pdfmark || ctx->args.dopdfmarks;
149
86.0k
    ctx->device_state.annotations_preserved = ctx->device_state.writepdfmarks && !has_ForOPDFRead;
150
151
    /* PreserveTrMode is for pdfwrite device */
152
86.0k
    ctx->device_state.preserve_tr_mode = pdfi_device_check_param_bool(dev, "PreserveTrMode");
153
86.0k
    ctx->device_state.preserve_smask = pdfi_device_check_param_bool(dev, "PreserveSMask");
154
86.0k
    ctx->device_state.HighLevelDevice = pdfi_device_check_param_bool(dev, "HighLevelDevice");
155
86.0k
    ctx->device_state.ForOPDFRead = pdfi_device_check_param_bool(dev, "ForOPDFRead");
156
86.0k
    ctx->device_state.WantsPageLabels = pdfi_device_check_param_bool(dev, "WantsPageLabels");
157
86.0k
    ctx->device_state.WantsOptionalContent = pdfi_device_check_param_bool(dev, "WantsOptionalContent");
158
86.0k
    ctx->device_state.PassUserUnit = pdfi_device_check_param_bool(dev, "PassUserUnit");
159
160
    /* See if it is a DeviceN (spot capable) */
161
86.0k
    ctx->device_state.spot_capable = dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0);
162
163
86.0k
    ctx->device_state.ModifiesPageSize = pdfi_device_check_param_bool(dev, "ModifiesPageSize");
164
86.0k
    ctx->device_state.ModifiesPageOrder = pdfi_device_check_param_bool(dev, "ModifiesPageOrder");
165
166
    /* If multi-page output, can't do certain pdfmarks */
167
86.0k
    if (ctx->device_state.writepdfmarks) {
168
4.00k
        if (gx_outputfile_is_separate_pages(((gx_device_vector *)dev)->fname, dev->memory) || ctx->device_state.ModifiesPageOrder) {
169
0
            ctx->args.no_pdfmark_outlines = true;
170
0
            ctx->args.no_pdfmark_dests = true;
171
0
        }
172
4.00k
    }
173
174
#if DEBUG_DEVICE
175
    dbgmprintf2(ctx->memory, "Device writepdfmarks=%s, annotations_preserved=%s\n",
176
        ctx->writepdfmarks ? "TRUE" : "FALSE",
177
                ctx->annotations_preserved ? "TRUE" : "FALSE");
178
#endif
179
86.0k
}
180
181
/* Config the output device
182
 * This will configure any special device parameters.
183
 * Right now it just sets up some stuff for pdfwrite.
184
 */
185
int pdfi_device_misc_config(pdf_context *ctx)
186
0
{
187
0
    bool has_pdfmark = false;
188
0
    int code;
189
0
    gx_device *dev = ctx->pgs->device;
190
191
0
    if (ctx->args.first_page != 0 || ctx->args.last_page != 0) {
192
0
        code = pdfi_device_set_param_bool(dev, "DisablePageHandler", true);
193
0
        if (code < 0) goto exit;
194
0
    }
195
196
    /* I am using pdfmark to identify the pdfwrite device */
197
0
    has_pdfmark = pdfi_device_check_param_bool(dev, "pdfmark");
198
    /* (only handling pdfwrite for now) */
199
0
    if (!has_pdfmark)
200
0
        return 0;
201
202
    /* TODO: I think the pdfwrite device should have these automatically set to true,
203
     * but that doesn't seem to be the case now.
204
     * See pdf_document_metadata()
205
     */
206
0
    code = pdfi_device_set_param_string(dev, "AutoRotatePages", "PageByPage");
207
0
    if (code < 0) goto exit;
208
209
0
exit:
210
0
    return code;
211
0
}