Coverage Report

Created: 2026-07-24 07:44

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