Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpx.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
78.4M
#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
11.8k
#define MAX_CACHED_CHARS 400
98
11.7k
#define MAX_CHAR_DATA 500000
99
1.11M
#define MAX_CHAR_SIZE 5000
100
1.12M
#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
22.3k
{
158
22.3k
    set_dev_proc(dev, open_device, pclxl_open_device);
159
22.3k
    set_dev_proc(dev, output_page, pclxl_output_page);
160
22.3k
    set_dev_proc(dev, close_device, pclxl_close_device);
161
22.3k
    set_dev_proc(dev, map_rgb_color, map_rgb_color);
162
22.3k
    set_dev_proc(dev, map_color_rgb, map_color_rgb);
163
22.3k
    set_dev_proc(dev, fill_rectangle, gdev_vector_fill_rectangle);
164
22.3k
    set_dev_proc(dev, copy_mono, pclxl_copy_mono);
165
22.3k
    set_dev_proc(dev, copy_color, pclxl_copy_color);
166
22.3k
    set_dev_proc(dev, get_params, pclxl_get_params);
167
22.3k
    set_dev_proc(dev, put_params, pclxl_put_params);
168
22.3k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
169
22.3k
    set_dev_proc(dev, fill_path, gdev_vector_fill_path);
170
22.3k
    set_dev_proc(dev, stroke_path, gdev_vector_stroke_path);
171
22.3k
    set_dev_proc(dev, fill_mask, pclxl_fill_mask);
172
22.3k
    set_dev_proc(dev, fill_trapezoid, gdev_vector_fill_trapezoid);
173
22.3k
    set_dev_proc(dev, fill_parallelogram, gdev_vector_fill_parallelogram);
174
22.3k
    set_dev_proc(dev, fill_triangle, gdev_vector_fill_triangle);
175
22.3k
    set_dev_proc(dev, begin_typed_image, pclxl_begin_typed_image);
176
22.3k
    set_dev_proc(dev, strip_copy_rop2, pclxl_strip_copy_rop2);
177
22.3k
    set_dev_proc(dev, text_begin, pclxl_text_begin);
178
22.3k
}
179
180
static void
181
pxlmono_initialize_device_procs(gx_device *dev)
182
9.66k
{
183
9.66k
    pclxl_initialize_device_procs(dev,
184
9.66k
                                  gx_default_gray_map_rgb_color,
185
9.66k
                                  gx_default_gray_map_color_rgb);
186
9.66k
}
187
188
static void
189
pxlcolor_initialize_device_procs(gx_device *dev)
190
12.6k
{
191
12.6k
    pclxl_initialize_device_procs(dev,
192
12.6k
                                  gx_default_rgb_map_rgb_color,
193
12.6k
                                  gx_default_rgb_map_color_rgb);
194
12.6k
}
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
237M
{
209
237M
    return gdev_vector_stream((gx_device_vector *) xdev);
210
237M
}
211
212
/* Initialize for a page. */
213
static void
214
pclxl_page_init(gx_device_pclxl * xdev)
215
41.5k
{
216
41.5k
    gdev_vector_init((gx_device_vector *) xdev);
217
41.5k
    xdev->in_page = false;
218
41.5k
    xdev->fill_rule = gx_path_type_winding_number;
219
41.5k
    xdev->clip_rule = gx_path_type_winding_number;
220
41.5k
    xdev->color_space = eNoColorSpace;
221
41.5k
    xdev->palette.size = 0;
222
41.5k
    xdev->font_set = false;
223
41.5k
    xdev->state_rotated = 0;
224
41.5k
    xdev->scaled = false;
225
41.5k
    xdev->x_scale = 1;
226
41.5k
    xdev->y_scale = 1;
227
41.5k
    xdev->pen_null = false;
228
41.5k
    xdev->brush_null = false;
229
41.5k
}
230
231
/* Test whether a RGB color is actually a gray shade. */
232
22.1M
#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
30.7M
{
238
30.7M
    if (xdev->color_space != color_space) {
239
598k
        stream *s = pclxl_stream(xdev);
240
241
598k
        px_put_ub(s, (byte) color_space);
242
598k
        px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
243
598k
        xdev->color_space = color_space;
244
598k
        xdev->palette.size = 0; /* purge the cached palette */
245
598k
    }
246
30.7M
}
247
static void
248
pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
249
                        const byte * palette, uint palette_size)
250
172k
{
251
172k
    if (xdev->color_space != color_space ||
252
172k
        xdev->palette.size != palette_size ||
253
172k
        memcmp(xdev->palette.data, palette, palette_size)
254
172k
        ) {
255
1.94k
        stream *s = pclxl_stream(xdev);
256
257
1.94k
        static const byte csp_[] = {
258
1.94k
            DA(pxaColorSpace),
259
1.94k
            DUB(e8Bit), DA(pxaPaletteDepth),
260
1.94k
            pxt_ubyte_array
261
1.94k
        };
262
263
1.94k
        px_put_ub(s, (byte) color_space);
264
1.94k
        PX_PUT_LIT(s, csp_);
265
1.94k
        px_put_u(s, palette_size);
266
1.94k
        px_put_bytes(s, palette, palette_size);
267
1.94k
        px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
268
1.94k
        xdev->color_space = color_space;
269
1.94k
        xdev->palette.size = palette_size;
270
1.94k
        memcpy(xdev->palette.data, palette, palette_size);
271
1.94k
    }
272
172k
}
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
52.5M
{
284
52.5M
    stream *s = pclxl_stream(xdev);
285
286
52.5M
    if (op == pxtSetPenSource) {
287
52.1M
        if (xdev->pen_null)
288
52.0M
            return 0;
289
149k
        else
290
149k
            xdev->pen_null = true;
291
52.1M
    }
292
530k
    if (op == pxtSetBrushSource) {
293
380k
        if (xdev->brush_null)
294
248k
            return 0;
295
131k
        else
296
131k
            xdev->brush_null = true;
297
380k
    }
298
281k
    px_put_uba(s, 0, (byte) null_source);
299
281k
    spputc(s, (byte) op);
300
281k
    return 0;
301
530k
}
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
30.2M
{
308
30.2M
    stream *s = pclxl_stream(xdev);
309
310
30.2M
    if (gx_dc_is_pure(pdc)) {
311
30.2M
        gx_color_index color = gx_dc_pure_color(pdc);
312
313
30.2M
        if (op == pxtSetPenSource)
314
133k
            xdev->pen_null = false;
315
30.2M
        if (op == pxtSetBrushSource)
316
30.0M
            xdev->brush_null = false;
317
318
30.2M
        if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
319
14.8M
            pclxl_set_color_space(xdev, eGray);
320
14.8M
            px_put_uba(s, (byte) color, pxaGrayLevel);
321
15.3M
        } else {
322
15.3M
            pclxl_set_color_space(xdev, eRGB);
323
15.3M
            spputc(s, pxt_ubyte_array);
324
15.3M
            px_put_ub(s, 3);
325
15.3M
            spputc(s, (byte) (color >> 16));
326
15.3M
            spputc(s, (byte) (color >> 8));
327
15.3M
            spputc(s, (byte) color);
328
15.3M
            px_put_a(s, pxaRGBColor);
329
15.3M
        }
330
30.2M
    } 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
16.2k
        return_error(gs_error_rangecheck);
337
30.2M
    spputc(s, (byte) op);
338
30.2M
    return 0;
339
30.2M
}
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
12.4k
{
346
12.4k
    gs_color_space_index index;
347
348
    /* an image with no colorspace info arrived; cannot handle */
349
12.4k
    if (!pcs)
350
0
        return false;
351
12.4k
    index = gs_color_space_get_index(pcs);
352
353
12.4k
    if (index == gs_color_space_index_Indexed) {
354
544
        if (pcs->params.indexed.use_proc)
355
0
            return false;
356
544
        index =
357
544
            gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
358
11.9k
    } else if (index == gs_color_space_index_ICC) {
359
11.9k
        index = gsicc_get_default_type(pcs->cmm_icc_profile_data);
360
11.9k
        return ((index < gs_color_space_index_DevicePixel) ? true : false);
361
11.9k
    }
362
363
575
    return !(index == gs_color_space_index_Separation ||
364
575
             index == gs_color_space_index_Pattern ||
365
575
             index == gs_color_space_index_DeviceN ||
366
575
             index == gs_color_space_index_ICC ||
367
575
             (index <= gs_color_space_index_CIEA &&
368
0
             index >= gs_color_space_index_CIEDEFG)
369
575
             );
370
12.4k
}
371
372
/* Test whether we can icclink-transform an image. */
373
static bool
374
pclxl_can_icctransform(const gs_image_t * pim)
375
1.83k
{
376
1.83k
    const gs_color_space *pcs = pim->ColorSpace;
377
1.83k
    int bits_per_pixel;
378
379
    /* an image with no colorspace info arrived; cannot transform */
380
1.83k
    if (!pcs)
381
0
        return false;
382
1.83k
    bits_per_pixel =
383
1.83k
        (pim->ImageMask ? 1 :
384
1.83k
         pim->BitsPerComponent * gs_color_space_num_components(pcs));
385
386
1.83k
    if ((gs_color_space_get_index(pcs) == gs_color_space_index_ICC)
387
1.83k
        && (bits_per_pixel == 24 || bits_per_pixel == 32))
388
540
        return true;
389
390
1.29k
    return false;
391
1.83k
}
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
245k
{
402
245k
    gx_transfer_map *red = pgs->set_transfer.red;
403
245k
    gx_transfer_map *green = pgs->set_transfer.green;
404
245k
    gx_transfer_map *blue = pgs->set_transfer.blue;
405
406
245k
    return (red || green || blue);
407
408
245k
}
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
52.5M
{
413
52.5M
    stream *s = pclxl_stream(xdev);
414
52.5M
    gx_path_type_t rule = type & gx_path_type_rule;
415
416
52.5M
    if (!(type & gx_path_type_fill) &&
417
52.5M
        (color_is_set(&xdev->saved_fill_color.saved_dev_color) ||
418
379k
         !gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color)
419
379k
        )
420
52.5M
        ) {
421
379k
        pclxl_set_cached_nulls(xdev, pxaNullBrush, pxtSetBrushSource);
422
379k
        color_set_null(&xdev->saved_fill_color.saved_dev_color);
423
379k
        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
379k
    }
430
52.5M
    if (!(type & gx_path_type_stroke) &&
431
52.5M
        (color_is_set(&xdev->saved_stroke_color.saved_dev_color) ||
432
52.1M
         !gx_dc_is_null(&xdev->saved_stroke_color.saved_dev_color)
433
52.1M
        )
434
52.5M
        ) {
435
52.1M
        pclxl_set_cached_nulls(xdev, pxaNullPen, pxtSetPenSource);
436
52.1M
        color_set_null(&xdev->saved_stroke_color.saved_dev_color);
437
52.1M
    }
438
52.5M
}
439
440
static void
441
pclxl_set_page_origin(stream * s, int x, int y)
442
179k
{
443
179k
    px_put_ssp(s, x, y);
444
179k
    px_put_ac(s, pxaPageOrigin, pxtSetPageOrigin);
445
179k
    return;
446
179k
}
447
448
static void
449
pclxl_set_page_scale(gx_device_pclxl * xdev, double x_scale, double y_scale)
450
18.8M
{
451
18.8M
    stream *s = pclxl_stream(xdev);
452
453
18.8M
    if (xdev->scaled) {
454
9.92M
        xdev->x_scale = x_scale;
455
9.92M
        xdev->y_scale = y_scale;
456
9.92M
        px_put_rp(s, x_scale, y_scale);
457
9.92M
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
458
9.92M
    }
459
18.8M
    return;
460
18.8M
}
461
462
static void
463
pclxl_unset_page_scale(gx_device_pclxl * xdev)
464
40.3M
{
465
40.3M
    stream *s = pclxl_stream(xdev);
466
467
40.3M
    if (xdev->scaled) {
468
9.92M
        px_put_rp(s, 1 / xdev->x_scale, 1 / xdev->y_scale);
469
9.92M
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
470
9.92M
        xdev->scaled = false;
471
9.92M
        xdev->x_scale = 1;
472
9.92M
        xdev->y_scale = 1;
473
9.92M
    }
474
40.3M
    return;
475
40.3M
}
476
477
/* Set the cursor. */
478
static int
479
pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
480
13.8M
{
481
13.8M
    stream *s = pclxl_stream(xdev);
482
13.8M
    double x_scale = 1;
483
13.8M
    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
13.8M
    if (abs(x) > 0x7FFF) {
490
2.78M
        x_scale = ((double)abs(x)) / 0x7FFF;
491
2.78M
        x = (x > 0 ? 0x7FFF : -0x7FFF);
492
2.78M
        xdev->scaled = true;
493
2.78M
    }
494
13.8M
    if (abs(y) > 0x7FFF) {
495
2.49M
        y_scale = ((double)abs(y)) / 0x7FFF;
496
2.49M
        y = (y > 0 ? 0x7FFF : -0x7FFF);
497
2.49M
        xdev->scaled = true;
498
2.49M
    }
499
13.8M
    pclxl_set_page_scale(xdev, x_scale, y_scale);
500
13.8M
    px_put_ssp(s, x, y);
501
13.8M
    px_put_ac(s, pxaPoint, pxtSetCursor);
502
13.8M
    pclxl_unset_page_scale(xdev);
503
13.8M
    return 0;
504
13.8M
}
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
19.1M
{
512
19.1M
    px_put_uba(s, (byte) count, pxaNumberOfPoints);
513
19.1M
    px_put_uba(s, (byte) dtype, pxaPointType);
514
19.1M
}
515
static int
516
pclxl_flush_points(gx_device_pclxl * xdev)
517
44.6M
{
518
44.6M
    int count = xdev->points.count;
519
520
44.6M
    if (count) {
521
26.4M
        stream *s = pclxl_stream(xdev);
522
26.4M
        px_tag_t op;
523
26.4M
        int x = xdev->points.current.x, y = xdev->points.current.y;
524
26.4M
        int uor = 0, sor = 0;
525
26.4M
        pxeDataType_t data_type;
526
26.4M
        int i, di;
527
26.4M
        byte diffs[NUM_POINTS * 2];
528
26.4M
        double x_scale = 1;
529
26.4M
        double y_scale = 1;
530
26.4M
        int temp_origin_x = 0, temp_origin_y = 0;
531
26.4M
        int count_smalls = 0;
532
533
26.4M
        if (xdev->points.type != POINTS_NONE) {
534
171M
            for (i = 0; i < count; ++i) {
535
144M
                if ((abs(xdev->points.data[i].x) > 0x7FFF)
536
144M
                    || (abs(xdev->points.data[i].y) > 0x7FFF))
537
18.5M
                    xdev->scaled = true;
538
144M
                if ((abs(xdev->points.data[i].x) < 0x8000)
539
144M
                    && (abs(xdev->points.data[i].y) < 0x8000)) {
540
126M
                    if ((temp_origin_x != xdev->points.data[i].x)
541
126M
                        || (temp_origin_y != xdev->points.data[i].y)) {
542
109M
                        temp_origin_x = xdev->points.data[i].x;
543
109M
                        temp_origin_y = xdev->points.data[i].y;
544
109M
                        count_smalls++;
545
109M
                    }
546
126M
                }
547
144M
            }
548
26.4M
            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
5.08M
                if (count_smalls) {
555
89.5k
                    pclxl_set_page_origin(s, temp_origin_x, temp_origin_y);
556
89.5k
                }
557
24.4M
                for (i = 0; i < count; ++i) {
558
19.4M
                    x_scale = max(((double)
559
19.4M
                                   abs(xdev->points.data[i].x -
560
19.4M
                                       temp_origin_x)) / 0x7FFF, x_scale);
561
19.4M
                    y_scale = max(((double)
562
19.4M
                                   abs(xdev->points.data[i].y -
563
19.4M
                                       temp_origin_y)) / 0x7FFF, y_scale);
564
19.4M
                }
565
24.4M
                for (i = 0; i < count; ++i) {
566
19.4M
                    xdev->points.data[i].x =
567
19.4M
                        (int)((xdev->points.data[i].x -
568
19.4M
                               temp_origin_x) / x_scale + 0.5);
569
19.4M
                    xdev->points.data[i].y =
570
19.4M
                        (int)((xdev->points.data[i].y -
571
19.4M
                               temp_origin_y) / y_scale + 0.5);
572
19.4M
                }
573
5.08M
                x = (int)((x - temp_origin_x) / x_scale + 0.5);
574
5.08M
                y = (int)((y - temp_origin_y) / y_scale + 0.5);
575
5.08M
                pclxl_set_page_scale(xdev, x_scale, y_scale);
576
21.4M
            } else {
577
                /* don't reset origin if we did not scale */
578
21.4M
                count_smalls = 0;
579
21.4M
            }
580
26.4M
        }
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
26.4M
        switch (xdev->points.type) {
593
0
            case POINTS_NONE:
594
0
                return 0;
595
17.3M
            case POINTS_LINES:
596
17.3M
                op = pxtLinePath;
597
17.3M
                if (count < 3) {
598
16.8M
                    for (i = 0; i < count; ++i) {
599
9.46M
                        px_put_ssp(s, xdev->points.data[i].x,
600
9.46M
                                   xdev->points.data[i].y);
601
9.46M
                        px_put_a(s, pxaEndPoint);
602
9.46M
                        spputc(s, (byte) op);
603
9.46M
                    }
604
7.35M
                    pclxl_unset_page_scale(xdev);
605
7.35M
                    if (count_smalls)
606
17.2k
                        pclxl_set_page_origin(s, -temp_origin_x,
607
17.2k
                                              -temp_origin_y);
608
7.35M
                    goto zap;
609
7.35M
                }
610
                /* See if we can use byte values. */
611
45.3M
                for (i = di = 0; i < count; ++i, di += 2) {
612
35.3M
                    int dx = xdev->points.data[i].x - x;
613
35.3M
                    int dy = xdev->points.data[i].y - y;
614
615
35.3M
                    diffs[di] = (byte) dx;
616
35.3M
                    diffs[di + 1] = (byte) dy;
617
35.3M
                    uor |= dx | dy;
618
35.3M
                    sor |= (dx + 0x80) | (dy + 0x80);
619
35.3M
                    x += dx, y += dy;
620
35.3M
                }
621
9.99M
                if (!(uor & ~0xff))
622
2.54M
                    data_type = eUByte;
623
7.45M
                else if (!(sor & ~0xff))
624
6.04M
                    data_type = eSByte;
625
1.40M
                else
626
1.40M
                    break;
627
8.59M
                op = pxtLineRelPath;
628
                /* Use byte values. */
629
17.4M
              useb:px_put_np(s, count, data_type);
630
17.4M
                spputc(s, (byte) op);
631
17.4M
                px_put_data_length(s, count * 2);       /* 2 bytes per point */
632
17.4M
                px_put_bytes(s, diffs, count * 2);
633
17.4M
                pclxl_unset_page_scale(xdev);
634
17.4M
                if (count_smalls)
635
26
                    pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
636
17.4M
                goto zap;
637
9.14M
            case POINTS_CURVES:
638
9.14M
                op = pxtBezierPath;
639
                /* See if we can use byte values. */
640
42.4M
                for (i = di = 0; i < count; i += 3, di += 6) {
641
33.3M
                    int dx1 = xdev->points.data[i].x - x;
642
33.3M
                    int dy1 = xdev->points.data[i].y - y;
643
33.3M
                    int dx2 = xdev->points.data[i + 1].x - x;
644
33.3M
                    int dy2 = xdev->points.data[i + 1].y - y;
645
33.3M
                    int dx = xdev->points.data[i + 2].x - x;
646
33.3M
                    int dy = xdev->points.data[i + 2].y - y;
647
648
33.3M
                    diffs[di] = (byte) dx1;
649
33.3M
                    diffs[di + 1] = (byte) dy1;
650
33.3M
                    diffs[di + 2] = (byte) dx2;
651
33.3M
                    diffs[di + 3] = (byte) dy2;
652
33.3M
                    diffs[di + 4] = (byte) dx;
653
33.3M
                    diffs[di + 5] = (byte) dy;
654
33.3M
                    uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
655
33.3M
                    sor |= (dx1 + 0x80) | (dy1 + 0x80) |
656
33.3M
                        (dx2 + 0x80) | (dy2 + 0x80) |
657
33.3M
                        (dx + 0x80) | (dy + 0x80);
658
33.3M
                    x += dx, y += dy;
659
33.3M
                }
660
9.14M
                if (!(uor & ~0xff))
661
764k
                    data_type = eUByte;
662
8.37M
                else if (!(sor & ~0xff))
663
8.12M
                    data_type = eSByte;
664
248k
                else
665
248k
                    break;
666
8.89M
                op = pxtBezierRelPath;
667
8.89M
                goto useb;
668
0
            default:           /* can't happen */
669
0
                return_error(gs_error_unknownerror);
670
26.4M
        }
671
1.65M
        px_put_np(s, count, eSInt16);
672
1.65M
        spputc(s, (byte) op);
673
1.65M
        px_put_data_length(s, count * 4);       /* 2 UInt16s per point */
674
11.0M
        for (i = 0; i < count; ++i) {
675
9.37M
            px_put_s(s, xdev->points.data[i].x);
676
9.37M
            px_put_s(s, xdev->points.data[i].y);
677
9.37M
        }
678
1.65M
        pclxl_unset_page_scale(xdev);
679
1.65M
        if (count_smalls)
680
72.1k
            pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
681
26.4M
      zap:xdev->points.type = POINTS_NONE;
682
26.4M
        xdev->points.count = 0;
683
26.4M
    }
684
44.6M
    return 0;
685
44.6M
}
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
154k
{
701
154k
    stream *s = pclxl_stream(xdev);
702
703
154k
    px_put_usa(s, width, pxaSourceWidth);
704
154k
    px_put_usa(s, height, pxaSourceHeight);
705
154k
    px_put_usp(s, dest_width, dest_height);
706
154k
    px_put_ac(s, pxaDestinationSize, pxtBeginImage);
707
154k
}
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
154k
{
718
154k
    stream *s = pclxl_stream(xdev);
719
154k
    uint width_bytes = (width_bits + 7) >> 3;
720
154k
    uint num_bytes = ROUND_UP(width_bytes, 4) * height;
721
154k
    bool compress = num_bytes >= 8;
722
154k
    int i;
723
154k
    int code;
724
725
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
726
154k
    int offset = data_bit >> 3;
727
154k
    const byte *data = base + offset;
728
729
154k
    px_put_usa(s, y, pxaStartLine);
730
154k
    px_put_usa(s, height, pxaBlockHeight);
731
154k
    if (compress) {
732
154k
        stream_RLE_state rlstate;
733
154k
        stream_cursor_write w;
734
154k
        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
154k
        byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
744
154k
                                   "pclxl_write_image_data");
745
746
154k
        if (buf == 0)
747
0
            goto nc;
748
154k
        s_RLE_set_defaults_inline(&rlstate);
749
154k
        rlstate.EndOfData = false;
750
154k
        rlstate.omitEOD = true;
751
154k
        s_RLE_init_inline(&rlstate);
752
154k
        w.ptr = buf - 1;
753
154k
        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
19.3M
        for (i = 0; i < height; ++i) {
760
19.2M
            r.ptr = data + i * raster - 1;
761
19.2M
            r.limit = r.ptr + width_bytes;
762
19.2M
            if ((*s_RLE_template.process)
763
19.2M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
764
19.2M
                r.ptr != r.limit)
765
15.2k
                goto ncfree;
766
19.1M
            r.ptr = (const byte *)"\000\000\000\000\000";
767
19.1M
            r.limit = r.ptr + (-(int)width_bytes & 3);
768
19.1M
            if ((*s_RLE_template.process)
769
19.1M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
770
19.1M
                r.ptr != r.limit)
771
57
                goto ncfree;
772
19.1M
        }
773
139k
        r.ptr = r.limit;
774
139k
        code = (*s_RLE_template.process)
775
139k
            ((stream_state *) & rlstate, &r, &w, true);
776
139k
        if (code != EOFC && code != 0)
777
44.6k
            goto ncfree;
778
94.5k
        {
779
94.5k
            uint count = w.ptr + 1 - buf;
780
781
94.5k
            px_put_ub(s, eRLECompression);
782
94.5k
            px_put_ac(s, pxaCompressMode, pxtReadImage);
783
94.5k
            px_put_data_length(s, count);
784
94.5k
            px_put_bytes(s, buf, count);
785
94.5k
        }
786
94.5k
        gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
787
94.5k
        return;
788
59.9k
      ncfree:gs_free_object(xdev->v_memory, buf,
789
59.9k
                       "pclxl_write_image_data");
790
59.9k
    }
791
59.9k
  nc:
792
    /* Write the data uncompressed. */
793
59.9k
    px_put_ub(s, eNoCompression);
794
59.9k
    px_put_ac(s, pxaCompressMode, pxtReadImage);
795
59.9k
    px_put_data_length(s, num_bytes);
796
11.7M
    for (i = 0; i < height; ++i) {
797
11.7M
        px_put_bytes(s, data + i * raster, width_bytes);
798
11.7M
        px_put_bytes(s, (const byte *)"\000\000\000\000",
799
11.7M
                     -(int)width_bytes & 3);
800
11.7M
    }
801
59.9k
}
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
    int 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) * 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
154k
{
990
    /* If we only have 1 line, it does not make sense to do JPEG/DeltaRow */
991
154k
    if (height < 2) {
992
100
        pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
993
100
                                   y, height);
994
100
        return;
995
100
    }
996
997
154k
    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
154k
        default:
1013
154k
            pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
1014
154k
                                       width_bits, y, height);
1015
154k
            break;
1016
154k
    }
1017
154k
}
1018
1019
/* End an image. */
1020
static void
1021
pclxl_write_end_image(gx_device_pclxl * xdev)
1022
154k
{
1023
154k
    spputc(xdev->strm, pxtEndImage);
1024
154k
}
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
1.12M
{
1032
1.12M
    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
1.12M
    } else {
1037
1.12M
        spputc(s, pxt_ubyte_array);
1038
1.12M
        px_put_u(s, len);
1039
1.12M
        px_put_bytes(s, data, len);
1040
1.12M
    }
1041
1.12M
}
1042
1043
/* Write a 16-bit big-endian value. */
1044
static void
1045
px_put_us_be(stream * s, uint i)
1046
11.9k
{
1047
11.9k
    spputc(s, (byte) (i >> 8));
1048
11.9k
    spputc(s, (byte) i);
1049
11.9k
}
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
85
{
1056
85
    stream *s = pclxl_stream(xdev);
1057
1058
85
    static const byte bfh_[] = {
1059
85
        DA(pxaFontName), DUB(0), DA(pxaFontFormat),
1060
85
        pxtBeginFontHeader,
1061
85
        DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
1062
85
        pxtReadFontHeader,
1063
85
        pxt_dataLengthByte, 8 + 6 + 4 + 6,
1064
85
        0, 0, 0, 0,
1065
85
        254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
1066
85
        'B', 'R', 0, 0, 0, 4
1067
85
    };
1068
85
    static const byte efh_[] = {
1069
85
        0xff, 0xff, 0, 0, 0, 0,
1070
85
        pxtEndFontHeader
1071
85
    };
1072
1073
85
    PX_PUT_LIT(s, bfh_);
1074
85
    px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
1075
85
    px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
1076
85
    PX_PUT_LIT(s, efh_);
1077
85
}
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
339
{
1084
339
    stream *s = pclxl_stream(xdev);
1085
1086
339
    static const byte sf_[] = {
1087
339
        DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
1088
339
        pxtSetFont
1089
339
    };
1090
1091
339
    PX_PUT_LIT(s, sf_);
1092
339
}
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
5.86k
{
1101
5.86k
    stream *s = pclxl_stream(xdev);
1102
5.86k
    uint width_bytes = (width_bits + 7) >> 3;
1103
5.86k
    uint size = 10 + width_bytes * height;
1104
5.86k
    uint i;
1105
1106
5.86k
    px_put_ac(s, pxaFontName, pxtBeginChar);
1107
5.86k
    px_put_u(s, ccode);
1108
5.86k
    px_put_a(s, pxaCharCode);
1109
5.86k
    if (size > 0xffff) {
1110
0
        spputc(s, pxt_uint32);
1111
0
        px_put_l(s, (ulong) size);
1112
0
    } else
1113
5.86k
        px_put_us(s, size);
1114
5.86k
    px_put_ac(s, pxaCharDataSize, pxtReadChar);
1115
5.86k
    px_put_data_length(s, size);
1116
5.86k
    px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
1117
5.86k
    px_put_us_be(s, width_bits);
1118
5.86k
    px_put_us_be(s, height);
1119
98.8k
    for (i = 0; i < height; ++i)
1120
93.0k
        px_put_bytes(s, data + i * raster, width_bytes);
1121
5.86k
    spputc(s, pxtEndChar);
1122
5.86k
}
1123
1124
/* Write the name of the only font we define. */
1125
static void
1126
pclxl_write_font_name(gx_device_pclxl * xdev)
1127
6.29k
{
1128
6.29k
    stream *s = pclxl_stream(xdev);
1129
1130
6.29k
    px_put_string(s, (const byte *)"@", 1, false);
1131
6.29k
}
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
1.12M
{
1138
1.12M
    int i, i_empty = -1;
1139
1.12M
    uint ccode;
1140
1141
1.12M
    for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
1142
1.14M
         i = (i == 0 ? countof(xdev->chars.table) : i) - 1) {
1143
1.14M
        ccode = xdev->chars.table[i];
1144
1.14M
        if (ccode == 0)
1145
11.7k
            return (i_empty >= 0 ? i_empty : i);
1146
1.13M
        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
1.13M
        } else if (xdev->chars.data[ccode].id == id)
1152
1.10M
            return i;
1153
1.14M
    }
1154
1.12M
}
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
1.11M
{
1186
1.11M
    uint width_bytes = (w + 7) >> 3;
1187
1.11M
    uint size = width_bytes * h;
1188
1.11M
    int index;
1189
1.11M
    uint ccode;
1190
1.11M
    stream *s = pclxl_stream(xdev);
1191
1192
1.11M
    if (size > MAX_CHAR_SIZE)
1193
0
        return -1;
1194
1.11M
    index = pclxl_char_index(xdev, id);
1195
1.11M
    if ((ccode = xdev->chars.table[index]) < 2) {
1196
        /* Enter the character in the table. */
1197
5.86k
        while (xdev->chars.used + size > MAX_CHAR_DATA ||
1198
5.86k
               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
5.86k
        index = pclxl_char_index(xdev, id);
1206
5.86k
        ccode = xdev->chars.next_in;
1207
5.86k
        xdev->chars.data[ccode].id = id;
1208
5.86k
        xdev->chars.data[ccode].size = size;
1209
5.86k
        xdev->chars.table[index] = ccode;
1210
5.86k
        xdev->chars.next_in = (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1211
5.86k
        if (!xdev->chars.count++) {
1212
            /* This is the very first character. */
1213
85
            pclxl_write_font_name(xdev);
1214
85
            pclxl_define_bitmap_font(xdev);
1215
85
        }
1216
5.86k
        xdev->chars.used += size;
1217
5.86k
        pclxl_write_font_name(xdev);
1218
5.86k
        pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
1219
5.86k
    }
1220
1.11M
    if (!xdev->font_set) {
1221
339
        pclxl_write_font_name(xdev);
1222
339
        pclxl_set_font(xdev);
1223
339
        xdev->font_set = true;
1224
339
    }
1225
1.11M
    {
1226
1.11M
        byte cc_bytes[2];
1227
1228
1.11M
        cc_bytes[0] = (byte) ccode;
1229
1.11M
        cc_bytes[1] = ccode >> 8;
1230
1.11M
        px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
1231
1.11M
    }
1232
1.11M
    px_put_ac(s, pxaTextData, pxtText);
1233
1.11M
    return 0;
1234
1.11M
}
1235
1236
/* ---------------- Vector implementation procedures ---------------- */
1237
1238
static int
1239
pclxl_beginpage(gx_device_vector * vdev)
1240
20.3k
{
1241
20.3k
    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
20.3k
    stream *s = vdev->strm;
1248
20.3k
    byte media_source = eAutoSelect;    /* default */
1249
1250
20.3k
    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
20.3k
    px_write_page_header(s, (const gx_device *)vdev);
1259
1260
20.3k
    if (xdev->ManualFeed_set && xdev->ManualFeed)
1261
0
        media_source = 2;
1262
20.3k
    else if (xdev->MediaPosition_set && xdev->MediaPosition >= 0)
1263
20.3k
        media_source = xdev->MediaPosition;
1264
1265
20.3k
    px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size,
1266
20.3k
                          &media_source,
1267
20.3k
                          xdev->page, xdev->Duplex, xdev->Tumble,
1268
20.3k
                          xdev->MediaType_set, xdev->MediaType);
1269
1270
20.3k
    spputc(s, pxtBeginPage);
1271
20.3k
    return 0;
1272
20.3k
}
1273
1274
static int
1275
pclxl_setlinewidth(gx_device_vector * vdev, double width)
1276
15.2k
{
1277
15.2k
    stream *s = gdev_vector_stream(vdev);
1278
1279
15.2k
    px_put_us(s, (uint) (width + 0.5));
1280
15.2k
    px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
1281
15.2k
    return 0;
1282
15.2k
}
1283
1284
static int
1285
pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
1286
8.29k
{
1287
8.29k
    stream *s = gdev_vector_stream(vdev);
1288
1289
    /* The PCL XL cap styles just happen to be identical to PostScript. */
1290
8.29k
    px_put_ub(s, (byte) cap);
1291
8.29k
    px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
1292
8.29k
    return 0;
1293
8.29k
}
1294
1295
static int
1296
pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
1297
16.7k
{
1298
16.7k
    stream *s = gdev_vector_stream(vdev);
1299
1300
16.7k
    if (((int)join < 0) || ((int)join > 3)) {
1301
5
        emprintf1(vdev->memory,
1302
5
                  "Igoring invalid linejoin enumerator %d\n", join);
1303
5
        return 0;
1304
5
    }
1305
    /* The PCL XL join styles just happen to be identical to PostScript. */
1306
16.7k
    px_put_ub(s, (byte) join);
1307
16.7k
    px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
1308
16.7k
    return 0;
1309
16.7k
}
1310
1311
static int
1312
pclxl_setmiterlimit(gx_device_vector * vdev, double limit)
1313
343
{
1314
343
    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
343
    int i_limit = (int)(limit + 0.5);
1321
1322
343
    px_put_u(s, max(i_limit, 1));
1323
343
    px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
1324
343
    return 0;
1325
343
}
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
844
#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
1.46k
{
1339
1.46k
    stream *s = gdev_vector_stream(vdev);
1340
1341
1.46k
    if (count == 0) {
1342
622
        static const byte nac_[] = {
1343
622
            DUB(0), DA(pxaSolidLine)
1344
622
        };
1345
1346
622
        PX_PUT_LIT(s, nac_);
1347
844
    } else if (count > MAX_DASH_ELEMENTS)
1348
0
        return_error(gs_error_limitcheck);
1349
844
    else {
1350
844
        uint i;
1351
844
        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
2.39k
        for (i = 0; i < count; ++i)
1359
1.55k
            pattern_length += (uint) (pattern[i]);
1360
844
        if (pattern_length == 0)
1361
0
            return_error(gs_error_rangecheck);
1362
1363
844
        spputc(s, pxt_uint16_array);
1364
844
        px_put_ub(s, (byte) count);
1365
2.39k
        for (i = 0; i < count; ++i)
1366
1.55k
            px_put_s(s, (uint) pattern[i]);
1367
844
        px_put_a(s, pxaLineDashStyle);
1368
844
        if (offset != 0)
1369
0
            px_put_usa(s, (uint) offset, pxaDashOffset);
1370
844
    }
1371
1.46k
    spputc(s, pxtSetLineDash);
1372
1.46k
    return 0;
1373
1.46k
}
1374
1375
static int
1376
pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
1377
               gs_logical_operation_t diff)
1378
471k
{
1379
471k
    stream *s = gdev_vector_stream(vdev);
1380
1381
471k
    if (diff & lop_S_transparent) {
1382
6.26k
        px_put_ub(s, (byte) (lop & lop_S_transparent ? 1 : 0));
1383
6.26k
        px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
1384
6.26k
    }
1385
471k
    if (diff & lop_T_transparent) {
1386
420
        px_put_ub(s, (byte) (lop & lop_T_transparent ? 1 : 0));
1387
420
        px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
1388
420
    }
1389
471k
    if (lop_rop(diff)) {
1390
465k
        px_put_ub(s, (byte) lop_rop(lop));
1391
465k
        px_put_ac(s, pxaROP3, pxtSetROP);
1392
465k
    }
1393
471k
    return 0;
1394
471k
}
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
54.0M
{
1400
54.0M
    return false;
1401
54.0M
}
1402
1403
static int
1404
pclxl_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs,
1405
                   const gx_drawing_color * pdc)
1406
30.1M
{
1407
30.1M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1408
1409
30.1M
    return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
1410
30.1M
}
1411
1412
static int
1413
pclxl_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs,
1414
                     const gx_drawing_color * pdc)
1415
133k
{
1416
133k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1417
1418
133k
    return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
1419
133k
}
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
41.5M
{
1425
41.5M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1426
41.5M
    stream *s = gdev_vector_stream(vdev);
1427
1428
    /* Check for out-of-range points. */
1429
290M
#define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
1430
41.5M
    if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
1431
41.5M
        OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
1432
41.5M
        )
1433
109k
        return_error(gs_error_rangecheck);
1434
41.4M
#undef OUT_OF_RANGE
1435
41.4M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1436
41.3M
        pclxl_set_paints(xdev, type);
1437
41.3M
        px_put_usq_fixed(s, x0, y0, x1, y1);
1438
41.3M
        px_put_ac(s, pxaBoundingBox, pxtRectangle);
1439
41.3M
    }
1440
41.4M
    if (type & gx_path_type_clip) {
1441
40.9k
        static const byte cr_[] = {
1442
40.9k
            DA(pxaBoundingBox),
1443
40.9k
            DUB(eInterior), DA(pxaClipRegion),
1444
40.9k
            pxtSetClipRectangle
1445
40.9k
        };
1446
1447
40.9k
        px_put_usq_fixed(s, x0, y0, x1, y1);
1448
40.9k
        PX_PUT_LIT(s, cr_);
1449
40.9k
    }
1450
41.4M
    return 0;
1451
41.5M
}
1452
1453
static int
1454
pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
1455
11.7M
{
1456
11.7M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1457
11.7M
    stream *s = gdev_vector_stream(vdev);
1458
1459
11.7M
    spputc(s, pxtNewPath);
1460
11.7M
    xdev->points.type = POINTS_NONE;
1461
11.7M
    xdev->points.count = 0;
1462
11.7M
    return 0;
1463
11.7M
}
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
12.5M
{
1469
12.5M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1470
12.5M
    int code = pclxl_flush_points(xdev);
1471
1472
12.5M
    if (code < 0)
1473
0
        return code;
1474
12.5M
    return pclxl_set_cursor(xdev,
1475
12.5M
                            xdev->points.current.x = (int)(x + 0.5),
1476
12.5M
                            xdev->points.current.y = (int)(y + 0.5));
1477
12.5M
}
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
44.8M
{
1483
44.8M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1484
1485
44.8M
    if (xdev->points.type != POINTS_LINES || xdev->points.count >= NUM_POINTS - 2) {
1486
17.3M
        if (xdev->points.type != POINTS_NONE) {
1487
7.46M
            int code = pclxl_flush_points(xdev);
1488
1489
7.46M
            if (code < 0)
1490
0
                return code;
1491
7.46M
        }
1492
17.3M
        xdev->points.current.x = (int)(x0 + 0.5);
1493
17.3M
        xdev->points.current.y = (int)(y0 + 0.5);
1494
17.3M
        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
17.3M
        if (xdev->points.count >= NUM_POINTS - 1)
1500
0
            xdev->points.count--;
1501
17.3M
    }
1502
44.8M
    {
1503
44.8M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
1504
1505
44.8M
        ppt->x = (int)(x + 0.5), ppt->y = (int)(y + 0.5);
1506
44.8M
    }
1507
44.8M
    return 0;
1508
44.8M
}
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
33.3M
{
1515
33.3M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1516
1517
33.3M
    if (xdev->points.type != POINTS_CURVES ||
1518
33.3M
        xdev->points.count >= NUM_POINTS - 4) {
1519
9.14M
        if (xdev->points.type != POINTS_NONE) {
1520
6.51M
            int code = pclxl_flush_points(xdev);
1521
1522
6.51M
            if (code < 0)
1523
0
                return code;
1524
6.51M
        }
1525
9.14M
        xdev->points.current.x = (int)(x0 + 0.5);
1526
9.14M
        xdev->points.current.y = (int)(y0 + 0.5);
1527
9.14M
        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
9.14M
        if (xdev->points.count >= NUM_POINTS - 3)
1533
0
            xdev->points.count -= 3;
1534
9.14M
    }
1535
33.3M
    {
1536
33.3M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count];
1537
1538
33.3M
        ppt->x = (int)(x1 + 0.5), ppt->y = (int)(y1 + 0.5), ++ppt;
1539
33.3M
        ppt->x = (int)(x2 + 0.5), ppt->y = (int)(y2 + 0.5), ++ppt;
1540
33.3M
        ppt->x = (int)(x3 + 0.5), ppt->y = (int)(y3 + 0.5);
1541
33.3M
    }
1542
33.3M
    xdev->points.count += 3;
1543
33.3M
    return 0;
1544
33.3M
}
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
6.32M
{
1550
6.32M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1551
6.32M
    stream *s = gdev_vector_stream(vdev);
1552
6.32M
    int code = pclxl_flush_points(xdev);
1553
1554
6.32M
    if (code < 0)
1555
0
        return code;
1556
6.32M
    spputc(s, pxtCloseSubPath);
1557
6.32M
    xdev->points.current.x = (int)(x_start + 0.5);
1558
6.32M
    xdev->points.current.y = (int)(y_start + 0.5);
1559
6.32M
    return 0;
1560
6.32M
}
1561
1562
static int
1563
pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
1564
11.7M
{
1565
11.7M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1566
11.7M
    stream *s = gdev_vector_stream(vdev);
1567
11.7M
    int code = pclxl_flush_points(xdev);
1568
11.7M
    gx_path_type_t rule = type & gx_path_type_rule;
1569
1570
11.7M
    if (code < 0)
1571
0
        return code;
1572
11.7M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1573
11.1M
        if (rule != xdev->fill_rule) {
1574
2.77k
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1575
2.77k
                                 eNonZeroWinding));
1576
2.77k
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
1577
2.77k
            xdev->fill_rule = rule;
1578
2.77k
        }
1579
11.1M
        pclxl_set_paints(xdev, type);
1580
11.1M
        spputc(s, pxtPaintPath);
1581
11.1M
    }
1582
11.7M
    if (type & gx_path_type_clip) {
1583
611k
        static const byte scr_[] = {
1584
611k
            DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
1585
611k
        };
1586
1587
611k
        if (rule != xdev->clip_rule) {
1588
260
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1589
260
                                 eNonZeroWinding));
1590
260
            px_put_ac(s, pxaClipMode, pxtSetClipMode);
1591
260
            xdev->clip_rule = rule;
1592
260
        }
1593
611k
        PX_PUT_LIT(s, scr_);
1594
611k
    }
1595
11.7M
    return 0;
1596
11.7M
}
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
22.3k
{
1634
22.3k
    gx_device_vector *vdev = (gx_device_vector *) dev;
1635
22.3k
    gx_device_pclxl *xdev = (gx_device_pclxl *) dev;
1636
22.3k
    int code;
1637
1638
22.3k
    vdev->v_memory = dev->memory->stable_memory;
1639
22.3k
    vdev->vec_procs = &pclxl_vector_procs;
1640
22.3k
    code = gdev_vector_open_file_options(vdev, 512,
1641
22.3k
                                         VECTOR_OPEN_FILE_SEQUENTIAL);
1642
22.3k
    if (code < 0)
1643
0
        return code;
1644
1645
22.3k
    while (dev->child)
1646
0
        dev = dev->child;
1647
22.3k
    vdev = (gx_device_vector *) dev;
1648
22.3k
    xdev = (gx_device_pclxl *) dev;
1649
1650
22.3k
    pclxl_page_init(xdev);
1651
22.3k
    px_write_file_header(vdev->strm, dev, xdev->Staple);
1652
22.3k
    xdev->media_size = pxeMediaSize_next;       /* no size selected */
1653
22.3k
    memset(&xdev->chars, 0, sizeof(xdev->chars));
1654
22.3k
    xdev->chars.next_in = xdev->chars.next_out = 2;
1655
    /* xdev->iccTransform = false; *//* set true/false here to ignore command line */
1656
22.3k
    return 0;
1657
22.3k
}
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
19.2k
{
1664
19.2k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1665
19.2k
    stream *s;
1666
19.2k
    int code;
1667
1668
    /* Note that unlike close_device, end_page must not omit blank pages. */
1669
19.2k
    if (!xdev->in_page)
1670
0
        pclxl_beginpage((gx_device_vector *) dev);
1671
19.2k
    s = xdev->strm;
1672
19.2k
    px_put_usa(s, (uint) num_copies, pxaPageCopies);    /* num_copies */
1673
19.2k
    spputc(s, pxtEndPage);
1674
19.2k
    sflush(s);
1675
19.2k
    pclxl_page_init(xdev);
1676
19.2k
    if (gp_ferror(xdev->file))
1677
0
        return_error(gs_error_ioerror);
1678
19.2k
    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
19.2k
    if (gx_outputfile_is_separate_pages
1682
19.2k
        (((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
19.2k
    return code;
1688
19.2k
}
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
22.3k
{
1696
22.3k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1697
22.3k
    gp_file *file = xdev->file;
1698
1699
22.3k
    if (xdev->strm != NULL)
1700
22.3k
        sflush(xdev->strm);
1701
22.3k
    if (xdev->in_page)
1702
1.13k
        gp_fputc(pxtEndPage, file);
1703
22.3k
    px_write_file_trailer(file);
1704
22.3k
    return gdev_vector_close_file((gx_device_vector *) dev);
1705
22.3k
}
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
31.7k
{
1719
31.7k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1720
31.7k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1721
31.7k
    int code;
1722
31.7k
    stream *s;
1723
31.7k
    gx_color_index color0 = zero, color1 = one;
1724
31.7k
    gx_color_index white = ((gx_color_index)1 << dev->color_info.depth) - 1;
1725
31.7k
    gx_color_index black = 0;
1726
31.7k
    gs_logical_operation_t lop;
1727
31.7k
    byte palette[2 * 3];
1728
31.7k
    int palette_size;
1729
31.7k
    pxeColorSpace_t color_space;
1730
1731
31.7k
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1732
31.7k
    code = gdev_vector_update_clip_path(vdev, NULL);
1733
31.7k
    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
31.7k
    if (((data_x & 7) != 0) || (h == 1) || (w == 1))
1741
28.5k
        return gx_default_copy_mono(dev, data, data_x, raster, id,
1742
28.5k
                                    x, y, w, h, zero, one);
1743
1744
3.15k
    pclxl_set_cursor(xdev, x, y);
1745
3.15k
    if (id != gs_no_id && zero == gx_no_color_index &&
1746
3.15k
        one != gx_no_color_index && data_x == 0) {
1747
1.61k
        gx_drawing_color dcolor;
1748
1749
1.61k
        code = gdev_vector_update_log_op(vdev, rop3_T | lop_T_transparent);
1750
1.61k
        if (code < 0)
1751
0
            return 0;
1752
1753
1.61k
        set_nonclient_dev_color(&dcolor, one);
1754
1.61k
        pclxl_setfillcolor(vdev, NULL, &dcolor);
1755
1.61k
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1756
1.61k
            return 0;
1757
1.61k
    }
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.54k
    if (zero == gx_no_color_index) {
1784
1.13k
        if (one == gx_no_color_index)
1785
0
            return 0;
1786
1.13k
        if (one != white) {
1787
1.13k
            if (one == black) {
1788
879
                lop = (rop3_S & rop3_D);
1789
879
            } else {
1790
253
                lop = rop3_S | lop_S_transparent;
1791
253
            }
1792
1.13k
            color0 = white;
1793
1.13k
        } else {
1794
0
            lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1795
0
            color0 = black;
1796
0
        }
1797
1.13k
    } 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
416
    } else {
1810
416
        lop = rop3_S;
1811
416
    }
1812
1813
1.54k
    if (dev->color_info.num_components == 1 ||
1814
1.54k
        (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
1815
1.54k
        ) {
1816
1.35k
        palette[0] = (byte) color0;
1817
1.35k
        palette[1] = (byte) color1;
1818
1.35k
        palette_size = 2;
1819
1.35k
        color_space = eGray;
1820
1.35k
        if_debug2m('b', dev->memory, "color palette %02X %02X\n",
1821
1.35k
                   palette[0], palette[1]);
1822
1.35k
    } else {
1823
190
        palette[0] = (byte) (color0 >> 16);
1824
190
        palette[1] = (byte) (color0 >> 8);
1825
190
        palette[2] = (byte) color0;
1826
190
        palette[3] = (byte) (color1 >> 16);
1827
190
        palette[4] = (byte) (color1 >> 8);
1828
190
        palette[5] = (byte) color1;
1829
190
        palette_size = 6;
1830
190
        color_space = eRGB;
1831
190
    }
1832
1.54k
    code = gdev_vector_update_log_op(vdev, lop);
1833
1.54k
    if (code < 0)
1834
0
        return 0;
1835
1.54k
    pclxl_set_color_palette(xdev, color_space, palette, palette_size);
1836
1.54k
    s = pclxl_stream(xdev);
1837
1.54k
    {
1838
1.54k
        static const byte mi_[] = {
1839
1.54k
            DUB(e1Bit), DA(pxaColorDepth),
1840
1.54k
            DUB(eIndexedPixel), DA(pxaColorMapping)
1841
1.54k
        };
1842
1843
1.54k
        PX_PUT_LIT(s, mi_);
1844
1.54k
    }
1845
1.54k
    pclxl_write_begin_image(xdev, w, h, w, h);
1846
1.54k
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1847
1.54k
    pclxl_write_end_image(xdev);
1848
1.54k
    return 0;
1849
1.54k
}
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
432k
{
1857
432k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1858
432k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1859
432k
    stream *s;
1860
432k
    uint source_bit;
1861
432k
    int code;
1862
1863
432k
    fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
1864
432k
    code = gdev_vector_update_clip_path(vdev, NULL);
1865
432k
    if (code < 0)
1866
0
        return code;
1867
1868
432k
    source_bit = sourcex * dev->color_info.depth;
1869
1870
    /* side-effect from fill/stroke may have set color space to eGray */
1871
432k
    if (dev->color_info.num_components == 3)
1872
280k
        pclxl_set_color_space(xdev, eRGB);
1873
151k
    else if (dev->color_info.num_components == 1)
1874
151k
        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
432k
    if (((source_bit & 7) != 0) || (w == 1) || (h == 1))
1889
413k
        return gx_default_copy_color(dev, base, sourcex, raster, id,
1890
413k
                                     x, y, w, h);
1891
18.0k
    code = gdev_vector_update_log_op(vdev, rop3_S);
1892
18.0k
    if (code < 0)
1893
0
        return 0;
1894
18.0k
    pclxl_set_cursor(xdev, x, y);
1895
18.0k
    s = pclxl_stream(xdev);
1896
18.0k
    {
1897
18.0k
        static const byte ci_[] = {
1898
18.0k
            DA(pxaColorDepth),
1899
18.0k
            DUB(eDirectPixel), DA(pxaColorMapping)
1900
18.0k
        };
1901
1902
18.0k
        px_put_ub(s, eBit_values[dev->color_info.depth /
1903
18.0k
                                 dev->color_info.num_components]);
1904
18.0k
        PX_PUT_LIT(s, ci_);
1905
18.0k
    }
1906
18.0k
    pclxl_write_begin_image(xdev, w, h, w, h);
1907
18.0k
    pclxl_write_image_data(xdev, base, source_bit, raster,
1908
18.0k
                           w * dev->color_info.depth, 0, h, false);
1909
18.0k
    pclxl_write_end_image(xdev);
1910
18.0k
    return 0;
1911
18.0k
}
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
1.23M
{
1921
1.23M
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1922
1.23M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1923
1.23M
    int code;
1924
1.23M
    stream *s;
1925
1.23M
    gx_color_index foreground;
1926
1927
1.23M
    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
1.11M
    if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 || (w == 1)
1933
1.11M
        || (h == 1))
1934
3.68k
        return gx_default_fill_mask(dev, data, data_x, raster, id, x, y, w, h,
1935
3.68k
                                    pdcolor, depth, lop, pcpath);
1936
1.11M
    code = gdev_vector_update_clip_path(vdev, pcpath);
1937
1.11M
    foreground = gx_dc_pure_color(pdcolor);
1938
1.11M
    if (code < 0)
1939
0
        return code;
1940
1.11M
    code = gdev_vector_update_fill_color(vdev, NULL, pdcolor);
1941
1.11M
    if (code < 0)
1942
0
        return 0;
1943
1.11M
    pclxl_set_cursor(xdev, x, y);
1944
1.11M
    if (id != gs_no_id && data_x == 0) {
1945
1.11M
        code = gdev_vector_update_log_op(vdev, lop);
1946
1.11M
        if (code < 0)
1947
0
            return 0;
1948
1.11M
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1949
1.11M
            return 0;
1950
1.11M
    }
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
174k
#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
246k
{
2038
246k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
2039
246k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
2040
246k
    const gs_image_t *pim = (const gs_image_t *)pic;
2041
246k
    const gs_color_space *pcs;
2042
246k
    pclxl_image_enum_t *pie;
2043
246k
    byte *row_data;
2044
246k
    int num_rows;
2045
246k
    uint row_raster;
2046
246k
    int bits_per_pixel;
2047
246k
    gs_matrix mat;
2048
246k
    int code;
2049
2050
    /* We only cope with image type 1 here. */
2051
246k
    if (pic->type->index != 1)
2052
78
        goto use_default;
2053
2054
245k
    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
245k
    bits_per_pixel =
2060
245k
        (pim->ImageMask ? 1 :
2061
245k
         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
245k
    code = gs_matrix_invert(&pim->ImageMatrix, &mat);
2068
245k
    if (code < 0)
2069
5
        goto use_default;
2070
245k
    if (pmat == NULL)
2071
245k
        pmat = &ctm_only(pgs);
2072
245k
    gs_matrix_multiply(&mat, pmat, &mat);
2073
2074
245k
    if (pclxl_nontrivial_transfer(pgs))
2075
13
        goto use_default;
2076
2077
245k
    if (pim->Width == 0 || pim->Height == 0)
2078
16
        goto use_default;
2079
2080
245k
    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
113
        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
113
        if (pim->Decode[0] != 0 || pim->Decode[1] != 1 ||
2095
113
            pim->Decode[2] != 0 || pim->Decode[3] != 1 ||
2096
113
            pim->Decode[4] != 0 || pim->Decode[5] != 1)
2097
0
            goto use_default;
2098
113
    }
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
245k
    if ((!((mat.xx * mat.yy != 0) && (mat.xy == 0) && (mat.yx == 0)) &&
2109
245k
         !((mat.xx == 0) && (mat.yy == 0) && (mat.xy * mat.yx != 0))) ||
2110
245k
        (pim->ImageMask ?
2111
169k
         (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
2112
176k
         ((!pclxl_can_handle_color_space(pcs) ||
2113
7.05k
           (bits_per_pixel != 1 && bits_per_pixel != 4 &&
2114
5.47k
            bits_per_pixel != 8 && bits_per_pixel != 24 &&
2115
5.47k
            bits_per_pixel != 32))
2116
7.05k
          && !(pclxl_can_icctransform(pim) && xdev->iccTransform))) ||
2117
245k
        pim->format != gs_image_format_chunky || pim->Interpolate || prect)
2118
71.0k
        goto use_default;
2119
174k
    row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
2120
174k
    num_rows = MAX_ROW_DATA / row_raster;
2121
174k
    if (num_rows > pim->Height)
2122
172k
        num_rows = pim->Height;
2123
174k
    if (num_rows <= 0)
2124
2
        num_rows = 1;
2125
174k
    pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
2126
174k
                          "pclxl_begin_image");
2127
174k
    row_data = gs_alloc_bytes(mem, num_rows * row_raster,
2128
174k
                              "pclxl_begin_image(rows)");
2129
174k
    if (pie == 0 || row_data == 0) {
2130
1
        code = gs_note_error(gs_error_VMerror);
2131
1
        goto fail;
2132
1
    }
2133
174k
    code = gdev_vector_begin_image(vdev, pgs, pim, pim->format, prect,
2134
174k
                                   pdcolor, pcpath, mem,
2135
174k
                                   &pclxl_image_enum_procs,
2136
174k
                                   (gdev_vector_image_enum_t *) pie);
2137
174k
    if (code < 0)
2138
0
        goto fail;
2139
2140
    /* emit a PXL XL rotation and adjust mat correspondingly */
2141
174k
    pie->flipped = false;
2142
174k
    if (mat.xx * mat.yy > 0) {
2143
158k
        if (mat.xx < 0) {
2144
5.06k
            stream *s = pclxl_stream(xdev);
2145
2146
5.06k
            mat.xx = -mat.xx;
2147
5.06k
            mat.yy = -mat.yy;
2148
5.06k
            mat.tx = -mat.tx;
2149
5.06k
            mat.ty = -mat.ty;
2150
5.06k
            px_put_ss(s, 180);
2151
5.06k
            xdev->state_rotated = 2;
2152
5.06k
            px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2153
5.06k
        }
2154
        /* leave the matrix alone if it is portrait */
2155
158k
    } else if (mat.xx * mat.yy < 0) {
2156
207
        pie->flipped = true;
2157
207
        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
193
        } else {
2166
193
            mat.yy = -mat.yy;
2167
193
            mat.ty = -mat.ty;
2168
193
        }
2169
16.1k
    } else if (mat.xy * mat.yx < 0) {
2170
        /* rotate +90 or -90 */
2171
16.0k
        float tmpf;
2172
16.0k
        stream *s = pclxl_stream(xdev);
2173
2174
16.0k
        if (mat.xy > 0) {
2175
31
            mat.xx = mat.xy;
2176
31
            mat.yy = -mat.yx;
2177
31
            tmpf = mat.tx;
2178
31
            mat.tx = mat.ty;
2179
31
            mat.ty = -tmpf;
2180
31
            px_put_ss(s, -90);
2181
31
            xdev->state_rotated = -1;
2182
16.0k
        } else {
2183
16.0k
            mat.xx = -mat.xy;
2184
16.0k
            mat.yy = mat.yx;
2185
16.0k
            tmpf = mat.tx;
2186
16.0k
            mat.tx = -mat.ty;
2187
16.0k
            mat.ty = tmpf;
2188
16.0k
            px_put_ss(s, +90);
2189
16.0k
            xdev->state_rotated = +1;
2190
16.0k
        }
2191
16.0k
        mat.xy = mat.yx = 0;
2192
16.0k
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2193
16.0k
    } else if (mat.xy * mat.yx > 0) {
2194
54
        float tmpf;
2195
54
        stream *s = pclxl_stream(xdev);
2196
2197
54
        pie->flipped = true;
2198
54
        if (mat.xy > 0) {
2199
38
            mat.xx = mat.xy;
2200
38
            mat.yy = mat.yx;
2201
38
            tmpf = mat.tx;
2202
38
            mat.tx = mat.ty;
2203
38
            mat.ty = tmpf;
2204
38
            px_put_ss(s, -90);
2205
38
            xdev->state_rotated = -1;
2206
38
        } else {
2207
16
            mat.xx = -mat.xy;
2208
16
            mat.yy = -mat.yx;
2209
16
            tmpf = mat.tx;
2210
16
            mat.tx = -mat.ty;
2211
16
            mat.ty = -tmpf;
2212
16
            px_put_ss(s, +90);
2213
16
            xdev->state_rotated = +1;
2214
16
        }
2215
54
        mat.xy = mat.yx = 0;
2216
54
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2217
54
    }
2218
2219
174k
    pie->mat = mat;
2220
174k
    pie->rows.data = row_data;
2221
174k
    pie->rows.num_rows = num_rows;
2222
174k
    pie->rows.first_y = 0;
2223
174k
    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
174k
    if (!pim->ImageMask && (!pclxl_can_handle_color_space(pcs)
2246
5.43k
                            || (bits_per_pixel == 32 && dev->icc_struct
2247
5.43k
                                && !dev->icc_struct->usefastcolor))
2248
174k
        && pclxl_can_icctransform(pim) && pcs->cmm_icc_profile_data) {
2249
111
        gsicc_rendering_param_t rendering_params;
2250
2251
111
        rendering_params.black_point_comp = pgs->blackptcomp;
2252
111
        rendering_params.graphics_type_tag = GS_IMAGE_TAG;
2253
111
        rendering_params.rendering_intent = pgs->renderingintent;
2254
111
        pie->icclink = gsicc_get_link(pgs, dev, pcs, NULL /*des */ ,
2255
111
                                      &rendering_params, pgs->memory);
2256
111
    } else
2257
174k
        pie->icclink = NULL;
2258
174k
    *pinfo = (gx_image_enum_common_t *) pie;
2259
174k
    {
2260
174k
        gs_logical_operation_t lop = pgs->log_op;
2261
2262
174k
        if (pim->ImageMask) {
2263
169k
            const byte *palette = (const byte *)
2264
169k
                (pim->Decode[0] ? "\377\000" : "\000\377");
2265
169k
            gx_color_index foreground = gx_dc_pure_color(pdcolor);
2266
2267
169k
            code = gdev_vector_update_fill_color(vdev, NULL,    /* use process color */
2268
169k
                                                 pdcolor);
2269
169k
            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
169k
            if (foreground == ((gx_color_index)1 << dev->color_info.depth) - 1) {       /* white */
2275
274
                lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
2276
169k
            } else if (foreground == 0) {       /* black */
2277
166k
                lop = (rop3_S & rop3_D);
2278
166k
            } else
2279
3.06k
                lop |= rop3_S | lop_S_transparent;
2280
2281
169k
            code = gdev_vector_update_log_op(vdev, lop);
2282
169k
            if (code < 0)
2283
0
                goto fail;
2284
169k
            pclxl_set_color_palette(xdev, eGray, palette, 2);
2285
169k
        } else {
2286
5.43k
            if (bits_per_pixel == 24 || bits_per_pixel == 32) {
2287
3.87k
                code = gdev_vector_update_log_op
2288
3.87k
                    (vdev,
2289
3.87k
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2290
3.87k
                if (code < 0)
2291
0
                    goto fail;
2292
3.87k
                if (dev->color_info.num_components == 1) {
2293
651
                    pclxl_set_color_space(xdev, eGray);
2294
3.22k
                } else {
2295
3.22k
                    pclxl_set_color_space(xdev, eRGB);
2296
3.22k
                }
2297
3.87k
            } else {
2298
1.56k
                int bpc = pim->BitsPerComponent;
2299
1.56k
                int num_components =
2300
1.56k
                    pie->plane_depths[0] * pie->num_planes / bpc;
2301
1.56k
                int sample_max = (1 << bpc) - 1;
2302
1.56k
                byte palette[256 * 3];
2303
1.56k
                int i;
2304
2305
1.56k
                code = gdev_vector_update_log_op
2306
1.56k
                    (vdev,
2307
1.56k
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2308
1.56k
                if (code < 0)
2309
0
                    goto fail;
2310
317k
                for (i = 0; i < 1 << bits_per_pixel; ++i) {
2311
315k
                    gs_client_color cc;
2312
315k
                    gx_device_color devc;
2313
315k
                    int cv = i, j;
2314
315k
                    gx_color_index ci;
2315
2316
631k
                    for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
2317
315k
                        cc.paint.values[j] = pim->Decode[j * 2] +
2318
315k
                            (cv & sample_max) *
2319
315k
                            (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
2320
315k
                            sample_max;
2321
315k
                    (*pcs->type->remap_color)
2322
315k
                        (&cc, pcs, &devc, pgs, dev, gs_color_select_source);
2323
315k
                    if (!gx_dc_is_pure(&devc))
2324
0
                        return_error(gs_error_Fatal);
2325
315k
                    ci = gx_dc_pure_color(&devc);
2326
315k
                    if (dev->color_info.num_components == 1) {
2327
285k
                        palette[i] = (byte) ci;
2328
285k
                    } else {
2329
30.7k
                        byte *ppal = &palette[i * 3];
2330
2331
30.7k
                        ppal[0] = (byte) (ci >> 16);
2332
30.7k
                        ppal[1] = (byte) (ci >> 8);
2333
30.7k
                        ppal[2] = (byte) ci;
2334
30.7k
                    }
2335
315k
                }
2336
1.56k
                if (dev->color_info.num_components == 1)
2337
1.19k
                    pclxl_set_color_palette(xdev, eGray, palette,
2338
1.19k
                                            1 << bits_per_pixel);
2339
366
                else
2340
366
                    pclxl_set_color_palette(xdev, eRGB, palette,
2341
366
                                            3 << bits_per_pixel);
2342
1.56k
            }
2343
5.43k
        }
2344
174k
    }
2345
174k
    return 0;
2346
1
  fail:
2347
1
    gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
2348
1
    gs_free_object(mem, pie, "pclxl_begin_image");
2349
71.1k
  use_default:
2350
71.1k
    if (dev->color_info.num_components == 1)
2351
42.9k
        pclxl_set_color_space(xdev, eGray);
2352
28.2k
    else
2353
28.2k
        pclxl_set_color_space(xdev, eRGB);
2354
71.1k
    return gx_default_begin_typed_image(dev, pgs, pmat, pic, prect,
2355
71.1k
                                        pdcolor, pcpath, mem, pinfo);
2356
1
}
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
435k
{
2362
435k
    return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
2363
435k
                 ((const gx_device_pclxl *)pie->dev)->scale.x);
2364
435k
}
2365
static int
2366
image_transform_y(const pclxl_image_enum_t * pie, int sy)
2367
435k
{
2368
435k
    return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
2369
435k
                 ((const gx_device_pclxl *)pie->dev)->scale.y);
2370
435k
}
2371
2372
static int
2373
pclxl_image_write_rows(pclxl_image_enum_t * pie)
2374
217k
{
2375
217k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) pie->dev;
2376
217k
    stream *s = pclxl_stream(xdev);
2377
217k
    int y = pie->rows.first_y;
2378
217k
    int h = pie->y - y;
2379
217k
    int xo = image_transform_x(pie, 0);
2380
217k
    int yo = image_transform_y(pie, y);
2381
217k
    int dw = image_transform_x(pie, pie->width) - xo;
2382
217k
    int dh = image_transform_y(pie, y + h) - yo;
2383
217k
    int rows_raster = pie->rows.raster;
2384
217k
    int offset_lastflippedstrip = 0;
2385
2386
217k
    if (pie->flipped) {
2387
257
        yo = -yo - dh;
2388
257
        if (!pie->icclink)
2389
257
            offset_lastflippedstrip =
2390
257
                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
257
    };
2396
2397
217k
    if (dw <= 0 || dh <= 0)
2398
82.9k
        return 0;
2399
134k
    pclxl_set_cursor(xdev, xo, yo);
2400
134k
    if (pie->bits_per_pixel == 24) {
2401
38.7k
        static const byte ci_[] = {
2402
38.7k
            DA(pxaColorDepth),
2403
38.7k
            DUB(eDirectPixel), DA(pxaColorMapping)
2404
38.7k
        };
2405
2406
38.7k
        px_put_ub(s, eBit_values[8]);
2407
38.7k
        PX_PUT_LIT(s, ci_);
2408
38.7k
        if (xdev->color_info.depth == 8) {
2409
1.65k
            rows_raster /= 3;
2410
1.65k
            if (!pie->icclink) {
2411
1.65k
                byte *in = pie->rows.data + offset_lastflippedstrip;
2412
1.65k
                byte *out = pie->rows.data + offset_lastflippedstrip;
2413
1.65k
                int i;
2414
1.65k
                int j;
2415
2416
130k
                for (j = 0; j < h; j++) {
2417
197M
                    for (i = 0; i < rows_raster; i++) {
2418
197M
                        *out =
2419
197M
                            (byte) (((*(in + 0) * (ulong) lum_red_weight) +
2420
197M
                                     (*(in + 1) * (ulong) lum_green_weight) +
2421
197M
                                     (*(in + 2) * (ulong) lum_blue_weight) +
2422
197M
                                     (lum_all_weights / 2)) /
2423
197M
                                    lum_all_weights);
2424
197M
                        in += 3;
2425
197M
                        out++;
2426
197M
                    }
2427
128k
                }
2428
1.65k
            }
2429
1.65k
        }
2430
96.2k
    } else if (pie->bits_per_pixel == 32) {
2431
149
        static const byte ci_[] = {
2432
149
            DA(pxaColorDepth),
2433
149
            DUB(eDirectPixel), DA(pxaColorMapping)
2434
149
        };
2435
2436
149
        px_put_ub(s, eBit_values[8]);
2437
149
        PX_PUT_LIT(s, ci_);
2438
149
        if (xdev->color_info.depth == 8) {
2439
            /* CMYK to Gray */
2440
65
            rows_raster /= 4;
2441
65
            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
84
        } else {
2464
            /* CMYK to RGB */
2465
84
            rows_raster /= 4;
2466
84
            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
84
            rows_raster *= 3;
2491
84
        }
2492
96.0k
    } else {
2493
96.0k
        static const byte ii_[] = {
2494
96.0k
            DA(pxaColorDepth),
2495
96.0k
            DUB(eIndexedPixel), DA(pxaColorMapping)
2496
96.0k
        };
2497
96.0k
        px_put_ub(s, eBit_values[pie->bits_per_pixel]);
2498
96.0k
        PX_PUT_LIT(s, ii_);
2499
96.0k
    }
2500
134k
    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
134k
    pclxl_write_image_data(xdev, pie->rows.data + offset_lastflippedstrip, 0,
2504
134k
                           rows_raster, rows_raster << 3, 0, h,
2505
134k
                           ((pie->bits_per_pixel == 24
2506
134k
                             || pie->bits_per_pixel == 32) ? true : false));
2507
134k
    pclxl_write_end_image(xdev);
2508
134k
    return 0;
2509
217k
}
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
17.1M
{
2517
17.1M
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2518
17.1M
    int data_bit = planes[0].data_x * info->plane_depths[0];
2519
17.1M
    int width_bits = pie->width * info->plane_depths[0];
2520
17.1M
    int i;
2521
2522
    /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
2523
17.1M
    if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
2524
48
        return_error(gs_error_rangecheck);
2525
17.1M
    if (height > pie->height - pie->y)
2526
108k
        height = pie->height - pie->y;
2527
37.5M
    for (i = 0; i < height; pie->y++, ++i) {
2528
20.3M
        int flipped_strip_offset;
2529
2530
20.3M
        if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
2531
43.6k
            int code = pclxl_image_write_rows(pie);
2532
2533
43.6k
            if (code < 0)
2534
0
                return code;
2535
43.6k
            pie->rows.first_y = pie->y;
2536
43.6k
        }
2537
20.3M
        flipped_strip_offset = (pie->flipped ?
2538
8.62k
                                (pie->rows.num_rows -
2539
8.62k
                                 (pie->y - pie->rows.first_y) -
2540
20.3M
                                 1) : (pie->y - pie->rows.first_y));
2541
20.3M
        if (!pie->icclink)
2542
20.3M
            memcpy(pie->rows.data +
2543
20.3M
                   pie->rows.raster * flipped_strip_offset,
2544
20.3M
                   planes[0].data + planes[0].raster * i + (data_bit >> 3),
2545
20.3M
                   pie->rows.raster);
2546
23.8k
        else {
2547
23.8k
            gsicc_bufferdesc_t input_buff_desc;
2548
23.8k
            gsicc_bufferdesc_t output_buff_desc;
2549
23.8k
            int pixels_per_row =
2550
23.8k
                pie->rows.raster / (pie->bits_per_pixel >> 3);
2551
23.8k
            int out_raster_stride =
2552
23.8k
                pixels_per_row * info->dev->color_info.num_components;
2553
23.8k
            gsicc_init_buffer(&input_buff_desc,
2554
23.8k
                              (pie->bits_per_pixel >> 3) /*num_chan */ ,
2555
23.8k
                              1 /*bytes_per_chan */ ,
2556
23.8k
                              false /*has_alpha */ , false /*alpha_first */ ,
2557
23.8k
                              false /*is_planar */ ,
2558
23.8k
                              0 /*plane_stride */ ,
2559
23.8k
                              pie->rows.raster /*row_stride */ ,
2560
23.8k
                              1 /*num_rows */ ,
2561
23.8k
                              pixels_per_row /*pixels_per_row */ );
2562
23.8k
            gsicc_init_buffer(&output_buff_desc,
2563
23.8k
                              info->dev->color_info.num_components, 1, false,
2564
23.8k
                              false, false, 0, out_raster_stride, 1,
2565
23.8k
                              pixels_per_row);
2566
23.8k
            gscms_transform_color_buffer(info->dev, pie->icclink,
2567
23.8k
                                         &input_buff_desc, &output_buff_desc,
2568
23.8k
                                         (void *)(planes[0].data +
2569
23.8k
                                                  planes[0].raster * i +
2570
23.8k
                                                  (data_bit >> 3)) /*src */ ,
2571
23.8k
                                         pie->rows.data + out_raster_stride * flipped_strip_offset      /*des */
2572
23.8k
                                         );
2573
23.8k
        }
2574
20.3M
    }
2575
17.1M
    *rows_used = height;
2576
17.1M
    return pie->y >= pie->height;
2577
17.1M
}
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
174k
{
2583
174k
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2584
174k
    int code = 0;
2585
2586
    /* Write the final strip, if any. */
2587
174k
    if (pie->y > pie->rows.first_y && draw_last)
2588
174k
        code = pclxl_image_write_rows(pie);
2589
174k
    if (draw_last) {
2590
174k
        gx_device_pclxl *xdev = (gx_device_pclxl *) info->dev;
2591
174k
        stream *s = pclxl_stream(xdev);
2592
2593
174k
        switch (xdev->state_rotated) {
2594
16.0k
            case 1:
2595
16.0k
                xdev->state_rotated = 0;
2596
16.0k
                px_put_ss(s, -90);
2597
16.0k
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2598
16.0k
                break;
2599
69
            case -1:
2600
69
                xdev->state_rotated = 0;
2601
69
                px_put_ss(s, +90);
2602
69
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2603
69
                break;
2604
5.07k
            case 2:
2605
5.07k
                xdev->state_rotated = 0;
2606
5.07k
                px_put_ss(s, -180);
2607
5.07k
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2608
5.07k
                break;
2609
153k
            case 0:
2610
153k
            default:
2611
                /* do nothing */
2612
153k
                break;
2613
174k
        }
2614
174k
    }
2615
174k
    if (pie->icclink)
2616
111
        gsicc_release_link(pie->icclink);
2617
174k
    gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
2618
174k
    gx_image_free_enum(&info);
2619
174k
    return code;
2620
174k
}
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
335k
{                               /* I - Parameter list */
2630
335k
    gx_device_pclxl *xdev;      /* PCL XL device */
2631
335k
    int code;                   /* Return code */
2632
335k
    gs_param_string s;          /* Temporary string value */
2633
2634
    /*
2635
     * First process the "standard" page device parameters...
2636
     */
2637
2638
335k
    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
335k
    xdev = (gx_device_pclxl *) dev;
2646
2647
335k
    if ((code = param_write_bool(plist, "Duplex", &(xdev->Duplex))) < 0)
2648
0
        return (code);
2649
2650
335k
    if ((code = param_write_bool(plist, "ManualFeed",
2651
335k
         &(xdev->ManualFeed))) < 0)
2652
0
        return (code);
2653
2654
335k
    if ((code = param_write_int(plist, "MediaPosition",
2655
335k
        &(xdev->MediaPosition))) < 0)
2656
0
        return (code);
2657
2658
335k
    param_string_from_string(s, xdev->MediaType);
2659
2660
335k
    if ((code = param_write_string(plist, "MediaType", &s)) < 0)
2661
0
        return (code);
2662
2663
335k
    if ((code = param_write_bool(plist, "Staple", &(xdev->Staple))) < 0)
2664
0
        return (code);
2665
2666
335k
    if ((code = param_write_bool(plist, "Tumble", &(xdev->Tumble))) < 0)
2667
0
        return (code);
2668
2669
335k
    if ((code = param_write_int(plist, "CompressMode",
2670
335k
                                &(xdev->CompressMode))) < 0)
2671
0
        return (code);
2672
2673
335k
    if ((code =
2674
335k
         param_write_bool(plist, "iccTransform", &(xdev->iccTransform))) < 0)
2675
0
        return (code);
2676
2677
335k
    return (0);
2678
335k
}
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
157k
{                               /* I - Parameter list */
2688
157k
    gx_device_pclxl *xdev;      /* PCL XL device */
2689
157k
    int code;                   /* Error code */
2690
157k
    int intval;                 /* Integer value */
2691
157k
    bool boolval;               /* Boolean value */
2692
157k
    gs_param_string stringval;  /* String value */
2693
157k
    bool ManualFeed;
2694
157k
    bool ManualFeed_set = false;
2695
157k
    int MediaPosition;
2696
157k
    bool MediaPosition_set = false;
2697
2698
    /*
2699
     * Process PCL-XL driver parameters...
2700
     */
2701
2702
157k
    xdev = (gx_device_pclxl *) dev;
2703
2704
157k
#define intoption(name, sname, type) \
2705
157k
  if ((code = param_read_int(plist, sname, &intval)) < 0) \
2706
157k
  { \
2707
0
    if_debug1('|', "Error setting %s\n", sname); \
2708
0
    param_signal_error(plist, sname, code); \
2709
0
    return (code); \
2710
0
  } \
2711
157k
  else if (code == 0) \
2712
157k
  { \
2713
14.3k
    if_debug2('|', "setting %s to %d\n", sname, intval); \
2714
14.3k
    xdev->name = (type)intval; \
2715
14.3k
  }
2716
2717
157k
#define booloption(name, sname) \
2718
630k
  if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
2719
630k
  { \
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
630k
  else if (code == 0) {                                   \
2731
57.2k
    if_debug2('|', "setting %s to %d\n", sname, boolval); \
2732
57.2k
    xdev->name = (bool)boolval; \
2733
57.2k
  }
2734
2735
157k
#define stringoption(name, sname)                                \
2736
157k
  if ((code = param_read_string(plist, sname, &stringval)) < 0)  \
2737
157k
    {                                                            \
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
157k
  else if (code == 0) {                                          \
2751
14.3k
    strncpy(xdev->name, (const char *)(stringval.data),          \
2752
14.3k
            stringval.size);                                     \
2753
14.3k
    xdev->name[stringval.size] = '\0';                           \
2754
14.3k
    if_debug2('|', "setting %s to %s\n", sname, xdev->name);     \
2755
14.3k
  }
2756
2757
    /* We need to have *_set to distinguish defaults from explicitly sets */
2758
157k
    booloption(Duplex, "Duplex");
2759
157k
    if (code == 0)
2760
14.3k
        if (xdev->Duplex) {
2761
0
            if_debug0('|', "round up page count\n");
2762
0
            xdev->page = (xdev->page + 1) & ~1;
2763
0
        }
2764
157k
    code = param_read_bool(plist, "ManualFeed", &ManualFeed);
2765
157k
    if (code == 0)
2766
14.3k
        ManualFeed_set = true;
2767
157k
    if (code >= 0) {
2768
157k
        code = param_read_int(plist, "MediaPosition", &MediaPosition);
2769
157k
        if (code == 0)
2770
36.6k
            MediaPosition_set = true;
2771
121k
        else if (code < 0) {
2772
0
            if (param_read_null(plist, "MediaPosition") == 0) {
2773
0
                code = 0;
2774
0
            }
2775
0
        }
2776
157k
    }
2777
157k
    stringoption(MediaType, "MediaType");
2778
157k
    if (code == 0) {
2779
14.3k
        xdev->MediaType_set = true;
2780
        /* round up for duplex */
2781
14.3k
        if (strcmp(xdev->MediaType_old, xdev->MediaType)) {
2782
0
            if_debug0('|', "round up page count\n");
2783
0
            xdev->page = (xdev->page + 1) & ~1;
2784
0
            strcpy(xdev->MediaType_old, xdev->MediaType);
2785
0
        }
2786
14.3k
    }
2787
157k
    booloption(Staple, "Staple");
2788
157k
    booloption(Tumble, "Tumble");
2789
157k
    intoption(CompressMode, "CompressMode", int);
2790
2791
157k
    booloption(iccTransform, "iccTransform");
2792
2793
    /*
2794
     * Then process standard page device parameters...
2795
     */
2796
2797
157k
    if (code >= 0)
2798
157k
        if ((code = gdev_vector_put_params(dev, plist)) < 0)
2799
54
            return (code);
2800
2801
157k
    if (code >= 0) {
2802
157k
        if (ManualFeed_set) {
2803
14.3k
            xdev->ManualFeed = ManualFeed;
2804
14.3k
            xdev->ManualFeed_set = true;
2805
14.3k
        }
2806
157k
        if (MediaPosition_set) {
2807
36.6k
            xdev->MediaPosition = MediaPosition;
2808
36.6k
            xdev->MediaPosition_set = true;
2809
36.6k
            if (xdev->MediaPosition_old != xdev->MediaPosition) {
2810
22.3k
                if_debug0('|', "round up page count\n");
2811
22.3k
                xdev->page = (xdev->page+1) & ~1 ;
2812
22.3k
                xdev->MediaPosition_old = xdev->MediaPosition;
2813
22.3k
            }
2814
36.6k
        }
2815
157k
    }
2816
2817
157k
    return (0);
2818
157k
}
2819
2820
static int pclxl_text_begin(gx_device * dev, gs_gstate * pgs,
2821
                    const gs_text_params_t *text, gs_font * font,
2822
                    const gx_clip_path * pcpath,
2823
                    gs_text_enum_t ** ppte)
2824
2.05M
{
2825
2.05M
    font->dir->ccache.upper = 0;
2826
2.05M
    return gx_default_text_begin(dev, pgs, text, font, pcpath, ppte);
2827
2.05M
}