~ubuntu-branches/ubuntu/vivid/ghostscript/vivid-security

« back to all changes in this revision

Viewing changes to devices/gdevclj.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2013-08-09 20:01:36 UTC
  • mfrom: (1.1.37)
  • Revision ID: package-import@ubuntu.com-20130809200136-amb6zrr7hnjb5jq9
Tags: 9.08~rc1~dfsg-0ubuntu1
* New upstream release
   - Ghostscript 9.08rc1.
   - We are using the system's liblcms2 and libopenjpeg now.
* debian/patches/020130401-852e545-pxl-xl-driver-produced-drawing-commands-without-setting-color-space.patch:
  Removed patch backported from upstream.
* debian/patches/ojdk-8007925+8007926.patch,
  debian/patches/ojdk-8007927.patch,
  debian/patches/ojdk-8007929.patch,
  debian/patches/ojdk-8009654.patch: Removed patches on build in liblcms2, we
  use the system's liblcms2 now.
* debian/patches/2001_docdir_fix_for_debian.patch: Manually updated to new
  upstream source code.
* debian/patches/2003_support_multiarch.patch: Refreshed with quilt.
* debian/control: Added build dependencies on liblcms2-dev and
  libopenjpeg-dev.
* debian/rules: Check for removed lcms2/ and openjpeg/ subdirectories in
  the repackaging check again, also set build options for shared liblcms2
  and libopenjpeg libraries.
* debian/rules: Makefile.in and configure.ac are in the root directory of
  the source now and do not need to get linked from base/. Also there is no
  gstoraster and gstopxl CUPS filter in the package any more and no
  "install-cups" make target any more.
* debian/control, debian/rules, debian/ghostscript-cups.install,
  debian/ghostscript-cups.ppd-updater: Removed the ghostscript-cups binary
  package. The files are now provided by cups-filters.
* debian/symbols.common: Updated for new upstream source. Applied patch
  which dpkg-gensymbols generated for debian/libgs9.symbols to this file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
 
13
   CA  94903, 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
#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
#define CLJ_MAX_RES        300.0
 
108
#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
{
 
118
    int     i;
 
119
 
 
120
    for (i = 0; i < countof(supported_resolutions); i++) {
 
121
        if (HWResolution[0] == supported_resolutions[i])
 
122
            return HWResolution[0] == HWResolution[1];
 
123
    }
 
124
    return false;
 
125
}
 
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
{
 
144
    static const float      tolerance = 5.0;
 
145
    float                   width = MediaSize[0];
 
146
    float                   height = MediaSize[1];
 
147
    const clj_paper_size *  psize = 0;
 
148
    int                     i;
 
149
 
 
150
    for (i = 0, psize = clj_paper_sizes; i < countof(clj_paper_sizes); i++, psize++) {
 
151
        if ( (fabs(width - psize->width) <= tolerance)  &&
 
152
             (fabs(height - psize->height) <= tolerance)  ) {
 
153
            if (rotatep != 0)
 
154
                *rotatep = false;
 
155
            return psize;
 
156
        } else if ( (fabs(width - psize->height) <= tolerance) &&
 
157
                    (fabs(height - psize->width) <= tolerance)   ) {
 
158
            if (rotatep != 0)
 
159
                *rotatep = true;
 
160
            return psize;
 
161
        }
 
162
    }
 
163
 
 
164
    return 0;
 
165
}
 
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
{
 
178
    floatp              fs_res = pdev->HWResolution[0] / 72.0;
 
179
    floatp              ss_res = pdev->HWResolution[1] / 72.0;
 
180
    const clj_paper_size *psize;
 
181
 
 
182
    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
    if (psize == 0) {
 
187
        pmat->xx = fs_res;
 
188
        pmat->xy = 0.0;
 
189
        pmat->yx = 0.0;
 
190
        pmat->yy = -ss_res;
 
191
        pmat->tx = 0.0;
 
192
        pmat->ty = pdev->MediaSize[1] * ss_res;
 
193
        return;
 
194
    }
 
195
 
 
196
    if (pclj->rotated) {
 
197
        pmat->xx = 0.0;
 
198
        pmat->xy = ss_res;
 
199
        pmat->yx = fs_res;
 
200
        pmat->yy = 0.0;
 
201
        pmat->tx = -psize->offsets.x * fs_res;
 
202
        pmat->ty = -psize->offsets.y * ss_res;
 
203
    } else {
 
204
        pmat->xx = fs_res;
 
205
        pmat->xy = 0.0;
 
206
        pmat->yx = 0.0;
 
207
        pmat->yy = -ss_res;
 
208
        pmat->tx = -psize->offsets.x * fs_res;
 
209
        pmat->ty = pdev->height + psize->offsets.y * ss_res;
 
210
    }
 
211
}
 
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
{
 
221
    gs_param_dict mdict;
 
222
    int code = gdev_prn_get_params(pdev, plist);
 
223
    int ecode = code;
 
224
    int i;
 
225
 
 
226
    code = gdev_begin_input_media(plist, &mdict, countof(clj_paper_sizes));
 
227
    if (code < 0)
 
228
        ecode = code;
 
229
    else {
 
230
        for (i = 0; i < countof(clj_paper_sizes); ++i) {
 
231
            code = gdev_write_input_page_size(i, &mdict,
 
232
                                              clj_paper_sizes[i].width,
 
233
                                              clj_paper_sizes[i].height);
 
234
            if (code < 0)
 
235
                ecode = code;
 
236
        }
 
237
        code = gdev_end_input_media(plist, &mdict);
 
238
        if (code < 0)
 
239
            ecode = code;
 
240
    }
 
241
    return ecode;
 
242
}
 
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)
 
251
{
 
252
    gs_param_float_array fres;
 
253
    gs_param_float_array fsize;
 
254
    gs_param_int_array hwsize;
 
255
    int have_pagesize = 0;
 
256
 
 
257
    if ( (param_read_float_array(plist, "HWResolution", &fres) == 0) &&
 
258
          !is_supported_resolution(fres.data) )
 
259
        return_error(gs_error_rangecheck);
 
260
 
 
261
    if ( (param_read_float_array(plist, "PageSize", &fsize) == 0) ||
 
262
         (param_read_float_array(plist, ".MediaSize", &fsize) == 0) ) {
 
263
        mediasize[0] = fsize.data[0];
 
264
        mediasize[1] = fsize.data[1];
 
265
        have_pagesize = 1;
 
266
    }
 
267
 
 
268
    if (param_read_int_array(plist, "HWSize", &hwsize) == 0) {
 
269
        mediasize[0] = ((float)hwsize.data[0]) * 72 / fres.data[0];
 
270
        mediasize[1] = ((float)hwsize.data[1]) * 72 / fres.data[1];
 
271
        have_pagesize = 1;
 
272
    }
 
273
 
 
274
    return have_pagesize;
 
275
}
 
276
 
 
277
/*
 
278
 * Special put_params routine, to make certain the desired MediaSize and
 
279
 * HWResolution are supported.
 
280
 */
 
281
  static int
 
282
clj_put_params(
 
283
    gx_device *             pdev,
 
284
    gs_param_list *         plist
 
285
)
 
286
{
 
287
    float                   mediasize[2];
 
288
    bool                    rotate = false;
 
289
    int                     have_pagesize = clj_media_size(mediasize, plist);
 
290
 
 
291
    if (have_pagesize < 0)
 
292
        return have_pagesize;
 
293
    if (have_pagesize) {
 
294
        if (get_paper_size(mediasize, &rotate) == 0 || rotate)
 
295
            return_error(gs_error_rangecheck);
 
296
    }
 
297
    return gdev_prn_put_params(pdev, plist);
 
298
}
 
299
 
 
300
/*
 
301
 * Pack and then compress a scanline of data. Return the size of the compressed
 
302
 * data produced.
 
303
 *
 
304
 * Input is arranged with one byte per pixel, but only the three low-order bits
 
305
 * are used. These bits are in order ymc, with yellow being the highest order
 
306
 * bit.
 
307
 *
 
308
 * Output is arranged in three planes, with one bit per pixel per plane. The
 
309
 * Color LaserJet 5/5M does support more congenial pixel encodings, but use
 
310
 * of anything other than the fixed palettes seems to result in very poor
 
311
 * performance.
 
312
 *
 
313
 * Only compresion mode 2 is used. Compression mode 1 (pure run length) has
 
314
 * an advantage over compression mode 2 only in cases in which very long runs
 
315
 * occur (> 128 bytes). Since both methods provide good compression in that
 
316
 * case, it is not worth worrying about, and compression mode 2 provides much
 
317
 * better worst-case behavior. Compression mode 3 requires considerably more
 
318
 * effort to generate, so it is useful only when it is known a prior that
 
319
 * scanlines repeat frequently.
 
320
 */
 
321
  static void
 
322
pack_and_compress_scanline(
 
323
    const byte *        pin,
 
324
    int                 in_size,
 
325
    byte  *             pout[3],
 
326
    int                 out_size[3]
 
327
)
 
328
{
 
329
#define BUFF_SIZE                                                           \
 
330
    ( ((int)(CLJ_MAX_RES * CLJ_MAX_SCANLINE / 72.0) + sizeof(ulong) - 1)    \
 
331
         / sizeof(ulong) )
 
332
 
 
333
    ulong               buff[3 * BUFF_SIZE];
 
334
    byte *              p_c = (byte *)buff;
 
335
    byte *              p_m = (byte *)(buff + BUFF_SIZE);
 
336
    byte *              p_y = (byte *)(buff + 2 * BUFF_SIZE);
 
337
    ulong *             ptrs[3];
 
338
    byte                c_val = 0, m_val = 0, y_val = 0;
 
339
    ulong               mask = 0x80;
 
340
    int                 i;
 
341
 
 
342
    /* pack the input for 4-bits per index */
 
343
    for (i = 0; i < in_size; i++) {
 
344
        uint    ival = *pin++;
 
345
 
 
346
        if (ival != 0) {
 
347
            if ((ival & 0x4) != 0)
 
348
                y_val |= mask;
 
349
            if ((ival & 0x2) != 0)
 
350
                m_val |= mask;
 
351
            if ((ival & 0x1) != 0)
 
352
                c_val |= mask;
 
353
        }
 
354
 
 
355
        if ((mask >>= 1) == 0) {
 
356
            /* NB - write out in byte units */
 
357
            *p_c++ = c_val;
 
358
            c_val = 0L;
 
359
            *p_m++ = m_val;
 
360
            m_val = 0L;
 
361
            *p_y++ = y_val;
 
362
            y_val = 0L;
 
363
            mask = 0x80;
 
364
        }
 
365
    }
 
366
    if (mask != 0x80) {
 
367
        /* NB - write out in byte units */
 
368
        *p_c++ = c_val;
 
369
        *p_m++ = m_val;
 
370
        *p_y++ = y_val;
 
371
    }
 
372
 
 
373
    /* clear to up a longword boundary */
 
374
    while ((((ulong)p_c) & (sizeof(ulong) - 1)) != 0) {
 
375
        *p_c++ = 0;
 
376
        *p_m++ = 0;
 
377
        *p_y++ = 0;
 
378
    }
 
379
 
 
380
    ptrs[0] = (ulong *)p_c;
 
381
    ptrs[1] = (ulong *)p_m;
 
382
    ptrs[2] = (ulong *)p_y;
 
383
 
 
384
    for (i = 0; i < 3; i++) {
 
385
        ulong * p_start = buff + i * BUFF_SIZE;
 
386
        ulong * p_end = ptrs[i];
 
387
 
 
388
        /* eleminate trailing 0's */
 
389
        while ((p_end > p_start) && (p_end[-1] == 0))
 
390
            p_end--;
 
391
 
 
392
        if (p_start == p_end)
 
393
            out_size[i] = 0;
 
394
        else
 
395
            out_size[i] = gdev_pcl_mode2compress(p_start, p_end, pout[i]);
 
396
    }
 
397
 
 
398
#undef BUFF_SIZE
 
399
}
 
400
 
 
401
/*
 
402
 * Send the page to the printer.  Compress each scan line.
 
403
 */
 
404
  static int
 
405
clj_print_page(
 
406
    gx_device_printer *     pdev,
 
407
    FILE *                  prn_stream
 
408
)
 
409
{
 
410
    gs_memory_t *mem = pdev->memory;
 
411
    bool                    rotate;
 
412
    const clj_paper_size *  psize = get_paper_size(pdev->MediaSize, &rotate);
 
413
    int                     lsize = pdev->width;
 
414
    int                     clsize = (lsize + (lsize + 255) / 128) / 8;
 
415
    byte *                  data = 0;
 
416
    byte *                  cdata[3];
 
417
    int                     blank_lines = 0;
 
418
    int                     i;
 
419
    floatp                  fs_res = pdev->HWResolution[0] / 72.0;
 
420
    floatp                  ss_res = pdev->HWResolution[1] / 72.0;
 
421
    int                     imageable_width, imageable_height;
 
422
 
 
423
    /* no paper size at this point is a serious error */
 
424
    if (psize == 0)
 
425
        return_error(gs_error_unregistered);
 
426
 
 
427
    /* allocate memory for the raw and compressed data */
 
428
    if ((data = gs_alloc_bytes(mem, lsize, "clj_print_page(data)")) == 0)
 
429
        return_error(gs_error_VMerror);
 
430
    if ((cdata[0] = gs_alloc_bytes(mem, 3 * clsize, "clj_print_page(cdata)")) == 0) {
 
431
        gs_free_object(mem, data, "clj_print_page(data)");
 
432
        return_error(gs_error_VMerror);
 
433
    }
 
434
    cdata[1] = cdata[0] + clsize;
 
435
    cdata[2] = cdata[1] + clsize;
 
436
 
 
437
    /* Imageable area is without the margins. Note that the actual rotation
 
438
     * of page size into pdev->width & height has been done. We just use
 
439
     * rotate to access the correct offsets. */
 
440
    if (pclj->rotated) {
 
441
        imageable_width = pdev->width - (int)((2 * psize->offsets.x) * fs_res);
 
442
        imageable_height = pdev->height - (int)((2 * psize->offsets.y) * ss_res);
 
443
    }
 
444
    else {
 
445
        imageable_width = pdev->width - (int)((2 * psize->offsets.y) * ss_res);
 
446
        imageable_height = pdev->height - (int)((2 * psize->offsets.x) * fs_res);
 
447
    }
 
448
 
 
449
    /* start the page.  The pcl origin (0, 150 dots by default, y
 
450
       increasing down the long edge side of the page) needs to be
 
451
       offset such that it coincides with the offsets of the imageable
 
452
       area.  This calculation should be independant of rotation but
 
453
       only the rotated case has been tested with a real device. */
 
454
    fprintf( prn_stream,
 
455
             "\033E\033&u300D\033&l%da1x%dO\033*p0x0y+50x-100Y\033*t%dR"
 
456
#ifdef USE_FAST_MODE
 
457
             "\033*r-3U"
 
458
#else
 
459
             "\033*v6W\001\002\003\001\001\001"
 
460
#endif
 
461
             "\033*r0f%ds%dt1A\033*b2M",
 
462
             psize->tag,
 
463
             pclj->rotated,
 
464
             (int)(pdev->HWResolution[0]),
 
465
             imageable_width,
 
466
             imageable_height
 
467
             );
 
468
 
 
469
    /* process each scanline */
 
470
    for (i = 0; i < imageable_height; i++) {
 
471
        int     clen[3];
 
472
 
 
473
        gdev_prn_copy_scan_lines(pdev, i, data, lsize);
 
474
 
 
475
        /* The 'lsize' bytes of data have the blank margin area at the end due  */
 
476
        /* to the 'initial_matrix' offsets that are applied.                    */
 
477
        pack_and_compress_scanline(data, imageable_width, cdata, clen);
 
478
        if ((clen[0] == 0) && (clen[1] == 0) && (clen[2] == 0))
 
479
            ++blank_lines;
 
480
        else {
 
481
            if (blank_lines != 0) {
 
482
                fprintf(prn_stream, "\033*b%dY", blank_lines);
 
483
                blank_lines = 0;
 
484
            }
 
485
            fprintf(prn_stream, "\033*b%dV", clen[0]);
 
486
            fwrite(cdata[0], sizeof(byte), clen[0], prn_stream);
 
487
            fprintf(prn_stream, "\033*b%dV", clen[1]);
 
488
            fwrite(cdata[1], sizeof(byte), clen[1], prn_stream);
 
489
            fprintf(prn_stream, "\033*b%dW", clen[2]);
 
490
            fwrite(cdata[2], sizeof(byte), clen[2], prn_stream);
 
491
        }
 
492
    }
 
493
 
 
494
    /* PCL will take care of blank lines at the end */
 
495
    fputs("\033*rC\f", prn_stream);
 
496
 
 
497
    /* free the buffers used */
 
498
    gs_free_object(mem, cdata[0], "clj_print_page(cdata)");
 
499
    gs_free_object(mem, data, "clj_print_page(data)");
 
500
 
 
501
    return 0;
 
502
}
 
503
 
 
504
/* CLJ device methods */
 
505
#define CLJ_PROCS(get_params, put_params)\
 
506
    gdev_prn_open,                  /* open_device */\
 
507
    clj_get_initial_matrix,         /* get_initial matrix */\
 
508
    NULL,                           /* sync_output */\
 
509
/* Since the print_page doesn't alter the device, this device can print in the background */\
 
510
    gdev_prn_bg_output_page,        /* output_page */\
 
511
    gdev_prn_close,                 /* close_device */\
 
512
    gdev_pcl_3bit_map_rgb_color,    /* map_rgb_color */\
 
513
    gdev_pcl_3bit_map_color_rgb,    /* map_color_rgb */\
 
514
    NULL,                           /* fill_rectangle */\
 
515
    NULL,                           /* tile_rectangle */\
 
516
    NULL,                           /* copy_mono */\
 
517
    NULL,                           /* copy_color */\
 
518
    NULL,                           /* obsolete draw_line */\
 
519
    NULL,                           /* get_bits */\
 
520
    get_params,                     /* get_params */\
 
521
    put_params,                     /* put_params */\
 
522
    NULL,                           /* map_cmyk_color */\
 
523
    NULL,                           /* get_xfont_procs */\
 
524
    NULL,                           /* get_xfont_device */\
 
525
    NULL,                           /* map_rgb_alpha_color */\
 
526
    gx_page_device_get_page_device  /* get_page_device */
 
527
 
 
528
static gx_device_procs cljet5_procs = {
 
529
    CLJ_PROCS(clj_get_params, clj_put_params)
 
530
};
 
531
 
 
532
/* CLJ device structure */
 
533
#define CLJ_DEVICE_BODY(procs, dname, rotated)\
 
534
  prn_device_body(\
 
535
    gx_device_clj,\
 
536
    procs,                  /* procedures */\
 
537
    dname,                  /* device name */\
 
538
    110,                    /* width - will be overridden subsequently */\
 
539
    85,                     /* height - will be overridden subsequently */\
 
540
    X_DPI, Y_DPI,           /* resolutions - current must be the same */\
 
541
    0.167, 0.167,           /* margins (left, bottom, right, top */\
 
542
    0.167, 0.167,\
 
543
    3,                      /* num_components - 3 colors, 1 bit per pixel */\
 
544
    8,                      /* depth - pack into bytes */\
 
545
    1, 1,                   /* max_gray=max_component=1 */\
 
546
    2, 2,                   /* dithered_grays=dithered_components=2 */ \
 
547
    clj_print_page          /* routine to output page */\
 
548
),\
 
549
    rotated                 /* rotated - may be overridden subsequently */
 
550
 
 
551
gx_device_clj gs_cljet5_device = {
 
552
    CLJ_DEVICE_BODY(cljet5_procs, "cljet5", 0 /*false*/)
 
553
};
 
554
 
 
555
/* ---------------- Driver with page rotation ---------------- */
 
556
 
 
557
/*
 
558
 * For use with certain PCL interpreters, which don't implement
 
559
 * setpagedevice, we provide a version of this driver that attempts to
 
560
 * handle page rotation at the driver level.  This version breaks an
 
561
 * invariant that all drivers must obey, namely, that drivers are not
 
562
 * allowed to change the parameters passed by put_params (they can only
 
563
 * accept or reject them).  Consequently, this driver must not be used in
 
564
 * any context other than these specific PCL interpreters.  We support this
 
565
 * hack only because these PCL interpreters can't be changed to handle page
 
566
 * rotation properly.
 
567
 */
 
568
 
 
569
/*
 
570
 * Special get_params routine, to fake MediaSize, width, and height if
 
571
 * we were in a 'rotated' state.
 
572
 */
 
573
static int
 
574
clj_pr_get_params( gx_device *pdev, gs_param_list *plist )
 
575
{
 
576
    int code;
 
577
 
 
578
    /* First un-rotate the MediaSize, etc. if we were in a rotated mode         */
 
579
    if (pclj->rotated) {
 
580
        float ftmp;
 
581
        int   itmp;
 
582
 
 
583
        ftmp = pdev->MediaSize[0];
 
584
        pdev->MediaSize[0] = pdev->MediaSize[1];
 
585
        pdev->MediaSize[1] = ftmp;
 
586
        itmp = pdev->width;
 
587
        pdev->width = pdev->height;
 
588
        pdev->height = itmp;
 
589
    }
 
590
 
 
591
    /* process the parameter list */
 
592
    code = gdev_prn_get_params(pdev, plist);
 
593
 
 
594
    /* Now re-rotate the page size if needed */
 
595
    if (pclj->rotated) {
 
596
        float ftmp;
 
597
        int   itmp;
 
598
 
 
599
        ftmp = pdev->MediaSize[0];
 
600
        pdev->MediaSize[0] = pdev->MediaSize[1];
 
601
        pdev->MediaSize[1] = ftmp;
 
602
        itmp = pdev->width;
 
603
        pdev->width = pdev->height;
 
604
        pdev->height = itmp;
 
605
    }
 
606
 
 
607
    return code;
 
608
}
 
609
 
 
610
/*
 
611
 * Special put_params routine, to intercept changes in the MediaSize, and to
 
612
 * make certain the desired MediaSize and HWResolution are supported.
 
613
 *
 
614
 * This function will rotate MediaSize if it is needed by the device in
 
615
 * order to print this size page.
 
616
 */
 
617
  static int
 
618
clj_pr_put_params(
 
619
    gx_device *             pdev,
 
620
    gs_param_list *         plist
 
621
)
 
622
{
 
623
    float                   mediasize[2];
 
624
    int                     code = 0;
 
625
    bool                    rotate = false;
 
626
    int                     have_pagesize = clj_media_size(mediasize, plist);
 
627
 
 
628
    if (have_pagesize < 0)
 
629
        return have_pagesize;
 
630
    if (have_pagesize) {
 
631
        if (get_paper_size(mediasize, &rotate) == 0)
 
632
            return_error(gs_error_rangecheck);
 
633
        if (rotate) {
 
634
            /* We need to rotate the requested page size, so synthesize a new   */
 
635
            /* parameter list in front of the requestor's list to force the     */
 
636
            /* rotated page size.                                               */
 
637
            gs_param_float_array        pf_array;
 
638
            gs_c_param_list             alist;
 
639
            float                       ftmp = mediasize[0];
 
640
 
 
641
            mediasize[0] = mediasize[1];
 
642
            mediasize[1] = ftmp;
 
643
            pf_array.data = mediasize;
 
644
            pf_array.size = 2;
 
645
            pf_array.persistent = false;
 
646
 
 
647
            gs_c_param_list_write(&alist, pdev->memory);
 
648
            code = param_write_float_array((gs_param_list *)&alist, ".MediaSize", &pf_array);
 
649
            gs_c_param_list_read(&alist);
 
650
 
 
651
            /* stick this synthesized parameter on the front of the existing list */
 
652
            gs_c_param_list_set_target(&alist, plist);
 
653
            if ((code = gdev_prn_put_params(pdev, (gs_param_list *)&alist)) >= 0)
 
654
                pclj->rotated = true;
 
655
            gs_c_param_list_release(&alist);
 
656
        } else {
 
657
            if ((code = gdev_prn_put_params(pdev, plist)) >= 0)
 
658
                pclj->rotated = false;
 
659
        }
 
660
    } else
 
661
        code = gdev_prn_put_params(pdev, plist);
 
662
 
 
663
    return code;
 
664
}
 
665
 
 
666
/* CLJ device methods -- se above for CLJ_PROCS */
 
667
static gx_device_procs cljet5pr_procs = {
 
668
    CLJ_PROCS(clj_pr_get_params, clj_pr_put_params)
 
669
};
 
670
 
 
671
/* CLJ device structure -- see above for CLJ_DEVICE_BODY */
 
672
gx_device_clj gs_cljet5pr_device = {
 
673
    CLJ_DEVICE_BODY(cljet5pr_procs, "cljet5pr", 1 /*true*/)
 
674
};