Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxpthr.c
Line
Count
Source
1
/* Copyright (C) 2001-2023 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
/* pxpthr.c.c */
18
/* PCL XL passtrough mode */
19
#include "stdio_.h"             /* std.h + NULL */
20
#include "gsdevice.h"
21
#include "gstypes.h"
22
#include "gspath.h"
23
#include "gscoord.h"
24
#include "gsfont.h"
25
#include "gsstate.h"
26
#include "gsicc_manage.h"
27
#include "pcommand.h"
28
#include "pgmand.h"
29
#include "pcstate.h"
30
#include "pcfont.h"
31
#include "pcparse.h"
32
#include "pctop.h"
33
#include "pcpage.h"
34
#include "pcdraw.h"
35
#include "pxoper.h"
36
#include "pxstate.h"
37
#include "pxfont.h"
38
#include "pxgstate.h"
39
#include "pxpthr.h"
40
#include "pxparse.h"
41
#include "plfont.h"
42
#include "pjtop.h"
43
#include "pxptable.h"
44
45
46
/* forward decl */
47
void pxpcl_release(px_state_t* pxs);
48
49
void pxpcl_pagestatereset(px_state_t* pxs);
50
51
/* NB: tests for this function are used to flag pxl snippet mode
52
 */
53
static int
54
pcl_end_page_noop(pcl_state_t * pcs, int num_copies, int flush)
55
0
{
56
0
    return pxPassThrough;
57
0
}
58
59
/* set variables other than setting the page device that do not
60
   default to pcl reset values */
61
int
62
pxPassthrough_pcl_state_nonpage_exceptions(px_state_t * pxs)
63
35
{
64
    /* xl cursor -> pcl cursor position */
65
35
    gs_point xlcp, pclcp, dp;
66
35
    int code;
67
68
    /* make the pcl ctm active, after resets the hpgl/2 ctm is
69
       active. */
70
35
    code = pcl_set_graphics_state(pxs->pcs);
71
35
    if (code < 0) {
72
0
        return code;
73
0
    }
74
75
    /* xl current point -> device point -> pcl current
76
       point.  If anything fails we assume the current
77
       point is not valid and use the cap from the pcl
78
       state initialization - pcl's origin */
79
35
    if (gs_currentpoint(pxs->pgs, &xlcp) ||
80
30
        gs_transform(pxs->pgs, xlcp.x, xlcp.y, &dp) ||
81
30
        gs_itransform(pxs->pcs->pgs, dp.x, dp.y, &pclcp)) {
82
5
        pxs->pcs->cap.x = 0;
83
5
        pxs->pcs->cap.y = inch2coord(2.0 / 6.0);      /* 1/6" off by 2x in resolution. */
84
5
        if (gs_debug_c('i'))
85
5
            dmprintf2(pxs->memory,
86
5
                      "passthrough: changing cap NO currentpoint (%d, %d) \n",
87
5
                      pxs->pcs->cap.x, pxs->pcs->cap.y);
88
30
    } else {
89
30
        if (gs_debug_c('i'))
90
30
            dmprintf8(pxs->memory,
91
30
                      "passthrough: changing cap from (%d,%d) (%d,%d) (%d, %d) (%d, %d) \n",
92
30
                      pxs->pcs->cap.x, pxs->pcs->cap.y, (coord) xlcp.x,
93
30
                      (coord) xlcp.y, (coord) dp.x, (coord) dp.y,
94
30
                      (coord) pclcp.x, (coord) pclcp.y);
95
30
        pxs->pcs->cap.x = (coord) pclcp.x;
96
30
        pxs->pcs->cap.y = (coord) pclcp.y;
97
30
    }
98
35
    if (pxs->pcs->underline_enabled)
99
0
        pxs->pcs->underline_start = pxs->pcs->cap;
100
101
102
35
    pxs->char_angle = pxs->pxgs->char_angle;
103
35
    pxs->char_shear.x = pxs->pxgs->char_shear.x;
104
35
    pxs->char_shear.y = pxs->pxgs->char_shear.y;
105
35
    pxs->char_scale.x = pxs->pxgs->char_scale.x;
106
35
    pxs->char_scale.y = pxs->pxgs->char_scale.y;
107
35
    pxs->char_bold_value = pxs->pxgs->char_bold_value;
108
109
35
    return 0;
110
35
}
111
112
/* retrieve the current pcl state and initialize pcl */
113
static int
114
pxPassthrough_init(px_state_t * pxs)
115
35
{
116
35
    int code;
117
118
35
    if (gs_debug_c('i'))
119
35
        dmprintf(pxs->memory, "passthrough: initializing global pcl state\n");
120
35
    pxs->pcs = pcl_get_gstate(pxs->pcls);
121
122
35
    if (pxs->have_page) {
123
30
        if (gs_debug_c('i'))
124
30
            dmprintf(pxs->memory, "passthrough: snippet mode\n");
125
        /* disable an end page in pcl, also used to flag in snippet mode */
126
30
        pxs->pcs->end_page = pcl_end_page_noop;
127
30
    }
128
129
    /* default to pcl5c */
130
35
    pxs->pcs->personality = 0;
131
    /* for now we do not support intepolation in XL passthrough mode. */
132
35
    pxs->pcs->interpolate = false;
133
    /* we don't see a nice way to support the following options with
134
       passthrough at this time (NB) */
135
35
    pxs->pcs->page_set_on_command_line = false;
136
35
    pxs->pcs->res_set_on_command_line = false;
137
35
    pxs->pcs->high_level_device = false;
138
35
    pxs->pcs->scanconverter = GS_SCANCONVERTER_DEFAULT;
139
140
35
    {
141
35
        char buf[100];
142
35
        int ret;
143
35
        stream_cursor_read r;
144
145
35
        ret =
146
35
            gs_snprintf(buf, sizeof(buf),
147
35
                    "@PJL SET PAPERLENGTH = %d\n@PJL SET PAPERWIDTH = %d\n",
148
35
                    (int)(pxs->media_dims.y * 10 + .5),
149
35
                    (int)(pxs->media_dims.x * 10 + .5));
150
151
        /* There is no reason gs_snprintf should fail, but to shut coverity up... */
152
35
        if (ret > 0) {
153
35
            stream_cursor_read_init(&r, (const byte *)buf, ret);
154
35
            pjl_proc_process(pxs->pjls, &r);
155
35
        }
156
35
    }
157
158
35
    pxs->pcs->xfm_state.paper_size = pcl_get_default_paper(pxs->pcs);
159
160
    /* initialize pcl and install xl's page device in pcl's state */
161
35
    pcl_init_state(pxs->pcs, pxs->memory);
162
35
    code = gs_setdevice_no_erase(pxs->pcs->pgs, gs_currentdevice(pxs->pgs));
163
35
    if (code < 0)
164
0
        return code;
165
166
    /* yet another reset with the new page device */
167
35
    pxs->pcs->xfm_state.paper_size = pcl_get_default_paper(pxs->pcs);
168
169
    /* set the parser state and initialize the pcl parser */
170
35
    pxs->pcl_parser_state.definitions = pxs->pcs->pcl_commands;
171
35
    pxs->pcl_parser_state.hpgl_parser_state = &pxs->gl_parser_state;
172
35
    pcl_process_init(&pxs->pcl_parser_state, pxs->pcs);
173
    /* default 600 to match XL allow PCL to override */
174
35
    pxs->pcs->uom_cp = 7200L / 600L;
175
35
    return gs_setgray(pxs->pcs->pgs, 0);
176
35
}
177
178
static int
179
pxPassthrough_setpagestate(px_state_t * pxs)
180
35
{
181
35
  int code = 0;
182
183
    /* by definition we are in "snippet mode" if pxl has dirtied
184
       the page */
185
35
    if (pxs->have_page) {
186
30
        if (gs_debug_c('i'))
187
30
            dmprintf(pxs->memory, "passthrough: snippet mode\n");
188
        /* disable an end page in pcl, also used to flag in snippet mode */
189
30
        pxs->pcs->end_page = pcl_end_page_noop;
190
        /* set the page size and orientation.  Really just sets
191
           the page tranformation does not feed a page (see noop
192
           above) */
193
30
        code = pcl_new_logical_page_for_passthrough(pxs->pcs,
194
30
                                             (int)pxs->orientation,
195
30
                                             &pxs->media_dims);
196
197
30
        if (gs_debug_c('i'))
198
30
            dmprintf2(pxs->memory,
199
30
                      "passthrough: snippet mode changing orientation from %d to %d\n",
200
30
                      pxs->pcs->xfm_state.lp_orient, (int)pxs->orientation);
201
202
30
    } else {                    /* not snippet mode - full page mode */
203
        /* pcl can feed the page and presumedely pcl commands will
204
           be used to set pcl's state. */
205
5
        pxs->pcs->end_page = pcl_end_page_top;
206
        /* clean the pcl page if it was marked by a previous snippet
207
           and set to full page mode. */
208
5
        pxs->pcs->page_marked = 0;
209
5
        code = pcl_new_logical_page_for_passthrough(pxs->pcs,
210
5
                                             (int)pxs->orientation,
211
5
                                             &pxs->media_dims);
212
5
        if (gs_debug_c('i'))
213
5
            dmprintf(pxs->memory, "passthrough: full page mode\n");
214
5
    }
215
35
    return code;
216
35
}
217
218
const byte apxPassthrough[] = { 0, 0 };
219
220
int
221
pxPassthrough(px_args_t * par, px_state_t * pxs)
222
39
{
223
39
    stream_cursor_read r;
224
39
    int code = 0;
225
39
    uint used;
226
227
    /* apparently if there is no open data source we open one.  By the
228
       spec this should already be open, in practice it is not. */
229
39
    if (!pxs->data_source_open) {
230
0
        if (gs_debug_c('i'))
231
0
            dmprintf(pxs->memory,
232
0
                     "passthrough: data source not open upon entry\n");
233
0
        pxs->data_source_open = true;
234
0
        pxs->data_source_big_endian = true;
235
0
    }
236
237
    /* source available is part of the equation to determine if this
238
       operator is being called for the first time */
239
39
    if (par->source.available == 0) {
240
35
        if (par->source.phase == 0) {
241
35
            if (gs_debug_c('i'))
242
35
                dmprintf(pxs->memory,
243
35
                         "passthrough starting getting more data\n");
244
245
35
            if (!pxs->pcs)
246
35
                pxPassthrough_init(pxs);
247
248
            /* this is the first passthrough on this page */
249
35
            if (pxs->pass_first) {
250
35
                code = pxPassthrough_setpagestate(pxs);
251
35
                if (code < 0)
252
0
                    return code;
253
35
                code = pxPassthrough_pcl_state_nonpage_exceptions(pxs);
254
35
                if (code < 0)
255
0
                    return code;
256
35
                pxs->pass_first = false;
257
35
            } else {
258
                /* there was a previous passthrough check if there were
259
                   any intervening XL commands */
260
0
                if (pxs->this_pass_contiguous == false) {
261
0
                    code = pxPassthrough_pcl_state_nonpage_exceptions(pxs);
262
0
                    if (code < 0)
263
0
                        return code;
264
0
                }
265
0
            }
266
35
            par->source.phase = 1;
267
35
        }
268
35
        return pxNeedData;
269
35
    }
270
271
    /* set pcl data stream pointers to xl's and process this batch of data. */
272
4
    r.ptr = par->source.data - 1;
273
4
    r.limit = par->source.data + par->source.available - 1;
274
4
    code = pcl_process(&pxs->pcl_parser_state, pxs->pcs, &r);
275
    /* updata xl's parser position to reflect what pcl has consumed. */
276
4
    used = (r.ptr + 1 - par->source.data);
277
4
    par->source.available -= used;
278
4
    par->source.data = r.ptr + 1;
279
280
4
    if (code < 0) {
281
0
        dmprintf1(pxs->memory, "passthrough: error return %d\n", code);
282
0
        return code;
283
0
    }
284
    /* always return need data and we exit at the top when the data is
285
       exhausted. */
286
4
    {
287
4
        if (used > px_parser_data_left(par->parser)) {
288
0
            dmprintf(pxs->memory, "error: read past end of stream\n");
289
0
            return -1;
290
4
        } else if (used < px_parser_data_left(par->parser)) {
291
1
            return pxNeedData;
292
3
        } else {
293
            /* end of operator and data */
294
3
            return 0;
295
3
        }
296
4
    }
297
4
}
298
299
void
300
pxpcl_pagestatereset(px_state_t* pxs)
301
9.11k
{
302
9.11k
    pxs->pass_first = true;
303
9.11k
    if (pxs->pcs) {
304
104
        pxs->pcs->xfm_state.left_offset_cp = 0.0;
305
104
        pxs->pcs->xfm_state.top_offset_cp = 0.0;
306
104
        pxs->pcs->margins.top = 0;
307
104
        pxs->pcs->margins.left = 0;
308
104
    }
309
9.11k
}
310
311
void
312
pxpcl_release(px_state_t * pxs)
313
5.87k
{
314
5.87k
    if (pxs->pcs) {
315
35
        if (gs_debug_c('i'))
316
35
            dmprintf(pxs->pcs->memory,
317
35
                     "passthrough: releasing global pcl state\n");
318
35
        pcl_grestore(pxs->pcs);
319
35
        gs_grestore_only(pxs->pcs->pgs);
320
35
        gs_nulldevice(pxs->pcs->pgs);
321
35
        pxs->pcs->end_page = pcl_end_page_top;        /* pcl_end_page handling */
322
35
        pxpcl_pagestatereset(pxs);
323
35
        pxs->pcs = NULL;
324
35
        pxs->this_pass_contiguous = false;
325
35
        pxs->pass_first = true;
326
35
        pxs->char_angle = 0;
327
35
        pxs->char_shear.x = 0;
328
35
        pxs->char_shear.y = 0;
329
35
        pxs->char_scale.x = 1.0;
330
35
        pxs->char_scale.y = 1.0;
331
35
        pxs->char_bold_value = 0.0;
332
35
    }
333
5.87k
}
334
335
/* the pxl parser must give us this information */
336
void
337
pxpcl_passthroughcontiguous(px_state_t * pxs, bool cont)
338
49
{
339
49
    pxs->this_pass_contiguous = cont;
340
49
}
341
342
/* copy state from pcl to pxl after a non-snippet passthrough
343
 */
344
void
345
pxpcl_endpassthroughcontiguous(px_state_t * pxs)
346
0
{
347
0
    if (pxs->pcs->end_page == pcl_end_page_top &&
348
0
        pxs->pcs->page_marked &&
349
0
        pxs->orientation != pxs->pcs->xfm_state.lp_orient) {
350
351
        /* end of pcl whole job; need to reflect pcl orientation changes */
352
0
        pxs->orientation = pxs->pcs->xfm_state.lp_orient;
353
0
        pxBeginPageFromPassthrough(pxs);
354
0
    }
355
356
0
    pxs->pxgs->char_angle = pxs->char_angle;
357
0
    pxs->pxgs->char_shear.x = pxs->char_shear.x;
358
0
    pxs->pxgs->char_shear.y = pxs->char_shear.y;
359
0
    pxs->pxgs->char_scale.x = pxs->char_scale.x;
360
0
    pxs->pxgs->char_scale.y = pxs->char_scale.y;
361
0
    pxs->pxgs->char_bold_value = pxs->char_bold_value;
362
0
}
363
int
364
pxpcl_selectfont(px_args_t * par, px_state_t * pxs)
365
0
{
366
0
    int code;
367
0
    stream_cursor_read r;
368
0
    const px_value_t *pstr = par->pv[3];
369
0
    const byte *str = (const byte *)pstr->value.array.data;
370
0
    uint len = pstr->value.array.size;
371
0
    px_gstate_t *pxgs = pxs->pxgs;
372
0
    pcl_font_selection_t *pfp;
373
374
0
    if (!pxs->pcs)
375
0
        pxPassthrough_init(pxs);
376
377
    /* this is the first passthrough on this page */
378
0
    if (pxs->pass_first) {
379
0
        code = pxPassthrough_setpagestate(pxs);
380
0
        if (code < 0)
381
0
            return code;
382
0
        code = pxPassthrough_pcl_state_nonpage_exceptions(pxs);
383
0
        if (code < 0)
384
0
            return code;
385
0
        pxs->pass_first = false;
386
0
    } else {
387
        /* there was a previous passthrough check if there were
388
           any intervening XL commands */
389
0
        if (pxs->this_pass_contiguous == false) {
390
0
            code = pxPassthrough_pcl_state_nonpage_exceptions(pxs);
391
0
            if (code < 0)
392
0
                return code;
393
0
        }
394
0
    }
395
0
    r.ptr = str - 1;
396
0
    r.limit = str + len - 1;
397
398
0
    code = pcl_process(&pxs->pcl_parser_state, pxs->pcs, &r);
399
0
    if (code < 0)
400
0
        return code;
401
402
0
    code = pcl_recompute_font(pxs->pcs, false);       /* select font */
403
0
    if (code < 0)
404
0
        return code;
405
406
0
    code = gs_setfont(pxs->pgs, pxs->pcs->font->pfont);
407
0
    if (code < 0)
408
0
        return code;
409
410
0
    pfp = &pxs->pcs->font_selection[pxs->pcs->font_selected];
411
412
0
    {
413
0
#define CP_PER_INCH         (7200.0)
414
0
#define CP_PER_MM           (7200.0/25.4)
415
0
#define CP_PER_10ths_of_MM  (CP_PER_MM/10.0)
416
417
0
        static const double centipoints_per_measure[4] = {
418
0
            CP_PER_INCH,        /* eInch */
419
0
            CP_PER_MM,          /* eMillimeter */
420
0
            CP_PER_10ths_of_MM, /* eTenthsOfAMillimeter */
421
0
            1                   /* pxeMeasure_next, won't reach */
422
0
        };
423
424
0
        gs_point sz;
425
426
0
        pcl_font_scale(pxs->pcs, &sz);
427
0
        pxgs->char_size = sz.x /
428
0
            centipoints_per_measure[pxs->measure] * pxs->units_per_measure.x;
429
0
    }
430
0
    pxgs->symbol_set = pfp->params.symbol_set;
431
432
0
    if (pcl_downloaded_and_bound(pxs->pcs->font)) {
433
0
        pxgs->symbol_map = 0;
434
0
    } else {
435
0
        px_set_symbol_map(pxs, pxs->pcs->font->font_type == plft_16bit);
436
0
    }
437
438
0
    {
439
0
        pl_font_t *plf = pxs->pcs->font;
440
441
        /* unfortunately the storage identifier is inconsistent
442
           between PCL and PCL XL, NB we should use the pxfont.h
443
           enumerations pxfsInternal and pxfsDownloaded but there is a
444
           foolish type redefinition in that header that need to be
445
           fixed. */
446
447
0
        if (plf->storage == 4)
448
0
            plf->storage = 1;
449
0
        else
450
0
            plf->storage = 0;
451
452
0
        pxgs->base_font = (px_font_t *) plf;
453
0
    }
454
0
    pxgs->char_matrix_set = false;
455
0
    return 0;
456
0
}