Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxsessio.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
/* pxsessio.c */
18
/* PCL XL session operators */
19
20
#include "math_.h"              /* for fabs */
21
#include "stdio_.h"
22
#include "string_.h"
23
#include "pxoper.h"
24
#include "pxpthr.h"
25
#include "pxstate.h"
26
#include "pxfont.h"
27
#include "pjparse.h"
28
#include "gschar.h"
29
#include "gscoord.h"
30
#include "gserrors.h"           /* for gs_error_undefined */
31
#include "gspaint.h"
32
#include "gsparam.h"
33
#include "gsstate.h"
34
#include "gxfixed.h"
35
#include "gxpath.h"             /* for gx_clip_to_rectangle */
36
#include "gxdcolor.h"
37
#include "gxpcolor.h"
38
#include "gxfcache.h"
39
#include "gxdevice.h"
40
#include "gxstate.h"
41
#include "pjtop.h"
42
#include "pllfont.h"
43
#include "pxptable.h"
44
#include "gzstate.h"
45
46
/* Imported operators */
47
px_operator_proc(pxCloseDataSource);
48
px_operator_proc(pxNewPath);
49
px_operator_proc(pxPopGS);
50
px_operator_proc(pxPushGS);
51
px_operator_proc(pxSetHalftoneMethod);
52
px_operator_proc(pxSetPageDefaultCTM);
53
54
/*
55
 * Define the known paper sizes and unprintable margins.  For convenience,
56
 * we define this in terms of 300 dpi pixels, in portrait orientation.  This
57
 * table should obviously be device-dependent.
58
 */
59
8.31k
#define media_size_scale (72.0 / 300.0)
60
#define m_default 50, 50, 50, 50
61
#define m_data(ms_enum, mstr, res, width, height)                        \
62
    {ms_enum, mstr, width * 300 / (res), height * 300 / (res), m_default},
63
static px_media_t known_media[] = {
64
    px_enumerate_media(m_data)
65
};
66
#undef m_data
67
#undef m_default
68
69
/* Define the mapping from the Measure enumeration to points. */
70
static const double measure_to_points[] = pxeMeasure_to_points;
71
72
/* ---------------- Internal procedures ---------------- */
73
74
/* system paper size string (same as pjl paper size) to pxl enumeration type */
75
static pxeMediaSize_t
76
px_paper_string_to_media(pjl_envvar_t * paper_str)
77
6.63k
{
78
    /* table to map pjl paper type strings to pxl enums */
79
6.63k
    int i;
80
81
13.6k
    for (i = 0; i < countof(known_media); i++) {
82
13.6k
        if (!pjl_compare(paper_str, known_media[i].mname))
83
6.62k
            return known_media[i].ms_enum;
84
13.6k
    }
85
    /* not found return letter */
86
10
    return eLetterPaper;
87
6.63k
}
88
89
/* return the default media set up in the XL state */
90
static px_media_t *
91
px_get_default_media(px_state_t * pxs)
92
2.40k
{
93
2.40k
    int i;
94
95
4.81k
    for (i = 0; i < countof(known_media); i++)
96
4.81k
        if (known_media[i].ms_enum == pxs->media_size)
97
2.40k
            return &known_media[i];
98
    /* shouldn't get here but just in case we return letter. */
99
0
    return &known_media[1];
100
2.40k
}
101
102
void
103
px_get_default_media_size(px_state_t * pxs, gs_point * pt)
104
2.40k
{
105
2.40k
    px_media_t *media = px_get_default_media(pxs);
106
107
2.40k
    pt->x = media->width * media_size_scale;
108
2.40k
    pt->y = media->height * media_size_scale;
109
2.40k
}
110
111
/* Finish putting one device parameter. */
112
static int
113
px_put1(gx_device * dev, gs_c_param_list * plist, int ecode)
114
15.8k
{
115
15.8k
    int code = ecode;
116
117
15.8k
    if (code >= 0) {
118
15.8k
        gs_c_param_list_read(plist);
119
15.8k
        code = gs_putdeviceparams(dev, (gs_param_list *) plist);
120
15.8k
    }
121
15.8k
    gs_c_param_list_release(plist);
122
15.8k
    return (code == 0 || code == gs_error_undefined ? ecode : code);
123
15.8k
}
124
125
/* Adjust one scale factor to an integral value if we can. */
126
static double
127
px_adjust_scale(double value, double extent)
128
7.03k
{
129
    /* If we can make the value an integer with a total error */
130
    /* of less than 1/2 pixel over the entire page, we do it. */
131
7.03k
    double int_value = floor(value + 0.5);
132
133
7.03k
    return (fabs((int_value - value) * extent) < 0.5 ? int_value : value);
134
7.03k
}
135
136
/* Clean up at the end of a page, but before rendering. */
137
static void
138
px_end_page_cleanup(px_state_t * pxs)
139
7.24k
{
140
7.24k
    px_dict_release(&pxs->page_pattern_dict);
141
    /* Clean up stray gstate information. */
142
7.34k
    while (pxs->pxgs->stack_depth > 0)
143
101
        pxPopGS(NULL, pxs);
144
    /* Pop an extra time to mirror the push in BeginPage. */
145
7.24k
    pxs->pxgs->stack_depth++;
146
7.24k
    pxPopGS(NULL, pxs);
147
7.24k
    pxNewPath(NULL, pxs);
148
7.24k
    px_purge_pattern_cache(pxs, ePagePattern);
149
7.24k
    pxpcl_pagestatereset(pxs);
150
7.24k
}
151
152
/* Purge all */
153
static bool
154
purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy)
155
15.5k
{
156
15.5k
    return true;
157
15.5k
}
158
159
/* clears the entire cache */
160
/* Clean up at the end of a session. */
161
static void
162
px_end_session_cleanup(px_state_t * pxs)
163
4.82k
{
164
4.82k
    if (pxs->data_source_open)
165
1.78k
        pxCloseDataSource(NULL, pxs);
166
4.82k
    px_purge_character_cache(pxs);
167
4.82k
    px_dict_release(&pxs->session_pattern_dict);
168
4.82k
    if (gstate_pattern_cache(pxs->pgs)) {
169
0
        (gstate_pattern_cache(pxs->pgs)->free_all)
170
0
            (gstate_pattern_cache(pxs->pgs));
171
0
        gs_free_object(pxs->memory,
172
0
                       gstate_pattern_cache(pxs->pgs)->tiles,
173
0
                       "px_end_session_cleanup(tiles)");
174
0
        gs_free_object(pxs->memory,
175
0
                       gstate_pattern_cache(pxs->pgs),
176
0
                       "px_end_session_cleanup(struct)");
177
0
        {
178
0
            gs_gstate *pgs = pxs->pgs;
179
180
0
            while (pgs) {
181
0
                gstate_set_pattern_cache(pgs, 0);
182
0
                pgs = gs_gstate_saved(pgs);
183
0
            }
184
0
        }
185
0
    }
186
    /* We believe that streams do *not* persist across sessions.... */
187
4.82k
    px_dict_release(&pxs->stream_dict);
188
    /* delete downloaded fonts on end of session */
189
4.82k
    px_dict_release(&pxs->font_dict);
190
4.82k
    pxpcl_release(pxs);
191
4.82k
}
192
193
/* ---------------- Non-operator procedures ---------------- */
194
195
/* Clean up after an error or UEL. */
196
void
197
px_state_cleanup(px_state_t * pxs)
198
4.81k
{
199
4.81k
    px_end_page_cleanup(pxs);
200
4.81k
    px_end_session_cleanup(pxs);
201
4.81k
    pxs->have_page = false;
202
4.81k
}
203
204
void
205
px_purge_character_cache(px_state_t * pxs)
206
4.82k
{
207
4.82k
    gx_purge_selected_cached_chars(pxs->font_dir, purge_all, pxs);
208
4.82k
}
209
210
/* ---------------- Operators ---------------- */
211
212
const byte apxBeginSession[] = {
213
    pxaMeasure, pxaUnitsPerMeasure, 0,
214
    pxaErrorReport, 0
215
};
216
int
217
pxBeginSession(px_args_t * par, px_state_t * pxs)
218
6.40k
{
219
6.40k
    pxs->measure = par->pv[0]->value.i;
220
6.40k
    pxs->units_per_measure.x = real_value(par->pv[1], 0);
221
6.40k
    pxs->units_per_measure.y = real_value(par->pv[1], 1);
222
223
6.40k
    pxs->stream_level = 0;
224
225
6.40k
    if (par->pv[2])
226
6.40k
        pxs->error_report = par->pv[2]->value.i;
227
0
    else
228
0
        pxs->error_report = eNoReporting;
229
6.40k
    px_dict_init(&pxs->session_pattern_dict, pxs->memory, px_free_pattern);
230
    /* Set media parameters to device defaults, in case BeginPage */
231
    /* doesn't specify valid ones. */
232
    /* This is obviously device-dependent. */
233
    /* get the pjl state */
234
6.40k
    {
235
6.40k
        pjl_envvar_t *pjl_psize = pjl_proc_get_envvar(pxs->pjls, "paper");
236
237
        /* NB.  We are not sure about the interaction of pjl's
238
           wide a4 commands so we don't attempt to implement
239
           it. */
240
        /* bool pjl_widea4
241
           = pjl_proc_compare(pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "widea4"), "no"); */
242
6.40k
        int pjl_copies
243
6.40k
            =
244
6.40k
            pjl_proc_vartoi(pxs->pjls,
245
6.40k
                            pjl_proc_get_envvar(pxs->pjls, "copies"));
246
6.40k
        bool pjl_duplex =
247
6.40k
            pjl_proc_compare(pxs->pjls,
248
6.40k
                             pjl_proc_get_envvar(pxs->pjls, "duplex"), "off");
249
6.40k
        bool pjl_bindshort =
250
6.40k
            pjl_proc_compare(pxs->pjls,
251
6.40k
                             pjl_proc_get_envvar(pxs->pjls, "binding"),
252
6.40k
                             "longedge");
253
6.40k
        bool pjl_manualfeed =
254
6.40k
            pjl_proc_compare(pxs->pjls,
255
6.40k
                             pjl_proc_get_envvar(pxs->pjls, "manualfeed"),
256
6.40k
                             "off");
257
6.40k
        pxs->media_size = px_paper_string_to_media(pjl_psize);
258
6.40k
        pxs->media_source = (pjl_manualfeed ? eManualFeed : eDefaultSource);
259
6.40k
        pxs->duplex = pjl_duplex;
260
6.40k
        pxs->duplex_page_mode = (pjl_bindshort ? eDuplexHorizontalBinding :
261
6.40k
                                 eDuplexVerticalBinding);
262
6.40k
        pxs->duplex_back_side = eFrontMediaSide;
263
6.40k
        pxs->copies = pjl_copies;
264
6.40k
        pxs->media_destination = eDefaultDestination;
265
6.40k
        pxs->media_type = eDefaultType;
266
267
6.40k
        if (!pjl_proc_compare
268
6.40k
            (pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "orientation"),
269
6.40k
             "LANDSCAPE"))
270
0
            pxs->orientation = eLandscapeOrientation;
271
6.40k
        if (!pjl_proc_compare
272
6.40k
            (pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "orientation"),
273
6.40k
             "PORTRAIT"))
274
6.40k
            pxs->orientation = ePortraitOrientation;
275
        /* NB reverse orientations missing */
276
277
        /* install the built in fonts */
278
6.40k
        if (!pl_load_built_in_fonts
279
6.40k
            (pjl_proc_fontsource_to_path(pxs->pjls, "I"), pxs->memory,
280
6.40k
             &pxs->builtin_font_dict, pxs->font_dir, (int)pxfsInternal,
281
6.40k
             true /* use unicode key names */ )) {
282
0
            errprintf(pxs->memory, "Fonts not found\n");
283
0
            return gs_error_Fatal;
284
285
0
        }
286
6.40k
    }
287
6.40k
    return 0;
288
6.40k
}
289
290
const byte apxEndSession[] = { 0, 0 };
291
int
292
pxEndSession(px_args_t * par, px_state_t * pxs)
293
3
{
294
3
    px_end_session_cleanup(pxs);
295
3
    if (pxs->warning_length)
296
0
        return_error(errorWarningsReported);
297
3
    return 0;
298
3
}
299
300
const byte apxBeginPage[] = {
301
    0, pxaOrientation,
302
    pxaMediaSource, pxaMediaSize, pxaCustomMediaSize, pxaCustomMediaSizeUnits,
303
    pxaSimplexPageMode, pxaDuplexPageMode, pxaDuplexPageSide,
304
    pxaMediaDestination, pxaMediaType, 0
305
};
306
int
307
pxBeginPage(px_args_t * par, px_state_t * pxs)
308
1.75k
{
309
1.75k
    gs_gstate *pgs = pxs->pgs;
310
1.75k
    gx_device *dev = gs_currentdevice(pgs);
311
1.75k
    gs_point page_size_pixels;
312
1.75k
    gs_matrix points2device;
313
1.75k
    bool no_pv_2 = false;
314
1.75k
    int code;
315
316
    /* check for 2.1 no parameter special cases */
317
1.75k
    {
318
1.75k
        int i;
319
1.75k
        bool have_params = false;
320
321
1.75k
        for (i = (par->pv[0] == 0 ? 0 : 1);
322
1.77k
             i < sizeof(par->pv) / sizeof(par->pv[0]); i++) {
323
1.77k
            if (par->pv[i]) {
324
1.75k
                have_params = true;
325
1.75k
                break;
326
1.75k
            }
327
1.77k
        }
328
1.75k
        if (have_params == false) {
329
0
            if (par->pv[0]) {
330
0
                int32_t orientation = par->pv[0]->value.i;
331
332
0
                if (orientation < 0 || orientation >= pxeOrientation_next) {
333
0
                    px_record_warning("IllegalOrientation", true, pxs);
334
0
                    orientation = ePortraitOrientation;
335
0
                }
336
0
                pxs->orientation = (pxeOrientation_t) orientation;
337
0
            }
338
0
            goto setd;
339
0
        }
340
1.75k
    }
341
    /* Check parameter presence for legal combinations. */
342
1.75k
    if (par->pv[2]) {
343
1.75k
        if (par->pv[3] || par->pv[4])
344
0
            return_error(errorIllegalAttributeCombination);
345
1.75k
    } else if (par->pv[3] && par->pv[4]) {
346
0
        if (par->pv[2])
347
0
            return_error(errorIllegalAttributeCombination);
348
4
    } else {
349
4
        pxs->pm = px_get_default_media(pxs);
350
4
        no_pv_2 = true;
351
4
    }
352
1.75k
    if (par->pv[5]) {
353
0
        if (par->pv[6] || par->pv[7])
354
0
            return_error(errorIllegalAttributeCombination);
355
1.75k
    } else if (par->pv[6]) {
356
1
        if (par->pv[5])
357
0
            return_error(errorIllegalAttributeCombination);
358
1
    }
359
360
    /* Copy parameters to the PCL XL state. */
361
    /* For some reason, invalid Orientations only produces a warning. */
362
1.75k
    if (par->pv[0]) {
363
1.75k
        int32_t orientation = par->pv[0]->value.i;
364
365
1.75k
        if (orientation < 0 || orientation >= pxeOrientation_next) {
366
0
            px_record_warning("IllegalOrientation", true, pxs);
367
0
            orientation = ePortraitOrientation;
368
0
        }
369
1.75k
        pxs->orientation = (pxeOrientation_t) orientation;
370
1.75k
    }
371
372
1.75k
    if (par->pv[1])
373
1.74k
        pxs->media_source = par->pv[1]->value.i;
374
1.75k
    if (par->pv[2]) {
375
        /* default to letter */
376
1.75k
        pxeMediaSize_t ms_enum = eLetterPaper;
377
1.75k
        int i;
378
379
        /* could be an array or enumeration */
380
1.75k
        if (par->pv[2]->type & pxd_array) {
381
            /* it's an array, so convert it to the associated
382
               enumeration */
383
226
            byte *str = gs_alloc_string(pxs->memory,
384
226
                                        array_value_size(par->pv[2]) + 1,
385
226
                                        "pxBeginPage");
386
387
226
            if (str == 0)
388
0
                return_error(errorInsufficientMemory);
389
            /* null terminate */
390
226
            memcpy(str, par->pv[2]->value.array.data,
391
226
                   array_value_size(par->pv[2]));
392
226
            str[array_value_size(par->pv[2])] = '\0';
393
226
            ms_enum =
394
226
                px_paper_string_to_media( /* NB */ (pjl_envvar_t *) str);
395
226
            gs_free_string(pxs->memory, str, array_value_size(par->pv[2]) + 1,
396
226
                           "pxBeginPage");
397
398
1.52k
        } else if (par->pv[2]->value.i) {       /* it's an enumeration */
399
6
            ms_enum = par->pv[2]->value.i;
400
6
        }
401
1.75k
        if (ms_enum == eDefaultPaperSize) {
402
0
            pxs->pm = px_get_default_media(pxs);
403
1.75k
        } else {
404
1.75k
            bool found_media = false;
405
406
3.51k
            for (pxs->pm = known_media, i = 0; i < countof(known_media);
407
1.76k
                 ++pxs->pm, ++i)
408
3.51k
                if (pxs->pm->ms_enum == ms_enum) {
409
1.75k
                    found_media = true;
410
1.75k
                    break;
411
1.75k
                }
412
1.75k
            if (!found_media) { /* No match, select default media. */
413
0
                pxs->pm = px_get_default_media(pxs);
414
0
                px_record_warning("IllegalMediaSize", false, pxs);
415
0
            }
416
1.75k
        }
417
1.75k
      media:pxs->media_size = pxs->pm->ms_enum;
418
1.75k
        pxs->media_dims.x = pxs->pm->width * media_size_scale;
419
1.75k
        pxs->media_dims.y = pxs->pm->height * media_size_scale;
420
1.75k
        pxs->media_height = pxs->pm->height;
421
1.75k
        pxs->media_width = pxs->pm->width;
422
1.75k
    } else if (no_pv_2) {
423
4
        goto media;
424
4
    } else {                    /* custom (!par->pv[2]) */
425
0
        double scale = measure_to_points[par->pv[4]->value.i];
426
427
0
        pxs->media_dims.x = real_value(par->pv[3], 0) * scale;
428
0
        pxs->media_dims.y = real_value(par->pv[3], 1) * scale;
429
        /*
430
         * Assume the unprintable margins for custom media are the same
431
         * as for the default media.  This may not be right.
432
         */
433
0
        pxs->pm = px_get_default_media(pxs);
434
0
        pxs->media_height = (short)(pxs->media_dims.y / media_size_scale);
435
0
        pxs->media_width = (short)(pxs->media_dims.x / media_size_scale);
436
0
    }
437
1.75k
    if (par->pv[5]) {
438
0
        pxs->duplex = false;
439
1.75k
    } else if (par->pv[6]) {
440
1
        pxs->duplex = true;
441
1
        pxs->duplex_page_mode = par->pv[6]->value.i;
442
1
        if (par->pv[7])
443
0
            pxs->duplex_back_side = (par->pv[7]->value.i == eBackMediaSide);
444
1
    }
445
1.75k
    if (par->pv[8])
446
3
        pxs->media_destination = par->pv[8]->value.i;
447
1.75k
    if (par->pv[9])
448
0
        pxs->media_type = par->pv[9]->value.i;
449
450
    /* Pass the media parameters to the device. */
451
1.75k
  setd:{
452
1.75k
        gs_memory_t *mem = pxs->memory;
453
1.75k
        gs_c_param_list list;
454
15.8k
#define plist ((gs_param_list *)&list)
455
1.75k
        gs_param_float_array fa;
456
1.75k
        float fv[4];
457
1.75k
        int iv;
458
1.75k
        bool bv;
459
1.75k
        int ecode = 0;
460
1.75k
        int page_spot_colors = 0;
461
462
1.75k
        fa.data = fv;
463
1.75k
        fa.persistent = false;
464
465
1.75k
        gs_c_param_list_write(&list, mem);
466
1.75k
        iv = pxs->orientation;  /* might not be an int */
467
1.75k
        ecode = param_write_int(plist, "Orientation", &iv);
468
1.75k
        ecode = px_put1(dev, &list, ecode);
469
1.75k
        if (ecode < 0)
470
0
            return ecode;
471
472
        /* PXL never has spot colors on the page */
473
1.75k
        gs_c_param_list_write(&list, mem);
474
1.75k
        ecode = param_write_int(plist, "PageSpotColors", &(page_spot_colors));
475
1.75k
        ecode = px_put1(dev, &list, ecode);
476
1.75k
        if (ecode < 0)
477
0
            return ecode;
478
479
1.75k
        gs_c_param_list_write(&list, mem);
480
1.75k
        fv[0] = pxs->media_dims.x;
481
1.75k
        fv[1] = pxs->media_dims.y;
482
1.75k
        fa.size = 2;
483
1.75k
        ecode = param_write_float_array(plist, ".MediaSize", &fa);
484
1.75k
        ecode = px_put1(dev, &list, ecode);
485
1.75k
        if (ecode < 0)
486
0
            return ecode;
487
488
1.75k
        iv = pxs->media_source; /* might not be an int */
489
1.75k
        if (iv < 0 || iv >= pxeMediaSource_next)
490
3
            px_record_warning("IllegalMediaSource", false, pxs);
491
1.75k
        else {
492
1.75k
            gs_c_param_list_write(&list, mem);
493
1.75k
            ecode = param_write_int(plist, ".MediaSource", &iv);
494
1.75k
            ecode = px_put1(dev, &list, ecode);
495
1.75k
            if (ecode < 0)
496
0
                return ecode;
497
1.75k
        }
498
499
1.75k
        gs_c_param_list_write(&list, mem);
500
1.75k
        ecode = param_write_bool(plist, "Duplex", &pxs->duplex);
501
1.75k
        ecode = px_put1(dev, &list, ecode);
502
1.75k
        if (ecode < 0)
503
0
            return ecode;
504
505
1.75k
        gs_c_param_list_write(&list, mem);
506
1.75k
        bv = pxs->duplex_page_mode == eDuplexHorizontalBinding;
507
1.75k
        ecode = param_write_bool(plist, "Tumble", &bv);
508
1.75k
        ecode = px_put1(dev, &list, ecode);
509
1.75k
        if (ecode < 0)
510
0
            return ecode;
511
512
1.75k
        gs_c_param_list_write(&list, mem);
513
1.75k
        bv = !pxs->duplex_back_side;
514
1.75k
        ecode = param_write_bool(plist, "FirstSide", &bv);
515
1.75k
        ecode = px_put1(dev, &list, ecode);
516
1.75k
        if (ecode < 0)
517
0
            return ecode;
518
519
1.75k
        gs_c_param_list_write(&list, mem);
520
1.75k
        iv = pxs->media_destination;    /* might not be an int */
521
1.75k
        ecode = param_write_int(plist, ".MediaDestination", &iv);
522
1.75k
        ecode = px_put1(dev, &list, ecode);
523
1.75k
        if (ecode < 0)
524
0
            return ecode;
525
526
1.75k
        gs_c_param_list_write(&list, mem);
527
1.75k
        iv = pxs->media_type;   /* might not be an int */
528
1.75k
        ecode = param_write_int(plist, ".MediaType", &iv);
529
1.75k
        ecode = px_put1(dev, &list, ecode);
530
1.75k
        if (ecode < 0)
531
0
            return ecode;
532
533
        /*
534
         * We aren't sure what to do if the device rejects the parameter
535
         * value....
536
         */
537
1.75k
        switch (ecode) {
538
0
            case 1:
539
0
                code = gs_setdevice(pgs, dev);
540
0
                if (code < 0)
541
0
                    return code;
542
1.75k
            case 0:
543
1.75k
                break;
544
0
            default:
545
0
                return_error(errorIllegalAttributeValue);
546
1.75k
        }
547
1.75k
#undef plist
548
1.75k
    }
549
1.75k
    if (!dev->is_open) {
550
7
        code = gs_opendevice(dev);
551
7
        if (code < 0)
552
0
            return code;
553
7
    }
554
1.75k
    {
555
1.75k
        code = px_initgraphics(pxs);
556
1.75k
        if (code < 0) return code;
557
1.75k
        gs_currentmatrix(pgs, &points2device);
558
1.75k
        gs_dtransform(pgs, pxs->media_dims.x, pxs->media_dims.y,
559
1.75k
                      &page_size_pixels);
560
1.75k
        {                       /*
561
                                 * Put the origin at the upper left corner of the page;
562
                                 * also account for the orientation.
563
                                 */
564
1.75k
            gs_matrix orient;
565
566
1.75k
            orient.xx = orient.xy = orient.yx = orient.yy =
567
1.75k
                orient.tx = orient.ty = 0;
568
1.75k
            switch (pxs->orientation) {
569
0
                case eDefaultOrientation:
570
1.75k
                case ePortraitOrientation:
571
1.75k
                    code = gs_translate(pgs, 0.0, pxs->media_dims.y);
572
1.75k
                    orient.xx = 1, orient.yy = -1;
573
1.75k
                    break;
574
0
                case eLandscapeOrientation:
575
0
                    code = 0;
576
0
                    orient.xy = 1, orient.yx = 1;
577
0
                    break;
578
0
                case eReversePortrait:
579
0
                    code = gs_translate(pgs, pxs->media_dims.x, 0);
580
0
                    orient.xx = -1, orient.yy = 1;
581
0
                    break;
582
0
                case eReverseLandscape:
583
0
                    code =
584
0
                        gs_translate(pgs, pxs->media_dims.x,
585
0
                                     pxs->media_dims.y);
586
0
                    orient.xy = -1, orient.yx = -1;
587
0
                    break;
588
0
                default:       /* can't happen */
589
0
                    return_error(errorIllegalAttributeValue);
590
1.75k
            }
591
1.75k
            if (code < 0 || (code = gs_concat(pgs, &orient)) < 0)
592
0
                return code;
593
1.75k
        }
594
1.75k
        {                       /* Scale according to session parameters. */
595
            /* If we can make the scale integral safely, we do. */
596
1.75k
            double scale = measure_to_points[pxs->measure];
597
1.75k
            gs_matrix mat;
598
599
1.75k
            if ((code = gs_scale(pgs, scale / pxs->units_per_measure.x,
600
1.75k
                                 scale / pxs->units_per_measure.y)) < 0)
601
0
                return code;
602
1.75k
            gs_currentmatrix(pgs, &mat);
603
1.75k
            mat.xx = px_adjust_scale(mat.xx, page_size_pixels.x);
604
1.75k
            mat.xy = px_adjust_scale(mat.xy, page_size_pixels.y);
605
1.75k
            mat.yx = px_adjust_scale(mat.yx, page_size_pixels.x);
606
1.75k
            mat.yy = px_adjust_scale(mat.yy, page_size_pixels.y);
607
1.75k
            gs_setmatrix(pgs, &mat);
608
1.75k
            pxs->initial_matrix = mat;
609
1.75k
        }
610
1.75k
    }
611
0
    {                           /*
612
                                 * Set the default halftone method.  We have to do this here,
613
                                 * rather than earlier, so that the origin is set correctly.
614
                                 */
615
1.75k
        px_args_t args = { 0 };
616
1.75k
        px_value_t device_matrix;
617
618
1.75k
        args.pv[1] = &device_matrix;    /* DeviceMatrix */
619
1.75k
        device_matrix.type = pxd_scalar | pxd_ubyte;
620
1.75k
        device_matrix.value.i = eDeviceBest;
621
1.75k
        code = pxSetHalftoneMethod(&args, pxs);
622
1.75k
        if (code < 0) return code;
623
1.75k
    }
624
    /* Initialize other parts of the PCL XL state. */
625
1.75k
    px_dict_init(&pxs->page_pattern_dict, pxs->memory, px_free_pattern);
626
1.75k
    code = gs_erasepage(pgs);
627
1.75k
    if (code < 0) return code;
628
1.75k
    pxs->have_page = false;
629
    /* Make sure there is a legitimate halftone installed. */
630
1.75k
    {
631
1.75k
        code = px_set_halftone(pxs);
632
633
1.75k
        if (code < 0)
634
0
            return code;
635
1.75k
    }
636
    /*
637
     * Do a gsave so we can be sure to get rid of all page-related
638
     * state at the end of the page, but make sure PopGS doesn't pop
639
     * this state from the stack.
640
     */
641
1.75k
    {
642
1.75k
        code = pxPushGS(NULL, pxs);
643
644
1.75k
        if (code < 0)
645
0
            return code;
646
1.75k
        pxs->pxgs->stack_depth--;
647
1.75k
        return code;
648
1.75k
    }
649
1.75k
}
650
651
int
652
pxBeginPageFromPassthrough(px_state_t * pxs)
653
0
{
654
0
    int code;
655
0
    gs_gstate *pgs = pxs->pgs;
656
0
    gs_point page_size_pixels;
657
0
    gs_matrix points2device;
658
659
0
    code = px_initgraphics(pxs);
660
0
    if (code < 0) return code;
661
0
    gs_currentmatrix(pgs, &points2device);
662
0
    gs_dtransform(pgs, pxs->media_dims.x, pxs->media_dims.y,
663
0
                  &page_size_pixels);
664
0
    {
665
        /*
666
         * Put the origin at the upper left corner of the page;
667
         * also account for the orientation.
668
         */
669
0
        gs_matrix orient;
670
671
0
        orient.xx = orient.xy = orient.yx = orient.yy =
672
0
            orient.tx = orient.ty = 0;
673
0
        switch (pxs->orientation) {
674
0
            case eDefaultOrientation:
675
0
            case ePortraitOrientation:
676
0
                code = gs_translate(pgs, 0.0, pxs->media_dims.y);
677
0
                orient.xx = 1, orient.yy = -1;
678
0
                break;
679
0
            case eLandscapeOrientation:
680
0
                code = 0;
681
0
                orient.xy = 1, orient.yx = 1;
682
0
                break;
683
0
            case eReversePortrait:
684
0
                code = gs_translate(pgs, pxs->media_dims.x, 0);
685
0
                orient.xx = -1, orient.yy = 1;
686
0
                break;
687
0
            case eReverseLandscape:
688
0
                code =
689
0
                    gs_translate(pgs, pxs->media_dims.x, pxs->media_dims.y);
690
0
                orient.xy = -1, orient.yx = -1;
691
0
                break;
692
0
            default:           /* can't happen */
693
0
                return_error(errorIllegalAttributeValue);
694
0
        }
695
0
        if (code < 0 || (code = gs_concat(pgs, &orient)) < 0)
696
0
            return code;
697
0
    }
698
0
    {                           /* Scale according to session parameters. */
699
        /* If we can make the scale integral safely, we do. */
700
0
        double scale = measure_to_points[pxs->measure];
701
0
        gs_matrix mat;
702
703
0
        if ((code = gs_scale(pgs, scale / pxs->units_per_measure.x,
704
0
                             scale / pxs->units_per_measure.y)) < 0)
705
0
            return code;
706
0
        gs_currentmatrix(pgs, &mat);
707
0
        mat.xx = px_adjust_scale(mat.xx, page_size_pixels.x);
708
0
        mat.xy = px_adjust_scale(mat.xy, page_size_pixels.y);
709
0
        mat.yx = px_adjust_scale(mat.yx, page_size_pixels.x);
710
0
        mat.yy = px_adjust_scale(mat.yy, page_size_pixels.y);
711
0
        gs_setmatrix(pgs, &mat);
712
0
        pxs->initial_matrix = mat;
713
0
    }
714
0
    pxs->have_page = true;
715
0
    return 0;
716
0
}
717
718
const byte apxEndPage[] = {
719
    0,
720
    pxaPageCopies, 0
721
};
722
int
723
pxEndPage(px_args_t * par, px_state_t * pxs)
724
2.42k
{
725
2.42k
    px_end_page_cleanup(pxs);
726
2.42k
    (*pxs->end_page) (pxs, (par->pv[0] ? par->pv[0]->value.i : pxs->copies),
727
2.42k
                      1);
728
2.42k
    pxs->have_page = false;
729
2.42k
    if (pxs->duplex)
730
5
        pxs->duplex_back_side = !pxs->duplex_back_side;
731
2.41k
    else
732
2.41k
        pxs->duplex_back_side = false;
733
2.42k
    return 0;
734
2.42k
}
735
/* The default end-page procedure just calls the device procedure. */
736
int
737
px_default_end_page(px_state_t * pxs, int num_copies, int flush)
738
0
{
739
0
    return gs_output_page(pxs->pgs, num_copies, flush);
740
0
}
741
742
const byte apxVendorUnique[] = {
743
    pxaVUExtension, 0, pxaVUDataLength, pxaVUAttr1, pxaVUAttr2, pxaVUAttr3,
744
    pxaVUAttr4, pxaVUAttr5, pxaVUAttr6, pxaSourceWidth, pxaSourceHeight,
745
    pxaStartLine, pxaBlockHeight, 0
746
};
747
748
/** we do NOTHING with the vendor unique command.
749
 * it is undocumented, but appears that it contains the sames color commands as the
750
 * XL 2.1 spec.  This is based on only finding it in hpclj 4500 driver output.
751
 * of course HP denys that the 4500 supports XL.
752
 */
753
int
754
pxVendorUnique(px_args_t * par, px_state_t * pxs)
755
0
{
756
0
    int code = 0;
757
758
0
    if (par->pv[1]) {
759
0
        ulong len = par->pv[1]->value.i;
760
0
        ulong copy = min(len - par->source.position,
761
0
                         par->source.available);
762
0
        par->source.data += copy;
763
0
        par->source.available -= copy;
764
0
        par->source.position += copy;
765
0
        if (par->source.position == len)
766
0
            code = 0;
767
0
        else
768
0
            code = pxNeedData;
769
0
    }
770
0
    return code;
771
0
}
772
773
const byte apxComment[] = {
774
    0,
775
    pxaCommentData, 0
776
};
777
int
778
pxComment(px_args_t * par, px_state_t * pxs)
779
74
{
780
74
    return 0;
781
74
}
782
783
const byte apxOpenDataSource[] = {
784
    pxaSourceType, pxaDataOrg, 0, 0
785
};
786
int
787
pxOpenDataSource(px_args_t * par, px_state_t * pxs)
788
1.79k
{
789
1.79k
    if (pxs->data_source_open)
790
0
        return_error(errorDataSourceNotClosed);
791
1.79k
    pxs->data_source_open = true;
792
1.79k
    pxs->data_source_big_endian = par->pv[1]->value.i == eBinaryHighByteFirst;
793
1.79k
    return 0;
794
1.79k
}
795
796
const byte apxCloseDataSource[] = { 0, 0 };
797
int
798
pxCloseDataSource(px_args_t * par, px_state_t * pxs)
799
1.81k
{
800
1.81k
    pxs->data_source_open = false;
801
1.81k
    return 0;
802
1.81k
}