Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/devices/gdevclj.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/*
17
 * H-P Color LaserJet 5/5M device; based on the PaintJet.
18
 */
19
#include "math_.h"
20
#include "gx.h"
21
#include "gsparam.h"
22
#include "gdevprn.h"
23
#include "gdevpcl.h"
24
25
typedef struct gx_device_clj_s gx_device_clj;
26
struct gx_device_clj_s {
27
        gx_device_common;
28
        gx_prn_device_common;
29
        bool rotated;
30
};
31
32
0
#define pclj ((gx_device_clj *)pdev)
33
34
/*
35
 * The HP Color LaserJet 5/5M provides a rather unexpected speed/performance
36
 * tradeoff.
37
 *
38
 * When generating rasters, only the fixed (simple) color spaces provide
39
 * reasonable performance (in this case, reasonable != good). However, in
40
 * these modes, certain of the fully-saturated primary colors (cyan, blue,
41
 * green, and red) are rendered differently as rasters as opposed to colored
42
 * geometric objects. Hence, the color of the output will be other than what
43
 * is expected.
44
 *
45
 * Alternatively, the direct color, 1-bit per pixel scheme can be used. This
46
 * will produce the expected colors, but performance will deteriorate
47
 * significantly (observed printing time will be about 3 times longer than
48
 * when using the simple color mode).
49
 *
50
 * Note that when using the latter mode to view output from the PCL
51
 * interpreter, geometric objects and raster rendered with other than
52
 * geometric color spaces will have the same appearance as if sent directly
53
 * to the CLJ, but rasters generated from simple color spaces will have a
54
 * different appearance. To make the latter rasters match in appearance, the
55
 * faster printing mode must be used (in which the case the other objects
56
 * will not have the same appearance).
57
 */
58
#define USE_FAST_MODE
59
60
/* X_DPI and Y_DPI must be the same */
61
#define X_DPI 300
62
#define Y_DPI 300
63
64
/*
65
 * Array of paper sizes, and the corresponding offsets.
66
 */
67
typedef struct clj_paper_size_s {
68
    uint        tag;                /* paper type tag */
69
    int         orient;             /* logical page orientation to use */
70
    float       width, height;      /* in pts; +- 5 pts */
71
    gs_point    offsets;            /* offsets in the given orientation */
72
} clj_paper_size;
73
74
/*
75
 * The Color LaserJet prints page sizes up to 11.8" wide (A4 size) in
76
 * long-edge-feed (landscape) orientation. Only executive, letter, and
77
 * A4 size are supported for color, so we don't bother to list the others.
78
 */
79
static const clj_paper_size    clj_paper_sizes[] = {
80
    /* U.S. letter size comes first so it will be the default. */
81
    {   2,  1, 11.00f * 72.0f, 8.50f * 72.0f, { .200f * 72.0f, 0.0 } },
82
    {   1,  1, 10.50f * 72.0f, 7.25f * 72.0f, { .200f * 72.0f, 0.0 } },
83
    {  26,  1, 11.69f * 72.0f, 8.27f * 72.0f, { .197f * 72.0f, 0.0 } }
84
};
85
86
/*
87
 * The supported set of resolutions.
88
 *
89
 * The Color LaserJet 5/5M is actually a pseudo-contone device, with hardware
90
 * capable of providing about 16 levels of intensity. The current code does
91
 * not take advantage of this feature, because it is not readily controllable
92
 * via PCL. Rather, the device is modeled as a bi-level device in each of
93
 * three color planes. The maximum supported resolution for such an arrangement
94
 * is 300 dpi.
95
 *
96
 * The CLJ does support raster scaling, but to invoke that scaling, even for
97
 * integral factors, involves a large performance penalty. Hence, only those
98
 * resolutions that can be supported without invoking raster scaling are
99
 * included here. These resolutions are always the same in the fast and slow
100
 * scan directions, so only a single value is listed here.
101
 *
102
 * All valuse are in dots per inch.
103
 */
104
static const float supported_resolutions[] = { 75.0, 100.0, 150.0, 300.0 };
105
106
/* indicate the maximum supported resolution and scan-line length (pts) */
107
0
#define CLJ_MAX_RES        300.0
108
0
#define CLJ_MAX_SCANLINE   (12.0 * 72.0)
109
110
/*
111
 * Determine a requested resolution pair is supported.
112
 */
113
  static bool
114
is_supported_resolution(
115
    const float HWResolution[2]
116
)
117
0
{
118
0
    int     i;
119
120
0
    for (i = 0; i < countof(supported_resolutions); i++) {
121
0
        if (HWResolution[0] == supported_resolutions[i])
122
0
            return HWResolution[0] == HWResolution[1];
123
0
    }
124
0
    return false;
125
0
}
126
127
/* ---------------- Standard driver ---------------- */
128
129
/*
130
 * Find the paper size information corresponding to a given pair of dimensions.
131
 * If rotatep != 0, *rotatep is set to true if the page must be rotated 90
132
 * degrees to fit.
133
 *
134
 * A return value of 0 indicates the paper size is not supported.
135
 *
136
 * Note that for the standard driver, rotation is not allowed.
137
 */
138
  static const clj_paper_size *
139
get_paper_size(
140
    const float             MediaSize[2],
141
    bool *                  rotatep
142
)
143
0
{
144
0
    static const float      tolerance = 5.0;
145
0
    float                   width = MediaSize[0];
146
0
    float                   height = MediaSize[1];
147
0
    const clj_paper_size *  psize = 0;
148
0
    int                     i;
149
150
0
    for (i = 0, psize = clj_paper_sizes; i < countof(clj_paper_sizes); i++, psize++) {
151
0
        if ( (fabs(width - psize->width) <= tolerance)  &&
152
0
             (fabs(height - psize->height) <= tolerance)  ) {
153
0
            if (rotatep != 0)
154
0
                *rotatep = false;
155
0
            return psize;
156
0
        } else if ( (fabs(width - psize->height) <= tolerance) &&
157
0
                    (fabs(height - psize->width) <= tolerance)   ) {
158
0
            if (rotatep != 0)
159
0
                *rotatep = true;
160
0
            return psize;
161
0
        }
162
0
    }
163
164
0
    return 0;
165
0
}
166
167
/*
168
 * Get the (PostScript style) default matrix for the current page size.
169
 *
170
 * For all of the supported sizes, the page will be printed with long-edge
171
 * feed (the CLJ does support some additional sizes, but only for monochrome).
172
 * As will all HP laser printers, the printable region marin is 12 pts. from
173
 * the edge of the physical page.
174
 */
175
static void
176
clj_get_initial_matrix( gx_device *pdev, gs_matrix *pmat)
177
0
{
178
0
    double        fs_res = pdev->HWResolution[0] / 72.0;
179
0
    double        ss_res = pdev->HWResolution[1] / 72.0;
180
0
    const clj_paper_size *psize;
181
182
0
    psize = get_paper_size(pdev->MediaSize, NULL);
183
    /* if the paper size is not recognized, not much can be done */
184
    /* This shouldn't be possible since clj_put_params rejects   */
185
    /* unknown media sizes.          */
186
0
    if (psize == 0) {
187
0
        pmat->xx = fs_res;
188
0
        pmat->xy = 0.0;
189
0
        pmat->yx = 0.0;
190
0
        pmat->yy = -ss_res;
191
0
        pmat->tx = 0.0;
192
0
        pmat->ty = pdev->MediaSize[1] * ss_res;
193
0
        return;
194
0
    }
195
196
0
    if (pclj->rotated) {
197
0
        pmat->xx = 0.0;
198
0
        pmat->xy = ss_res;
199
0
        pmat->yx = fs_res;
200
0
        pmat->yy = 0.0;
201
0
        pmat->tx = -psize->offsets.x * fs_res;
202
0
        pmat->ty = -psize->offsets.y * ss_res;
203
0
    } else {
204
0
        pmat->xx = fs_res;
205
0
        pmat->xy = 0.0;
206
0
        pmat->yx = 0.0;
207
0
        pmat->yy = -ss_res;
208
0
        pmat->tx = -psize->offsets.x * fs_res;
209
0
        pmat->ty = pdev->height + psize->offsets.y * ss_res;
210
0
    }
211
0
}
212
213
/*
214
 * Get parameters, including InputAttributes for all supported page sizes.
215
 * We associate each page size with a different "media source", since that
216
 * is currently the only way to register multiple page sizes.
217
 */
218
static int
219
clj_get_params(gx_device *pdev, gs_param_list *plist)
220
0
{
221
0
    gs_param_dict mdict;
222
0
    int code = gdev_prn_get_params(pdev, plist);
223
0
    int ecode = code;
224
0
    int i;
225
226
0
    code = gdev_begin_input_media(plist, &mdict, countof(clj_paper_sizes));
227
0
    if (code < 0)
228
0
        ecode = code;
229
0
    else {
230
0
        for (i = 0; i < countof(clj_paper_sizes); ++i) {
231
0
            code = gdev_write_input_page_size(i, &mdict,
232
0
                                              clj_paper_sizes[i].width,
233
0
                                              clj_paper_sizes[i].height);
234
0
            if (code < 0)
235
0
                ecode = code;
236
0
        }
237
0
        code = gdev_end_input_media(plist, &mdict);
238
0
        if (code < 0)
239
0
            ecode = code;
240
0
    }
241
0
    return ecode;
242
0
}
243
244
/*
245
 * Get the media size being set by put_params, if any.  Return 0 if no media
246
 * size is being set, 1 (and set mediasize[]) if the size is being set, <0
247
 * on error.
248
 */
249
static int
250
clj_media_size(float mediasize[2], gs_param_list *plist, gx_device *dev)
251
0
{
252
0
    gs_param_float_array fres;
253
0
    gs_param_float_array fsize;
254
0
    gs_param_int_array hwsize;
255
0
    int have_pagesize = 0;
256
0
    float res[2];
257
258
0
    if ( param_read_float_array(plist, "HWResolution", &fres) == 0) {
259
0
        res[0] = fres.data[0];
260
0
        res[1] = fres.data[1];
261
0
    }
262
0
    else
263
0
    {
264
0
        res[0] = dev->HWResolution[0];
265
0
        res[1] = dev->HWResolution[1];
266
0
    }
267
0
    if (!is_supported_resolution(res) )
268
0
        return_error(gs_error_rangecheck);
269
270
0
    if ( (param_read_float_array(plist, "PageSize", &fsize) == 0) ||
271
0
         (param_read_float_array(plist, ".MediaSize", &fsize) == 0) ) {
272
0
        mediasize[0] = fsize.data[0];
273
0
        mediasize[1] = fsize.data[1];
274
0
        have_pagesize = 1;
275
0
    }
276
277
0
    if (param_read_int_array(plist, "HWSize", &hwsize) == 0) {
278
0
        mediasize[0] = ((float)hwsize.data[0]) * 72 / res[0];
279
0
        mediasize[1] = ((float)hwsize.data[1]) * 72 / res[1];
280
0
        have_pagesize = 1;
281
0
    }
282
283
0
    return have_pagesize;
284
0
}
285
286
/*
287
 * Special put_params routine, to make certain the desired MediaSize and
288
 * HWResolution are supported.
289
 */
290
  static int
291
clj_put_params(
292
    gx_device *             pdev,
293
    gs_param_list *         plist
294
)
295
0
{
296
0
    float       mediasize[2];
297
0
    bool                    rotate = false;
298
0
    int                     have_pagesize = clj_media_size(mediasize, plist, pdev);
299
300
0
    if (have_pagesize < 0)
301
0
        return have_pagesize;
302
0
    if (have_pagesize) {
303
0
        if (get_paper_size(mediasize, &rotate) == 0 || rotate)
304
0
            return_error(gs_error_rangecheck);
305
0
    }
306
0
    return gdev_prn_put_params(pdev, plist);
307
0
}
308
309
/*
310
 * Pack and then compress a scanline of data. Return the size of the compressed
311
 * data produced.
312
 *
313
 * Input is arranged with one byte per pixel, but only the three low-order bits
314
 * are used. These bits are in order ymc, with yellow being the highest order
315
 * bit.
316
 *
317
 * Output is arranged in three planes, with one bit per pixel per plane. The
318
 * Color LaserJet 5/5M does support more congenial pixel encodings, but use
319
 * of anything other than the fixed palettes seems to result in very poor
320
 * performance.
321
 *
322
 * Only compresion mode 2 is used. Compression mode 1 (pure run length) has
323
 * an advantage over compression mode 2 only in cases in which very long runs
324
 * occur (> 128 bytes). Since both methods provide good compression in that
325
 * case, it is not worth worrying about, and compression mode 2 provides much
326
 * better worst-case behavior. Compression mode 3 requires considerably more
327
 * effort to generate, so it is useful only when it is known a prior that
328
 * scanlines repeat frequently.
329
 */
330
  static void
331
pack_and_compress_scanline(
332
    const byte *        pin,
333
    int                 in_size,
334
    byte  *             pout[3],
335
    int                 out_size[3]
336
)
337
0
{
338
0
#define BUFF_SIZE                                                           \
339
0
    ( ((int)(CLJ_MAX_RES * CLJ_MAX_SCANLINE / 72.0) + sizeof(ulong) - 1)    \
340
0
         / sizeof(ulong) )
341
342
0
    ulong               buff[3 * BUFF_SIZE];
343
0
    byte *              p_c = (byte *)buff;
344
0
    byte *              p_m = (byte *)(buff + BUFF_SIZE);
345
0
    byte *              p_y = (byte *)(buff + 2 * BUFF_SIZE);
346
0
    ulong *             ptrs[3];
347
0
    byte                c_val = 0, m_val = 0, y_val = 0;
348
0
    ulong               mask = 0x80;
349
0
    int                 i;
350
351
    /* pack the input for 4-bits per index */
352
0
    for (i = 0; i < in_size; i++) {
353
0
        uint    ival = *pin++;
354
355
0
        if (ival != 0) {
356
0
            if ((ival & 0x4) != 0)
357
0
                y_val |= mask;
358
0
            if ((ival & 0x2) != 0)
359
0
                m_val |= mask;
360
0
            if ((ival & 0x1) != 0)
361
0
                c_val |= mask;
362
0
        }
363
364
0
        if ((mask >>= 1) == 0) {
365
            /* NB - write out in byte units */
366
0
            *p_c++ = c_val;
367
0
            c_val = 0L;
368
0
            *p_m++ = m_val;
369
0
            m_val = 0L;
370
0
            *p_y++ = y_val;
371
0
            y_val = 0L;
372
0
            mask = 0x80;
373
0
        }
374
0
    }
375
0
    if (mask != 0x80) {
376
        /* NB - write out in byte units */
377
0
        *p_c++ = c_val;
378
0
        *p_m++ = m_val;
379
0
        *p_y++ = y_val;
380
0
    }
381
382
    /* clear to up a longword boundary */
383
0
    while ((((ulong)p_c) & (sizeof(ulong) - 1)) != 0) {
384
0
        *p_c++ = 0;
385
0
        *p_m++ = 0;
386
0
        *p_y++ = 0;
387
0
    }
388
389
0
    ptrs[0] = (ulong *)p_c;
390
0
    ptrs[1] = (ulong *)p_m;
391
0
    ptrs[2] = (ulong *)p_y;
392
393
0
    for (i = 0; i < 3; i++) {
394
0
        ulong * p_start = buff + i * BUFF_SIZE;
395
0
        ulong * p_end = ptrs[i];
396
397
        /* eleminate trailing 0's */
398
0
        while ((p_end > p_start) && (p_end[-1] == 0))
399
0
            p_end--;
400
401
0
        if (p_start == p_end)
402
0
            out_size[i] = 0;
403
0
        else
404
0
            out_size[i] = gdev_pcl_mode2compress(p_start, p_end, pout[i]);
405
0
    }
406
407
0
#undef BUFF_SIZE
408
0
}
409
410
/*
411
 * Send the page to the printer.  Compress each scan line.
412
 */
413
  static int
414
clj_print_page(
415
    gx_device_printer *     pdev,
416
    gp_file *               prn_stream
417
)
418
0
{
419
0
    gs_memory_t *mem = pdev->memory;
420
0
    bool                    rotate;
421
0
    const clj_paper_size *  psize = get_paper_size(pdev->MediaSize, &rotate);
422
0
    int                     lsize = pdev->width;
423
0
    int                     clsize = (lsize + (lsize + 255) / 128) / 8;
424
0
    byte *                  data = 0;
425
0
    byte *                  cdata[3];
426
0
    int                     blank_lines = 0;
427
0
    int                     i;
428
0
    double                  fs_res = pdev->HWResolution[0] / 72.0;
429
0
    double                  ss_res = pdev->HWResolution[1] / 72.0;
430
0
    int         imageable_width, imageable_height;
431
0
    int                     code = 0;
432
433
    /* no paper size at this point is a serious error */
434
0
    if (psize == 0)
435
0
        return_error(gs_error_unregistered);
436
437
    /* allocate memory for the raw and compressed data */
438
0
    if ((data = gs_alloc_bytes(mem, lsize, "clj_print_page(data)")) == 0)
439
0
        return_error(gs_error_VMerror);
440
0
    if ((cdata[0] = gs_alloc_bytes(mem, 3 * clsize, "clj_print_page(cdata)")) == 0) {
441
0
        gs_free_object(mem, data, "clj_print_page(data)");
442
0
        return_error(gs_error_VMerror);
443
0
    }
444
0
    cdata[1] = cdata[0] + clsize;
445
0
    cdata[2] = cdata[1] + clsize;
446
447
    /* Imageable area is without the margins. Note that the actual rotation
448
     * of page size into pdev->width & height has been done. We just use
449
     * rotate to access the correct offsets. */
450
0
    if (pclj->rotated) {
451
0
        imageable_width = pdev->width - (int)((2 * psize->offsets.x) * fs_res);
452
0
        imageable_height = pdev->height - (int)((2 * psize->offsets.y) * ss_res);
453
0
    }
454
0
    else {
455
0
        imageable_width = pdev->width - (int)((2 * psize->offsets.y) * ss_res);
456
0
        imageable_height = pdev->height - (int)((2 * psize->offsets.x) * fs_res);
457
0
    }
458
459
    /* start the page.  The pcl origin (0, 150 dots by default, y
460
       increasing down the long edge side of the page) needs to be
461
       offset such that it coincides with the offsets of the imageable
462
       area.  This calculation should be independant of rotation but
463
       only the rotated case has been tested with a real device. */
464
0
    gp_fprintf( prn_stream,
465
0
             "\033E\033&u300D\033&l%da1x%dO\033*p0x0y+50x-100Y\033*t%dR"
466
0
#ifdef USE_FAST_MODE
467
0
             "\033*r-3U"
468
#else
469
             "\033*v6W\001\002\003\001\001\001"
470
#endif
471
0
             "\033*r0f%ds%dt1A\033*b2M",
472
0
             psize->tag,
473
0
             pclj->rotated,
474
0
             (int)(pdev->HWResolution[0]),
475
0
             imageable_width,
476
0
             imageable_height
477
0
             );
478
479
    /* process each scanline */
480
0
    for (i = 0; i < imageable_height; i++) {
481
0
        int     clen[3];
482
483
0
        code = gdev_prn_copy_scan_lines(pdev, i, data, lsize);
484
0
        if (code < 0)
485
0
            goto xit;
486
487
        /* The 'lsize' bytes of data have the blank margin area at the end due  */
488
        /* to the 'initial_matrix' offsets that are applied.      */
489
0
        pack_and_compress_scanline(data, imageable_width, cdata, clen);
490
0
        if ((clen[0] == 0) && (clen[1] == 0) && (clen[2] == 0))
491
0
            ++blank_lines;
492
0
        else {
493
0
            if (blank_lines != 0) {
494
0
                gp_fprintf(prn_stream, "\033*b%dY", blank_lines);
495
0
                blank_lines = 0;
496
0
            }
497
0
            gp_fprintf(prn_stream, "\033*b%dV", clen[0]);
498
0
            gp_fwrite(cdata[0], sizeof(byte), clen[0], prn_stream);
499
0
            gp_fprintf(prn_stream, "\033*b%dV", clen[1]);
500
0
            gp_fwrite(cdata[1], sizeof(byte), clen[1], prn_stream);
501
0
            gp_fprintf(prn_stream, "\033*b%dW", clen[2]);
502
0
            gp_fwrite(cdata[2], sizeof(byte), clen[2], prn_stream);
503
0
        }
504
0
    }
505
506
    /* PCL will take care of blank lines at the end */
507
0
    gp_fputs("\033*rC\f", prn_stream);
508
509
0
xit:
510
    /* free the buffers used */
511
0
    gs_free_object(mem, cdata[0], "clj_print_page(cdata)");
512
0
    gs_free_object(mem, data, "clj_print_page(data)");
513
514
0
    return code;
515
0
}
516
517
/* CLJ device methods */
518
#define CLJ_PROCS(get_params, put_params)\
519
    gdev_prn_open,                  /* open_device */\
520
    clj_get_initial_matrix,         /* get_initial matrix */\
521
    NULL,                     /* sync_output */\
522
/* Since the print_page doesn't alter the device, this device can print in the background */\
523
    gdev_prn_bg_output_page,        /* output_page */\
524
    gdev_prn_close,                 /* close_device */\
525
    gdev_pcl_3bit_map_rgb_color,    /* map_rgb_color */\
526
    gdev_pcl_3bit_map_color_rgb,    /* map_color_rgb */\
527
    NULL,                     /* fill_rectangle */\
528
    NULL,                     /* tile_rectangle */\
529
    NULL,                     /* copy_mono */\
530
    NULL,                     /* copy_color */\
531
    NULL,                     /* obsolete draw_line */\
532
    NULL,                     /* get_bits */\
533
    get_params,               /* get_params */\
534
    put_params,                     /* put_params */\
535
    NULL,                     /* map_cmyk_color */\
536
    NULL,                     /* get_xfont_procs */\
537
    NULL,                     /* get_xfont_device */\
538
    NULL,                     /* map_rgb_alpha_color */\
539
    gx_page_device_get_page_device  /* get_page_device */
540
541
static gx_device_procs cljet5_procs = {
542
    CLJ_PROCS(clj_get_params, clj_put_params)
543
};
544
545
/* CLJ device structure */
546
#define CLJ_DEVICE_BODY(procs, dname, rotated)\
547
  prn_device_body(\
548
    gx_device_clj,\
549
    procs,                  /* procedures */\
550
    dname,                  /* device name */\
551
    110,                    /* width - will be overridden subsequently */\
552
    85,                     /* height - will be overridden subsequently */\
553
    X_DPI, Y_DPI,           /* resolutions - current must be the same */\
554
    0.167, 0.167,           /* margins (left, bottom, right, top */\
555
    0.167, 0.167,\
556
    3,                      /* num_components - 3 colors, 1 bit per pixel */\
557
    8,          /* depth - pack into bytes */\
558
    1, 1,         /* max_gray=max_component=1 */\
559
    2, 2,       /* dithered_grays=dithered_components=2 */ \
560
    clj_print_page          /* routine to output page */\
561
),\
562
    rotated       /* rotated - may be overridden subsequently */
563
564
gx_device_clj gs_cljet5_device = {
565
    CLJ_DEVICE_BODY(cljet5_procs, "cljet5", 0 /*false*/)
566
};
567
568
/* ---------------- Driver with page rotation ---------------- */
569
570
/*
571
 * For use with certain PCL interpreters, which don't implement
572
 * setpagedevice, we provide a version of this driver that attempts to
573
 * handle page rotation at the driver level.  This version breaks an
574
 * invariant that all drivers must obey, namely, that drivers are not
575
 * allowed to change the parameters passed by put_params (they can only
576
 * accept or reject them).  Consequently, this driver must not be used in
577
 * any context other than these specific PCL interpreters.  We support this
578
 * hack only because these PCL interpreters can't be changed to handle page
579
 * rotation properly.
580
 */
581
582
/*
583
 * Special get_params routine, to fake MediaSize, width, and height if
584
 * we were in a 'rotated' state.
585
 */
586
static int
587
clj_pr_get_params( gx_device *pdev, gs_param_list *plist )
588
0
{
589
0
    int code;
590
591
    /* First un-rotate the MediaSize, etc. if we were in a rotated mode   */
592
0
    if (pclj->rotated) {
593
0
        float ftmp;
594
0
        int   itmp;
595
596
0
        ftmp = pdev->MediaSize[0];
597
0
        pdev->MediaSize[0] = pdev->MediaSize[1];
598
0
        pdev->MediaSize[1] = ftmp;
599
0
        itmp = pdev->width;
600
0
        pdev->width = pdev->height;
601
0
        pdev->height = itmp;
602
0
    }
603
604
    /* process the parameter list */
605
0
    code = gdev_prn_get_params(pdev, plist);
606
607
    /* Now re-rotate the page size if needed */
608
0
    if (pclj->rotated) {
609
0
        float ftmp;
610
0
        int   itmp;
611
612
0
        ftmp = pdev->MediaSize[0];
613
0
        pdev->MediaSize[0] = pdev->MediaSize[1];
614
0
        pdev->MediaSize[1] = ftmp;
615
0
        itmp = pdev->width;
616
0
        pdev->width = pdev->height;
617
0
        pdev->height = itmp;
618
0
    }
619
620
0
    return code;
621
0
}
622
623
/*
624
 * Special put_params routine, to intercept changes in the MediaSize, and to
625
 * make certain the desired MediaSize and HWResolution are supported.
626
 *
627
 * This function will rotate MediaSize if it is needed by the device in
628
 * order to print this size page.
629
 */
630
  static int
631
clj_pr_put_params(
632
    gx_device *             pdev,
633
    gs_param_list *         plist
634
)
635
0
{
636
0
    float       mediasize[2];
637
0
    int                     code = 0;
638
0
    bool                    rotate = false;
639
0
    int                     have_pagesize = clj_media_size(mediasize, plist, pdev);
640
641
0
    if (have_pagesize < 0)
642
0
        return have_pagesize;
643
0
    if (have_pagesize) {
644
0
        if (get_paper_size(mediasize, &rotate) == 0)
645
0
            return_error(gs_error_rangecheck);
646
0
        if (rotate) {
647
            /* We need to rotate the requested page size, so synthesize a new */
648
            /* parameter list in front of the requestor's list to force the */
649
            /* rotated page size.           */
650
0
            gs_param_float_array  pf_array;
651
0
            gs_c_param_list   alist;
652
0
            float     ftmp = mediasize[0];
653
654
0
            mediasize[0] = mediasize[1];
655
0
            mediasize[1] = ftmp;
656
0
            pf_array.data = mediasize;
657
0
            pf_array.size = 2;
658
0
            pf_array.persistent = false;
659
660
0
            gs_c_param_list_write(&alist, pdev->memory);
661
0
            code = param_write_float_array((gs_param_list *)&alist, ".MediaSize", &pf_array);
662
0
            gs_c_param_list_read(&alist);
663
664
            /* stick this synthesized parameter on the front of the existing list */
665
0
            gs_c_param_list_set_target(&alist, plist);
666
0
            if ((code = gdev_prn_put_params(pdev, (gs_param_list *)&alist)) >= 0)
667
0
                pclj->rotated = true;
668
0
            gs_c_param_list_release(&alist);
669
0
        } else {
670
0
            if ((code = gdev_prn_put_params(pdev, plist)) >= 0)
671
0
                pclj->rotated = false;
672
0
        }
673
0
    } else
674
0
        code = gdev_prn_put_params(pdev, plist);
675
676
0
    return code;
677
0
}
678
679
/* CLJ device methods -- se above for CLJ_PROCS */
680
static gx_device_procs cljet5pr_procs = {
681
    CLJ_PROCS(clj_pr_get_params, clj_pr_put_params)
682
};
683
684
/* CLJ device structure -- see above for CLJ_DEVICE_BODY */
685
gx_device_clj gs_cljet5pr_device = {
686
    CLJ_DEVICE_BODY(cljet5pr_procs, "cljet5pr", 1 /*true*/)
687
};