Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpx.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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 PCL XL driver */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsccolor.h"
23
#include "gsdcolor.h"
24
#include "gxiparam.h"
25
#include "gxcspace.h"           /* for color mapping for images */
26
#include "gxdevice.h"
27
#include "gxpath.h"
28
#include "gdevvec.h"
29
#include "gdevmrop.h"
30
#include "strimpl.h"
31
#include "srlx.h"
32
#include "jpeglib_.h"
33
#include "sdct.h"
34
#include "sjpeg.h"
35
#include "gdevpxat.h"
36
#include "gdevpxen.h"
37
#include "gdevpxop.h"
38
#include "gdevpxut.h"
39
#include "gxlum.h"
40
#include "gdevpcl.h"            /* for gdev_pcl_mode3compress() */
41
#include "gsicc_manage.h"
42
#include "gsicc_cache.h"
43
#include <stdlib.h>             /* abs() */
44
45
/* ---------------- Device definition ---------------- */
46
47
/* Define the default resolution. */
48
#ifndef X_DPI
49
#  define X_DPI 600
50
#endif
51
#ifndef Y_DPI
52
#  define Y_DPI 600
53
#endif
54
55
/* Structure definition */
56
22.1M
#define NUM_POINTS 40           /* must be >= 3 and <= 255 */
57
typedef enum {
58
    POINTS_NONE,
59
    POINTS_LINES,
60
    POINTS_CURVES
61
} point_type_t;
62
typedef struct gx_device_pclxl_s {
63
    gx_device_vector_common;
64
    /* Additional state information */
65
    pxeMediaSize_t media_size;
66
    bool ManualFeed;            /* map ps setpage commands to pxl */
67
    bool ManualFeed_set;
68
    int MediaPosition_old;      /* old Position attribute - for duplex detection */
69
    int MediaPosition;          /* MediaPosition attribute */
70
    int MediaPosition_set;
71
    char MediaType_old[64];     /* old MediaType attribute - for duplex detection */
72
    char MediaType[64];         /* MediaType attribute */
73
    int MediaType_set;
74
    int page;                   /* Page number starting at 0 */
75
    bool Duplex;                /* Duplex attribute */
76
    bool Staple;                /* Staple attribute */
77
    bool Tumble;                /* Tumble attribute */
78
    gx_path_type_t fill_rule;   /* ...winding_number or ...even_odd  */
79
    gx_path_type_t clip_rule;   /* ditto */
80
    pxeColorSpace_t color_space;
81
    struct pal_ {
82
        int size;               /* # of bytes */
83
        byte data[256 * 3];     /* up to 8-bit samples */
84
    } palette;
85
    struct pts_ {
86
        /* buffer for accumulating path points */
87
        gs_int_point current;   /* current point as of start of data */
88
        point_type_t type;
89
        int count;
90
        gs_int_point data[NUM_POINTS];
91
    } points;
92
    struct ch_ {
93
    /* cache for downloaded characters */
94
1.22M
#define MAX_CACHED_CHARS 400
95
1.22M
#define MAX_CHAR_DATA 500000
96
3.70M
#define MAX_CHAR_SIZE 5000
97
4.31M
#define CHAR_HASH_FACTOR 247
98
        ushort table[MAX_CACHED_CHARS * 3 / 2];
99
        struct cd_ {
100
            gs_id id;           /* key */
101
            uint size;
102
        } data[MAX_CACHED_CHARS];
103
        int next_in;            /* next data element to fill in */
104
        int next_out;           /* next data element to discard */
105
        int count;              /* of occupied data elements */
106
        ulong used;
107
    } chars;
108
    bool font_set;
109
    int state_rotated;          /* 0, 1, 2, -1, mutiple of 90 deg */
110
    int CompressMode;           /* std PXL enum: None=0, RLE=1, JPEG=2, DeltaRow=3 */
111
    bool scaled;
112
    double x_scale;             /* chosen so that max(x) is scaled to 0x7FFF, to give max distinction between x values */
113
    double y_scale;
114
    bool pen_null;
115
    bool brush_null;
116
    bool iccTransform;
117
} gx_device_pclxl;
118
119
gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
120
                               "gx_device_pclxl",
121
                               device_pclxl_enum_ptrs,
122
                               device_pclxl_reloc_ptrs, gx_device_finalize,
123
                               st_device_vector);
124
125
#define pclxl_device_body(dname, depth, init)\
126
  std_device_dci_type_body(gx_device_pclxl, init, dname, &st_device_pclxl,\
127
                           DEFAULT_WIDTH_10THS * X_DPI / 10,\
128
                           DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
129
                           X_DPI, Y_DPI,\
130
                           (depth > 8 ? 3 : 1), depth,\
131
                           (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
132
                           (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
133
134
/* Driver procedures */
135
static dev_proc_open_device(pclxl_open_device);
136
static dev_proc_output_page(pclxl_output_page);
137
static dev_proc_close_device(pclxl_close_device);
138
static dev_proc_copy_mono(pclxl_copy_mono);
139
static dev_proc_copy_color(pclxl_copy_color);
140
static dev_proc_fill_mask(pclxl_fill_mask);
141
142
static dev_proc_get_params(pclxl_get_params);
143
static dev_proc_put_params(pclxl_put_params);
144
145
/*static dev_proc_draw_thin_line(pclxl_draw_thin_line); */
146
static dev_proc_begin_typed_image(pclxl_begin_typed_image);
147
static dev_proc_strip_copy_rop2(pclxl_strip_copy_rop2);
148
149
static void
150
pclxl_initialize_device_procs(gx_device *dev,
151
                              dev_proc_map_rgb_color(map_rgb_color),
152
                              dev_proc_map_color_rgb(map_color_rgb))
153
13.0k
{
154
13.0k
    set_dev_proc(dev, open_device, pclxl_open_device);
155
13.0k
    set_dev_proc(dev, output_page, pclxl_output_page);
156
13.0k
    set_dev_proc(dev, close_device, pclxl_close_device);
157
13.0k
    set_dev_proc(dev, map_rgb_color, map_rgb_color);
158
13.0k
    set_dev_proc(dev, map_color_rgb, map_color_rgb);
159
13.0k
    set_dev_proc(dev, fill_rectangle, gdev_vector_fill_rectangle);
160
13.0k
    set_dev_proc(dev, copy_mono, pclxl_copy_mono);
161
13.0k
    set_dev_proc(dev, copy_color, pclxl_copy_color);
162
13.0k
    set_dev_proc(dev, get_params, pclxl_get_params);
163
13.0k
    set_dev_proc(dev, put_params, pclxl_put_params);
164
13.0k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
165
13.0k
    set_dev_proc(dev, fill_path, gdev_vector_fill_path);
166
13.0k
    set_dev_proc(dev, stroke_path, gdev_vector_stroke_path);
167
13.0k
    set_dev_proc(dev, fill_mask, pclxl_fill_mask);
168
13.0k
    set_dev_proc(dev, fill_trapezoid, gdev_vector_fill_trapezoid);
169
13.0k
    set_dev_proc(dev, fill_parallelogram, gdev_vector_fill_parallelogram);
170
13.0k
    set_dev_proc(dev, fill_triangle, gdev_vector_fill_triangle);
171
13.0k
    set_dev_proc(dev, begin_typed_image, pclxl_begin_typed_image);
172
13.0k
    set_dev_proc(dev, strip_copy_rop2, pclxl_strip_copy_rop2);
173
13.0k
}
174
175
static void
176
pxlmono_initialize_device_procs(gx_device *dev)
177
6.65k
{
178
6.65k
    pclxl_initialize_device_procs(dev,
179
6.65k
                                  gx_default_gray_map_rgb_color,
180
6.65k
                                  gx_default_gray_map_color_rgb);
181
6.65k
}
182
183
static void
184
pxlcolor_initialize_device_procs(gx_device *dev)
185
6.39k
{
186
6.39k
    pclxl_initialize_device_procs(dev,
187
6.39k
                                  gx_default_rgb_map_rgb_color,
188
6.39k
                                  gx_default_rgb_map_color_rgb);
189
6.39k
}
190
191
const gx_device_pclxl gs_pxlmono_device = {
192
    pclxl_device_body("pxlmono", 8, pxlmono_initialize_device_procs)
193
};
194
195
const gx_device_pclxl gs_pxlcolor_device = {
196
    pclxl_device_body("pxlcolor", 24, pxlcolor_initialize_device_procs)
197
};
198
199
/* ---------------- Other utilities ---------------- */
200
201
static inline stream *
202
pclxl_stream(gx_device_pclxl * xdev)
203
97.5M
{
204
97.5M
    return gdev_vector_stream((gx_device_vector *) xdev);
205
97.5M
}
206
207
/* Initialize for a page. */
208
static void
209
pclxl_page_init(gx_device_pclxl * xdev)
210
22.7k
{
211
22.7k
    gdev_vector_init((gx_device_vector *) xdev);
212
22.7k
    xdev->in_page = false;
213
22.7k
    xdev->fill_rule = gx_path_type_winding_number;
214
22.7k
    xdev->clip_rule = gx_path_type_winding_number;
215
22.7k
    xdev->color_space = eNoColorSpace;
216
22.7k
    xdev->palette.size = 0;
217
22.7k
    xdev->font_set = false;
218
22.7k
    xdev->state_rotated = 0;
219
22.7k
    xdev->scaled = false;
220
22.7k
    xdev->x_scale = 1;
221
22.7k
    xdev->y_scale = 1;
222
22.7k
    xdev->pen_null = false;
223
22.7k
    xdev->brush_null = false;
224
22.7k
}
225
226
/* Test whether a RGB color is actually a gray shade. */
227
12.6M
#define RGB_IS_GRAY(ci) ((ci) >> 8 == ((ci) & 0xffff))
228
229
/* Set the color space and (optionally) palette. */
230
static void
231
pclxl_set_color_space(gx_device_pclxl * xdev, pxeColorSpace_t color_space)
232
13.3M
{
233
13.3M
    if (xdev->color_space != color_space) {
234
824k
        stream *s = pclxl_stream(xdev);
235
236
824k
        px_put_ub(s, (byte) color_space);
237
824k
        px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
238
824k
        xdev->color_space = color_space;
239
824k
        xdev->palette.size = 0; /* purge the cached palette */
240
824k
    }
241
13.3M
}
242
static void
243
pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
244
                        const byte * palette, uint palette_size)
245
3.06k
{
246
3.06k
    if (xdev->color_space != color_space ||
247
3.06k
        xdev->palette.size != palette_size ||
248
3.06k
        memcmp(xdev->palette.data, palette, palette_size)
249
3.06k
        ) {
250
352
        stream *s = pclxl_stream(xdev);
251
252
352
        static const byte csp_[] = {
253
352
            DA(pxaColorSpace),
254
352
            DUB(e8Bit), DA(pxaPaletteDepth),
255
352
            pxt_ubyte_array
256
352
        };
257
258
352
        px_put_ub(s, (byte) color_space);
259
352
        PX_PUT_LIT(s, csp_);
260
352
        px_put_u(s, palette_size);
261
352
        px_put_bytes(s, palette, palette_size);
262
352
        px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
263
352
        xdev->color_space = color_space;
264
352
        xdev->palette.size = palette_size;
265
352
        memcpy(xdev->palette.data, palette, palette_size);
266
352
    }
267
3.06k
}
268
269
/* For caching either NullPen or NullBrush, which happens a lot for
270
 * drawing masks in the PS3 CET test set.
271
 *
272
 * The expected null_source/op combos are:
273
 * pxaNullPen/pxtSetPenSource and pxaNullBrush/pxtSetBrushSource
274
 */
275
static int
276
pclxl_set_cached_nulls(gx_device_pclxl * xdev, px_attribute_t null_source,
277
                       px_tag_t op)
278
19.6M
{
279
19.6M
    stream *s = pclxl_stream(xdev);
280
281
19.6M
    if (op == pxtSetPenSource) {
282
19.6M
        if (xdev->pen_null)
283
19.5M
            return 0;
284
30.3k
        else
285
30.3k
            xdev->pen_null = true;
286
19.6M
    }
287
95.6k
    if (op == pxtSetBrushSource) {
288
65.3k
        if (xdev->brush_null)
289
32.8k
            return 0;
290
32.4k
        else
291
32.4k
            xdev->brush_null = true;
292
65.3k
    }
293
62.7k
    px_put_uba(s, 0, (byte) null_source);
294
62.7k
    spputc(s, (byte) op);
295
62.7k
    return 0;
296
95.6k
}
297
298
/* Set a drawing RGB color. */
299
static int
300
pclxl_set_color(gx_device_pclxl * xdev, const gx_drawing_color * pdc,
301
                px_attribute_t null_source, px_tag_t op)
302
13.2M
{
303
13.2M
    stream *s = pclxl_stream(xdev);
304
305
13.2M
    if (gx_dc_is_pure(pdc)) {
306
13.2M
        gx_color_index color = gx_dc_pure_color(pdc);
307
308
13.2M
        if (op == pxtSetPenSource)
309
22.5k
            xdev->pen_null = false;
310
13.2M
        if (op == pxtSetBrushSource)
311
13.1M
            xdev->brush_null = false;
312
313
13.2M
        if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
314
7.34M
            pclxl_set_color_space(xdev, eGray);
315
7.34M
            px_put_uba(s, (byte) color, pxaGrayLevel);
316
7.34M
        } else {
317
5.87M
            pclxl_set_color_space(xdev, eRGB);
318
5.87M
            spputc(s, pxt_ubyte_array);
319
5.87M
            px_put_ub(s, 3);
320
5.87M
            spputc(s, (byte) (color >> 16));
321
5.87M
            spputc(s, (byte) (color >> 8));
322
5.87M
            spputc(s, (byte) color);
323
5.87M
            px_put_a(s, pxaRGBColor);
324
5.87M
        }
325
13.2M
    } else if (gx_dc_is_null(pdc) || !color_is_set(pdc)) {
326
0
        if (op == pxtSetPenSource || op == pxtSetBrushSource)
327
0
            return pclxl_set_cached_nulls(xdev, null_source, op);
328
0
        else
329
0
            px_put_uba(s, 0, null_source);
330
0
    } else
331
1.81k
        return_error(gs_error_rangecheck);
332
13.2M
    spputc(s, (byte) op);
333
13.2M
    return 0;
334
13.2M
}
335
336
/* Test whether we can handle a given color space in an image. */
337
/* We cannot handle ICCBased color spaces. */
338
static bool
339
pclxl_can_handle_color_space(const gs_color_space * pcs)
340
4.69k
{
341
4.69k
    gs_color_space_index index;
342
343
    /* an image with no colorspace info arrived; cannot handle */
344
4.69k
    if (!pcs)
345
0
        return false;
346
4.69k
    index = gs_color_space_get_index(pcs);
347
348
4.69k
    if (index == gs_color_space_index_Indexed) {
349
369
        if (pcs->params.indexed.use_proc)
350
0
            return false;
351
369
        index =
352
369
            gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
353
4.32k
    } else if (index == gs_color_space_index_ICC) {
354
4.31k
        index = gsicc_get_default_type(pcs->cmm_icc_profile_data);
355
4.31k
        return ((index < gs_color_space_index_DevicePixel) ? true : false);
356
4.31k
    }
357
358
376
    return !(index == gs_color_space_index_Separation ||
359
376
             index == gs_color_space_index_Pattern ||
360
376
             index == gs_color_space_index_DeviceN ||
361
376
             index == gs_color_space_index_ICC);
362
4.69k
}
363
364
/* Test whether we can icclink-transform an image. */
365
static bool
366
pclxl_can_icctransform(const gs_image_t * pim)
367
1.42k
{
368
1.42k
    const gs_color_space *pcs = pim->ColorSpace;
369
1.42k
    int bits_per_pixel;
370
371
    /* an image with no colorspace info arrived; cannot transform */
372
1.42k
    if (!pcs)
373
0
        return false;
374
1.42k
    bits_per_pixel =
375
1.42k
        (pim->ImageMask ? 1 :
376
1.42k
         pim->BitsPerComponent * gs_color_space_num_components(pcs));
377
378
1.42k
    if ((gs_color_space_get_index(pcs) == gs_color_space_index_ICC)
379
1.42k
        && (bits_per_pixel == 24 || bits_per_pixel == 32))
380
861
        return true;
381
382
563
    return false;
383
1.42k
}
384
385
/*
386
 * Avoid PXL high level images if a transfer function has been set.
387
 * Allow the graphics library to render to a lower level
388
 * representation with the function applied to the colors.
389
 */
390
391
static bool
392
pclxl_nontrivial_transfer(const gs_gstate * pgs)
393
2.77k
{
394
2.77k
    gx_transfer_map *red = pgs->set_transfer.red;
395
2.77k
    gx_transfer_map *green = pgs->set_transfer.green;
396
2.77k
    gx_transfer_map *blue = pgs->set_transfer.blue;
397
398
2.77k
    return (red || green || blue);
399
400
2.77k
}
401
/* Set brush, pen, and mode for painting a path. */
402
static void
403
pclxl_set_paints(gx_device_pclxl * xdev, gx_path_type_t type)
404
19.6M
{
405
19.6M
    stream *s = pclxl_stream(xdev);
406
19.6M
    gx_path_type_t rule = type & gx_path_type_rule;
407
408
19.6M
    if (!(type & gx_path_type_fill) &&
409
19.6M
        (color_is_set(&xdev->saved_fill_color.saved_dev_color) ||
410
65.3k
         !gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color)
411
65.3k
        )
412
19.6M
        ) {
413
65.3k
        pclxl_set_cached_nulls(xdev, pxaNullBrush, pxtSetBrushSource);
414
65.3k
        color_set_null(&xdev->saved_fill_color.saved_dev_color);
415
65.3k
        if (rule != xdev->fill_rule) {
416
0
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
417
0
                                 eNonZeroWinding));
418
0
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
419
0
            xdev->fill_rule = rule;
420
0
        }
421
65.3k
    }
422
19.6M
    if (!(type & gx_path_type_stroke) &&
423
19.6M
        (color_is_set(&xdev->saved_stroke_color.saved_dev_color) ||
424
19.6M
         !gx_dc_is_null(&xdev->saved_stroke_color.saved_dev_color)
425
19.6M
        )
426
19.6M
        ) {
427
19.6M
        pclxl_set_cached_nulls(xdev, pxaNullPen, pxtSetPenSource);
428
19.6M
        color_set_null(&xdev->saved_stroke_color.saved_dev_color);
429
19.6M
    }
430
19.6M
}
431
432
static void
433
pclxl_set_page_origin(stream * s, int x, int y)
434
7.57k
{
435
7.57k
    px_put_ssp(s, x, y);
436
7.57k
    px_put_ac(s, pxaPageOrigin, pxtSetPageOrigin);
437
7.57k
    return;
438
7.57k
}
439
440
static void
441
pclxl_set_page_scale(gx_device_pclxl * xdev, double x_scale, double y_scale)
442
7.99M
{
443
7.99M
    stream *s = pclxl_stream(xdev);
444
445
7.99M
    if (xdev->scaled) {
446
503k
        xdev->x_scale = x_scale;
447
503k
        xdev->y_scale = y_scale;
448
503k
        px_put_rp(s, x_scale, y_scale);
449
503k
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
450
503k
    }
451
7.99M
    return;
452
7.99M
}
453
454
static void
455
pclxl_unset_page_scale(gx_device_pclxl * xdev)
456
15.7M
{
457
15.7M
    stream *s = pclxl_stream(xdev);
458
459
15.7M
    if (xdev->scaled) {
460
503k
        px_put_rp(s, 1 / xdev->x_scale, 1 / xdev->y_scale);
461
503k
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
462
503k
        xdev->scaled = false;
463
503k
        xdev->x_scale = 1;
464
503k
        xdev->y_scale = 1;
465
503k
    }
466
15.7M
    return;
467
15.7M
}
468
469
/* Set the cursor. */
470
static int
471
pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
472
7.74M
{
473
7.74M
    stream *s = pclxl_stream(xdev);
474
7.74M
    double x_scale = 1;
475
7.74M
    double y_scale = 1;
476
477
    /* Points must be one of ubyte/uint16/sint16;
478
       Here we play with PageScale (one of ubyte/uint16/real32_xy) to go higher.
479
       This gives us 32768 x 3.4e38 in UnitsPerMeasure.
480
       If we ever need to go higher, we play with UnitsPerMeasure. */
481
7.74M
    if (abs(x) > 0x7FFF) {
482
203k
        x_scale = ((double)abs(x)) / 0x7FFF;
483
203k
        x = (x > 0 ? 0x7FFF : -0x7FFF);
484
203k
        xdev->scaled = true;
485
203k
    }
486
7.74M
    if (abs(y) > 0x7FFF) {
487
192k
        y_scale = ((double)abs(y)) / 0x7FFF;
488
192k
        y = (y > 0 ? 0x7FFF : -0x7FFF);
489
192k
        xdev->scaled = true;
490
192k
    }
491
7.74M
    pclxl_set_page_scale(xdev, x_scale, y_scale);
492
7.74M
    px_put_ssp(s, x, y);
493
7.74M
    px_put_ac(s, pxaPoint, pxtSetCursor);
494
7.74M
    pclxl_unset_page_scale(xdev);
495
7.74M
    return 0;
496
7.74M
}
497
498
/* ------ Paths ------ */
499
500
/* Flush any buffered path points. */
501
static void
502
px_put_np(stream * s, int count, pxeDataType_t dtype)
503
5.22M
{
504
5.22M
    px_put_uba(s, (byte) count, pxaNumberOfPoints);
505
5.22M
    px_put_uba(s, (byte) dtype, pxaPointType);
506
5.22M
}
507
static int
508
pclxl_flush_points(gx_device_pclxl * xdev)
509
11.8M
{
510
11.8M
    int count = xdev->points.count;
511
512
11.8M
    if (count) {
513
7.97M
        stream *s = pclxl_stream(xdev);
514
7.97M
        px_tag_t op;
515
7.97M
        int x = xdev->points.current.x, y = xdev->points.current.y;
516
7.97M
        int uor = 0, sor = 0;
517
7.97M
        pxeDataType_t data_type;
518
7.97M
        int i, di;
519
7.97M
        byte diffs[NUM_POINTS * 2];
520
7.97M
        double x_scale = 1;
521
7.97M
        double y_scale = 1;
522
7.97M
        int temp_origin_x = 0, temp_origin_y = 0;
523
7.97M
        int count_smalls = 0;
524
525
7.97M
        if (xdev->points.type != POINTS_NONE) {
526
41.6M
            for (i = 0; i < count; ++i) {
527
33.6M
                if ((abs(xdev->points.data[i].x) > 0x7FFF)
528
33.6M
                    || (abs(xdev->points.data[i].y) > 0x7FFF))
529
814k
                    xdev->scaled = true;
530
33.6M
                if ((abs(xdev->points.data[i].x) < 0x8000)
531
33.6M
                    && (abs(xdev->points.data[i].y) < 0x8000)) {
532
32.8M
                    if ((temp_origin_x != xdev->points.data[i].x)
533
32.8M
                        || (temp_origin_y != xdev->points.data[i].y)) {
534
27.7M
                        temp_origin_x = xdev->points.data[i].x;
535
27.7M
                        temp_origin_y = xdev->points.data[i].y;
536
27.7M
                        count_smalls++;
537
27.7M
                    }
538
32.8M
                }
539
33.6M
            }
540
7.97M
            if (xdev->scaled) {
541
                /* if there are some points with small co-ordinates, we set origin to it
542
                   before scaling, an unset afterwards. This works around problems
543
                   for small co-ordinates being moved snapped to 32767 x 32767 grid points;
544
                   if there are more than 1, the other points
545
                   will be in-accurate, unfortunately */
546
254k
                if (count_smalls) {
547
3.78k
                    pclxl_set_page_origin(s, temp_origin_x, temp_origin_y);
548
3.78k
                }
549
1.10M
                for (i = 0; i < count; ++i) {
550
846k
                    x_scale = max(((double)
551
846k
                                   abs(xdev->points.data[i].x -
552
846k
                                       temp_origin_x)) / 0x7FFF, x_scale);
553
846k
                    y_scale = max(((double)
554
846k
                                   abs(xdev->points.data[i].y -
555
846k
                                       temp_origin_y)) / 0x7FFF, y_scale);
556
846k
                }
557
1.10M
                for (i = 0; i < count; ++i) {
558
846k
                    xdev->points.data[i].x =
559
846k
                        (int)((xdev->points.data[i].x -
560
846k
                               temp_origin_x) / x_scale + 0.5);
561
846k
                    xdev->points.data[i].y =
562
846k
                        (int)((xdev->points.data[i].y -
563
846k
                               temp_origin_y) / y_scale + 0.5);
564
846k
                }
565
254k
                x = (int)((x - temp_origin_x) / x_scale + 0.5);
566
254k
                y = (int)((y - temp_origin_y) / y_scale + 0.5);
567
254k
                pclxl_set_page_scale(xdev, x_scale, y_scale);
568
7.71M
            } else {
569
                /* don't reset origin if we did not scale */
570
7.71M
                count_smalls = 0;
571
7.71M
            }
572
7.97M
        }
573
        /*
574
         * Writing N lines using a point list requires 11 + 4*N or 11 +
575
         * 2*N bytes, as opposed to 8*N bytes using separate commands;
576
         * writing N curves requires 11 + 12*N or 11 + 6*N bytes
577
         * vs. 22*N.  So it's always shorter to write curves with a
578
         * list (except for N = 1 with full-size coordinates, but since
579
         * the difference is only 1 byte, we don't bother to ever use
580
         * the non-list form), but lines are shorter only if N >= 3
581
         * (again, with a 1-byte difference if N = 2 and byte
582
         * coordinates).
583
         */
584
7.97M
        switch (xdev->points.type) {
585
0
            case POINTS_NONE:
586
0
                return 0;
587
5.39M
            case POINTS_LINES:
588
5.39M
                op = pxtLinePath;
589
5.39M
                if (count < 3) {
590
7.29M
                    for (i = 0; i < count; ++i) {
591
4.54M
                        px_put_ssp(s, xdev->points.data[i].x,
592
4.54M
                                   xdev->points.data[i].y);
593
4.54M
                        px_put_a(s, pxaEndPoint);
594
4.54M
                        spputc(s, (byte) op);
595
4.54M
                    }
596
2.74M
                    pclxl_unset_page_scale(xdev);
597
2.74M
                    if (count_smalls)
598
179
                        pclxl_set_page_origin(s, -temp_origin_x,
599
179
                                              -temp_origin_y);
600
2.74M
                    goto zap;
601
2.74M
                }
602
                /* See if we can use byte values. */
603
14.3M
                for (i = di = 0; i < count; ++i, di += 2) {
604
11.6M
                    int dx = xdev->points.data[i].x - x;
605
11.6M
                    int dy = xdev->points.data[i].y - y;
606
607
11.6M
                    diffs[di] = (byte) dx;
608
11.6M
                    diffs[di + 1] = (byte) dy;
609
11.6M
                    uor |= dx | dy;
610
11.6M
                    sor |= (dx + 0x80) | (dy + 0x80);
611
11.6M
                    x += dx, y += dy;
612
11.6M
                }
613
2.64M
                if (!(uor & ~0xff))
614
51.4k
                    data_type = eUByte;
615
2.59M
                else if (!(sor & ~0xff))
616
2.48M
                    data_type = eSByte;
617
111k
                else
618
111k
                    break;
619
2.53M
                op = pxtLineRelPath;
620
                /* Use byte values. */
621
5.08M
              useb:px_put_np(s, count, data_type);
622
5.08M
                spputc(s, (byte) op);
623
5.08M
                px_put_data_length(s, count * 2);       /* 2 bytes per point */
624
5.08M
                px_put_bytes(s, diffs, count * 2);
625
5.08M
                pclxl_unset_page_scale(xdev);
626
5.08M
                if (count_smalls)
627
3
                    pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
628
5.08M
                goto zap;
629
2.57M
            case POINTS_CURVES:
630
2.57M
                op = pxtBezierPath;
631
                /* See if we can use byte values. */
632
8.39M
                for (i = di = 0; i < count; i += 3, di += 6) {
633
5.81M
                    int dx1 = xdev->points.data[i].x - x;
634
5.81M
                    int dy1 = xdev->points.data[i].y - y;
635
5.81M
                    int dx2 = xdev->points.data[i + 1].x - x;
636
5.81M
                    int dy2 = xdev->points.data[i + 1].y - y;
637
5.81M
                    int dx = xdev->points.data[i + 2].x - x;
638
5.81M
                    int dy = xdev->points.data[i + 2].y - y;
639
640
5.81M
                    diffs[di] = (byte) dx1;
641
5.81M
                    diffs[di + 1] = (byte) dy1;
642
5.81M
                    diffs[di + 2] = (byte) dx2;
643
5.81M
                    diffs[di + 3] = (byte) dy2;
644
5.81M
                    diffs[di + 4] = (byte) dx;
645
5.81M
                    diffs[di + 5] = (byte) dy;
646
5.81M
                    uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
647
5.81M
                    sor |= (dx1 + 0x80) | (dy1 + 0x80) |
648
5.81M
                        (dx2 + 0x80) | (dy2 + 0x80) |
649
5.81M
                        (dx + 0x80) | (dy + 0x80);
650
5.81M
                    x += dx, y += dy;
651
5.81M
                }
652
2.57M
                if (!(uor & ~0xff))
653
868k
                    data_type = eUByte;
654
1.70M
                else if (!(sor & ~0xff))
655
1.68M
                    data_type = eSByte;
656
21.0k
                else
657
21.0k
                    break;
658
2.55M
                op = pxtBezierRelPath;
659
2.55M
                goto useb;
660
0
            default:           /* can't happen */
661
0
                return_error(gs_error_unknownerror);
662
7.97M
        }
663
132k
        px_put_np(s, count, eSInt16);
664
132k
        spputc(s, (byte) op);
665
132k
        px_put_data_length(s, count * 4);       /* 2 UInt16s per point */
666
857k
        for (i = 0; i < count; ++i) {
667
725k
            px_put_s(s, xdev->points.data[i].x);
668
725k
            px_put_s(s, xdev->points.data[i].y);
669
725k
        }
670
132k
        pclxl_unset_page_scale(xdev);
671
132k
        if (count_smalls)
672
3.60k
            pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
673
7.97M
      zap:xdev->points.type = POINTS_NONE;
674
7.97M
        xdev->points.count = 0;
675
7.97M
    }
676
11.8M
    return 0;
677
11.8M
}
678
679
/* ------ Images ------ */
680
681
static image_enum_proc_plane_data(pclxl_image_plane_data);
682
static image_enum_proc_end_image(pclxl_image_end_image);
683
684
static const gx_image_enum_procs_t pclxl_image_enum_procs = {
685
    pclxl_image_plane_data, pclxl_image_end_image
686
};
687
688
/* Begin an image. */
689
static void
690
pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
691
                        uint dest_width, uint dest_height)
692
17.7k
{
693
17.7k
    stream *s = pclxl_stream(xdev);
694
695
17.7k
    px_put_usa(s, width, pxaSourceWidth);
696
17.7k
    px_put_usa(s, height, pxaSourceHeight);
697
17.7k
    px_put_usp(s, dest_width, dest_height);
698
17.7k
    px_put_ac(s, pxaDestinationSize, pxtBeginImage);
699
17.7k
}
700
701
/* Write rows of an image. */
702
/****** IGNORES data_bit ******/
703
/* 2009: we try to cope with the case of data_bit being multiple of 8 now */
704
/* RLE version */
705
static void
706
pclxl_write_image_data_RLE(gx_device_pclxl * xdev, const byte * base,
707
                           int data_bit, uint raster, uint width_bits, int y,
708
                           int height)
709
17.7k
{
710
17.7k
    stream *s = pclxl_stream(xdev);
711
17.7k
    uint width_bytes = (width_bits + 7) >> 3;
712
17.7k
    uint num_bytes = ROUND_UP(width_bytes, 4) * height;
713
17.7k
    bool compress = num_bytes >= 8;
714
17.7k
    int i;
715
17.7k
    int code;
716
717
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
718
17.7k
    int offset = data_bit >> 3;
719
17.7k
    const byte *data = base + offset;
720
721
17.7k
    px_put_usa(s, y, pxaStartLine);
722
17.7k
    px_put_usa(s, height, pxaBlockHeight);
723
17.7k
    if (compress) {
724
17.7k
        stream_RLE_state rlstate;
725
17.7k
        stream_cursor_write w;
726
17.7k
        stream_cursor_read r;
727
728
        /*
729
         * H-P printers require that all the data for an operator be
730
         * contained in a single data block.  Thus, we must allocate a
731
         * temporary buffer for the compressed data.  Currently we don't go
732
         * to the trouble of doing two passes if we can't allocate a buffer
733
         * large enough for the entire transfer.
734
         */
735
17.7k
        byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
736
17.7k
                                   "pclxl_write_image_data");
737
738
17.7k
        if (buf == 0)
739
0
            goto nc;
740
17.7k
        s_RLE_set_defaults_inline(&rlstate);
741
17.7k
        rlstate.EndOfData = false;
742
17.7k
        rlstate.omitEOD = true;
743
17.7k
        s_RLE_init_inline(&rlstate);
744
17.7k
        w.ptr = buf - 1;
745
17.7k
        w.limit = w.ptr + num_bytes;
746
        /*
747
         * If we ever overrun the buffer, it means that the compressed
748
         * data was larger than the uncompressed.  If this happens,
749
         * write the data uncompressed.
750
         */
751
2.04M
        for (i = 0; i < height; ++i) {
752
2.02M
            r.ptr = data + i * raster - 1;
753
2.02M
            r.limit = r.ptr + width_bytes;
754
2.02M
            if ((*s_RLE_template.process)
755
2.02M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
756
2.02M
                r.ptr != r.limit)
757
745
                goto ncfree;
758
2.02M
            r.ptr = (const byte *)"\000\000\000\000\000";
759
2.02M
            r.limit = r.ptr + (-(int)width_bytes & 3);
760
2.02M
            if ((*s_RLE_template.process)
761
2.02M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
762
2.02M
                r.ptr != r.limit)
763
34
                goto ncfree;
764
2.02M
        }
765
17.0k
        r.ptr = r.limit;
766
17.0k
        code = (*s_RLE_template.process)
767
17.0k
            ((stream_state *) & rlstate, &r, &w, true);
768
17.0k
        if (code != EOFC && code != 0)
769
796
            goto ncfree;
770
16.2k
        {
771
16.2k
            uint count = w.ptr + 1 - buf;
772
773
16.2k
            px_put_ub(s, eRLECompression);
774
16.2k
            px_put_ac(s, pxaCompressMode, pxtReadImage);
775
16.2k
            px_put_data_length(s, count);
776
16.2k
            px_put_bytes(s, buf, count);
777
16.2k
        }
778
16.2k
        gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
779
16.2k
        return;
780
1.57k
      ncfree:gs_free_object(xdev->v_memory, buf,
781
1.57k
                       "pclxl_write_image_data");
782
1.57k
    }
783
1.58k
  nc:
784
    /* Write the data uncompressed. */
785
1.58k
    px_put_ub(s, eNoCompression);
786
1.58k
    px_put_ac(s, pxaCompressMode, pxtReadImage);
787
1.58k
    px_put_data_length(s, num_bytes);
788
124k
    for (i = 0; i < height; ++i) {
789
122k
        px_put_bytes(s, data + i * raster, width_bytes);
790
122k
        px_put_bytes(s, (const byte *)"\000\000\000\000",
791
122k
                     -(int)width_bytes & 3);
792
122k
    }
793
1.58k
}
794
795
static void
796
pclxl_write_image_data_JPEG(gx_device_pclxl * xdev, const byte * base,
797
                            int data_bit, uint raster, uint width_bits, int y,
798
                            int height)
799
0
{
800
0
    stream *s = pclxl_stream(xdev);
801
0
    uint width_bytes = (width_bits + 7) >> 3;
802
0
    int i;
803
0
    int count;
804
0
    int code;
805
806
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
807
0
    int offset = data_bit >> 3;
808
0
    const byte *data = base + offset;
809
0
    jpeg_compress_data *jcdp =
810
0
        gs_alloc_struct_immovable(xdev->v_memory, jpeg_compress_data,
811
0
                                  &st_jpeg_compress_data,
812
0
                                  "pclxl_write_image_data_JPEG(jpeg_compress_data)");
813
0
    stream_DCT_state state;
814
0
    stream_cursor_read r;
815
0
    stream_cursor_write w;
816
817
    /* Approx. The worse case is ~ header + width_bytes * height.
818
       Apparently minimal SOI/DHT/DQT/SOS/EOI is 341 bytes. TO CHECK. */
819
0
    int buffersize = 341 + width_bytes * height;
820
821
0
    byte *buf = gs_alloc_bytes(xdev->v_memory, buffersize,
822
0
                               "pclxl_write_image_data_JPEG(buf)");
823
824
    /* RLE can write uncompressed without extra-allocation */
825
0
    if ((buf == 0) || (jcdp == 0)) {
826
0
        goto failed_so_use_rle_instead;
827
0
    }
828
    /* Create the DCT encoder state. */
829
0
    jcdp->templat = s_DCTE_template;
830
0
    s_init_state((stream_state *) & state, &jcdp->templat, 0);
831
0
    if (state.templat->set_defaults) {
832
0
        state.memory = xdev->v_memory;
833
0
        (*state.templat->set_defaults) ((stream_state *) & state);
834
0
        state.memory = NULL;
835
0
    }
836
0
    state.ColorTransform = (xdev->color_info.num_components == 3 ? 1 : 0);
837
0
    state.data.compress = jcdp;
838
0
    state.icc_profile = NULL;
839
    /* state.memory needs set for creation..... */
840
0
    state.memory = jcdp->memory = state.jpeg_memory = xdev->v_memory;
841
0
    if ((code = gs_jpeg_create_compress(&state)) < 0)
842
0
        goto cleanup_and_use_rle;
843
    /* .... and NULL after, so we don't try to free the stack based "state" */
844
0
    state.memory = NULL;
845
    /* image-specific info */
846
0
    jcdp->cinfo.image_width = width_bytes / xdev->color_info.num_components;
847
0
    jcdp->cinfo.image_height = height;
848
0
    switch (xdev->color_info.num_components) {
849
0
        case 3:
850
0
            jcdp->cinfo.input_components = 3;
851
0
            jcdp->cinfo.in_color_space = JCS_RGB;
852
0
            break;
853
0
        case 1:
854
0
            jcdp->cinfo.input_components = 1;
855
0
            jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
856
0
            break;
857
0
        default:
858
0
            goto cleanup_and_use_rle;
859
0
            break;
860
0
    }
861
    /* Set compression parameters. */
862
0
    if ((code = gs_jpeg_set_defaults(&state)) < 0)
863
0
        goto cleanup_and_use_rle;
864
865
0
    if (state.templat->init)
866
0
        (*state.templat->init) ((stream_state *) & state);
867
0
    state.scan_line_size = jcdp->cinfo.input_components *
868
0
        jcdp->cinfo.image_width;
869
0
    jcdp->templat.min_in_size =
870
0
        max(s_DCTE_template.min_in_size, state.scan_line_size);
871
0
    jcdp->templat.min_out_size =
872
0
        max(s_DCTE_template.min_out_size, state.Markers.size);
873
874
0
    w.ptr = buf - 1;
875
0
    w.limit = w.ptr + buffersize;
876
0
    for (i = 0; i < height; ++i) {
877
0
        r.ptr = data + i * raster - 1;
878
0
        r.limit = r.ptr + width_bytes;
879
0
        if (((code = (*state.templat->process)
880
0
              ((stream_state *) & state, &r, &w, false)) != 0 && code != EOFC)
881
0
            || r.ptr != r.limit)
882
0
            goto cleanup_and_use_rle;
883
0
    }
884
0
    count = w.ptr + 1 - buf;
885
0
    px_put_usa(s, y, pxaStartLine);
886
0
    px_put_usa(s, height, pxaBlockHeight);
887
0
    px_put_ub(s, eJPEGCompression);
888
0
    px_put_ac(s, pxaCompressMode, pxtReadImage);
889
0
    px_put_data_length(s, count);
890
0
    px_put_bytes(s, buf, count);
891
892
0
    gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data_JPEG(buf)");
893
0
    if (jcdp)
894
0
        gs_jpeg_destroy(&state);        /* frees *jcdp */
895
0
    return;
896
897
0
  cleanup_and_use_rle:
898
    /* cleans up - something went wrong after allocation */
899
0
    gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data_JPEG(buf)");
900
0
    if (jcdp)
901
0
        gs_jpeg_destroy(&state);        /* frees *jcdp */
902
    /* fall through to redo in RLE */
903
0
  failed_so_use_rle_instead:
904
    /* the RLE routine can write without new allocation - use as fallback. */
905
0
    pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits, y,
906
0
                               height);
907
0
    return;
908
0
}
909
910
/* DeltaRow compression (also called "mode 3"):
911
   drawn heavily from gdevcljc.c:cljc_print_page(),
912
   This is simplier since PCL XL does not allow
913
   compression mix-and-match.
914
915
   Worse case of RLE is + 1/128, but worse case of DeltaRow is + 1/8
916
 */
917
static void
918
pclxl_write_image_data_DeltaRow(gx_device_pclxl * xdev, const byte * base,
919
                                int data_bit, uint raster, uint width_bits,
920
                                int y, int height)
921
0
{
922
0
    stream *s = pclxl_stream(xdev);
923
0
    uint width_bytes = (width_bits + 7) >> 3;
924
0
    int worst_case_comp_size = width_bytes + (width_bytes / 8) + 1;
925
0
    byte *cdata = 0;
926
0
    byte *prow = 0;
927
0
    int i;
928
0
    int count;
929
930
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
931
0
    int offset = data_bit >> 3;
932
0
    const byte *data = base + offset;
933
934
    /* allocate the worst case scenario; PCL XL has an extra 2 byte per row compared to PCL5 */
935
0
    byte *buf =
936
0
        gs_alloc_bytes(xdev->v_memory, (worst_case_comp_size + 2) * height,
937
0
                       "pclxl_write_image_data_DeltaRow(buf)");
938
939
0
    prow =
940
0
        gs_alloc_bytes(xdev->v_memory, width_bytes,
941
0
                       "pclxl_write_image_data_DeltaRow(prow)");
942
    /* the RLE routine can write uncompressed without extra-allocation */
943
0
    if ((buf == 0) || (prow == 0)) {
944
0
        pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
945
0
                                   y, height);
946
0
        return;
947
0
    }
948
    /* initialize the seed row */
949
0
    memset(prow, 0, width_bytes);
950
0
    cdata = buf;
951
0
    for (i = 0; i < height; i++) {
952
0
        int compressed_size =
953
0
            gdev_pcl_mode3compress(width_bytes, data + i * raster, prow,
954
0
                                   cdata + 2);
955
956
        /* PCL XL prepends row data with byte count */
957
0
        *cdata = compressed_size & 0xff;
958
0
        *(cdata + 1) = compressed_size >> 8;
959
0
        cdata += compressed_size + 2;
960
0
    }
961
0
    px_put_usa(s, y, pxaStartLine);
962
0
    px_put_usa(s, height, pxaBlockHeight);
963
0
    px_put_ub(s, eDeltaRowCompression);
964
0
    px_put_ac(s, pxaCompressMode, pxtReadImage);
965
0
    count = cdata - buf;
966
0
    px_put_data_length(s, count);
967
0
    px_put_bytes(s, buf, count);
968
969
0
    gs_free_object(xdev->v_memory, buf,
970
0
                   "pclxl_write_image_data_DeltaRow(buf)");
971
0
    gs_free_object(xdev->v_memory, prow,
972
0
                   "pclxl_write_image_data_DeltaRow(prow)");
973
0
    return;
974
0
}
975
976
/* calling from copy_mono/copy_color/fill_mask should never do lossy compression */
977
static void
978
pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data,
979
                       int data_bit, uint raster, uint width_bits, int y,
980
                       int height, bool allow_lossy)
981
17.7k
{
982
    /* If we only have 1 line, it does not make sense to do JPEG/DeltaRow */
983
17.7k
    if (height < 2) {
984
17
        pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
985
17
                                   y, height);
986
17
        return;
987
17
    }
988
989
17.7k
    switch (xdev->CompressMode) {
990
0
        case eDeltaRowCompression:
991
0
            pclxl_write_image_data_DeltaRow(xdev, data, data_bit, raster,
992
0
                                            width_bits, y, height);
993
0
            break;
994
0
        case eJPEGCompression:
995
            /* JPEG should not be used for mask or other data */
996
0
            if (allow_lossy)
997
0
                pclxl_write_image_data_JPEG(xdev, data, data_bit, raster,
998
0
                                            width_bits, y, height);
999
0
            else
1000
0
                pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
1001
0
                                           width_bits, y, height);
1002
0
            break;
1003
0
        case eRLECompression:
1004
17.7k
        default:
1005
17.7k
            pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
1006
17.7k
                                       width_bits, y, height);
1007
17.7k
            break;
1008
17.7k
    }
1009
17.7k
}
1010
1011
/* End an image. */
1012
static void
1013
pclxl_write_end_image(gx_device_pclxl * xdev)
1014
17.7k
{
1015
17.7k
    spputc(xdev->strm, pxtEndImage);
1016
17.7k
}
1017
1018
/* ------ Fonts ------ */
1019
1020
/* Write a string (single- or double-byte). */
1021
static void
1022
px_put_string(stream * s, const byte * data, uint len, bool wide)
1023
4.18M
{
1024
4.18M
    if (wide) {
1025
460k
        spputc(s, pxt_uint16_array);
1026
460k
        px_put_u(s, len);
1027
460k
        px_put_bytes(s, data, len * 2);
1028
3.72M
    } else {
1029
3.72M
        spputc(s, pxt_ubyte_array);
1030
3.72M
        px_put_u(s, len);
1031
3.72M
        px_put_bytes(s, data, len);
1032
3.72M
    }
1033
4.18M
}
1034
1035
/* Write a 16-bit big-endian value. */
1036
static void
1037
px_put_us_be(stream * s, uint i)
1038
941k
{
1039
941k
    spputc(s, (byte) (i >> 8));
1040
941k
    spputc(s, (byte) i);
1041
941k
}
1042
1043
/* Define a bitmap font.  The client must call px_put_string */
1044
/* with the font name immediately before calling this procedure. */
1045
static void
1046
pclxl_define_bitmap_font(gx_device_pclxl * xdev)
1047
3.59k
{
1048
3.59k
    stream *s = pclxl_stream(xdev);
1049
1050
3.59k
    static const byte bfh_[] = {
1051
3.59k
        DA(pxaFontName), DUB(0), DA(pxaFontFormat),
1052
3.59k
        pxtBeginFontHeader,
1053
3.59k
        DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
1054
3.59k
        pxtReadFontHeader,
1055
3.59k
        pxt_dataLengthByte, 8 + 6 + 4 + 6,
1056
3.59k
        0, 0, 0, 0,
1057
3.59k
        254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
1058
3.59k
        'B', 'R', 0, 0, 0, 4
1059
3.59k
    };
1060
3.59k
    static const byte efh_[] = {
1061
3.59k
        0xff, 0xff, 0, 0, 0, 0,
1062
3.59k
        pxtEndFontHeader
1063
3.59k
    };
1064
1065
3.59k
    PX_PUT_LIT(s, bfh_);
1066
3.59k
    px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
1067
3.59k
    px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
1068
3.59k
    PX_PUT_LIT(s, efh_);
1069
3.59k
}
1070
1071
/* Set the font.  The client must call px_put_string */
1072
/* with the font name immediately before calling this procedure. */
1073
static void
1074
pclxl_set_font(gx_device_pclxl * xdev)
1075
7.84k
{
1076
7.84k
    stream *s = pclxl_stream(xdev);
1077
1078
7.84k
    static const byte sf_[] = {
1079
7.84k
        DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
1080
7.84k
        pxtSetFont
1081
7.84k
    };
1082
1083
7.84k
    PX_PUT_LIT(s, sf_);
1084
7.84k
}
1085
1086
/* Define a character in a bitmap font.  The client must call px_put_string */
1087
/* with the font name immediately before calling this procedure. */
1088
static void
1089
pclxl_define_bitmap_char(gx_device_pclxl * xdev, uint ccode,
1090
                         const byte * data, uint raster, uint width_bits,
1091
                         uint height)
1092
467k
{
1093
467k
    stream *s = pclxl_stream(xdev);
1094
467k
    uint width_bytes = (width_bits + 7) >> 3;
1095
467k
    uint size = 10 + width_bytes * height;
1096
467k
    uint i;
1097
1098
467k
    px_put_ac(s, pxaFontName, pxtBeginChar);
1099
467k
    px_put_u(s, ccode);
1100
467k
    px_put_a(s, pxaCharCode);
1101
467k
    if (size > 0xffff) {
1102
0
        spputc(s, pxt_uint32);
1103
0
        px_put_l(s, (ulong) size);
1104
0
    } else
1105
467k
        px_put_us(s, size);
1106
467k
    px_put_ac(s, pxaCharDataSize, pxtReadChar);
1107
467k
    px_put_data_length(s, size);
1108
467k
    px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
1109
467k
    px_put_us_be(s, width_bits);
1110
467k
    px_put_us_be(s, height);
1111
10.9M
    for (i = 0; i < height; ++i)
1112
10.4M
        px_put_bytes(s, data + i * raster, width_bytes);
1113
467k
    spputc(s, pxtEndChar);
1114
467k
}
1115
1116
/* Write the name of the only font we define. */
1117
static void
1118
pclxl_write_font_name(gx_device_pclxl * xdev)
1119
478k
{
1120
478k
    stream *s = pclxl_stream(xdev);
1121
1122
478k
    px_put_string(s, (const byte *)"@", 1, false);
1123
478k
}
1124
1125
/* Look up a bitmap id, return the index in the character table. */
1126
/* If the id is missing, return an index for inserting. */
1127
static int
1128
pclxl_char_index(gx_device_pclxl * xdev, gs_id id)
1129
4.31M
{
1130
4.31M
    int i, i_empty = -1;
1131
4.31M
    uint ccode;
1132
1133
4.31M
    for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
1134
62.4M
         i = (i == 0 ? countof(xdev->chars.table) : i) - 1) {
1135
62.4M
        ccode = xdev->chars.table[i];
1136
62.4M
        if (ccode == 0)
1137
859k
            return (i_empty >= 0 ? i_empty : i);
1138
61.6M
        else if (ccode == 1) {
1139
19.0M
            if (i_empty < 0)
1140
361k
                i_empty = i;
1141
18.6M
            else if (i == i_empty)      /* full table */
1142
74.6k
                return i;
1143
42.5M
        } else if (xdev->chars.data[ccode].id == id)
1144
3.38M
            return i;
1145
62.4M
    }
1146
4.31M
}
1147
1148
/* Remove the character table entry at a given index. */
1149
static void
1150
pclxl_remove_char(gx_device_pclxl * xdev, int index)
1151
145k
{
1152
145k
    uint ccode = xdev->chars.table[index];
1153
145k
    int i;
1154
1155
145k
    if (ccode < 2)
1156
0
        return;
1157
145k
    xdev->chars.count--;
1158
145k
    xdev->chars.used -= xdev->chars.data[ccode].size;
1159
145k
    xdev->chars.table[index] = 1;       /* mark as deleted */
1160
145k
    i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
1161
145k
    if (xdev->chars.table[i] == 0) {
1162
        /* The next slot in probe order is empty. */
1163
        /* Mark this slot and any deleted predecessors as empty. */
1164
13.8k
        for (i = index; xdev->chars.table[i] == 1;
1165
7.63k
             i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
1166
6.20k
            )
1167
7.63k
            xdev->chars.table[i] = 0;
1168
6.20k
    }
1169
145k
}
1170
1171
/* Write a bitmap as a text character if possible. */
1172
/* The caller must set the color, cursor, and RasterOp. */
1173
/* We know id != gs_no_id. */
1174
static int
1175
pclxl_copy_text_char(gx_device_pclxl * xdev, const byte * data,
1176
                     int raster, gx_bitmap_id id, int w, int h)
1177
3.70M
{
1178
3.70M
    uint width_bytes = (w + 7) >> 3;
1179
3.70M
    uint size = width_bytes * h;
1180
3.70M
    int index;
1181
3.70M
    uint ccode;
1182
3.70M
    stream *s = pclxl_stream(xdev);
1183
1184
3.70M
    if (size > MAX_CHAR_SIZE)
1185
448
        return -1;
1186
3.70M
    index = pclxl_char_index(xdev, id);
1187
3.70M
    if ((ccode = xdev->chars.table[index]) < 2) {
1188
        /* Enter the character in the table. */
1189
612k
        while (xdev->chars.used + size > MAX_CHAR_DATA ||
1190
612k
               xdev->chars.count >= MAX_CACHED_CHARS - 2) {
1191
145k
            ccode = xdev->chars.next_out;
1192
145k
            index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
1193
145k
            pclxl_remove_char(xdev, index);
1194
145k
            xdev->chars.next_out =
1195
145k
                (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1196
145k
        }
1197
467k
        index = pclxl_char_index(xdev, id);
1198
467k
        ccode = xdev->chars.next_in;
1199
467k
        xdev->chars.data[ccode].id = id;
1200
467k
        xdev->chars.data[ccode].size = size;
1201
467k
        xdev->chars.table[index] = ccode;
1202
467k
        xdev->chars.next_in = (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1203
467k
        if (!xdev->chars.count++) {
1204
            /* This is the very first character. */
1205
3.59k
            pclxl_write_font_name(xdev);
1206
3.59k
            pclxl_define_bitmap_font(xdev);
1207
3.59k
        }
1208
467k
        xdev->chars.used += size;
1209
467k
        pclxl_write_font_name(xdev);
1210
467k
        pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
1211
467k
    }
1212
3.70M
    if (!xdev->font_set) {
1213
7.84k
        pclxl_write_font_name(xdev);
1214
7.84k
        pclxl_set_font(xdev);
1215
7.84k
        xdev->font_set = true;
1216
7.84k
    }
1217
3.70M
    {
1218
3.70M
        byte cc_bytes[2];
1219
1220
3.70M
        cc_bytes[0] = (byte) ccode;
1221
3.70M
        cc_bytes[1] = ccode >> 8;
1222
3.70M
        px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
1223
3.70M
    }
1224
3.70M
    px_put_ac(s, pxaTextData, pxtText);
1225
3.70M
    return 0;
1226
3.70M
}
1227
1228
/* ---------------- Vector implementation procedures ---------------- */
1229
1230
static int
1231
pclxl_beginpage(gx_device_vector * vdev)
1232
10.6k
{
1233
10.6k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1234
1235
    /*
1236
     * We can't use gdev_vector_stream here, because this may be called
1237
     * from there before in_page is set.
1238
     */
1239
10.6k
    stream *s = vdev->strm;
1240
10.6k
    byte media_source = eAutoSelect;    /* default */
1241
1242
10.6k
    xdev->page++;               /* even/odd for duplex front/back */
1243
1244
/*
1245
    errprintf(vdev->memory, "PAGE: %d %d\n", xdev->page, xdev->NumCopies);
1246
    errprintf(vdev->memory, "INFO: Printing page %d...\n", xdev->page);
1247
    errflush(vdev->memory);
1248
*/
1249
1250
10.6k
    px_write_page_header(s, (const gx_device *)vdev);
1251
1252
10.6k
    if (xdev->ManualFeed_set && xdev->ManualFeed)
1253
0
        media_source = 2;
1254
10.6k
    else if (xdev->MediaPosition_set && xdev->MediaPosition >= 0)
1255
10.6k
        media_source = xdev->MediaPosition;
1256
1257
10.6k
    px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size,
1258
10.6k
                          &media_source,
1259
10.6k
                          xdev->page, xdev->Duplex, xdev->Tumble,
1260
10.6k
                          xdev->MediaType_set, xdev->MediaType);
1261
1262
10.6k
    spputc(s, pxtBeginPage);
1263
10.6k
    return 0;
1264
10.6k
}
1265
1266
static int
1267
pclxl_setlinewidth(gx_device_vector * vdev, double width)
1268
6.97k
{
1269
6.97k
    stream *s = gdev_vector_stream(vdev);
1270
1271
6.97k
    px_put_us(s, (uint) (width + 0.5));
1272
6.97k
    px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
1273
6.97k
    return 0;
1274
6.97k
}
1275
1276
static int
1277
pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
1278
1.88k
{
1279
1.88k
    stream *s = gdev_vector_stream(vdev);
1280
1281
    /* The PCL XL cap styles just happen to be identical to PostScript. */
1282
1.88k
    px_put_ub(s, (byte) cap);
1283
1.88k
    px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
1284
1.88k
    return 0;
1285
1.88k
}
1286
1287
static int
1288
pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
1289
2.42k
{
1290
2.42k
    stream *s = gdev_vector_stream(vdev);
1291
1292
2.42k
    if (((int)join < 0) || ((int)join > 3)) {
1293
1
        emprintf1(vdev->memory,
1294
1
                  "Igoring invalid linejoin enumerator %d\n", join);
1295
1
        return 0;
1296
1
    }
1297
    /* The PCL XL join styles just happen to be identical to PostScript. */
1298
2.42k
    px_put_ub(s, (byte) join);
1299
2.42k
    px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
1300
2.42k
    return 0;
1301
2.42k
}
1302
1303
static int
1304
pclxl_setmiterlimit(gx_device_vector * vdev, double limit)
1305
1.22k
{
1306
1.22k
    stream *s = gdev_vector_stream(vdev);
1307
1308
    /*
1309
     * Amazingly enough, the PCL XL specification doesn't allow real
1310
     * numbers for the miter limit.
1311
     */
1312
1.22k
    int i_limit = (int)(limit + 0.5);
1313
1314
1.22k
    px_put_u(s, max(i_limit, 1));
1315
1.22k
    px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
1316
1.22k
    return 0;
1317
1.22k
}
1318
1319
/*
1320
 * The number of elements in the dash pattern array is device
1321
 * dependent but a maximum of 20 has been observed on several HP
1322
 * printers.
1323
 */
1324
1325
368
#define MAX_DASH_ELEMENTS 20
1326
1327
static int
1328
pclxl_setdash(gx_device_vector * vdev, const float *pattern, uint count,
1329
              double offset)
1330
709
{
1331
709
    stream *s = gdev_vector_stream(vdev);
1332
1333
709
    if (count == 0) {
1334
341
        static const byte nac_[] = {
1335
341
            DUB(0), DA(pxaSolidLine)
1336
341
        };
1337
1338
341
        PX_PUT_LIT(s, nac_);
1339
368
    } else if (count > MAX_DASH_ELEMENTS)
1340
0
        return_error(gs_error_limitcheck);
1341
368
    else {
1342
368
        uint i;
1343
368
        uint pattern_length = 0;
1344
        /*
1345
         * Astoundingly, PCL XL doesn't allow real numbers here.
1346
         * Do the best we can.
1347
         */
1348
1349
        /* check if the resulting total pattern length will be 0 */
1350
1.10k
        for (i = 0; i < count; ++i)
1351
734
            pattern_length += (uint) (pattern[i]);
1352
368
        if (pattern_length == 0)
1353
0
            return_error(gs_error_rangecheck);
1354
1355
368
        spputc(s, pxt_uint16_array);
1356
368
        px_put_ub(s, (byte) count);
1357
1.10k
        for (i = 0; i < count; ++i)
1358
734
            px_put_s(s, (uint) pattern[i]);
1359
368
        px_put_a(s, pxaLineDashStyle);
1360
368
        if (offset != 0)
1361
0
            px_put_usa(s, (uint) offset, pxaDashOffset);
1362
368
    }
1363
709
    spputc(s, pxtSetLineDash);
1364
709
    return 0;
1365
709
}
1366
1367
static int
1368
pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
1369
               gs_logical_operation_t diff)
1370
202k
{
1371
202k
    stream *s = gdev_vector_stream(vdev);
1372
1373
202k
    if (diff & lop_S_transparent) {
1374
460
        px_put_ub(s, (byte) (lop & lop_S_transparent ? 1 : 0));
1375
460
        px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
1376
460
    }
1377
202k
    if (diff & lop_T_transparent) {
1378
64
        px_put_ub(s, (byte) (lop & lop_T_transparent ? 1 : 0));
1379
64
        px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
1380
64
    }
1381
202k
    if (lop_rop(diff)) {
1382
202k
        px_put_ub(s, (byte) lop_rop(lop));
1383
202k
        px_put_ac(s, pxaROP3, pxtSetROP);
1384
202k
    }
1385
202k
    return 0;
1386
202k
}
1387
1388
static int
1389
pclxl_can_handle_hl_color(gx_device_vector * vdev, const gs_gstate * pgs,
1390
                          const gx_drawing_color * pdc)
1391
23.4M
{
1392
23.4M
    return false;
1393
23.4M
}
1394
1395
static int
1396
pclxl_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs,
1397
                   const gx_drawing_color * pdc)
1398
13.1M
{
1399
13.1M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1400
1401
13.1M
    return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
1402
13.1M
}
1403
1404
static int
1405
pclxl_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs,
1406
                     const gx_drawing_color * pdc)
1407
22.6k
{
1408
22.6k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1409
1410
22.6k
    return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
1411
22.6k
}
1412
1413
static int
1414
pclxl_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
1415
             fixed y1, gx_path_type_t type)
1416
16.1M
{
1417
16.1M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1418
16.1M
    stream *s = gdev_vector_stream(vdev);
1419
1420
    /* Check for out-of-range points. */
1421
113M
#define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
1422
16.1M
    if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
1423
16.1M
        OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
1424
16.1M
        )
1425
14.1k
        return_error(gs_error_rangecheck);
1426
16.1M
#undef OUT_OF_RANGE
1427
16.1M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1428
16.0M
        pclxl_set_paints(xdev, type);
1429
16.0M
        px_put_usq_fixed(s, x0, y0, x1, y1);
1430
16.0M
        px_put_ac(s, pxaBoundingBox, pxtRectangle);
1431
16.0M
    }
1432
16.1M
    if (type & gx_path_type_clip) {
1433
70.8k
        static const byte cr_[] = {
1434
70.8k
            DA(pxaBoundingBox),
1435
70.8k
            DUB(eInterior), DA(pxaClipRegion),
1436
70.8k
            pxtSetClipRectangle
1437
70.8k
        };
1438
1439
70.8k
        px_put_usq_fixed(s, x0, y0, x1, y1);
1440
70.8k
        PX_PUT_LIT(s, cr_);
1441
70.8k
    }
1442
16.1M
    return 0;
1443
16.1M
}
1444
1445
static int
1446
pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
1447
3.64M
{
1448
3.64M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1449
3.64M
    stream *s = gdev_vector_stream(vdev);
1450
1451
3.64M
    spputc(s, pxtNewPath);
1452
3.64M
    xdev->points.type = POINTS_NONE;
1453
3.64M
    xdev->points.count = 0;
1454
3.64M
    return 0;
1455
3.64M
}
1456
1457
static int
1458
pclxl_moveto(gx_device_vector * vdev, double x0, double y0, double x,
1459
             double y, gx_path_type_t type)
1460
4.02M
{
1461
4.02M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1462
4.02M
    int code = pclxl_flush_points(xdev);
1463
1464
4.02M
    if (code < 0)
1465
0
        return code;
1466
4.02M
    return pclxl_set_cursor(xdev,
1467
4.02M
                            xdev->points.current.x = (int)(x + 0.5),
1468
4.02M
                            xdev->points.current.y = (int)(y + 0.5));
1469
4.02M
}
1470
1471
static int
1472
pclxl_lineto(gx_device_vector * vdev, double x0, double y0, double x,
1473
             double y, gx_path_type_t type)
1474
16.2M
{
1475
16.2M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1476
1477
16.2M
    if (xdev->points.type != POINTS_LINES || xdev->points.count >= NUM_POINTS - 2) {
1478
5.39M
        if (xdev->points.type != POINTS_NONE) {
1479
1.75M
            int code = pclxl_flush_points(xdev);
1480
1481
1.75M
            if (code < 0)
1482
0
                return code;
1483
1.75M
        }
1484
5.39M
        xdev->points.current.x = (int)(x0 + 0.5);
1485
5.39M
        xdev->points.current.y = (int)(y0 + 0.5);
1486
5.39M
        xdev->points.type = POINTS_LINES;
1487
1488
        /* This can only happen if we get two 'POINTS_NONE' in a row, in which case
1489
         * just overwrite the previous one below.
1490
         */
1491
5.39M
        if (xdev->points.count >= NUM_POINTS - 1)
1492
0
            xdev->points.count--;
1493
5.39M
    }
1494
16.2M
    {
1495
16.2M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
1496
1497
16.2M
        ppt->x = (int)(x + 0.5), ppt->y = (int)(y + 0.5);
1498
16.2M
    }
1499
16.2M
    return 0;
1500
16.2M
}
1501
1502
static int
1503
pclxl_curveto(gx_device_vector * vdev, double x0, double y0,
1504
              double x1, double y1, double x2, double y2, double x3,
1505
              double y3, gx_path_type_t type)
1506
5.81M
{
1507
5.81M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1508
1509
5.81M
    if (xdev->points.type != POINTS_CURVES ||
1510
5.81M
        xdev->points.count >= NUM_POINTS - 4) {
1511
2.57M
        if (xdev->points.type != POINTS_NONE) {
1512
2.18M
            int code = pclxl_flush_points(xdev);
1513
1514
2.18M
            if (code < 0)
1515
0
                return code;
1516
2.18M
        }
1517
2.57M
        xdev->points.current.x = (int)(x0 + 0.5);
1518
2.57M
        xdev->points.current.y = (int)(y0 + 0.5);
1519
2.57M
        xdev->points.type = POINTS_CURVES;
1520
1521
        /* This can only happen if we get multiple 'POINTS_NONE' in a row, in which case
1522
         * just overwrite the previous one below.
1523
         */
1524
2.57M
        if (xdev->points.count >= NUM_POINTS - 3)
1525
0
            xdev->points.count -= 3;
1526
2.57M
    }
1527
5.81M
    {
1528
5.81M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count];
1529
1530
5.81M
        ppt->x = (int)(x1 + 0.5), ppt->y = (int)(y1 + 0.5), ++ppt;
1531
5.81M
        ppt->x = (int)(x2 + 0.5), ppt->y = (int)(y2 + 0.5), ++ppt;
1532
5.81M
        ppt->x = (int)(x3 + 0.5), ppt->y = (int)(y3 + 0.5);
1533
5.81M
    }
1534
5.81M
    xdev->points.count += 3;
1535
5.81M
    return 0;
1536
5.81M
}
1537
1538
static int
1539
pclxl_closepath(gx_device_vector * vdev, double x, double y,
1540
                double x_start, double y_start, gx_path_type_t type)
1541
226k
{
1542
226k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1543
226k
    stream *s = gdev_vector_stream(vdev);
1544
226k
    int code = pclxl_flush_points(xdev);
1545
1546
226k
    if (code < 0)
1547
0
        return code;
1548
226k
    spputc(s, pxtCloseSubPath);
1549
226k
    xdev->points.current.x = (int)(x_start + 0.5);
1550
226k
    xdev->points.current.y = (int)(y_start + 0.5);
1551
226k
    return 0;
1552
226k
}
1553
1554
static int
1555
pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
1556
3.64M
{
1557
3.64M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1558
3.64M
    stream *s = gdev_vector_stream(vdev);
1559
3.64M
    int code = pclxl_flush_points(xdev);
1560
3.64M
    gx_path_type_t rule = type & gx_path_type_rule;
1561
1562
3.64M
    if (code < 0)
1563
0
        return code;
1564
3.64M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1565
3.62M
        if (rule != xdev->fill_rule) {
1566
541
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1567
541
                                 eNonZeroWinding));
1568
541
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
1569
541
            xdev->fill_rule = rule;
1570
541
        }
1571
3.62M
        pclxl_set_paints(xdev, type);
1572
3.62M
        spputc(s, pxtPaintPath);
1573
3.62M
    }
1574
3.64M
    if (type & gx_path_type_clip) {
1575
25.5k
        static const byte scr_[] = {
1576
25.5k
            DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
1577
25.5k
        };
1578
1579
25.5k
        if (rule != xdev->clip_rule) {
1580
659
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1581
659
                                 eNonZeroWinding));
1582
659
            px_put_ac(s, pxaClipMode, pxtSetClipMode);
1583
659
            xdev->clip_rule = rule;
1584
659
        }
1585
25.5k
        PX_PUT_LIT(s, scr_);
1586
25.5k
    }
1587
3.64M
    return 0;
1588
3.64M
}
1589
1590
/* Vector implementation procedures */
1591
1592
static const gx_device_vector_procs pclxl_vector_procs = {
1593
    /* Page management */
1594
    pclxl_beginpage,
1595
    /* Imager state */
1596
    pclxl_setlinewidth,
1597
    pclxl_setlinecap,
1598
    pclxl_setlinejoin,
1599
    pclxl_setmiterlimit,
1600
    pclxl_setdash,
1601
    gdev_vector_setflat,
1602
    pclxl_setlogop,
1603
    /* Other state */
1604
    pclxl_can_handle_hl_color,
1605
    pclxl_setfillcolor,
1606
    pclxl_setstrokecolor,
1607
    /* Paths */
1608
    gdev_vector_dopath,
1609
    pclxl_dorect,
1610
    pclxl_beginpath,
1611
    pclxl_moveto,
1612
    pclxl_lineto,
1613
    pclxl_curveto,
1614
    pclxl_closepath,
1615
    pclxl_endpath
1616
};
1617
1618
/* ---------------- Driver procedures ---------------- */
1619
1620
/* ------ Open/close/page ------ */
1621
1622
/* Open the device. */
1623
static int
1624
pclxl_open_device(gx_device * dev)
1625
13.0k
{
1626
13.0k
    gx_device_vector *vdev = (gx_device_vector *) dev;
1627
13.0k
    gx_device_pclxl *xdev = (gx_device_pclxl *) dev;
1628
13.0k
    int code;
1629
1630
13.0k
    vdev->v_memory = dev->memory->stable_memory;
1631
13.0k
    vdev->vec_procs = &pclxl_vector_procs;
1632
13.0k
    code = gdev_vector_open_file_options(vdev, 512,
1633
13.0k
                                         VECTOR_OPEN_FILE_SEQUENTIAL);
1634
13.0k
    if (code < 0)
1635
0
        return code;
1636
1637
13.0k
    while (dev->child)
1638
0
        dev = dev->child;
1639
13.0k
    vdev = (gx_device_vector *) dev;
1640
13.0k
    xdev = (gx_device_pclxl *) dev;
1641
1642
13.0k
    pclxl_page_init(xdev);
1643
13.0k
    px_write_file_header(vdev->strm, dev, xdev->Staple);
1644
13.0k
    xdev->media_size = pxeMediaSize_next;       /* no size selected */
1645
13.0k
    memset(&xdev->chars, 0, sizeof(xdev->chars));
1646
13.0k
    xdev->chars.next_in = xdev->chars.next_out = 2;
1647
    /* xdev->iccTransform = false; *//* set true/false here to ignore command line */
1648
13.0k
    return 0;
1649
13.0k
}
1650
1651
/* Wrap up ("output") a page. */
1652
/* We only support flush = true */
1653
static int
1654
pclxl_output_page(gx_device * dev, int num_copies, int flush)
1655
9.74k
{
1656
9.74k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1657
9.74k
    stream *s;
1658
9.74k
    int code;
1659
1660
    /* Note that unlike close_device, end_page must not omit blank pages. */
1661
9.74k
    if (!xdev->in_page)
1662
0
        pclxl_beginpage((gx_device_vector *) dev);
1663
9.74k
    s = xdev->strm;
1664
9.74k
    px_put_usa(s, (uint) num_copies, pxaPageCopies);    /* num_copies */
1665
9.74k
    spputc(s, pxtEndPage);
1666
9.74k
    sflush(s);
1667
9.74k
    pclxl_page_init(xdev);
1668
9.74k
    if (gp_ferror(xdev->file))
1669
0
        return_error(gs_error_ioerror);
1670
9.74k
    if ((code = gx_finish_output_page(dev, num_copies, flush)) < 0)
1671
0
        return code;
1672
    /* Check if we need to change the output file for separate pages */
1673
9.74k
    if (gx_outputfile_is_separate_pages
1674
9.74k
        (((gx_device_vector *) dev)->fname, dev->memory)) {
1675
0
        if ((code = pclxl_close_device(dev)) < 0)
1676
0
            return code;
1677
0
        code = pclxl_open_device(dev);
1678
0
    }
1679
9.74k
    return code;
1680
9.74k
}
1681
1682
/* Close the device. */
1683
/* Note that if this is being called as a result of finalization, */
1684
/* the stream may no longer exist. */
1685
static int
1686
pclxl_close_device(gx_device * dev)
1687
13.0k
{
1688
13.0k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1689
13.0k
    gp_file *file = xdev->file;
1690
1691
13.0k
    if (xdev->strm != NULL)
1692
13.0k
        sflush(xdev->strm);
1693
13.0k
    if (xdev->in_page)
1694
893
        gp_fputc(pxtEndPage, file);
1695
13.0k
    px_write_file_trailer(file);
1696
13.0k
    return gdev_vector_close_file((gx_device_vector *) dev);
1697
13.0k
}
1698
1699
/* ------ One-for-one images ------ */
1700
1701
static const byte eBit_values[] = {
1702
    0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
1703
};
1704
1705
/* Copy a monochrome bitmap. */
1706
static int
1707
pclxl_copy_mono(gx_device * dev, const byte * data, int data_x, int raster,
1708
                gx_bitmap_id id, int x, int y, int w, int h,
1709
                gx_color_index zero, gx_color_index one)
1710
21.7k
{
1711
21.7k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1712
21.7k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1713
21.7k
    int code;
1714
21.7k
    stream *s;
1715
21.7k
    gx_color_index color0 = zero, color1 = one;
1716
21.7k
    gx_color_index white = ((gx_color_index)1 << dev->color_info.depth) - 1;
1717
21.7k
    gx_color_index black = 0;
1718
21.7k
    gs_logical_operation_t lop;
1719
21.7k
    byte palette[2 * 3];
1720
21.7k
    int palette_size;
1721
21.7k
    pxeColorSpace_t color_space;
1722
1723
21.7k
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1724
21.7k
    code = gdev_vector_update_clip_path(vdev, NULL);
1725
21.7k
    if (code < 0)
1726
0
        return code;
1727
1728
    /* write_image_data() needs byte-alignment,
1729
     * and gx_default_copy_* is more efficient than pxlcl_*
1730
     * for small rasters. See details in copy_color().
1731
     */
1732
21.7k
    if (((data_x & 7) != 0) || (h == 1) || (w == 1))
1733
21.1k
        return gx_default_copy_mono(dev, data, data_x, raster, id,
1734
21.1k
                                    x, y, w, h, zero, one);
1735
1736
548
    pclxl_set_cursor(xdev, x, y);
1737
548
    if (id != gs_no_id && zero == gx_no_color_index &&
1738
548
        one != gx_no_color_index && data_x == 0) {
1739
240
        gx_drawing_color dcolor;
1740
1741
240
        code = gdev_vector_update_log_op(vdev, rop3_T | lop_T_transparent);
1742
240
        if (code < 0)
1743
0
            return 0;
1744
1745
240
        set_nonclient_dev_color(&dcolor, one);
1746
240
        pclxl_setfillcolor(vdev, NULL, &dcolor);
1747
240
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1748
240
            return 0;
1749
240
    }
1750
    /*
1751
     * The following doesn't work if we're writing white with a mask.
1752
     * We'll fix it eventually.
1753
     *
1754
     * The logic goes like this: non-white + mask (transparent)
1755
     * works by setting the mask color to white and also declaring
1756
     * white-is-transparent. This doesn't work for drawing white + mask,
1757
     * since everything is then white+white-and-transparent. So instead
1758
     * we set mask color to black, invert and draw the destination/background
1759
     * through it, as well as drawing the white color.
1760
     *
1761
     * In rop3 terms, this is (D & ~S) | S
1762
     *
1763
     * This also only works in the case of the drawing color is white,
1764
     * because we need the inversion to not draw anything, (especially
1765
     * not the complimentary color/shade). So we have two different code paths,
1766
     * white + mask and non-whites + mask.
1767
     *
1768
     * There is a further refinement to this algorithm - it appears that
1769
     * black+mask is treated specially by the vector driver core (rendered
1770
     * as transparent on white), and does not work as non-white + mask.
1771
     * So Instead we set mask color to white and do (S & D) (i.e. draw
1772
     * background on mask, instead of transparent on mask).
1773
     *
1774
     */
1775
308
    if (zero == gx_no_color_index) {
1776
159
        if (one == gx_no_color_index)
1777
0
            return 0;
1778
159
        if (one != white) {
1779
159
            if (one == black) {
1780
159
                lop = (rop3_S & rop3_D);
1781
159
            } else {
1782
0
                lop = rop3_S | lop_S_transparent;
1783
0
            }
1784
159
            color0 = white;
1785
159
        } else {
1786
0
            lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1787
0
            color0 = black;
1788
0
        }
1789
159
    } else if (one == gx_no_color_index) {
1790
0
        if (zero != white) {
1791
0
            if (zero == black) {
1792
0
                lop = (rop3_S & rop3_D);
1793
0
            } else {
1794
0
                lop = rop3_S | lop_S_transparent;
1795
0
            }
1796
0
            color1 = white;
1797
0
        } else {
1798
0
            lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1799
0
            color1 = black;
1800
0
        }
1801
149
    } else {
1802
149
        lop = rop3_S;
1803
149
    }
1804
1805
308
    if (dev->color_info.num_components == 1 ||
1806
308
        (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
1807
308
        ) {
1808
308
        palette[0] = (byte) color0;
1809
308
        palette[1] = (byte) color1;
1810
308
        palette_size = 2;
1811
308
        color_space = eGray;
1812
308
        if_debug2m('b', dev->memory, "color palette %02X %02X\n",
1813
308
                   palette[0], palette[1]);
1814
308
    } else {
1815
0
        palette[0] = (byte) (color0 >> 16);
1816
0
        palette[1] = (byte) (color0 >> 8);
1817
0
        palette[2] = (byte) color0;
1818
0
        palette[3] = (byte) (color1 >> 16);
1819
0
        palette[4] = (byte) (color1 >> 8);
1820
0
        palette[5] = (byte) color1;
1821
0
        palette_size = 6;
1822
0
        color_space = eRGB;
1823
0
    }
1824
308
    code = gdev_vector_update_log_op(vdev, lop);
1825
308
    if (code < 0)
1826
0
        return 0;
1827
308
    pclxl_set_color_palette(xdev, color_space, palette, palette_size);
1828
308
    s = pclxl_stream(xdev);
1829
308
    {
1830
308
        static const byte mi_[] = {
1831
308
            DUB(e1Bit), DA(pxaColorDepth),
1832
308
            DUB(eIndexedPixel), DA(pxaColorMapping)
1833
308
        };
1834
1835
308
        PX_PUT_LIT(s, mi_);
1836
308
    }
1837
308
    pclxl_write_begin_image(xdev, w, h, w, h);
1838
308
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1839
308
    pclxl_write_end_image(xdev);
1840
308
    return 0;
1841
308
}
1842
1843
/* Copy a color bitmap. */
1844
static int
1845
pclxl_copy_color(gx_device * dev,
1846
                 const byte * base, int sourcex, int raster, gx_bitmap_id id,
1847
                 int x, int y, int w, int h)
1848
81.3k
{
1849
81.3k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1850
81.3k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1851
81.3k
    stream *s;
1852
81.3k
    uint source_bit;
1853
81.3k
    int code;
1854
1855
81.3k
    fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
1856
81.3k
    code = gdev_vector_update_clip_path(vdev, NULL);
1857
81.3k
    if (code < 0)
1858
0
        return code;
1859
1860
81.3k
    source_bit = sourcex * dev->color_info.depth;
1861
1862
    /* side-effect from fill/stroke may have set color space to eGray */
1863
81.3k
    if (dev->color_info.num_components == 3)
1864
61.6k
        pclxl_set_color_space(xdev, eRGB);
1865
19.6k
    else if (dev->color_info.num_components == 1)
1866
19.6k
        pclxl_set_color_space(xdev, eGray);
1867
1868
    /* write_image_data() needs byte-alignment,
1869
     * and gx_default_copy_* is more efficient than pxlcl_*
1870
     * for small rasters.
1871
     *
1872
     * SetBrushSource + Rectangle = 21 byte for 1x1 RGB
1873
     * SetCursor+ BeginImage + ReadImage + EndImage = 56 bytes for 1x1 RGB
1874
     * 3x1 RGB at 3 different colors takes 62 bytes for pxlcl_*
1875
     * but gx_default_copy_* uses 63 bytes. Below 3 pixels, gx_default_copy_*
1876
     * is better than pxlcl_*; above 3 pixels, it is less clear;
1877
     * in practice, single-lines seems better coded as painted rectangles
1878
     * than images.
1879
     */
1880
81.3k
    if (((source_bit & 7) != 0) || (w == 1) || (h == 1))
1881
78.2k
        return gx_default_copy_color(dev, base, sourcex, raster, id,
1882
78.2k
                                     x, y, w, h);
1883
3.01k
    code = gdev_vector_update_log_op(vdev, rop3_S);
1884
3.01k
    if (code < 0)
1885
0
        return 0;
1886
3.01k
    pclxl_set_cursor(xdev, x, y);
1887
3.01k
    s = pclxl_stream(xdev);
1888
3.01k
    {
1889
3.01k
        static const byte ci_[] = {
1890
3.01k
            DA(pxaColorDepth),
1891
3.01k
            DUB(eDirectPixel), DA(pxaColorMapping)
1892
3.01k
        };
1893
1894
3.01k
        px_put_ub(s, eBit_values[dev->color_info.depth /
1895
3.01k
                                 dev->color_info.num_components]);
1896
3.01k
        PX_PUT_LIT(s, ci_);
1897
3.01k
    }
1898
3.01k
    pclxl_write_begin_image(xdev, w, h, w, h);
1899
3.01k
    pclxl_write_image_data(xdev, base, source_bit, raster,
1900
3.01k
                           w * dev->color_info.depth, 0, h, false);
1901
3.01k
    pclxl_write_end_image(xdev);
1902
3.01k
    return 0;
1903
3.01k
}
1904
1905
/* Fill a mask. */
1906
static int
1907
pclxl_fill_mask(gx_device * dev,
1908
                const byte * data, int data_x, int raster, gx_bitmap_id id,
1909
                int x, int y, int w, int h,
1910
                const gx_drawing_color * pdcolor, int depth,
1911
                gs_logical_operation_t lop, const gx_clip_path * pcpath)
1912
4.46M
{
1913
4.46M
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1914
4.46M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1915
4.46M
    int code;
1916
4.46M
    stream *s;
1917
4.46M
    gx_color_index foreground;
1918
1919
4.46M
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1920
    /* write_image_data() needs byte-alignment,
1921
     * and gx_default_copy_* is more efficient than pxlcl_*
1922
     * for small rasters. See details in copy_color().
1923
     */
1924
3.71M
    if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 || (w == 1)
1925
3.71M
        || (h == 1))
1926
13.6k
        return gx_default_fill_mask(dev, data, data_x, raster, id, x, y, w, h,
1927
13.6k
                                    pdcolor, depth, lop, pcpath);
1928
3.70M
    code = gdev_vector_update_clip_path(vdev, pcpath);
1929
3.70M
    foreground = gx_dc_pure_color(pdcolor);
1930
3.70M
    if (code < 0)
1931
0
        return code;
1932
3.70M
    code = gdev_vector_update_fill_color(vdev, NULL, pdcolor);
1933
3.70M
    if (code < 0)
1934
0
        return 0;
1935
3.70M
    pclxl_set_cursor(xdev, x, y);
1936
3.70M
    if (id != gs_no_id && data_x == 0) {
1937
3.70M
        code = gdev_vector_update_log_op(vdev, lop);
1938
3.70M
        if (code < 0)
1939
0
            return 0;
1940
3.70M
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1941
3.70M
            return 0;
1942
3.70M
    }
1943
    /* This is similiar to the copy_mono white-on-mask,
1944
     * except we are drawing white on the black of a black/white mask,
1945
     * so we invert source, compared to copy_mono */
1946
2.53k
    if (foreground == ((gx_color_index)1 << dev->color_info.depth) - 1) {       /* white */
1947
25
        lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
1948
2.50k
    } else if (foreground == 0) {       /* black */
1949
2.26k
        lop = (rop3_S & rop3_D);
1950
2.26k
    } else
1951
247
        lop |= rop3_S | lop_S_transparent;
1952
1953
2.53k
    code = gdev_vector_update_log_op(vdev, lop);
1954
2.53k
    if (code < 0)
1955
0
        return 0;
1956
2.53k
    pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
1957
2.53k
    s = pclxl_stream(xdev);
1958
2.53k
    {
1959
2.53k
        static const byte mi_[] = {
1960
2.53k
            DUB(e1Bit), DA(pxaColorDepth),
1961
2.53k
            DUB(eIndexedPixel), DA(pxaColorMapping)
1962
2.53k
        };
1963
1964
2.53k
        PX_PUT_LIT(s, mi_);
1965
2.53k
    }
1966
2.53k
    pclxl_write_begin_image(xdev, w, h, w, h);
1967
2.53k
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1968
2.53k
    pclxl_write_end_image(xdev);
1969
2.53k
    return 0;
1970
2.53k
}
1971
1972
/* Do a RasterOp. */
1973
static int
1974
pclxl_strip_copy_rop2(gx_device * dev, const byte * sdata, int sourcex,
1975
                     uint sraster, gx_bitmap_id id,
1976
                     const gx_color_index * scolors,
1977
                     const gx_strip_bitmap * textures,
1978
                     const gx_color_index * tcolors,
1979
                     int x, int y, int width, int height,
1980
                     int phase_x, int phase_y, gs_logical_operation_t lop,
1981
                     uint plane_height)
1982
0
{
1983
0
    lop = lop_sanitize(lop);
1984
    /* Improvements possible here using PXL ROP3
1985
       for some combinations of args; use gx_default for now */
1986
0
    if (!rop3_uses_D(lop))  /* gx_default() cannot cope with D ops */
1987
0
        return gx_default_strip_copy_rop2(dev, sdata, sourcex,
1988
0
                                          sraster, id,
1989
0
                                          scolors,
1990
0
                                          textures,
1991
0
                                          tcolors,
1992
0
                                          x, y, width, height,
1993
0
                                          phase_x, phase_y, lop,
1994
0
                                          plane_height);
1995
0
    return 0;
1996
0
}
1997
1998
/* ------ High-level images ------ */
1999
2000
2.09k
#define MAX_ROW_DATA 500000     /* arbitrary */
2001
typedef struct pclxl_image_enum_s {
2002
    gdev_vector_image_enum_common;
2003
    gs_matrix mat;
2004
    struct ir_ {
2005
        byte *data;
2006
        int num_rows;           /* # of allocated rows */
2007
        int first_y;
2008
        uint raster;
2009
    } rows;
2010
    bool flipped;
2011
    gsicc_link_t *icclink;
2012
} pclxl_image_enum_t;
2013
2014
gs_private_st_suffix_add2(st_pclxl_image_enum, pclxl_image_enum_t,
2015
                          "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
2016
                          pclxl_image_enum_reloc_ptrs, st_vector_image_enum,
2017
                          rows.data, icclink);
2018
2019
/* Start processing an image. */
2020
static int
2021
pclxl_begin_typed_image(gx_device * dev,
2022
                  const gs_gstate * pgs,
2023
                  const gs_matrix *pmat,
2024
                  const gs_image_common_t * pic,
2025
                  const gs_int_rect * prect,
2026
                  const gx_drawing_color * pdcolor,
2027
                  const gx_clip_path * pcpath, gs_memory_t * mem,
2028
                  gx_image_enum_common_t ** pinfo)
2029
2.79k
{
2030
2.79k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
2031
2.79k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
2032
2.79k
    const gs_image_t *pim = (const gs_image_t *)pic;
2033
2.79k
    const gs_color_space *pcs;
2034
2.79k
    pclxl_image_enum_t *pie;
2035
2.79k
    byte *row_data;
2036
2.79k
    int num_rows;
2037
2.79k
    uint row_raster;
2038
2.79k
    int bits_per_pixel;
2039
2.79k
    gs_matrix mat;
2040
2.79k
    int code;
2041
2042
    /* We only cope with image type 1 here. */
2043
2.79k
    if (pic->type->index != 1)
2044
17
        goto use_default;
2045
2046
2.77k
    pcs = pim->ColorSpace;
2047
    /*
2048
     * Following should divide by num_planes, but we only handle chunky
2049
     * images, i.e., num_planes = 1.
2050
     */
2051
2.77k
    bits_per_pixel =
2052
2.77k
        (pim->ImageMask ? 1 :
2053
2.77k
         pim->BitsPerComponent * gs_color_space_num_components(pcs));
2054
2055
    /*
2056
     * Check whether we can handle this image.  PCL XL 1.0 and 2.0 only
2057
     * handle orthogonal transformations.
2058
     */
2059
2.77k
    code = gs_matrix_invert(&pim->ImageMatrix, &mat);
2060
2.77k
    if (code < 0)
2061
0
        goto use_default;
2062
2.77k
    if (pmat == NULL)
2063
2.77k
        pmat = &ctm_only(pgs);
2064
2.77k
    gs_matrix_multiply(&mat, pmat, &mat);
2065
2066
2.77k
    if (pclxl_nontrivial_transfer(pgs))
2067
2
        goto use_default;
2068
2069
2.77k
    if (pim->Width == 0 || pim->Height == 0)
2070
0
        goto use_default;
2071
2072
2.77k
    if (bits_per_pixel == 32) {
2073
        /*
2074
           32-bit cmyk depends on transformable to 24-bit rgb.
2075
           Some 32-bit aren't cmyk's. (e.g. DeviceN)
2076
         */
2077
400
        if (!pclxl_can_icctransform(pim))
2078
0
            goto use_default;
2079
2080
        /*
2081
           Strictly speaking, regardless of bits_per_pixel,
2082
           we cannot handle non-Identity Decode array.
2083
           Historically we did (wrongly), so this is inside
2084
           a 32-bit conditional to avoid regression, but shouldn't.
2085
         */
2086
400
        if (pim->Decode[0] != 0 || pim->Decode[1] != 1 ||
2087
400
            pim->Decode[2] != 0 || pim->Decode[3] != 1 ||
2088
400
            pim->Decode[4] != 0 || pim->Decode[5] != 1)
2089
0
            goto use_default;
2090
400
    }
2091
2092
    /*
2093
     * NOTE: this predicate should be fixed to be readable and easily
2094
     * debugged.  Each condition should be separate.  See the large
2095
     * similar conditional in clist_begin_typed_image which has
2096
     * already been reworked.  We can handle rotations of 90 degs +
2097
     * scaling + reflections.  * These have one of the diagonals being
2098
     * zeros * (and the other diagonals having non-zeros).
2099
     */
2100
2.77k
    if ((!((mat.xx * mat.yy != 0) && (mat.xy == 0) && (mat.yx == 0)) &&
2101
2.77k
         !((mat.xx == 0) && (mat.yy == 0) && (mat.xy * mat.yx != 0))) ||
2102
2.77k
        (pim->ImageMask ?
2103
101
         (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
2104
2.75k
         ((!pclxl_can_handle_color_space(pcs) ||
2105
2.65k
           (bits_per_pixel != 1 && bits_per_pixel != 4 &&
2106
2.03k
            bits_per_pixel != 8 && bits_per_pixel != 24 &&
2107
2.03k
            bits_per_pixel != 32))
2108
2.65k
          && !(pclxl_can_icctransform(pim) && xdev->iccTransform))) ||
2109
2.77k
        pim->format != gs_image_format_chunky || pim->Interpolate || prect)
2110
682
        goto use_default;
2111
2.09k
    row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
2112
2.09k
    num_rows = MAX_ROW_DATA / row_raster;
2113
2.09k
    if (num_rows > pim->Height)
2114
1.19k
        num_rows = pim->Height;
2115
2.09k
    if (num_rows <= 0)
2116
0
        num_rows = 1;
2117
2.09k
    pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
2118
2.09k
                          "pclxl_begin_image");
2119
2.09k
    row_data = gs_alloc_bytes(mem, num_rows * row_raster,
2120
2.09k
                              "pclxl_begin_image(rows)");
2121
2.09k
    if (pie == 0 || row_data == 0) {
2122
0
        code = gs_note_error(gs_error_VMerror);
2123
0
        goto fail;
2124
0
    }
2125
2.09k
    code = gdev_vector_begin_image(vdev, pgs, pim, pim->format, prect,
2126
2.09k
                                   pdcolor, pcpath, mem,
2127
2.09k
                                   &pclxl_image_enum_procs,
2128
2.09k
                                   (gdev_vector_image_enum_t *) pie);
2129
2.09k
    if (code < 0)
2130
0
        goto fail;
2131
2132
    /* emit a PXL XL rotation and adjust mat correspondingly */
2133
2.09k
    pie->flipped = false;
2134
2.09k
    if (mat.xx * mat.yy > 0) {
2135
2.08k
        if (mat.xx < 0) {
2136
2
            stream *s = pclxl_stream(xdev);
2137
2138
2
            mat.xx = -mat.xx;
2139
2
            mat.yy = -mat.yy;
2140
2
            mat.tx = -mat.tx;
2141
2
            mat.ty = -mat.ty;
2142
2
            px_put_ss(s, 180);
2143
2
            xdev->state_rotated = 2;
2144
2
            px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2145
2
        }
2146
        /* leave the matrix alone if it is portrait */
2147
2.08k
    } else if (mat.xx * mat.yy < 0) {
2148
4
        pie->flipped = true;
2149
4
        if (mat.xx < 0) {
2150
0
            stream *s = pclxl_stream(xdev);
2151
2152
0
            mat.xx = -mat.xx;
2153
0
            mat.tx = -mat.tx;
2154
0
            px_put_ss(s, +180);
2155
0
            xdev->state_rotated = +2;
2156
0
            px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2157
4
        } else {
2158
4
            mat.yy = -mat.yy;
2159
4
            mat.ty = -mat.ty;
2160
4
        }
2161
4
    } else if (mat.xy * mat.yx < 0) {
2162
        /* rotate +90 or -90 */
2163
0
        float tmpf;
2164
0
        stream *s = pclxl_stream(xdev);
2165
2166
0
        if (mat.xy > 0) {
2167
0
            mat.xx = mat.xy;
2168
0
            mat.yy = -mat.yx;
2169
0
            tmpf = mat.tx;
2170
0
            mat.tx = mat.ty;
2171
0
            mat.ty = -tmpf;
2172
0
            px_put_ss(s, -90);
2173
0
            xdev->state_rotated = -1;
2174
0
        } else {
2175
0
            mat.xx = -mat.xy;
2176
0
            mat.yy = mat.yx;
2177
0
            tmpf = mat.tx;
2178
0
            mat.tx = -mat.ty;
2179
0
            mat.ty = tmpf;
2180
0
            px_put_ss(s, +90);
2181
0
            xdev->state_rotated = +1;
2182
0
        }
2183
0
        mat.xy = mat.yx = 0;
2184
0
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2185
0
    } else if (mat.xy * mat.yx > 0) {
2186
0
        float tmpf;
2187
0
        stream *s = pclxl_stream(xdev);
2188
2189
0
        pie->flipped = true;
2190
0
        if (mat.xy > 0) {
2191
0
            mat.xx = mat.xy;
2192
0
            mat.yy = mat.yx;
2193
0
            tmpf = mat.tx;
2194
0
            mat.tx = mat.ty;
2195
0
            mat.ty = tmpf;
2196
0
            px_put_ss(s, -90);
2197
0
            xdev->state_rotated = -1;
2198
0
        } else {
2199
0
            mat.xx = -mat.xy;
2200
0
            mat.yy = -mat.yx;
2201
0
            tmpf = mat.tx;
2202
0
            mat.tx = -mat.ty;
2203
0
            mat.ty = -tmpf;
2204
0
            px_put_ss(s, +90);
2205
0
            xdev->state_rotated = +1;
2206
0
        }
2207
0
        mat.xy = mat.yx = 0;
2208
0
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2209
0
    }
2210
2211
2.09k
    pie->mat = mat;
2212
2.09k
    pie->rows.data = row_data;
2213
2.09k
    pie->rows.num_rows = num_rows;
2214
2.09k
    pie->rows.first_y = 0;
2215
2.09k
    pie->rows.raster = row_raster;
2216
    /*
2217
       pclxl_can_handle_color_space() is here to avoid regression,
2218
       to avoid icc if traditional code path works (somewhat).
2219
       It is flawed in that it claims to handles device colors with
2220
       icc profiles (and output device colours); so that "can transform"
2221
       won't transform; we need to override it for the case of
2222
       32-bit colour, except when usefastcolor is specified.
2223
2224
       "can_icctransform" should have been accompanied by a
2225
       "will tranform" (xdev->iccTransform) check. However, since
2226
       we want to transform for CMYK regardless, so just as well
2227
       there was not such a check, and we are not adding one now.
2228
2229
       In other words, the bizarre logic in the middle is to keep
2230
       the current workflow as much as possible, but force icc mode
2231
       or confirm fastcolor mode only for 32-bit image, regardless
2232
       of whether xdev->iccTransform is on.
2233
2234
       Whole-sale icc mode is to simply remove entire middle part,
2235
       a risky change.
2236
     */
2237
2.09k
    if (!pim->ImageMask && (!pclxl_can_handle_color_space(pcs)
2238
2.03k
                            || (bits_per_pixel == 32 && dev->icc_struct
2239
2.03k
                                && !dev->icc_struct->usefastcolor))
2240
2.09k
        && pclxl_can_icctransform(pim) && pcs->cmm_icc_profile_data) {
2241
399
        gsicc_rendering_param_t rendering_params;
2242
2243
399
        rendering_params.black_point_comp = pgs->blackptcomp;
2244
399
        rendering_params.graphics_type_tag = GS_IMAGE_TAG;
2245
399
        rendering_params.rendering_intent = pgs->renderingintent;
2246
399
        pie->icclink = gsicc_get_link(pgs, dev, pcs, NULL /*des */ ,
2247
399
                                      &rendering_params, pgs->memory);
2248
399
    } else
2249
1.69k
        pie->icclink = NULL;
2250
2.09k
    *pinfo = (gx_image_enum_common_t *) pie;
2251
2.09k
    {
2252
2.09k
        gs_logical_operation_t lop = pgs->log_op;
2253
2254
2.09k
        if (pim->ImageMask) {
2255
60
            const byte *palette = (const byte *)
2256
60
                (pim->Decode[0] ? "\377\000" : "\000\377");
2257
60
            gx_color_index foreground = gx_dc_pure_color(pdcolor);
2258
2259
60
            code = gdev_vector_update_fill_color(vdev, NULL,    /* use process color */
2260
60
                                                 pdcolor);
2261
60
            if (code < 0)
2262
0
                goto fail;
2263
            /* This is similiar to the copy_mono white-on-mask,
2264
             * except we are drawing white on the black of a black/white mask,
2265
             * so we invert source, compared to copy_mono */
2266
60
            if (foreground == ((gx_color_index)1 << dev->color_info.depth) - 1) {       /* white */
2267
1
                lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
2268
59
            } else if (foreground == 0) {       /* black */
2269
47
                lop = (rop3_S & rop3_D);
2270
47
            } else
2271
12
                lop |= rop3_S | lop_S_transparent;
2272
2273
60
            code = gdev_vector_update_log_op(vdev, lop);
2274
60
            if (code < 0)
2275
0
                goto fail;
2276
60
            pclxl_set_color_palette(xdev, eGray, palette, 2);
2277
2.03k
        } else {
2278
2.03k
            if (bits_per_pixel == 24 || bits_per_pixel == 32) {
2279
1.87k
                code = gdev_vector_update_log_op
2280
1.87k
                    (vdev,
2281
1.87k
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2282
1.87k
                if (code < 0)
2283
0
                    goto fail;
2284
1.87k
                if (dev->color_info.num_components == 1) {
2285
755
                    pclxl_set_color_space(xdev, eGray);
2286
1.11k
                } else {
2287
1.11k
                    pclxl_set_color_space(xdev, eRGB);
2288
1.11k
                }
2289
1.87k
            } else {
2290
163
                int bpc = pim->BitsPerComponent;
2291
163
                int num_components =
2292
163
                    pie->plane_depths[0] * pie->num_planes / bpc;
2293
163
                int sample_max = (1 << bpc) - 1;
2294
163
                byte palette[256 * 3];
2295
163
                int i;
2296
2297
163
                code = gdev_vector_update_log_op
2298
163
                    (vdev,
2299
163
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2300
163
                if (code < 0)
2301
0
                    goto fail;
2302
30.4k
                for (i = 0; i < 1 << bits_per_pixel; ++i) {
2303
30.2k
                    gs_client_color cc;
2304
30.2k
                    gx_device_color devc;
2305
30.2k
                    int cv = i, j;
2306
30.2k
                    gx_color_index ci;
2307
2308
60.5k
                    for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
2309
30.2k
                        cc.paint.values[j] = pim->Decode[j * 2] +
2310
30.2k
                            (cv & sample_max) *
2311
30.2k
                            (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
2312
30.2k
                            sample_max;
2313
30.2k
                    (*pcs->type->remap_color)
2314
30.2k
                        (&cc, pcs, &devc, pgs, dev, gs_color_select_source);
2315
30.2k
                    if (!gx_dc_is_pure(&devc))
2316
0
                        return_error(gs_error_Fatal);
2317
30.2k
                    ci = gx_dc_pure_color(&devc);
2318
30.2k
                    if (dev->color_info.num_components == 1) {
2319
19.2k
                        palette[i] = (byte) ci;
2320
19.2k
                    } else {
2321
11.0k
                        byte *ppal = &palette[i * 3];
2322
2323
11.0k
                        ppal[0] = (byte) (ci >> 16);
2324
11.0k
                        ppal[1] = (byte) (ci >> 8);
2325
11.0k
                        ppal[2] = (byte) ci;
2326
11.0k
                    }
2327
30.2k
                }
2328
163
                if (dev->color_info.num_components == 1)
2329
76
                    pclxl_set_color_palette(xdev, eGray, palette,
2330
76
                                            1 << bits_per_pixel);
2331
87
                else
2332
87
                    pclxl_set_color_palette(xdev, eRGB, palette,
2333
87
                                            3 << bits_per_pixel);
2334
163
            }
2335
2.03k
        }
2336
2.09k
    }
2337
2.09k
    return 0;
2338
0
  fail:
2339
0
    gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
2340
0
    gs_free_object(mem, pie, "pclxl_begin_image");
2341
701
  use_default:
2342
701
    if (dev->color_info.num_components == 1)
2343
45
        pclxl_set_color_space(xdev, eGray);
2344
656
    else
2345
656
        pclxl_set_color_space(xdev, eRGB);
2346
701
    return gx_default_begin_typed_image(dev, pgs, pmat, pic, prect,
2347
701
                                        pdcolor, pcpath, mem, pinfo);
2348
0
}
2349
2350
/* Write one strip of an image, from pie->rows.first_y to pie->y. */
2351
static int
2352
image_transform_x(const pclxl_image_enum_t * pie, int sx)
2353
23.8k
{
2354
23.8k
    return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
2355
23.8k
                 ((const gx_device_pclxl *)pie->dev)->scale.x);
2356
23.8k
}
2357
static int
2358
image_transform_y(const pclxl_image_enum_t * pie, int sy)
2359
23.8k
{
2360
23.8k
    return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
2361
23.8k
                 ((const gx_device_pclxl *)pie->dev)->scale.y);
2362
23.8k
}
2363
2364
static int
2365
pclxl_image_write_rows(pclxl_image_enum_t * pie)
2366
11.9k
{
2367
11.9k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) pie->dev;
2368
11.9k
    stream *s = pclxl_stream(xdev);
2369
11.9k
    int y = pie->rows.first_y;
2370
11.9k
    int h = pie->y - y;
2371
11.9k
    int xo = image_transform_x(pie, 0);
2372
11.9k
    int yo = image_transform_y(pie, y);
2373
11.9k
    int dw = image_transform_x(pie, pie->width) - xo;
2374
11.9k
    int dh = image_transform_y(pie, y + h) - yo;
2375
11.9k
    int rows_raster = pie->rows.raster;
2376
11.9k
    int offset_lastflippedstrip = 0;
2377
2378
11.9k
    if (pie->flipped) {
2379
4
        yo = -yo - dh;
2380
4
        if (!pie->icclink)
2381
4
            offset_lastflippedstrip =
2382
4
                pie->rows.raster * (pie->rows.num_rows - h);
2383
0
        else
2384
0
            offset_lastflippedstrip =
2385
0
                (pie->rows.raster / (pie->bits_per_pixel >> 3))
2386
0
                * xdev->color_info.num_components * (pie->rows.num_rows - h);
2387
4
    };
2388
2389
11.9k
    if (dw <= 0 || dh <= 0)
2390
1
        return 0;
2391
11.9k
    pclxl_set_cursor(xdev, xo, yo);
2392
11.9k
    if (pie->bits_per_pixel == 24) {
2393
10.4k
        static const byte ci_[] = {
2394
10.4k
            DA(pxaColorDepth),
2395
10.4k
            DUB(eDirectPixel), DA(pxaColorMapping)
2396
10.4k
        };
2397
2398
10.4k
        px_put_ub(s, eBit_values[8]);
2399
10.4k
        PX_PUT_LIT(s, ci_);
2400
10.4k
        if (xdev->color_info.depth == 8) {
2401
508
            rows_raster /= 3;
2402
508
            if (!pie->icclink) {
2403
508
                byte *in = pie->rows.data + offset_lastflippedstrip;
2404
508
                byte *out = pie->rows.data + offset_lastflippedstrip;
2405
508
                int i;
2406
508
                int j;
2407
2408
88.5k
                for (j = 0; j < h; j++) {
2409
30.7M
                    for (i = 0; i < rows_raster; i++) {
2410
30.7M
                        *out =
2411
30.7M
                            (byte) (((*(in + 0) * (ulong) lum_red_weight) +
2412
30.7M
                                     (*(in + 1) * (ulong) lum_green_weight) +
2413
30.7M
                                     (*(in + 2) * (ulong) lum_blue_weight) +
2414
30.7M
                                     (lum_all_weights / 2)) /
2415
30.7M
                                    lum_all_weights);
2416
30.7M
                        in += 3;
2417
30.7M
                        out++;
2418
30.7M
                    }
2419
88.0k
                }
2420
508
            }
2421
508
        }
2422
10.4k
    } else if (pie->bits_per_pixel == 32) {
2423
760
        static const byte ci_[] = {
2424
760
            DA(pxaColorDepth),
2425
760
            DUB(eDirectPixel), DA(pxaColorMapping)
2426
760
        };
2427
2428
760
        px_put_ub(s, eBit_values[8]);
2429
760
        PX_PUT_LIT(s, ci_);
2430
760
        if (xdev->color_info.depth == 8) {
2431
            /* CMYK to Gray */
2432
483
            rows_raster /= 4;
2433
483
            if (!pie->icclink) {
2434
0
                byte *in = pie->rows.data + offset_lastflippedstrip;
2435
0
                byte *out = pie->rows.data + offset_lastflippedstrip;
2436
0
                int i;
2437
0
                int j;
2438
2439
0
                for (j = 0; j < h; j++) {
2440
0
                    for (i = 0; i < rows_raster; i++) {
2441
                        /* DeviceCMYK to DeviceGray */
2442
0
                        int v =
2443
0
                            (255 - (*(in + 3))) * (int)lum_all_weights
2444
0
                            + (lum_all_weights / 2)
2445
0
                            - (*(in + 0) * (int)lum_red_weight)
2446
0
                            - (*(in + 1) * (int)lum_green_weight)
2447
0
                            - (*(in + 2) * (int)lum_blue_weight);
2448
2449
0
                        *out = max(v, 0) / lum_all_weights;
2450
0
                        in += 4;
2451
0
                        out++;
2452
0
                    }
2453
0
                }
2454
0
            }
2455
483
        } else {
2456
            /* CMYK to RGB */
2457
277
            rows_raster /= 4;
2458
277
            if (!pie->icclink) {
2459
0
                byte *in = pie->rows.data + offset_lastflippedstrip;
2460
0
                byte *out = pie->rows.data + offset_lastflippedstrip;
2461
0
                int i;
2462
0
                int j;
2463
2464
0
                for (j = 0; j < h; j++) {
2465
0
                    for (i = 0; i < rows_raster; i++) {
2466
                        /* DeviceCMYK to DeviceRGB */
2467
0
                        int r = (int)255 - (*(in + 0)) - (*(in + 3));
2468
0
                        int g = (int)255 - (*(in + 1)) - (*(in + 3));
2469
0
                        int b = (int)255 - (*(in + 2)) - (*(in + 3));
2470
2471
                        /* avoid trashing the first 12->9 conversion */
2472
0
                        *out = max(r, 0);
2473
0
                        out++;
2474
0
                        *out = max(g, 0);
2475
0
                        out++;
2476
0
                        *out = max(b, 0);
2477
0
                        out++;
2478
0
                        in += 4;
2479
0
                    }
2480
0
                }
2481
0
            }
2482
277
            rows_raster *= 3;
2483
277
        }
2484
760
    } else {
2485
691
        static const byte ii_[] = {
2486
691
            DA(pxaColorDepth),
2487
691
            DUB(eIndexedPixel), DA(pxaColorMapping)
2488
691
        };
2489
691
        px_put_ub(s, eBit_values[pie->bits_per_pixel]);
2490
691
        PX_PUT_LIT(s, ii_);
2491
691
    }
2492
11.9k
    pclxl_write_begin_image(xdev, pie->width, h, dw, dh);
2493
    /* 8-bit gray image may compress with jpeg, but we
2494
       cannot tell if it is 8-bit gray or 8-bit indexed */
2495
11.9k
    pclxl_write_image_data(xdev, pie->rows.data + offset_lastflippedstrip, 0,
2496
11.9k
                           rows_raster, rows_raster << 3, 0, h,
2497
11.9k
                           ((pie->bits_per_pixel == 24
2498
11.9k
                             || pie->bits_per_pixel == 32) ? true : false));
2499
11.9k
    pclxl_write_end_image(xdev);
2500
11.9k
    return 0;
2501
11.9k
}
2502
2503
/* Process the next piece of an image. */
2504
static int
2505
pclxl_image_plane_data(gx_image_enum_common_t * info,
2506
                       const gx_image_plane_t * planes, int height,
2507
                       int *rows_used)
2508
1.22M
{
2509
1.22M
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2510
1.22M
    int data_bit = planes[0].data_x * info->plane_depths[0];
2511
1.22M
    int width_bits = pie->width * info->plane_depths[0];
2512
1.22M
    int i;
2513
2514
    /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
2515
1.22M
    if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
2516
0
        return_error(gs_error_rangecheck);
2517
1.22M
    if (height > pie->height - pie->y)
2518
86
        height = pie->height - pie->y;
2519
2.54M
    for (i = 0; i < height; pie->y++, ++i) {
2520
1.32M
        int flipped_strip_offset;
2521
2522
1.32M
        if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
2523
9.92k
            int code = pclxl_image_write_rows(pie);
2524
2525
9.92k
            if (code < 0)
2526
0
                return code;
2527
9.92k
            pie->rows.first_y = pie->y;
2528
9.92k
        }
2529
1.32M
        flipped_strip_offset = (pie->flipped ?
2530
9
                                (pie->rows.num_rows -
2531
9
                                 (pie->y - pie->rows.first_y) -
2532
1.32M
                                 1) : (pie->y - pie->rows.first_y));
2533
1.32M
        if (!pie->icclink)
2534
1.18M
            memcpy(pie->rows.data +
2535
1.18M
                   pie->rows.raster * flipped_strip_offset,
2536
1.18M
                   planes[0].data + planes[0].raster * i + (data_bit >> 3),
2537
1.18M
                   pie->rows.raster);
2538
145k
        else {
2539
145k
            gsicc_bufferdesc_t input_buff_desc;
2540
145k
            gsicc_bufferdesc_t output_buff_desc;
2541
145k
            int pixels_per_row =
2542
145k
                pie->rows.raster / (pie->bits_per_pixel >> 3);
2543
145k
            int out_raster_stride =
2544
145k
                pixels_per_row * info->dev->color_info.num_components;
2545
145k
            gsicc_init_buffer(&input_buff_desc,
2546
145k
                              (pie->bits_per_pixel >> 3) /*num_chan */ ,
2547
145k
                              1 /*bytes_per_chan */ ,
2548
145k
                              false /*has_alpha */ , false /*alpha_first */ ,
2549
145k
                              false /*is_planar */ ,
2550
145k
                              0 /*plane_stride */ ,
2551
145k
                              pie->rows.raster /*row_stride */ ,
2552
145k
                              1 /*num_rows */ ,
2553
145k
                              pixels_per_row /*pixels_per_row */ );
2554
145k
            gsicc_init_buffer(&output_buff_desc,
2555
145k
                              info->dev->color_info.num_components, 1, false,
2556
145k
                              false, false, 0, out_raster_stride, 1,
2557
145k
                              pixels_per_row);
2558
145k
            gscms_transform_color_buffer(info->dev, pie->icclink,
2559
145k
                                         &input_buff_desc, &output_buff_desc,
2560
145k
                                         (void *)(planes[0].data +
2561
145k
                                                  planes[0].raster * i +
2562
145k
                                                  (data_bit >> 3)) /*src */ ,
2563
145k
                                         pie->rows.data + out_raster_stride * flipped_strip_offset      /*des */
2564
145k
                                         );
2565
145k
        }
2566
1.32M
    }
2567
1.22M
    *rows_used = height;
2568
1.22M
    return pie->y >= pie->height;
2569
1.22M
}
2570
2571
/* Clean up by releasing the buffers. */
2572
static int
2573
pclxl_image_end_image(gx_image_enum_common_t * info, bool draw_last)
2574
2.09k
{
2575
2.09k
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2576
2.09k
    int code = 0;
2577
2578
    /* Write the final strip, if any. */
2579
2.09k
    if (pie->y > pie->rows.first_y && draw_last)
2580
2.01k
        code = pclxl_image_write_rows(pie);
2581
2.09k
    if (draw_last) {
2582
2.09k
        gx_device_pclxl *xdev = (gx_device_pclxl *) info->dev;
2583
2.09k
        stream *s = pclxl_stream(xdev);
2584
2585
2.09k
        switch (xdev->state_rotated) {
2586
0
            case 1:
2587
0
                xdev->state_rotated = 0;
2588
0
                px_put_ss(s, -90);
2589
0
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2590
0
                break;
2591
0
            case -1:
2592
0
                xdev->state_rotated = 0;
2593
0
                px_put_ss(s, +90);
2594
0
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2595
0
                break;
2596
2
            case 2:
2597
2
                xdev->state_rotated = 0;
2598
2
                px_put_ss(s, -180);
2599
2
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2600
2
                break;
2601
2.09k
            case 0:
2602
2.09k
            default:
2603
                /* do nothing */
2604
2.09k
                break;
2605
2.09k
        }
2606
2.09k
    }
2607
2.09k
    if (pie->icclink)
2608
399
        gsicc_release_link(pie->icclink);
2609
2.09k
    gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
2610
2.09k
    gx_image_free_enum(&info);
2611
2.09k
    return code;
2612
2.09k
}
2613
2614
/*
2615
 * 'pclxl_get_params()' - Get pagedevice parameters.
2616
 */
2617
2618
static int                      /* O - Error status */
2619
pclxl_get_params(gx_device * dev,       /* I - Device info */
2620
                 gs_param_list * plist)
2621
144k
{                               /* I - Parameter list */
2622
144k
    gx_device_pclxl *xdev;      /* PCL XL device */
2623
144k
    int code;                   /* Return code */
2624
144k
    gs_param_string s;          /* Temporary string value */
2625
2626
    /*
2627
     * First process the "standard" page device parameters...
2628
     */
2629
2630
144k
    if ((code = gdev_vector_get_params(dev, plist)) < 0)
2631
0
        return (code);
2632
2633
    /*
2634
     * Then write the PCL-XL parameters...
2635
     */
2636
2637
144k
    xdev = (gx_device_pclxl *) dev;
2638
2639
144k
    if ((code = param_write_bool(plist, "Duplex", &(xdev->Duplex))) < 0)
2640
0
        return (code);
2641
2642
144k
    if ((code = param_write_bool(plist, "ManualFeed",
2643
144k
         &(xdev->ManualFeed))) < 0)
2644
0
        return (code);
2645
2646
144k
    if ((code = param_write_int(plist, "MediaPosition",
2647
144k
        &(xdev->MediaPosition))) < 0)
2648
0
        return (code);
2649
2650
144k
    param_string_from_string(s, xdev->MediaType);
2651
2652
144k
    if ((code = param_write_string(plist, "MediaType", &s)) < 0)
2653
0
        return (code);
2654
2655
144k
    if ((code = param_write_bool(plist, "Staple", &(xdev->Staple))) < 0)
2656
0
        return (code);
2657
2658
144k
    if ((code = param_write_bool(plist, "Tumble", &(xdev->Tumble))) < 0)
2659
0
        return (code);
2660
2661
144k
    if ((code = param_write_int(plist, "CompressMode",
2662
144k
                                &(xdev->CompressMode))) < 0)
2663
0
        return (code);
2664
2665
144k
    if ((code =
2666
144k
         param_write_bool(plist, "iccTransform", &(xdev->iccTransform))) < 0)
2667
0
        return (code);
2668
2669
144k
    return (0);
2670
144k
}
2671
2672
/*
2673
 * 'pclxl_put_params()' - Set pagedevice parameters.
2674
 */
2675
2676
static int                      /* O - Error status */
2677
pclxl_put_params(gx_device * dev,       /* I - Device info */
2678
                 gs_param_list * plist)
2679
62.8k
{                               /* I - Parameter list */
2680
62.8k
    gx_device_pclxl *xdev;      /* PCL XL device */
2681
62.8k
    int code;                   /* Error code */
2682
62.8k
    int intval;                 /* Integer value */
2683
62.8k
    bool boolval;               /* Boolean value */
2684
62.8k
    gs_param_string stringval;  /* String value */
2685
62.8k
    bool ManualFeed;
2686
62.8k
    bool ManualFeed_set = false;
2687
62.8k
    int MediaPosition;
2688
62.8k
    bool MediaPosition_set = false;
2689
2690
    /*
2691
     * Process PCL-XL driver parameters...
2692
     */
2693
2694
62.8k
    xdev = (gx_device_pclxl *) dev;
2695
2696
62.8k
#define intoption(name, sname, type) \
2697
62.8k
  if ((code = param_read_int(plist, sname, &intval)) < 0) \
2698
62.8k
  { \
2699
0
    if_debug1('|', "Error setting %s\n", sname); \
2700
0
    param_signal_error(plist, sname, code); \
2701
0
    return (code); \
2702
0
  } \
2703
62.8k
  else if (code == 0) \
2704
62.8k
  { \
2705
4.62k
    if_debug2('|', "setting %s to %d\n", sname, intval); \
2706
4.62k
    xdev->name = (type)intval; \
2707
4.62k
  }
2708
2709
62.8k
#define booloption(name, sname) \
2710
251k
  if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
2711
251k
  { \
2712
0
    if_debug1('|', "Error setting bool %s\n", sname);    \
2713
0
    if ((code = param_read_null(plist, sname)) < 0) \
2714
0
    { \
2715
0
      if_debug1('|', "Error setting bool %s null\n", sname);     \
2716
0
      param_signal_error(plist, sname, code); \
2717
0
      return (code); \
2718
0
    } \
2719
0
    if (code == 0) \
2720
0
      xdev->name = false; \
2721
0
  } \
2722
251k
  else if (code == 0) {                                   \
2723
18.4k
    if_debug2('|', "setting %s to %d\n", sname, boolval); \
2724
18.4k
    xdev->name = (bool)boolval; \
2725
18.4k
  }
2726
2727
62.8k
#define stringoption(name, sname)                                \
2728
62.8k
  if ((code = param_read_string(plist, sname, &stringval)) < 0)  \
2729
62.8k
    {                                                            \
2730
0
      if_debug1('|', "Error setting %s string\n", sname);        \
2731
0
      if ((code = param_read_null(plist, sname)) < 0)            \
2732
0
        {                                                        \
2733
0
          if_debug1('|', "Error setting %s null\n", sname);      \
2734
0
          param_signal_error(plist, sname, code);                \
2735
0
          return (code);                                         \
2736
0
        }                                                        \
2737
0
      if (code == 0) {                                           \
2738
0
        if_debug1('|', "setting %s to empty\n", sname);          \
2739
0
        xdev->name[0] = '\0';                                    \
2740
0
      }                                                          \
2741
0
    }                                                            \
2742
62.8k
  else if (code == 0) {                                          \
2743
4.62k
    strncpy(xdev->name, (const char *)(stringval.data),          \
2744
4.62k
            stringval.size);                                     \
2745
4.62k
    xdev->name[stringval.size] = '\0';                           \
2746
4.62k
    if_debug2('|', "setting %s to %s\n", sname, xdev->name);     \
2747
4.62k
  }
2748
2749
    /* We need to have *_set to distinguish defaults from explicitly sets */
2750
62.8k
    booloption(Duplex, "Duplex");
2751
62.8k
    if (code == 0)
2752
4.62k
        if (xdev->Duplex) {
2753
0
            if_debug0('|', "round up page count\n");
2754
0
            xdev->page = (xdev->page + 1) & ~1;
2755
0
        }
2756
62.8k
    code = param_read_bool(plist, "ManualFeed", &ManualFeed);
2757
62.8k
    if (code == 0)
2758
4.62k
        ManualFeed_set = true;
2759
62.8k
    if (code >= 0) {
2760
62.8k
        code = param_read_int(plist, "MediaPosition", &MediaPosition);
2761
62.8k
        if (code == 0)
2762
17.6k
            MediaPosition_set = true;
2763
45.1k
        else if (code < 0) {
2764
0
            if (param_read_null(plist, "MediaPosition") == 0) {
2765
0
                code = 0;
2766
0
            }
2767
0
        }
2768
62.8k
    }
2769
62.8k
    stringoption(MediaType, "MediaType");
2770
62.8k
    if (code == 0) {
2771
4.62k
        xdev->MediaType_set = true;
2772
        /* round up for duplex */
2773
4.62k
        if (strcmp(xdev->MediaType_old, xdev->MediaType)) {
2774
0
            if_debug0('|', "round up page count\n");
2775
0
            xdev->page = (xdev->page + 1) & ~1;
2776
0
            strcpy(xdev->MediaType_old, xdev->MediaType);
2777
0
        }
2778
4.62k
    }
2779
62.8k
    booloption(Staple, "Staple");
2780
62.8k
    booloption(Tumble, "Tumble");
2781
62.8k
    intoption(CompressMode, "CompressMode", int);
2782
2783
62.8k
    booloption(iccTransform, "iccTransform");
2784
2785
    /*
2786
     * Then process standard page device parameters...
2787
     */
2788
2789
62.8k
    if (code >= 0)
2790
62.8k
        if ((code = gdev_vector_put_params(dev, plist)) < 0)
2791
77
            return (code);
2792
2793
62.7k
    if (code >= 0) {
2794
62.7k
        if (ManualFeed_set) {
2795
4.62k
            xdev->ManualFeed = ManualFeed;
2796
4.62k
            xdev->ManualFeed_set = true;
2797
4.62k
        }
2798
62.7k
        if (MediaPosition_set) {
2799
17.6k
            xdev->MediaPosition = MediaPosition;
2800
17.6k
            xdev->MediaPosition_set = true;
2801
17.6k
            if (xdev->MediaPosition_old != xdev->MediaPosition) {
2802
13.0k
                if_debug0('|', "round up page count\n");
2803
13.0k
                xdev->page = (xdev->page+1) & ~1 ;
2804
13.0k
                xdev->MediaPosition_old = xdev->MediaPosition;
2805
13.0k
            }
2806
17.6k
        }
2807
62.7k
    }
2808
2809
62.7k
    return (0);
2810
62.8k
}