Coverage Report

Created: 2026-04-01 07:17

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
5
{
64
    /* xl cursor -> pcl cursor position */
65
5
    gs_point xlcp, pclcp, dp;
66
5
    int code;
67
68
    /* make the pcl ctm active, after resets the hpgl/2 ctm is
69
       active. */
70
5
    code = pcl_set_graphics_state(pxs->pcs);
71
5
    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
5
    if (gs_currentpoint(pxs->pgs, &xlcp) ||
80
3
        gs_transform(pxs->pgs, xlcp.x, xlcp.y, &dp) ||
81
3
        gs_itransform(pxs->pcs->pgs, dp.x, dp.y, &pclcp)) {
82
2
        pxs->pcs->cap.x = 0;
83
2
        pxs->pcs->cap.y = inch2coord(2.0 / 6.0);      /* 1/6" off by 2x in resolution. */
84
2
        if (gs_debug_c('i'))
85
2
            dmprintf2(pxs->memory,
86
2
                      "passthrough: changing cap NO currentpoint (%d, %d) \n",
87
2
                      pxs->pcs->cap.x, pxs->pcs->cap.y);
88
3
    } else {
89
3
        if (gs_debug_c('i'))
90
3
            dmprintf8(pxs->memory,
91
3
                      "passthrough: changing cap from (%d,%d) (%d,%d) (%d, %d) (%d, %d) \n",
92
3
                      pxs->pcs->cap.x, pxs->pcs->cap.y, (coord) xlcp.x,
93
3
                      (coord) xlcp.y, (coord) dp.x, (coord) dp.y,
94
3
                      (coord) pclcp.x, (coord) pclcp.y);
95
3
        pxs->pcs->cap.x = (coord) pclcp.x;
96
3
        pxs->pcs->cap.y = (coord) pclcp.y;
97
3
    }
98
5
    if (pxs->pcs->underline_enabled)
99
0
        pxs->pcs->underline_start = pxs->pcs->cap;
100
101
102
5
    pxs->char_angle = pxs->pxgs->char_angle;
103
5
    pxs->char_shear.x = pxs->pxgs->char_shear.x;
104
5
    pxs->char_shear.y = pxs->pxgs->char_shear.y;
105
5
    pxs->char_scale.x = pxs->pxgs->char_scale.x;
106
5
    pxs->char_scale.y = pxs->pxgs->char_scale.y;
107
5
    pxs->char_bold_value = pxs->pxgs->char_bold_value;
108
109
5
    return 0;
110
5
}
111
112
/* retrieve the current pcl state and initialize pcl */
113
static int
114
pxPassthrough_init(px_state_t * pxs)
115
5
{
116
5
    int code;
117
118
5
    if (gs_debug_c('i'))
119
5
        dmprintf(pxs->memory, "passthrough: initializing global pcl state\n");
120
5
    pxs->pcs = pcl_get_gstate(pxs->pcls);
121
122
5
    if (pxs->have_page) {
123
3
        if (gs_debug_c('i'))
124
3
            dmprintf(pxs->memory, "passthrough: snippet mode\n");
125
        /* disable an end page in pcl, also used to flag in snippet mode */
126
3
        pxs->pcs->end_page = pcl_end_page_noop;
127
3
    }
128
129
    /* default to pcl5c */
130
5
    pxs->pcs->personality = 0;
131
    /* for now we do not support intepolation in XL passthrough mode. */
132
5
    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
5
    pxs->pcs->page_set_on_command_line = false;
136
5
    pxs->pcs->res_set_on_command_line = false;
137
5
    pxs->pcs->high_level_device = false;
138
5
    pxs->pcs->scanconverter = GS_SCANCONVERTER_DEFAULT;
139
140
5
    {
141
5
        char buf[100];
142
5
        int ret;
143
5
        stream_cursor_read r;
144
145
5
        ret =
146
5
            gs_snprintf(buf, sizeof(buf),
147
5
                    "@PJL SET PAPERLENGTH = %d\n@PJL SET PAPERWIDTH = %d\n",
148
5
                    (int)(pxs->media_dims.y * 10 + .5),
149
5
                    (int)(pxs->media_dims.x * 10 + .5));
150
151
        /* There is no reason gs_snprintf should fail, but to shut coverity up... */
152
5
        if (ret > 0) {
153
5
            stream_cursor_read_init(&r, (const byte *)buf, ret);
154
5
            pjl_proc_process(pxs->pjls, &r);
155
5
        }
156
5
    }
157
158
5
    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
5
    pcl_init_state(pxs->pcs, pxs->memory);
162
5
    code = gs_setdevice_no_erase(pxs->pcs->pgs, gs_currentdevice(pxs->pgs));
163
5
    if (code < 0)
164
0
        return code;
165
166
    /* yet another reset with the new page device */
167
5
    pxs->pcs->xfm_state.paper_size = pcl_get_default_paper(pxs->pcs);
168
169
    /* set the parser state and initialize the pcl parser */
170
5
    pxs->pcl_parser_state.definitions = pxs->pcs->pcl_commands;
171
5
    pxs->pcl_parser_state.hpgl_parser_state = &pxs->gl_parser_state;
172
5
    pcl_process_init(&pxs->pcl_parser_state, pxs->pcs);
173
    /* default 600 to match XL allow PCL to override */
174
5
    pxs->pcs->uom_cp = 7200L / 600L;
175
5
    return gs_setgray(pxs->pcs->pgs, 0);
176
5
}
177
178
static int
179
pxPassthrough_setpagestate(px_state_t * pxs)
180
5
{
181
5
  int code = 0;
182
183
    /* by definition we are in "snippet mode" if pxl has dirtied
184
       the page */
185
5
    if (pxs->have_page) {
186
3
        if (gs_debug_c('i'))
187
3
            dmprintf(pxs->memory, "passthrough: snippet mode\n");
188
        /* disable an end page in pcl, also used to flag in snippet mode */
189
3
        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
3
        code = pcl_new_logical_page_for_passthrough(pxs->pcs,
194
3
                                             (int)pxs->orientation,
195
3
                                             &pxs->media_dims);
196
197
3
        if (gs_debug_c('i'))
198
3
            dmprintf2(pxs->memory,
199
3
                      "passthrough: snippet mode changing orientation from %d to %d\n",
200
3
                      pxs->pcs->xfm_state.lp_orient, (int)pxs->orientation);
201
202
3
    } 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
2
        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
2
        pxs->pcs->page_marked = 0;
209
2
        code = pcl_new_logical_page_for_passthrough(pxs->pcs,
210
2
                                             (int)pxs->orientation,
211
2
                                             &pxs->media_dims);
212
2
        if (gs_debug_c('i'))
213
2
            dmprintf(pxs->memory, "passthrough: full page mode\n");
214
2
    }
215
5
    return code;
216
5
}
217
218
const byte apxPassthrough[] = { 0, 0 };
219
220
int
221
pxPassthrough(px_args_t * par, px_state_t * pxs)
222
5
{
223
5
    stream_cursor_read r;
224
5
    int code = 0;
225
5
    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
5
    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
5
    if (par->source.available == 0) {
240
5
        if (par->source.phase == 0) {
241
5
            if (gs_debug_c('i'))
242
5
                dmprintf(pxs->memory,
243
5
                         "passthrough starting getting more data\n");
244
245
5
            if (!pxs->pcs)
246
5
                pxPassthrough_init(pxs);
247
248
            /* this is the first passthrough on this page */
249
5
            if (pxs->pass_first) {
250
5
                code = pxPassthrough_setpagestate(pxs);
251
5
                if (code < 0)
252
0
                    return code;
253
5
                code = pxPassthrough_pcl_state_nonpage_exceptions(pxs);
254
5
                if (code < 0)
255
0
                    return code;
256
5
                pxs->pass_first = false;
257
5
            } 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
5
            par->source.phase = 1;
267
5
        }
268
5
        return pxNeedData;
269
5
    }
270
271
    /* set pcl data stream pointers to xl's and process this batch of data. */
272
0
    r.ptr = par->source.data - 1;
273
0
    r.limit = par->source.data + par->source.available - 1;
274
0
    code = pcl_process(&pxs->pcl_parser_state, pxs->pcs, &r);
275
    /* updata xl's parser position to reflect what pcl has consumed. */
276
0
    used = (r.ptr + 1 - par->source.data);
277
0
    par->source.available -= used;
278
0
    par->source.data = r.ptr + 1;
279
280
0
    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
0
    {
287
0
        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
0
        } else if (used < px_parser_data_left(par->parser)) {
291
0
            return pxNeedData;
292
0
        } else {
293
            /* end of operator and data */
294
0
            return 0;
295
0
        }
296
0
    }
297
0
}
298
299
void
300
pxpcl_pagestatereset(px_state_t* pxs)
301
7.24k
{
302
7.24k
    pxs->pass_first = true;
303
7.24k
    if (pxs->pcs) {
304
15
        pxs->pcs->xfm_state.left_offset_cp = 0.0;
305
15
        pxs->pcs->xfm_state.top_offset_cp = 0.0;
306
15
        pxs->pcs->margins.top = 0;
307
15
        pxs->pcs->margins.left = 0;
308
15
    }
309
7.24k
}
310
311
void
312
pxpcl_release(px_state_t * pxs)
313
4.82k
{
314
4.82k
    if (pxs->pcs) {
315
5
        if (gs_debug_c('i'))
316
5
            dmprintf(pxs->pcs->memory,
317
5
                     "passthrough: releasing global pcl state\n");
318
5
        pcl_grestore(pxs->pcs);
319
5
        gs_grestore_only(pxs->pcs->pgs);
320
5
        gs_nulldevice(pxs->pcs->pgs);
321
5
        pxs->pcs->end_page = pcl_end_page_top;        /* pcl_end_page handling */
322
5
        pxpcl_pagestatereset(pxs);
323
5
        pxs->pcs = NULL;
324
5
        pxs->this_pass_contiguous = false;
325
5
        pxs->pass_first = true;
326
5
        pxs->char_angle = 0;
327
5
        pxs->char_shear.x = 0;
328
5
        pxs->char_shear.y = 0;
329
5
        pxs->char_scale.x = 1.0;
330
5
        pxs->char_scale.y = 1.0;
331
5
        pxs->char_bold_value = 0.0;
332
5
    }
333
4.82k
}
334
335
/* the pxl parser must give us this information */
336
void
337
pxpcl_passthroughcontiguous(px_state_t * pxs, bool cont)
338
38
{
339
38
    pxs->this_pass_contiguous = cont;
340
38
}
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
}