Coverage Report

Created: 2025-12-31 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpx.c
Line
Count
Source
1
/* Copyright (C) 2001-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
112M
#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
16.3k
#define MAX_CACHED_CHARS 400
98
16.2k
#define MAX_CHAR_DATA 500000
99
1.35M
#define MAX_CHAR_SIZE 5000
100
1.35M
#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
27.7k
{
158
27.7k
    set_dev_proc(dev, open_device, pclxl_open_device);
159
27.7k
    set_dev_proc(dev, output_page, pclxl_output_page);
160
27.7k
    set_dev_proc(dev, close_device, pclxl_close_device);
161
27.7k
    set_dev_proc(dev, map_rgb_color, map_rgb_color);
162
27.7k
    set_dev_proc(dev, map_color_rgb, map_color_rgb);
163
27.7k
    set_dev_proc(dev, fill_rectangle, gdev_vector_fill_rectangle);
164
27.7k
    set_dev_proc(dev, copy_mono, pclxl_copy_mono);
165
27.7k
    set_dev_proc(dev, copy_color, pclxl_copy_color);
166
27.7k
    set_dev_proc(dev, get_params, pclxl_get_params);
167
27.7k
    set_dev_proc(dev, put_params, pclxl_put_params);
168
27.7k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
169
27.7k
    set_dev_proc(dev, fill_path, gdev_vector_fill_path);
170
27.7k
    set_dev_proc(dev, stroke_path, gdev_vector_stroke_path);
171
27.7k
    set_dev_proc(dev, fill_mask, pclxl_fill_mask);
172
27.7k
    set_dev_proc(dev, fill_trapezoid, gdev_vector_fill_trapezoid);
173
27.7k
    set_dev_proc(dev, fill_parallelogram, gdev_vector_fill_parallelogram);
174
27.7k
    set_dev_proc(dev, fill_triangle, gdev_vector_fill_triangle);
175
27.7k
    set_dev_proc(dev, begin_typed_image, pclxl_begin_typed_image);
176
27.7k
    set_dev_proc(dev, strip_copy_rop2, pclxl_strip_copy_rop2);
177
27.7k
    set_dev_proc(dev, text_begin, pclxl_text_begin);
178
27.7k
}
179
180
static void
181
pxlmono_initialize_device_procs(gx_device *dev)
182
12.1k
{
183
12.1k
    pclxl_initialize_device_procs(dev,
184
12.1k
                                  gx_default_gray_map_rgb_color,
185
12.1k
                                  gx_default_gray_map_color_rgb);
186
12.1k
}
187
188
static void
189
pxlcolor_initialize_device_procs(gx_device *dev)
190
15.5k
{
191
15.5k
    pclxl_initialize_device_procs(dev,
192
15.5k
                                  gx_default_rgb_map_rgb_color,
193
15.5k
                                  gx_default_rgb_map_color_rgb);
194
15.5k
}
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
327M
{
209
327M
    return gdev_vector_stream((gx_device_vector *) xdev);
210
327M
}
211
212
/* Initialize for a page. */
213
static void
214
pclxl_page_init(gx_device_pclxl * xdev)
215
52.8k
{
216
52.8k
    gdev_vector_init((gx_device_vector *) xdev);
217
52.8k
    xdev->in_page = false;
218
52.8k
    xdev->fill_rule = gx_path_type_winding_number;
219
52.8k
    xdev->clip_rule = gx_path_type_winding_number;
220
52.8k
    xdev->color_space = eNoColorSpace;
221
52.8k
    xdev->palette.size = 0;
222
52.8k
    xdev->font_set = false;
223
52.8k
    xdev->state_rotated = 0;
224
52.8k
    xdev->scaled = false;
225
52.8k
    xdev->x_scale = 1;
226
52.8k
    xdev->y_scale = 1;
227
52.8k
    xdev->pen_null = false;
228
52.8k
    xdev->brush_null = false;
229
52.8k
}
230
231
/* Test whether a RGB color is actually a gray shade. */
232
27.3M
#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
39.7M
{
238
39.7M
    if (xdev->color_space != color_space) {
239
997k
        stream *s = pclxl_stream(xdev);
240
241
997k
        px_put_ub(s, (byte) color_space);
242
997k
        px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
243
997k
        xdev->color_space = color_space;
244
997k
        xdev->palette.size = 0; /* purge the cached palette */
245
997k
    }
246
39.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
222k
{
251
222k
    if (xdev->color_space != color_space ||
252
220k
        xdev->palette.size != palette_size ||
253
220k
        memcmp(xdev->palette.data, palette, palette_size)
254
222k
        ) {
255
3.26k
        stream *s = pclxl_stream(xdev);
256
257
3.26k
        static const byte csp_[] = {
258
3.26k
            DA(pxaColorSpace),
259
3.26k
            DUB(e8Bit), DA(pxaPaletteDepth),
260
3.26k
            pxt_ubyte_array
261
3.26k
        };
262
263
3.26k
        px_put_ub(s, (byte) color_space);
264
3.26k
        PX_PUT_LIT(s, csp_);
265
3.26k
        px_put_u(s, palette_size);
266
3.26k
        px_put_bytes(s, palette, palette_size);
267
3.26k
        px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
268
3.26k
        xdev->color_space = color_space;
269
3.26k
        xdev->palette.size = palette_size;
270
3.26k
        memcpy(xdev->palette.data, palette, palette_size);
271
3.26k
    }
272
222k
}
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
73.7M
{
284
73.7M
    stream *s = pclxl_stream(xdev);
285
286
73.7M
    if (op == pxtSetPenSource) {
287
73.2M
        if (xdev->pen_null)
288
73.0M
            return 0;
289
183k
        else
290
183k
            xdev->pen_null = true;
291
73.2M
    }
292
654k
    if (op == pxtSetBrushSource) {
293
470k
        if (xdev->brush_null)
294
308k
            return 0;
295
161k
        else
296
161k
            xdev->brush_null = true;
297
470k
    }
298
345k
    px_put_uba(s, 0, (byte) null_source);
299
345k
    spputc(s, (byte) op);
300
345k
    return 0;
301
654k
}
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
39.0M
{
308
39.0M
    stream *s = pclxl_stream(xdev);
309
310
39.0M
    if (gx_dc_is_pure(pdc)) {
311
39.0M
        gx_color_index color = gx_dc_pure_color(pdc);
312
313
39.0M
        if (op == pxtSetPenSource)
314
162k
            xdev->pen_null = false;
315
39.0M
        if (op == pxtSetBrushSource)
316
38.8M
            xdev->brush_null = false;
317
318
39.0M
        if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
319
19.6M
            pclxl_set_color_space(xdev, eGray);
320
19.6M
            px_put_uba(s, (byte) color, pxaGrayLevel);
321
19.6M
        } else {
322
19.3M
            pclxl_set_color_space(xdev, eRGB);
323
19.3M
            spputc(s, pxt_ubyte_array);
324
19.3M
            px_put_ub(s, 3);
325
19.3M
            spputc(s, (byte) (color >> 16));
326
19.3M
            spputc(s, (byte) (color >> 8));
327
19.3M
            spputc(s, (byte) color);
328
19.3M
            px_put_a(s, pxaRGBColor);
329
19.3M
        }
330
39.0M
    } else if (gx_dc_is_null(pdc) || !color_is_set(pdc)) {
331
3.10k
        if (op == pxtSetPenSource || op == pxtSetBrushSource)
332
3.10k
            return pclxl_set_cached_nulls(xdev, null_source, op);
333
0
        else
334
0
            px_put_uba(s, 0, null_source);
335
3.10k
    } else
336
27.2k
        return_error(gs_error_rangecheck);
337
39.0M
    spputc(s, (byte) op);
338
39.0M
    return 0;
339
39.0M
}
340
341
/* Test whether we can handle a given color space in an image. */
342
/* We cannot handle ICCBased color spaces. */
343
static bool
344
pclxl_can_handle_color_space(const gs_color_space * pcs)
345
15.1k
{
346
15.1k
    gs_color_space_index index;
347
348
    /* an image with no colorspace info arrived; cannot handle */
349
15.1k
    if (!pcs)
350
0
        return false;
351
15.1k
    index = gs_color_space_get_index(pcs);
352
353
15.1k
    if (index == gs_color_space_index_Indexed) {
354
750
        if (pcs->params.indexed.use_proc)
355
0
            return false;
356
750
        index =
357
750
            gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
358
14.4k
    } else if (index == gs_color_space_index_ICC) {
359
14.3k
        index = gsicc_get_default_type(pcs->cmm_icc_profile_data);
360
14.3k
        return ((index < gs_color_space_index_DevicePixel) ? true : false);
361
14.3k
    }
362
363
789
    return !(index == gs_color_space_index_Separation ||
364
775
             index == gs_color_space_index_Pattern ||
365
775
             index == gs_color_space_index_DeviceN ||
366
742
             index == gs_color_space_index_ICC ||
367
0
             (index <= gs_color_space_index_CIEA &&
368
0
             index >= gs_color_space_index_CIEDEFG)
369
789
             );
370
15.1k
}
371
372
/* Test whether we can icclink-transform an image. */
373
static bool
374
pclxl_can_icctransform(const gs_image_t * pim)
375
2.34k
{
376
2.34k
    const gs_color_space *pcs = pim->ColorSpace;
377
2.34k
    int bits_per_pixel;
378
379
    /* an image with no colorspace info arrived; cannot transform */
380
2.34k
    if (!pcs)
381
0
        return false;
382
2.34k
    bits_per_pixel =
383
2.34k
        (pim->ImageMask ? 1 :
384
2.34k
         pim->BitsPerComponent * gs_color_space_num_components(pcs));
385
386
2.34k
    if ((gs_color_space_get_index(pcs) == gs_color_space_index_ICC)
387
1.55k
        && (bits_per_pixel == 24 || bits_per_pixel == 32))
388
768
        return true;
389
390
1.57k
    return false;
391
2.34k
}
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
304k
{
402
304k
    gx_transfer_map *red = pgs->set_transfer.red;
403
304k
    gx_transfer_map *green = pgs->set_transfer.green;
404
304k
    gx_transfer_map *blue = pgs->set_transfer.blue;
405
406
304k
    return (red || green || blue);
407
408
304k
}
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
73.6M
{
413
73.6M
    stream *s = pclxl_stream(xdev);
414
73.6M
    gx_path_type_t rule = type & gx_path_type_rule;
415
416
73.6M
    if (!(type & gx_path_type_fill) &&
417
467k
        (color_is_set(&xdev->saved_fill_color.saved_dev_color) ||
418
0
         !gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color)
419
467k
        )
420
73.6M
        ) {
421
467k
        pclxl_set_cached_nulls(xdev, pxaNullBrush, pxtSetBrushSource);
422
467k
        color_set_null(&xdev->saved_fill_color.saved_dev_color);
423
467k
        if (rule != xdev->fill_rule) {
424
45
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
425
45
                                 eNonZeroWinding));
426
45
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
427
45
            xdev->fill_rule = rule;
428
45
        }
429
467k
    }
430
73.6M
    if (!(type & gx_path_type_stroke) &&
431
73.2M
        (color_is_set(&xdev->saved_stroke_color.saved_dev_color) ||
432
0
         !gx_dc_is_null(&xdev->saved_stroke_color.saved_dev_color)
433
73.2M
        )
434
73.6M
        ) {
435
73.2M
        pclxl_set_cached_nulls(xdev, pxaNullPen, pxtSetPenSource);
436
73.2M
        color_set_null(&xdev->saved_stroke_color.saved_dev_color);
437
73.2M
    }
438
73.6M
}
439
440
static void
441
pclxl_set_page_origin(stream * s, int x, int y)
442
138k
{
443
138k
    px_put_ssp(s, x, y);
444
138k
    px_put_ac(s, pxaPageOrigin, pxtSetPageOrigin);
445
138k
    return;
446
138k
}
447
448
static void
449
pclxl_set_page_scale(gx_device_pclxl * xdev, double x_scale, double y_scale)
450
24.6M
{
451
24.6M
    stream *s = pclxl_stream(xdev);
452
453
24.6M
    if (xdev->scaled) {
454
11.5M
        xdev->x_scale = x_scale;
455
11.5M
        xdev->y_scale = y_scale;
456
11.5M
        px_put_rp(s, x_scale, y_scale);
457
11.5M
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
458
11.5M
    }
459
24.6M
    return;
460
24.6M
}
461
462
static void
463
pclxl_unset_page_scale(gx_device_pclxl * xdev)
464
56.3M
{
465
56.3M
    stream *s = pclxl_stream(xdev);
466
467
56.3M
    if (xdev->scaled) {
468
11.5M
        px_put_rp(s, 1 / xdev->x_scale, 1 / xdev->y_scale);
469
11.5M
        px_put_ac(s, pxaPageScale, pxtSetPageScale);
470
11.5M
        xdev->scaled = false;
471
11.5M
        xdev->x_scale = 1;
472
11.5M
        xdev->y_scale = 1;
473
11.5M
    }
474
56.3M
    return;
475
56.3M
}
476
477
/* Set the cursor. */
478
static int
479
pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
480
18.5M
{
481
18.5M
    stream *s = pclxl_stream(xdev);
482
18.5M
    double x_scale = 1;
483
18.5M
    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
18.5M
    if (abs(x) > 0x7FFF) {
490
3.20M
        x_scale = ((double)abs(x)) / 0x7FFF;
491
3.20M
        x = (x > 0 ? 0x7FFF : -0x7FFF);
492
3.20M
        xdev->scaled = true;
493
3.20M
    }
494
18.5M
    if (abs(y) > 0x7FFF) {
495
2.75M
        y_scale = ((double)abs(y)) / 0x7FFF;
496
2.75M
        y = (y > 0 ? 0x7FFF : -0x7FFF);
497
2.75M
        xdev->scaled = true;
498
2.75M
    }
499
18.5M
    pclxl_set_page_scale(xdev, x_scale, y_scale);
500
18.5M
    px_put_ssp(s, x, y);
501
18.5M
    px_put_ac(s, pxaPoint, pxtSetCursor);
502
18.5M
    pclxl_unset_page_scale(xdev);
503
18.5M
    return 0;
504
18.5M
}
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
26.6M
{
512
26.6M
    px_put_uba(s, (byte) count, pxaNumberOfPoints);
513
26.6M
    px_put_uba(s, (byte) dtype, pxaPointType);
514
26.6M
}
515
static int
516
pclxl_flush_points(gx_device_pclxl * xdev)
517
61.0M
{
518
61.0M
    int count = xdev->points.count;
519
520
61.0M
    if (count) {
521
37.8M
        stream *s = pclxl_stream(xdev);
522
37.8M
        px_tag_t op;
523
37.8M
        int x = xdev->points.current.x, y = xdev->points.current.y;
524
37.8M
        int uor = 0, sor = 0;
525
37.8M
        pxeDataType_t data_type;
526
37.8M
        int i, di;
527
37.8M
        byte diffs[NUM_POINTS * 2];
528
37.8M
        double x_scale = 1;
529
37.8M
        double y_scale = 1;
530
37.8M
        int temp_origin_x = 0, temp_origin_y = 0;
531
37.8M
        int count_smalls = 0;
532
533
37.8M
        if (xdev->points.type != POINTS_NONE) {
534
248M
            for (i = 0; i < count; ++i) {
535
210M
                if ((abs(xdev->points.data[i].x) > 0x7FFF)
536
196M
                    || (abs(xdev->points.data[i].y) > 0x7FFF))
537
24.4M
                    xdev->scaled = true;
538
210M
                if ((abs(xdev->points.data[i].x) < 0x8000)
539
196M
                    && (abs(xdev->points.data[i].y) < 0x8000)) {
540
186M
                    if ((temp_origin_x != xdev->points.data[i].x)
541
162M
                        || (temp_origin_y != xdev->points.data[i].y)) {
542
162M
                        temp_origin_x = xdev->points.data[i].x;
543
162M
                        temp_origin_y = xdev->points.data[i].y;
544
162M
                        count_smalls++;
545
162M
                    }
546
186M
                }
547
210M
            }
548
37.8M
            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
6.12M
                if (count_smalls) {
555
69.4k
                    pclxl_set_page_origin(s, temp_origin_x, temp_origin_y);
556
69.4k
                }
557
31.0M
                for (i = 0; i < count; ++i) {
558
24.9M
                    x_scale = max(((double)
559
24.9M
                                   abs(xdev->points.data[i].x -
560
24.9M
                                       temp_origin_x)) / 0x7FFF, x_scale);
561
24.9M
                    y_scale = max(((double)
562
24.9M
                                   abs(xdev->points.data[i].y -
563
24.9M
                                       temp_origin_y)) / 0x7FFF, y_scale);
564
24.9M
                }
565
31.0M
                for (i = 0; i < count; ++i) {
566
24.9M
                    xdev->points.data[i].x =
567
24.9M
                        (int)((xdev->points.data[i].x -
568
24.9M
                               temp_origin_x) / x_scale + 0.5);
569
24.9M
                    xdev->points.data[i].y =
570
24.9M
                        (int)((xdev->points.data[i].y -
571
24.9M
                               temp_origin_y) / y_scale + 0.5);
572
24.9M
                }
573
6.12M
                x = (int)((x - temp_origin_x) / x_scale + 0.5);
574
6.12M
                y = (int)((y - temp_origin_y) / y_scale + 0.5);
575
6.12M
                pclxl_set_page_scale(xdev, x_scale, y_scale);
576
31.6M
            } else {
577
                /* don't reset origin if we did not scale */
578
31.6M
                count_smalls = 0;
579
31.6M
            }
580
37.8M
        }
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
37.8M
        switch (xdev->points.type) {
593
0
            case POINTS_NONE:
594
0
                return 0;
595
24.1M
            case POINTS_LINES:
596
24.1M
                op = pxtLinePath;
597
24.1M
                if (count < 3) {
598
25.8M
                    for (i = 0; i < count; ++i) {
599
14.7M
                        px_put_ssp(s, xdev->points.data[i].x,
600
14.7M
                                   xdev->points.data[i].y);
601
14.7M
                        px_put_a(s, pxaEndPoint);
602
14.7M
                        spputc(s, (byte) op);
603
14.7M
                    }
604
11.1M
                    pclxl_unset_page_scale(xdev);
605
11.1M
                    if (count_smalls)
606
18.1k
                        pclxl_set_page_origin(s, -temp_origin_x,
607
18.1k
                                              -temp_origin_y);
608
11.1M
                    goto zap;
609
11.1M
                }
610
                /* See if we can use byte values. */
611
60.6M
                for (i = di = 0; i < count; ++i, di += 2) {
612
47.6M
                    int dx = xdev->points.data[i].x - x;
613
47.6M
                    int dy = xdev->points.data[i].y - y;
614
615
47.6M
                    diffs[di] = (byte) dx;
616
47.6M
                    diffs[di + 1] = (byte) dy;
617
47.6M
                    uor |= dx | dy;
618
47.6M
                    sor |= (dx + 0x80) | (dy + 0x80);
619
47.6M
                    x += dx, y += dy;
620
47.6M
                }
621
12.9M
                if (!(uor & ~0xff))
622
2.70M
                    data_type = eUByte;
623
10.2M
                else if (!(sor & ~0xff))
624
8.64M
                    data_type = eSByte;
625
1.59M
                else
626
1.59M
                    break;
627
11.3M
                op = pxtLineRelPath;
628
                /* Use byte values. */
629
24.6M
              useb:px_put_np(s, count, data_type);
630
24.6M
                spputc(s, (byte) op);
631
24.6M
                px_put_data_length(s, count * 2);       /* 2 bytes per point */
632
24.6M
                px_put_bytes(s, diffs, count * 2);
633
24.6M
                pclxl_unset_page_scale(xdev);
634
24.6M
                if (count_smalls)
635
100
                    pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
636
24.6M
                goto zap;
637
13.6M
            case POINTS_CURVES:
638
13.6M
                op = pxtBezierPath;
639
                /* See if we can use byte values. */
640
63.0M
                for (i = di = 0; i < count; i += 3, di += 6) {
641
49.3M
                    int dx1 = xdev->points.data[i].x - x;
642
49.3M
                    int dy1 = xdev->points.data[i].y - y;
643
49.3M
                    int dx2 = xdev->points.data[i + 1].x - x;
644
49.3M
                    int dy2 = xdev->points.data[i + 1].y - y;
645
49.3M
                    int dx = xdev->points.data[i + 2].x - x;
646
49.3M
                    int dy = xdev->points.data[i + 2].y - y;
647
648
49.3M
                    diffs[di] = (byte) dx1;
649
49.3M
                    diffs[di + 1] = (byte) dy1;
650
49.3M
                    diffs[di + 2] = (byte) dx2;
651
49.3M
                    diffs[di + 3] = (byte) dy2;
652
49.3M
                    diffs[di + 4] = (byte) dx;
653
49.3M
                    diffs[di + 5] = (byte) dy;
654
49.3M
                    uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
655
49.3M
                    sor |= (dx1 + 0x80) | (dy1 + 0x80) |
656
49.3M
                        (dx2 + 0x80) | (dy2 + 0x80) |
657
49.3M
                        (dx + 0x80) | (dy + 0x80);
658
49.3M
                    x += dx, y += dy;
659
49.3M
                }
660
13.6M
                if (!(uor & ~0xff))
661
1.37M
                    data_type = eUByte;
662
12.3M
                else if (!(sor & ~0xff))
663
11.8M
                    data_type = eSByte;
664
449k
                else
665
449k
                    break;
666
13.2M
                op = pxtBezierRelPath;
667
13.2M
                goto useb;
668
0
            default:           /* can't happen */
669
0
                return_error(gs_error_unknownerror);
670
37.8M
        }
671
2.04M
        px_put_np(s, count, eSInt16);
672
2.04M
        spputc(s, (byte) op);
673
2.04M
        px_put_data_length(s, count * 4);       /* 2 UInt16s per point */
674
14.6M
        for (i = 0; i < count; ++i) {
675
12.6M
            px_put_s(s, xdev->points.data[i].x);
676
12.6M
            px_put_s(s, xdev->points.data[i].y);
677
12.6M
        }
678
2.04M
        pclxl_unset_page_scale(xdev);
679
2.04M
        if (count_smalls)
680
51.1k
            pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
681
37.8M
      zap:xdev->points.type = POINTS_NONE;
682
37.8M
        xdev->points.count = 0;
683
37.8M
    }
684
61.0M
    return 0;
685
61.0M
}
686
687
/* ------ Images ------ */
688
689
static image_enum_proc_plane_data(pclxl_image_plane_data);
690
static image_enum_proc_end_image(pclxl_image_end_image);
691
692
static const gx_image_enum_procs_t pclxl_image_enum_procs = {
693
    pclxl_image_plane_data, pclxl_image_end_image
694
};
695
696
/* Begin an image. */
697
static void
698
pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
699
                        uint dest_width, uint dest_height)
700
196k
{
701
196k
    stream *s = pclxl_stream(xdev);
702
703
196k
    px_put_usa(s, width, pxaSourceWidth);
704
196k
    px_put_usa(s, height, pxaSourceHeight);
705
196k
    px_put_usp(s, dest_width, dest_height);
706
196k
    px_put_ac(s, pxaDestinationSize, pxtBeginImage);
707
196k
}
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
196k
{
718
196k
    stream *s = pclxl_stream(xdev);
719
196k
    uint width_bytes = (width_bits + 7) >> 3;
720
196k
    uint num_bytes = ROUND_UP(width_bytes, 4) * height;
721
196k
    bool compress = num_bytes >= 8;
722
196k
    int i;
723
196k
    int code;
724
725
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
726
196k
    int offset = data_bit >> 3;
727
196k
    const byte *data = base + offset;
728
729
196k
    px_put_usa(s, y, pxaStartLine);
730
196k
    px_put_usa(s, height, pxaBlockHeight);
731
196k
    if (compress) {
732
196k
        stream_RLE_state rlstate;
733
196k
        stream_cursor_write w;
734
196k
        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
196k
        byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
744
196k
                                   "pclxl_write_image_data");
745
746
196k
        if (buf == 0)
747
0
            goto nc;
748
196k
        s_RLE_set_defaults_inline(&rlstate);
749
196k
        rlstate.EndOfData = false;
750
196k
        rlstate.omitEOD = true;
751
196k
        s_RLE_init_inline(&rlstate);
752
196k
        w.ptr = buf - 1;
753
196k
        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
22.0M
        for (i = 0; i < height; ++i) {
760
21.8M
            r.ptr = data + i * raster - 1;
761
21.8M
            r.limit = r.ptr + width_bytes;
762
21.8M
            if ((*s_RLE_template.process)
763
21.8M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
764
21.8M
                r.ptr != r.limit)
765
15.1k
                goto ncfree;
766
21.8M
            r.ptr = (const byte *)"\000\000\000\000\000";
767
21.8M
            r.limit = r.ptr + (-(int)width_bytes & 3);
768
21.8M
            if ((*s_RLE_template.process)
769
21.8M
                ((stream_state *) & rlstate, &r, &w, false) != 0 ||
770
21.8M
                r.ptr != r.limit)
771
14
                goto ncfree;
772
21.8M
        }
773
181k
        r.ptr = r.limit;
774
181k
        code = (*s_RLE_template.process)
775
181k
            ((stream_state *) & rlstate, &r, &w, true);
776
181k
        if (code != EOFC && code != 0)
777
46.0k
            goto ncfree;
778
135k
        {
779
135k
            uint count = w.ptr + 1 - buf;
780
781
135k
            px_put_ub(s, eRLECompression);
782
135k
            px_put_ac(s, pxaCompressMode, pxtReadImage);
783
135k
            px_put_data_length(s, count);
784
135k
            px_put_bytes(s, buf, count);
785
135k
        }
786
135k
        gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
787
135k
        return;
788
61.1k
      ncfree:gs_free_object(xdev->v_memory, buf,
789
61.1k
                       "pclxl_write_image_data");
790
61.1k
    }
791
61.1k
  nc:
792
    /* Write the data uncompressed. */
793
61.1k
    px_put_ub(s, eNoCompression);
794
61.1k
    px_put_ac(s, pxaCompressMode, pxtReadImage);
795
61.1k
    px_put_data_length(s, num_bytes);
796
11.9M
    for (i = 0; i < height; ++i) {
797
11.9M
        px_put_bytes(s, data + i * raster, width_bytes);
798
11.9M
        px_put_bytes(s, (const byte *)"\000\000\000\000",
799
11.9M
                     -(int)width_bytes & 3);
800
11.9M
    }
801
61.1k
}
802
803
static void
804
pclxl_write_image_data_JPEG(gx_device_pclxl * xdev, const byte * base,
805
                            int data_bit, uint raster, uint width_bits, int y,
806
                            int height)
807
0
{
808
0
    stream *s = pclxl_stream(xdev);
809
0
    uint width_bytes = (width_bits + 7) >> 3;
810
0
    int i;
811
0
    int count;
812
0
    int code;
813
814
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
815
0
    int offset = data_bit >> 3;
816
0
    const byte *data = base + offset;
817
0
    jpeg_compress_data *jcdp =
818
0
        gs_alloc_struct_immovable(xdev->v_memory, jpeg_compress_data,
819
0
                                  &st_jpeg_compress_data,
820
0
                                  "pclxl_write_image_data_JPEG(jpeg_compress_data)");
821
0
    stream_DCT_state state;
822
0
    stream_cursor_read r;
823
0
    stream_cursor_write w;
824
825
    /* Approx. The worse case is ~ header + width_bytes * height.
826
       Apparently minimal SOI/DHT/DQT/SOS/EOI is 341 bytes. TO CHECK. */
827
0
    size_t buffersize = 341 + width_bytes * height;
828
829
0
    byte *buf = gs_alloc_bytes(xdev->v_memory, buffersize,
830
0
                               "pclxl_write_image_data_JPEG(buf)");
831
832
    /* RLE can write uncompressed without extra-allocation */
833
0
    if ((buf == 0) || (jcdp == 0)) {
834
0
        goto failed_so_use_rle_instead;
835
0
    }
836
    /* Create the DCT encoder state. */
837
0
    jcdp->templat = s_DCTE_template;
838
0
    s_init_state((stream_state *) & state, &jcdp->templat, 0);
839
0
    if (state.templat->set_defaults) {
840
0
        state.memory = xdev->v_memory;
841
0
        (*state.templat->set_defaults) ((stream_state *) & state);
842
0
        state.memory = NULL;
843
0
    }
844
0
    state.ColorTransform = (xdev->color_info.num_components == 3 ? 1 : 0);
845
0
    state.data.compress = jcdp;
846
0
    state.icc_profile = NULL;
847
    /* state.memory needs set for creation..... */
848
0
    state.memory = jcdp->memory = state.jpeg_memory = xdev->v_memory;
849
0
    if ((code = gs_jpeg_create_compress(&state)) < 0)
850
0
        goto cleanup_and_use_rle;
851
    /* .... and NULL after, so we don't try to free the stack based "state" */
852
0
    state.memory = NULL;
853
    /* image-specific info */
854
0
    jcdp->cinfo.image_width = width_bytes / xdev->color_info.num_components;
855
0
    jcdp->cinfo.image_height = height;
856
0
    switch (xdev->color_info.num_components) {
857
0
        case 3:
858
0
            jcdp->cinfo.input_components = 3;
859
0
            jcdp->cinfo.in_color_space = JCS_RGB;
860
0
            break;
861
0
        case 1:
862
0
            jcdp->cinfo.input_components = 1;
863
0
            jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
864
0
            break;
865
0
        default:
866
0
            goto cleanup_and_use_rle;
867
0
            break;
868
0
    }
869
    /* Set compression parameters. */
870
0
    if ((code = gs_jpeg_set_defaults(&state)) < 0)
871
0
        goto cleanup_and_use_rle;
872
873
0
    if (state.templat->init)
874
0
        (*state.templat->init) ((stream_state *) & state);
875
0
    state.scan_line_size = jcdp->cinfo.input_components *
876
0
        jcdp->cinfo.image_width;
877
0
    jcdp->templat.min_in_size =
878
0
        max(s_DCTE_template.min_in_size, state.scan_line_size);
879
0
    jcdp->templat.min_out_size =
880
0
        max(s_DCTE_template.min_out_size, state.Markers.size);
881
882
0
    w.ptr = buf - 1;
883
0
    w.limit = w.ptr + buffersize;
884
0
    for (i = 0; i < height; ++i) {
885
0
        r.ptr = data + i * raster - 1;
886
0
        r.limit = r.ptr + width_bytes;
887
0
        if (((code = (*state.templat->process)
888
0
              ((stream_state *) & state, &r, &w, false)) != 0 && code != EOFC)
889
0
            || r.ptr != r.limit)
890
0
            goto cleanup_and_use_rle;
891
0
    }
892
0
    count = w.ptr + 1 - buf;
893
0
    px_put_usa(s, y, pxaStartLine);
894
0
    px_put_usa(s, height, pxaBlockHeight);
895
0
    px_put_ub(s, eJPEGCompression);
896
0
    px_put_ac(s, pxaCompressMode, pxtReadImage);
897
0
    px_put_data_length(s, count);
898
0
    px_put_bytes(s, buf, count);
899
900
0
    gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data_JPEG(buf)");
901
0
    if (jcdp)
902
0
        gs_jpeg_destroy(&state);        /* frees *jcdp */
903
0
    return;
904
905
0
  cleanup_and_use_rle:
906
    /* cleans up - something went wrong after allocation */
907
0
    gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data_JPEG(buf)");
908
0
    if (jcdp)
909
0
        gs_jpeg_destroy(&state);        /* frees *jcdp */
910
    /* fall through to redo in RLE */
911
0
  failed_so_use_rle_instead:
912
    /* the RLE routine can write without new allocation - use as fallback. */
913
0
    pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits, y,
914
0
                               height);
915
0
    return;
916
0
}
917
918
/* DeltaRow compression (also called "mode 3"):
919
   drawn heavily from gdevcljc.c:cljc_print_page(),
920
   This is simplier since PCL XL does not allow
921
   compression mix-and-match.
922
923
   Worse case of RLE is + 1/128, but worse case of DeltaRow is + 1/8
924
 */
925
static void
926
pclxl_write_image_data_DeltaRow(gx_device_pclxl * xdev, const byte * base,
927
                                int data_bit, uint raster, uint width_bits,
928
                                int y, int height)
929
0
{
930
0
    stream *s = pclxl_stream(xdev);
931
0
    uint width_bytes = (width_bits + 7) >> 3;
932
0
    int worst_case_comp_size = width_bytes + (width_bytes / 8) + 1;
933
0
    byte *cdata = 0;
934
0
    byte *prow = 0;
935
0
    int i;
936
0
    int count;
937
938
    /* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
939
0
    int offset = data_bit >> 3;
940
0
    const byte *data = base + offset;
941
942
    /* allocate the worst case scenario; PCL XL has an extra 2 byte per row compared to PCL5 */
943
0
    byte *buf =
944
0
        gs_alloc_bytes(xdev->v_memory, (worst_case_comp_size + 2) * (size_t)height,
945
0
                       "pclxl_write_image_data_DeltaRow(buf)");
946
947
0
    prow =
948
0
        gs_alloc_bytes(xdev->v_memory, width_bytes,
949
0
                       "pclxl_write_image_data_DeltaRow(prow)");
950
    /* the RLE routine can write uncompressed without extra-allocation */
951
0
    if ((buf == 0) || (prow == 0)) {
952
0
        pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
953
0
                                   y, height);
954
0
        return;
955
0
    }
956
    /* initialize the seed row */
957
0
    memset(prow, 0, width_bytes);
958
0
    cdata = buf;
959
0
    for (i = 0; i < height; i++) {
960
0
        int compressed_size =
961
0
            gdev_pcl_mode3compress(width_bytes, data + i * raster, prow,
962
0
                                   cdata + 2);
963
964
        /* PCL XL prepends row data with byte count */
965
0
        *cdata = compressed_size & 0xff;
966
0
        *(cdata + 1) = compressed_size >> 8;
967
0
        cdata += compressed_size + 2;
968
0
    }
969
0
    px_put_usa(s, y, pxaStartLine);
970
0
    px_put_usa(s, height, pxaBlockHeight);
971
0
    px_put_ub(s, eDeltaRowCompression);
972
0
    px_put_ac(s, pxaCompressMode, pxtReadImage);
973
0
    count = cdata - buf;
974
0
    px_put_data_length(s, count);
975
0
    px_put_bytes(s, buf, count);
976
977
0
    gs_free_object(xdev->v_memory, buf,
978
0
                   "pclxl_write_image_data_DeltaRow(buf)");
979
0
    gs_free_object(xdev->v_memory, prow,
980
0
                   "pclxl_write_image_data_DeltaRow(prow)");
981
0
    return;
982
0
}
983
984
/* calling from copy_mono/copy_color/fill_mask should never do lossy compression */
985
static void
986
pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data,
987
                       int data_bit, uint raster, uint width_bits, int y,
988
                       int height, bool allow_lossy)
989
196k
{
990
    /* If we only have 1 line, it does not make sense to do JPEG/DeltaRow */
991
196k
    if (height < 2) {
992
103
        pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
993
103
                                   y, height);
994
103
        return;
995
103
    }
996
997
196k
    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
196k
        default:
1013
196k
            pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
1014
196k
                                       width_bits, y, height);
1015
196k
            break;
1016
196k
    }
1017
196k
}
1018
1019
/* End an image. */
1020
static void
1021
pclxl_write_end_image(gx_device_pclxl * xdev)
1022
196k
{
1023
196k
    spputc(xdev->strm, pxtEndImage);
1024
196k
}
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.35M
{
1032
1.35M
    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.35M
    } else {
1037
1.35M
        spputc(s, pxt_ubyte_array);
1038
1.35M
        px_put_u(s, len);
1039
1.35M
        px_put_bytes(s, data, len);
1040
1.35M
    }
1041
1.35M
}
1042
1043
/* Write a 16-bit big-endian value. */
1044
static void
1045
px_put_us_be(stream * s, uint i)
1046
16.5k
{
1047
16.5k
    spputc(s, (byte) (i >> 8));
1048
16.5k
    spputc(s, (byte) i);
1049
16.5k
}
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
131
{
1056
131
    stream *s = pclxl_stream(xdev);
1057
1058
131
    static const byte bfh_[] = {
1059
131
        DA(pxaFontName), DUB(0), DA(pxaFontFormat),
1060
131
        pxtBeginFontHeader,
1061
131
        DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
1062
131
        pxtReadFontHeader,
1063
131
        pxt_dataLengthByte, 8 + 6 + 4 + 6,
1064
131
        0, 0, 0, 0,
1065
131
        254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
1066
131
        'B', 'R', 0, 0, 0, 4
1067
131
    };
1068
131
    static const byte efh_[] = {
1069
131
        0xff, 0xff, 0, 0, 0, 0,
1070
131
        pxtEndFontHeader
1071
131
    };
1072
1073
131
    PX_PUT_LIT(s, bfh_);
1074
131
    px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
1075
131
    px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
1076
131
    PX_PUT_LIT(s, efh_);
1077
131
}
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
441
{
1084
441
    stream *s = pclxl_stream(xdev);
1085
1086
441
    static const byte sf_[] = {
1087
441
        DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
1088
441
        pxtSetFont
1089
441
    };
1090
1091
441
    PX_PUT_LIT(s, sf_);
1092
441
}
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
8.12k
{
1101
8.12k
    stream *s = pclxl_stream(xdev);
1102
8.12k
    uint width_bytes = (width_bits + 7) >> 3;
1103
8.12k
    uint size = 10 + width_bytes * height;
1104
8.12k
    uint i;
1105
1106
8.12k
    px_put_ac(s, pxaFontName, pxtBeginChar);
1107
8.12k
    px_put_u(s, ccode);
1108
8.12k
    px_put_a(s, pxaCharCode);
1109
8.12k
    if (size > 0xffff) {
1110
0
        spputc(s, pxt_uint32);
1111
0
        px_put_l(s, (ulong) size);
1112
0
    } else
1113
8.12k
        px_put_us(s, size);
1114
8.12k
    px_put_ac(s, pxaCharDataSize, pxtReadChar);
1115
8.12k
    px_put_data_length(s, size);
1116
8.12k
    px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
1117
8.12k
    px_put_us_be(s, width_bits);
1118
8.12k
    px_put_us_be(s, height);
1119
138k
    for (i = 0; i < height; ++i)
1120
130k
        px_put_bytes(s, data + i * raster, width_bytes);
1121
8.12k
    spputc(s, pxtEndChar);
1122
8.12k
}
1123
1124
/* Write the name of the only font we define. */
1125
static void
1126
pclxl_write_font_name(gx_device_pclxl * xdev)
1127
8.69k
{
1128
8.69k
    stream *s = pclxl_stream(xdev);
1129
1130
8.69k
    px_put_string(s, (const byte *)"@", 1, false);
1131
8.69k
}
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.35M
{
1138
1.35M
    int i, i_empty = -1;
1139
1.35M
    uint ccode;
1140
1141
1.35M
    for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
1142
1.44M
         i = (i == 0 ? countof(xdev->chars.table) : i) - 1) {
1143
1.44M
        ccode = xdev->chars.table[i];
1144
1.44M
        if (ccode == 0)
1145
16.2k
            return (i_empty >= 0 ? i_empty : i);
1146
1.42M
        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.42M
        } else if (xdev->chars.data[ccode].id == id)
1152
1.34M
            return i;
1153
1.44M
    }
1154
1.35M
}
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.35M
{
1186
1.35M
    uint width_bytes = (w + 7) >> 3;
1187
1.35M
    uint size = width_bytes * h;
1188
1.35M
    int index;
1189
1.35M
    uint ccode;
1190
1.35M
    stream *s = pclxl_stream(xdev);
1191
1192
1.35M
    if (size > MAX_CHAR_SIZE)
1193
0
        return -1;
1194
1.35M
    index = pclxl_char_index(xdev, id);
1195
1.35M
    if ((ccode = xdev->chars.table[index]) < 2) {
1196
        /* Enter the character in the table. */
1197
8.12k
        while (xdev->chars.used + size > MAX_CHAR_DATA ||
1198
8.12k
               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
8.12k
        index = pclxl_char_index(xdev, id);
1206
8.12k
        ccode = xdev->chars.next_in;
1207
8.12k
        xdev->chars.data[ccode].id = id;
1208
8.12k
        xdev->chars.data[ccode].size = size;
1209
8.12k
        xdev->chars.table[index] = ccode;
1210
8.12k
        xdev->chars.next_in = (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1211
8.12k
        if (!xdev->chars.count++) {
1212
            /* This is the very first character. */
1213
131
            pclxl_write_font_name(xdev);
1214
131
            pclxl_define_bitmap_font(xdev);
1215
131
        }
1216
8.12k
        xdev->chars.used += size;
1217
8.12k
        pclxl_write_font_name(xdev);
1218
8.12k
        pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
1219
8.12k
    }
1220
1.35M
    if (!xdev->font_set) {
1221
441
        pclxl_write_font_name(xdev);
1222
441
        pclxl_set_font(xdev);
1223
441
        xdev->font_set = true;
1224
441
    }
1225
1.35M
    {
1226
1.35M
        byte cc_bytes[2];
1227
1228
1.35M
        cc_bytes[0] = (byte) ccode;
1229
1.35M
        cc_bytes[1] = ccode >> 8;
1230
1.35M
        px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
1231
1.35M
    }
1232
1.35M
    px_put_ac(s, pxaTextData, pxtText);
1233
1.35M
    return 0;
1234
1.35M
}
1235
1236
/* ---------------- Vector implementation procedures ---------------- */
1237
1238
static int
1239
pclxl_beginpage(gx_device_vector * vdev)
1240
26.6k
{
1241
26.6k
    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
26.6k
    stream *s = vdev->strm;
1248
26.6k
    byte media_source = eAutoSelect;    /* default */
1249
1250
26.6k
    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
26.6k
    px_write_page_header(s, (const gx_device *)vdev);
1259
1260
26.6k
    if (xdev->ManualFeed_set && xdev->ManualFeed)
1261
0
        media_source = 2;
1262
26.6k
    else if (xdev->MediaPosition_set && xdev->MediaPosition >= 0)
1263
26.6k
        media_source = xdev->MediaPosition;
1264
1265
26.6k
    px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size,
1266
26.6k
                          &media_source,
1267
26.6k
                          xdev->page, xdev->Duplex, xdev->Tumble,
1268
26.6k
                          xdev->MediaType_set, xdev->MediaType);
1269
1270
26.6k
    spputc(s, pxtBeginPage);
1271
26.6k
    return 0;
1272
26.6k
}
1273
1274
static int
1275
pclxl_setlinewidth(gx_device_vector * vdev, double width)
1276
18.7k
{
1277
18.7k
    stream *s = gdev_vector_stream(vdev);
1278
1279
18.7k
    px_put_us(s, (uint) (width + 0.5));
1280
18.7k
    px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
1281
18.7k
    return 0;
1282
18.7k
}
1283
1284
static int
1285
pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
1286
8.31k
{
1287
8.31k
    stream *s = gdev_vector_stream(vdev);
1288
1289
    /* The PCL XL cap styles just happen to be identical to PostScript. */
1290
8.31k
    px_put_ub(s, (byte) cap);
1291
8.31k
    px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
1292
8.31k
    return 0;
1293
8.31k
}
1294
1295
static int
1296
pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
1297
15.0k
{
1298
15.0k
    stream *s = gdev_vector_stream(vdev);
1299
1300
15.0k
    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
15.0k
    px_put_ub(s, (byte) join);
1307
15.0k
    px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
1308
15.0k
    return 0;
1309
15.0k
}
1310
1311
static int
1312
pclxl_setmiterlimit(gx_device_vector * vdev, double limit)
1313
732
{
1314
732
    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
732
    int i_limit = (int)(limit + 0.5);
1321
1322
732
    px_put_u(s, max(i_limit, 1));
1323
732
    px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
1324
732
    return 0;
1325
732
}
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
1.84k
#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
2.69k
{
1339
2.69k
    stream *s = gdev_vector_stream(vdev);
1340
1341
2.69k
    if (count == 0) {
1342
852
        static const byte nac_[] = {
1343
852
            DUB(0), DA(pxaSolidLine)
1344
852
        };
1345
1346
852
        PX_PUT_LIT(s, nac_);
1347
1.84k
    } else if (count > MAX_DASH_ELEMENTS)
1348
0
        return_error(gs_error_limitcheck);
1349
1.84k
    else {
1350
1.84k
        uint i;
1351
1.84k
        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
5.35k
        for (i = 0; i < count; ++i)
1359
3.50k
            pattern_length += (uint) (pattern[i]);
1360
1.84k
        if (pattern_length == 0)
1361
576
            return_error(gs_error_rangecheck);
1362
1363
1.26k
        spputc(s, pxt_uint16_array);
1364
1.26k
        px_put_ub(s, (byte) count);
1365
3.62k
        for (i = 0; i < count; ++i)
1366
2.35k
            px_put_s(s, (uint) pattern[i]);
1367
1.26k
        px_put_a(s, pxaLineDashStyle);
1368
1.26k
        if (offset != 0)
1369
5
            px_put_usa(s, (uint) offset, pxaDashOffset);
1370
1.26k
    }
1371
2.11k
    spputc(s, pxtSetLineDash);
1372
2.11k
    return 0;
1373
2.69k
}
1374
1375
static int
1376
pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
1377
               gs_logical_operation_t diff)
1378
648k
{
1379
648k
    stream *s = gdev_vector_stream(vdev);
1380
1381
648k
    if (diff & lop_S_transparent) {
1382
6.78k
        px_put_ub(s, (byte) (lop & lop_S_transparent ? 1 : 0));
1383
6.78k
        px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
1384
6.78k
    }
1385
648k
    if (diff & lop_T_transparent) {
1386
830
        px_put_ub(s, (byte) (lop & lop_T_transparent ? 1 : 0));
1387
830
        px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
1388
830
    }
1389
648k
    if (lop_rop(diff)) {
1390
642k
        px_put_ub(s, (byte) lop_rop(lop));
1391
642k
        px_put_ac(s, pxaROP3, pxtSetROP);
1392
642k
    }
1393
648k
    return 0;
1394
648k
}
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
75.5M
{
1400
75.5M
    return false;
1401
75.5M
}
1402
1403
static int
1404
pclxl_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs,
1405
                   const gx_drawing_color * pdc)
1406
38.8M
{
1407
38.8M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1408
1409
38.8M
    return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
1410
38.8M
}
1411
1412
static int
1413
pclxl_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs,
1414
                     const gx_drawing_color * pdc)
1415
163k
{
1416
163k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1417
1418
163k
    return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
1419
163k
}
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
58.9M
{
1425
58.9M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1426
58.9M
    stream *s = gdev_vector_stream(vdev);
1427
1428
    /* Check for out-of-range points. */
1429
411M
#define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
1430
58.9M
    if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
1431
58.6M
        OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
1432
58.9M
        )
1433
277k
        return_error(gs_error_rangecheck);
1434
58.6M
#undef OUT_OF_RANGE
1435
58.6M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1436
58.5M
        pclxl_set_paints(xdev, type);
1437
58.5M
        px_put_usq_fixed(s, x0, y0, x1, y1);
1438
58.5M
        px_put_ac(s, pxaBoundingBox, pxtRectangle);
1439
58.5M
    }
1440
58.6M
    if (type & gx_path_type_clip) {
1441
70.9k
        static const byte cr_[] = {
1442
70.9k
            DA(pxaBoundingBox),
1443
70.9k
            DUB(eInterior), DA(pxaClipRegion),
1444
70.9k
            pxtSetClipRectangle
1445
70.9k
        };
1446
1447
70.9k
        px_put_usq_fixed(s, x0, y0, x1, y1);
1448
70.9k
        PX_PUT_LIT(s, cr_);
1449
70.9k
    }
1450
58.6M
    return 0;
1451
58.9M
}
1452
1453
static int
1454
pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
1455
15.8M
{
1456
15.8M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1457
15.8M
    stream *s = gdev_vector_stream(vdev);
1458
1459
15.8M
    spputc(s, pxtNewPath);
1460
15.8M
    xdev->points.type = POINTS_NONE;
1461
15.8M
    xdev->points.count = 0;
1462
15.8M
    return 0;
1463
15.8M
}
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
17.0M
{
1469
17.0M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1470
17.0M
    int code = pclxl_flush_points(xdev);
1471
1472
17.0M
    if (code < 0)
1473
0
        return code;
1474
17.0M
    return pclxl_set_cursor(xdev,
1475
17.0M
                            xdev->points.current.x = (int)(x + 0.5),
1476
17.0M
                            xdev->points.current.y = (int)(y + 0.5));
1477
17.0M
}
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
62.3M
{
1483
62.3M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1484
1485
62.3M
    if (xdev->points.type != POINTS_LINES || xdev->points.count >= NUM_POINTS - 2) {
1486
24.1M
        if (xdev->points.type != POINTS_NONE) {
1487
10.9M
            int code = pclxl_flush_points(xdev);
1488
1489
10.9M
            if (code < 0)
1490
0
                return code;
1491
10.9M
        }
1492
24.1M
        xdev->points.current.x = (int)(x0 + 0.5);
1493
24.1M
        xdev->points.current.y = (int)(y0 + 0.5);
1494
24.1M
        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
24.1M
        if (xdev->points.count >= NUM_POINTS - 1)
1500
0
            xdev->points.count--;
1501
24.1M
    }
1502
62.3M
    {
1503
62.3M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
1504
1505
62.3M
        ppt->x = (int)(x + 0.5), ppt->y = (int)(y + 0.5);
1506
62.3M
    }
1507
62.3M
    return 0;
1508
62.3M
}
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
49.3M
{
1515
49.3M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1516
1517
49.3M
    if (xdev->points.type != POINTS_CURVES ||
1518
36.0M
        xdev->points.count >= NUM_POINTS - 4) {
1519
13.6M
        if (xdev->points.type != POINTS_NONE) {
1520
9.92M
            int code = pclxl_flush_points(xdev);
1521
1522
9.92M
            if (code < 0)
1523
0
                return code;
1524
9.92M
        }
1525
13.6M
        xdev->points.current.x = (int)(x0 + 0.5);
1526
13.6M
        xdev->points.current.y = (int)(y0 + 0.5);
1527
13.6M
        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
13.6M
        if (xdev->points.count >= NUM_POINTS - 3)
1533
0
            xdev->points.count -= 3;
1534
13.6M
    }
1535
49.3M
    {
1536
49.3M
        gs_int_point *ppt = &xdev->points.data[xdev->points.count];
1537
1538
49.3M
        ppt->x = (int)(x1 + 0.5), ppt->y = (int)(y1 + 0.5), ++ppt;
1539
49.3M
        ppt->x = (int)(x2 + 0.5), ppt->y = (int)(y2 + 0.5), ++ppt;
1540
49.3M
        ppt->x = (int)(x3 + 0.5), ppt->y = (int)(y3 + 0.5);
1541
49.3M
    }
1542
49.3M
    xdev->points.count += 3;
1543
49.3M
    return 0;
1544
49.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
7.30M
{
1550
7.30M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1551
7.30M
    stream *s = gdev_vector_stream(vdev);
1552
7.30M
    int code = pclxl_flush_points(xdev);
1553
1554
7.30M
    if (code < 0)
1555
0
        return code;
1556
7.30M
    spputc(s, pxtCloseSubPath);
1557
7.30M
    xdev->points.current.x = (int)(x_start + 0.5);
1558
7.30M
    xdev->points.current.y = (int)(y_start + 0.5);
1559
7.30M
    return 0;
1560
7.30M
}
1561
1562
static int
1563
pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
1564
15.8M
{
1565
15.8M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) vdev;
1566
15.8M
    stream *s = gdev_vector_stream(vdev);
1567
15.8M
    int code = pclxl_flush_points(xdev);
1568
15.8M
    gx_path_type_t rule = type & gx_path_type_rule;
1569
1570
15.8M
    if (code < 0)
1571
0
        return code;
1572
15.8M
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1573
15.1M
        if (rule != xdev->fill_rule) {
1574
11.4k
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1575
11.4k
                                 eNonZeroWinding));
1576
11.4k
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
1577
11.4k
            xdev->fill_rule = rule;
1578
11.4k
        }
1579
15.1M
        pclxl_set_paints(xdev, type);
1580
15.1M
        spputc(s, pxtPaintPath);
1581
15.1M
    }
1582
15.8M
    if (type & gx_path_type_clip) {
1583
774k
        static const byte scr_[] = {
1584
774k
            DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
1585
774k
        };
1586
1587
774k
        if (rule != xdev->clip_rule) {
1588
406
            px_put_ub(s, (byte) (rule == gx_path_type_even_odd ? eEvenOdd :
1589
406
                                 eNonZeroWinding));
1590
406
            px_put_ac(s, pxaClipMode, pxtSetClipMode);
1591
406
            xdev->clip_rule = rule;
1592
406
        }
1593
774k
        PX_PUT_LIT(s, scr_);
1594
774k
    }
1595
15.8M
    return 0;
1596
15.8M
}
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
27.7k
{
1634
27.7k
    gx_device_vector *vdev = (gx_device_vector *) dev;
1635
27.7k
    gx_device_pclxl *xdev = (gx_device_pclxl *) dev;
1636
27.7k
    int code;
1637
1638
27.7k
    vdev->v_memory = dev->memory->stable_memory;
1639
27.7k
    vdev->vec_procs = &pclxl_vector_procs;
1640
27.7k
    code = gdev_vector_open_file_options(vdev, 512,
1641
27.7k
                                         VECTOR_OPEN_FILE_SEQUENTIAL);
1642
27.7k
    if (code < 0)
1643
0
        return code;
1644
1645
27.7k
    while (dev->child)
1646
0
        dev = dev->child;
1647
27.7k
    vdev = (gx_device_vector *) dev;
1648
27.7k
    xdev = (gx_device_pclxl *) dev;
1649
1650
27.7k
    pclxl_page_init(xdev);
1651
27.7k
    px_write_file_header(vdev->strm, dev, xdev->Staple);
1652
27.7k
    xdev->media_size = pxeMediaSize_next;       /* no size selected */
1653
27.7k
    memset(&xdev->chars, 0, sizeof(xdev->chars));
1654
27.7k
    xdev->chars.next_in = xdev->chars.next_out = 2;
1655
    /* xdev->iccTransform = false; *//* set true/false here to ignore command line */
1656
27.7k
    return 0;
1657
27.7k
}
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
25.1k
{
1664
25.1k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1665
25.1k
    stream *s;
1666
25.1k
    int code;
1667
1668
    /* Note that unlike close_device, end_page must not omit blank pages. */
1669
25.1k
    if (!xdev->in_page)
1670
0
        pclxl_beginpage((gx_device_vector *) dev);
1671
25.1k
    s = xdev->strm;
1672
25.1k
    px_put_usa(s, (uint) num_copies, pxaPageCopies);    /* num_copies */
1673
25.1k
    spputc(s, pxtEndPage);
1674
25.1k
    sflush(s);
1675
25.1k
    pclxl_page_init(xdev);
1676
25.1k
    if (gp_ferror(xdev->file))
1677
0
        return_error(gs_error_ioerror);
1678
25.1k
    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
25.1k
    if (gx_outputfile_is_separate_pages
1682
25.1k
        (((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
25.1k
    return code;
1688
25.1k
}
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
27.7k
{
1696
27.7k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1697
27.7k
    gp_file *file = xdev->file;
1698
1699
27.7k
    if (xdev->strm != NULL)
1700
27.7k
        sflush(xdev->strm);
1701
27.7k
    if (xdev->in_page)
1702
1.47k
        gp_fputc(pxtEndPage, file);
1703
27.7k
    px_write_file_trailer(file);
1704
27.7k
    return gdev_vector_close_file((gx_device_vector *) dev);
1705
27.7k
}
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
183k
{
1719
183k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1720
183k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1721
183k
    int code;
1722
183k
    stream *s;
1723
183k
    gx_color_index color0 = zero, color1 = one;
1724
183k
    gx_color_index white = ((gx_color_index)1 << dev->color_info.depth) - 1;
1725
183k
    gx_color_index black = 0;
1726
183k
    gs_logical_operation_t lop;
1727
183k
    byte palette[2 * 3];
1728
183k
    int palette_size;
1729
183k
    pxeColorSpace_t color_space;
1730
1731
183k
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1732
183k
    code = gdev_vector_update_clip_path(vdev, NULL);
1733
183k
    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
183k
    if (((data_x & 7) != 0) || (h == 1) || (w == 1))
1741
176k
        return gx_default_copy_mono(dev, data, data_x, raster, id,
1742
176k
                                    x, y, w, h, zero, one);
1743
1744
6.63k
    pclxl_set_cursor(xdev, x, y);
1745
6.63k
    if (id != gs_no_id && zero == gx_no_color_index &&
1746
3.20k
        one != gx_no_color_index && data_x == 0) {
1747
3.20k
        gx_drawing_color dcolor;
1748
1749
3.20k
        code = gdev_vector_update_log_op(vdev, rop3_T | lop_T_transparent);
1750
3.20k
        if (code < 0)
1751
0
            return 0;
1752
1753
3.20k
        set_nonclient_dev_color(&dcolor, one);
1754
3.20k
        pclxl_setfillcolor(vdev, NULL, &dcolor);
1755
3.20k
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1756
3.20k
            return 0;
1757
3.20k
    }
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
3.43k
    if (zero == gx_no_color_index) {
1784
2.79k
        if (one == gx_no_color_index)
1785
0
            return 0;
1786
2.79k
        if (one != white) {
1787
2.70k
            if (one == black) {
1788
1.66k
                lop = (rop3_S & rop3_D);
1789
1.66k
            } else {
1790
1.03k
                lop = rop3_S | lop_S_transparent;
1791
1.03k
            }
1792
2.70k
            color0 = white;
1793
2.70k
        } else {
1794
91
            lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1795
91
            color0 = black;
1796
91
        }
1797
2.79k
    } 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
636
    } else {
1810
636
        lop = rop3_S;
1811
636
    }
1812
1813
3.43k
    if (dev->color_info.num_components == 1 ||
1814
1.99k
        (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
1815
3.43k
        ) {
1816
2.77k
        palette[0] = (byte) color0;
1817
2.77k
        palette[1] = (byte) color1;
1818
2.77k
        palette_size = 2;
1819
2.77k
        color_space = eGray;
1820
2.77k
        if_debug2m('b', dev->memory, "color palette %02X %02X\n",
1821
2.77k
                   palette[0], palette[1]);
1822
2.77k
    } else {
1823
660
        palette[0] = (byte) (color0 >> 16);
1824
660
        palette[1] = (byte) (color0 >> 8);
1825
660
        palette[2] = (byte) color0;
1826
660
        palette[3] = (byte) (color1 >> 16);
1827
660
        palette[4] = (byte) (color1 >> 8);
1828
660
        palette[5] = (byte) color1;
1829
660
        palette_size = 6;
1830
660
        color_space = eRGB;
1831
660
    }
1832
3.43k
    code = gdev_vector_update_log_op(vdev, lop);
1833
3.43k
    if (code < 0)
1834
0
        return 0;
1835
3.43k
    pclxl_set_color_palette(xdev, color_space, palette, palette_size);
1836
3.43k
    s = pclxl_stream(xdev);
1837
3.43k
    {
1838
3.43k
        static const byte mi_[] = {
1839
3.43k
            DUB(e1Bit), DA(pxaColorDepth),
1840
3.43k
            DUB(eIndexedPixel), DA(pxaColorMapping)
1841
3.43k
        };
1842
1843
3.43k
        PX_PUT_LIT(s, mi_);
1844
3.43k
    }
1845
3.43k
    pclxl_write_begin_image(xdev, w, h, w, h);
1846
3.43k
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1847
3.43k
    pclxl_write_end_image(xdev);
1848
3.43k
    return 0;
1849
3.43k
}
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
667k
{
1857
667k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1858
667k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1859
667k
    stream *s;
1860
667k
    uint source_bit;
1861
667k
    int code;
1862
1863
667k
    fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
1864
667k
    code = gdev_vector_update_clip_path(vdev, NULL);
1865
667k
    if (code < 0)
1866
0
        return code;
1867
1868
667k
    source_bit = sourcex * dev->color_info.depth;
1869
1870
    /* side-effect from fill/stroke may have set color space to eGray */
1871
667k
    if (dev->color_info.num_components == 3)
1872
294k
        pclxl_set_color_space(xdev, eRGB);
1873
373k
    else if (dev->color_info.num_components == 1)
1874
373k
        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
667k
    if (((source_bit & 7) != 0) || (w == 1) || (h == 1))
1889
654k
        return gx_default_copy_color(dev, base, sourcex, raster, id,
1890
654k
                                     x, y, w, h);
1891
13.2k
    code = gdev_vector_update_log_op(vdev, rop3_S);
1892
13.2k
    if (code < 0)
1893
0
        return 0;
1894
13.2k
    pclxl_set_cursor(xdev, x, y);
1895
13.2k
    s = pclxl_stream(xdev);
1896
13.2k
    {
1897
13.2k
        static const byte ci_[] = {
1898
13.2k
            DA(pxaColorDepth),
1899
13.2k
            DUB(eDirectPixel), DA(pxaColorMapping)
1900
13.2k
        };
1901
1902
13.2k
        px_put_ub(s, eBit_values[dev->color_info.depth /
1903
13.2k
                                 dev->color_info.num_components]);
1904
13.2k
        PX_PUT_LIT(s, ci_);
1905
13.2k
    }
1906
13.2k
    pclxl_write_begin_image(xdev, w, h, w, h);
1907
13.2k
    pclxl_write_image_data(xdev, base, source_bit, raster,
1908
13.2k
                           w * dev->color_info.depth, 0, h, false);
1909
13.2k
    pclxl_write_end_image(xdev);
1910
13.2k
    return 0;
1911
13.2k
}
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.50M
{
1921
1.50M
    gx_device_vector *const vdev = (gx_device_vector *) dev;
1922
1.50M
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
1923
1.50M
    int code;
1924
1.50M
    stream *s;
1925
1.50M
    gx_color_index foreground;
1926
1927
1.50M
    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.35M
    if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 || (w == 1)
1933
1.35M
        || (h == 1))
1934
4.21k
        return gx_default_fill_mask(dev, data, data_x, raster, id, x, y, w, h,
1935
4.21k
                                    pdcolor, depth, lop, pcpath);
1936
1.34M
    code = gdev_vector_update_clip_path(vdev, pcpath);
1937
1.34M
    foreground = gx_dc_pure_color(pdcolor);
1938
1.34M
    if (code < 0)
1939
0
        return code;
1940
1.34M
    code = gdev_vector_update_fill_color(vdev, NULL, pdcolor);
1941
1.34M
    if (code < 0)
1942
0
        return 0;
1943
1.34M
    pclxl_set_cursor(xdev, x, y);
1944
1.34M
    if (id != gs_no_id && data_x == 0) {
1945
1.34M
        code = gdev_vector_update_log_op(vdev, lop);
1946
1.34M
        if (code < 0)
1947
0
            return 0;
1948
1.34M
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1949
1.34M
            return 0;
1950
1.34M
    }
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
223k
#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
304k
{
2038
304k
    gx_device_vector *const vdev = (gx_device_vector *) dev;
2039
304k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) dev;
2040
304k
    const gs_image_t *pim = (const gs_image_t *)pic;
2041
304k
    const gs_color_space *pcs;
2042
304k
    pclxl_image_enum_t *pie;
2043
304k
    byte *row_data;
2044
304k
    int num_rows;
2045
304k
    uint row_raster;
2046
304k
    int bits_per_pixel;
2047
304k
    gs_matrix mat;
2048
304k
    int code;
2049
2050
    /* We only cope with image type 1 here. */
2051
304k
    if (pic->type->index != 1)
2052
119
        goto use_default;
2053
2054
304k
    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
304k
    bits_per_pixel =
2060
304k
        (pim->ImageMask ? 1 :
2061
304k
         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
304k
    code = gs_matrix_invert(&pim->ImageMatrix, &mat);
2068
304k
    if (code < 0)
2069
5
        goto use_default;
2070
304k
    if (pmat == NULL)
2071
304k
        pmat = &ctm_only(pgs);
2072
304k
    gs_matrix_multiply(&mat, pmat, &mat);
2073
2074
304k
    if (pclxl_nontrivial_transfer(pgs))
2075
16
        goto use_default;
2076
2077
304k
    if (pim->Width == 0 || pim->Height == 0)
2078
18
        goto use_default;
2079
2080
304k
    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
255
        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
255
        if (pim->Decode[0] != 0 || pim->Decode[1] != 1 ||
2095
255
            pim->Decode[2] != 0 || pim->Decode[3] != 1 ||
2096
255
            pim->Decode[4] != 0 || pim->Decode[5] != 1)
2097
0
            goto use_default;
2098
255
    }
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
304k
    if ((!((mat.xx * mat.yy != 0) && (mat.xy == 0) && (mat.yx == 0)) &&
2109
114k
         !((mat.xx == 0) && (mat.yy == 0) && (mat.xy * mat.yx != 0))) ||
2110
226k
        (pim->ImageMask ?
2111
217k
         (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
2112
226k
         ((!pclxl_can_handle_color_space(pcs) ||
2113
6.72k
           (bits_per_pixel != 1 && bits_per_pixel != 4 &&
2114
6.31k
            bits_per_pixel != 8 && bits_per_pixel != 24 &&
2115
306
            bits_per_pixel != 32))
2116
1.83k
          && !(pclxl_can_icctransform(pim) && xdev->iccTransform))) ||
2117
223k
        pim->format != gs_image_format_chunky || pim->Interpolate || prect)
2118
80.2k
        goto use_default;
2119
223k
    row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
2120
223k
    num_rows = MAX_ROW_DATA / row_raster;
2121
223k
    if (num_rows > pim->Height)
2122
220k
        num_rows = pim->Height;
2123
223k
    if (num_rows <= 0)
2124
2
        num_rows = 1;
2125
223k
    pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
2126
223k
                          "pclxl_begin_image");
2127
223k
    row_data = gs_alloc_bytes(mem, (size_t)num_rows * row_raster,
2128
223k
                              "pclxl_begin_image(rows)");
2129
223k
    if (pie == 0 || row_data == 0) {
2130
1
        code = gs_note_error(gs_error_VMerror);
2131
1
        goto fail;
2132
1
    }
2133
223k
    code = gdev_vector_begin_image(vdev, pgs, pim, pim->format, prect,
2134
223k
                                   pdcolor, pcpath, mem,
2135
223k
                                   &pclxl_image_enum_procs,
2136
223k
                                   (gdev_vector_image_enum_t *) pie);
2137
223k
    if (code < 0)
2138
0
        goto fail;
2139
2140
    /* emit a PXL XL rotation and adjust mat correspondingly */
2141
223k
    pie->flipped = false;
2142
223k
    if (mat.xx * mat.yy > 0) {
2143
187k
        if (mat.xx < 0) {
2144
14.0k
            stream *s = pclxl_stream(xdev);
2145
2146
14.0k
            mat.xx = -mat.xx;
2147
14.0k
            mat.yy = -mat.yy;
2148
14.0k
            mat.tx = -mat.tx;
2149
14.0k
            mat.ty = -mat.ty;
2150
14.0k
            px_put_ss(s, 180);
2151
14.0k
            xdev->state_rotated = 2;
2152
14.0k
            px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2153
14.0k
        }
2154
        /* leave the matrix alone if it is portrait */
2155
187k
    } else if (mat.xx * mat.yy < 0) {
2156
367
        pie->flipped = true;
2157
367
        if (mat.xx < 0) {
2158
15
            stream *s = pclxl_stream(xdev);
2159
2160
15
            mat.xx = -mat.xx;
2161
15
            mat.tx = -mat.tx;
2162
15
            px_put_ss(s, +180);
2163
15
            xdev->state_rotated = +2;
2164
15
            px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2165
352
        } else {
2166
352
            mat.yy = -mat.yy;
2167
352
            mat.ty = -mat.ty;
2168
352
        }
2169
35.9k
    } else if (mat.xy * mat.yx < 0) {
2170
        /* rotate +90 or -90 */
2171
35.8k
        float tmpf;
2172
35.8k
        stream *s = pclxl_stream(xdev);
2173
2174
35.8k
        if (mat.xy > 0) {
2175
40
            mat.xx = mat.xy;
2176
40
            mat.yy = -mat.yx;
2177
40
            tmpf = mat.tx;
2178
40
            mat.tx = mat.ty;
2179
40
            mat.ty = -tmpf;
2180
40
            px_put_ss(s, -90);
2181
40
            xdev->state_rotated = -1;
2182
35.7k
        } else {
2183
35.7k
            mat.xx = -mat.xy;
2184
35.7k
            mat.yy = mat.yx;
2185
35.7k
            tmpf = mat.tx;
2186
35.7k
            mat.tx = -mat.ty;
2187
35.7k
            mat.ty = tmpf;
2188
35.7k
            px_put_ss(s, +90);
2189
35.7k
            xdev->state_rotated = +1;
2190
35.7k
        }
2191
35.8k
        mat.xy = mat.yx = 0;
2192
35.8k
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2193
35.8k
    } else if (mat.xy * mat.yx > 0) {
2194
139
        float tmpf;
2195
139
        stream *s = pclxl_stream(xdev);
2196
2197
139
        pie->flipped = true;
2198
139
        if (mat.xy > 0) {
2199
71
            mat.xx = mat.xy;
2200
71
            mat.yy = mat.yx;
2201
71
            tmpf = mat.tx;
2202
71
            mat.tx = mat.ty;
2203
71
            mat.ty = tmpf;
2204
71
            px_put_ss(s, -90);
2205
71
            xdev->state_rotated = -1;
2206
71
        } else {
2207
68
            mat.xx = -mat.xy;
2208
68
            mat.yy = -mat.yx;
2209
68
            tmpf = mat.tx;
2210
68
            mat.tx = -mat.ty;
2211
68
            mat.ty = -tmpf;
2212
68
            px_put_ss(s, +90);
2213
68
            xdev->state_rotated = +1;
2214
68
        }
2215
139
        mat.xy = mat.yx = 0;
2216
139
        px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2217
139
    }
2218
2219
223k
    pie->mat = mat;
2220
223k
    pie->rows.data = row_data;
2221
223k
    pie->rows.num_rows = num_rows;
2222
223k
    pie->rows.first_y = 0;
2223
223k
    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
223k
    if (!pim->ImageMask && (!pclxl_can_handle_color_space(pcs)
2246
6.66k
                            || (bits_per_pixel == 32 && dev->icc_struct
2247
254
                                && !dev->icc_struct->usefastcolor))
2248
254
        && pclxl_can_icctransform(pim) && pcs->cmm_icc_profile_data) {
2249
254
        gsicc_rendering_param_t rendering_params;
2250
2251
254
        rendering_params.black_point_comp = pgs->blackptcomp;
2252
254
        rendering_params.graphics_type_tag = GS_IMAGE_TAG;
2253
254
        rendering_params.rendering_intent = pgs->renderingintent;
2254
254
        pie->icclink = gsicc_get_link(pgs, dev, pcs, NULL /*des */ ,
2255
254
                                      &rendering_params, pgs->memory);
2256
254
    } else
2257
223k
        pie->icclink = NULL;
2258
223k
    *pinfo = (gx_image_enum_common_t *) pie;
2259
223k
    {
2260
223k
        gs_logical_operation_t lop = pgs->log_op;
2261
2262
223k
        if (pim->ImageMask) {
2263
217k
            const byte *palette = (const byte *)
2264
217k
                (pim->Decode[0] ? "\377\000" : "\000\377");
2265
217k
            gx_color_index foreground = gx_dc_pure_color(pdcolor);
2266
2267
217k
            code = gdev_vector_update_fill_color(vdev, NULL,    /* use process color */
2268
217k
                                                 pdcolor);
2269
217k
            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
217k
            if (foreground == ((gx_color_index)1 << dev->color_info.depth) - 1) {       /* white */
2275
294
                lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
2276
217k
            } else if (foreground == 0) {       /* black */
2277
214k
                lop = (rop3_S & rop3_D);
2278
214k
            } else
2279
2.96k
                lop |= rop3_S | lop_S_transparent;
2280
2281
217k
            code = gdev_vector_update_log_op(vdev, lop);
2282
217k
            if (code < 0)
2283
0
                goto fail;
2284
217k
            pclxl_set_color_palette(xdev, eGray, palette, 2);
2285
217k
        } else {
2286
6.66k
            if (bits_per_pixel == 24 || bits_per_pixel == 32) {
2287
4.62k
                code = gdev_vector_update_log_op
2288
4.62k
                    (vdev,
2289
4.62k
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2290
4.62k
                if (code < 0)
2291
0
                    goto fail;
2292
4.62k
                if (dev->color_info.num_components == 1) {
2293
1.17k
                    pclxl_set_color_space(xdev, eGray);
2294
3.44k
                } else {
2295
3.44k
                    pclxl_set_color_space(xdev, eRGB);
2296
3.44k
                }
2297
4.62k
            } else {
2298
2.04k
                int bpc = pim->BitsPerComponent;
2299
2.04k
                int num_components =
2300
2.04k
                    pie->plane_depths[0] * pie->num_planes / bpc;
2301
2.04k
                int sample_max = (1 << bpc) - 1;
2302
2.04k
                byte palette[256 * 3];
2303
2.04k
                int i;
2304
2305
2.04k
                code = gdev_vector_update_log_op
2306
2.04k
                    (vdev,
2307
2.04k
                     (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2308
2.04k
                if (code < 0)
2309
0
                    goto fail;
2310
420k
                for (i = 0; i < 1 << bits_per_pixel; ++i) {
2311
418k
                    gs_client_color cc;
2312
418k
                    gx_device_color devc;
2313
418k
                    int cv = i, j;
2314
418k
                    gx_color_index ci;
2315
2316
837k
                    for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
2317
418k
                        cc.paint.values[j] = pim->Decode[j * 2] +
2318
418k
                            (cv & sample_max) *
2319
418k
                            (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
2320
418k
                            sample_max;
2321
418k
                    (*pcs->type->remap_color)
2322
418k
                        (&cc, pcs, &devc, pgs, dev, gs_color_select_source);
2323
418k
                    if (!gx_dc_is_pure(&devc))
2324
0
                        return_error(gs_error_Fatal);
2325
418k
                    ci = gx_dc_pure_color(&devc);
2326
418k
                    if (dev->color_info.num_components == 1) {
2327
383k
                        palette[i] = (byte) ci;
2328
383k
                    } else {
2329
35.5k
                        byte *ppal = &palette[i * 3];
2330
2331
35.5k
                        ppal[0] = (byte) (ci >> 16);
2332
35.5k
                        ppal[1] = (byte) (ci >> 8);
2333
35.5k
                        ppal[2] = (byte) ci;
2334
35.5k
                    }
2335
418k
                }
2336
2.04k
                if (dev->color_info.num_components == 1)
2337
1.65k
                    pclxl_set_color_palette(xdev, eGray, palette,
2338
1.65k
                                            1 << bits_per_pixel);
2339
393
                else
2340
393
                    pclxl_set_color_palette(xdev, eRGB, palette,
2341
393
                                            3 << bits_per_pixel);
2342
2.04k
            }
2343
6.66k
        }
2344
223k
    }
2345
223k
    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
80.4k
  use_default:
2350
80.4k
    if (dev->color_info.num_components == 1)
2351
38.3k
        pclxl_set_color_space(xdev, eGray);
2352
42.0k
    else
2353
42.0k
        pclxl_set_color_space(xdev, eRGB);
2354
80.4k
    return gx_default_begin_typed_image(dev, pgs, pmat, pic, prect,
2355
80.4k
                                        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
551k
{
2362
551k
    return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
2363
551k
                 ((const gx_device_pclxl *)pie->dev)->scale.x);
2364
551k
}
2365
static int
2366
image_transform_y(const pclxl_image_enum_t * pie, int sy)
2367
551k
{
2368
551k
    return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
2369
551k
                 ((const gx_device_pclxl *)pie->dev)->scale.y);
2370
551k
}
2371
2372
static int
2373
pclxl_image_write_rows(pclxl_image_enum_t * pie)
2374
275k
{
2375
275k
    gx_device_pclxl *const xdev = (gx_device_pclxl *) pie->dev;
2376
275k
    stream *s = pclxl_stream(xdev);
2377
275k
    int y = pie->rows.first_y;
2378
275k
    int h = pie->y - y;
2379
275k
    int xo = image_transform_x(pie, 0);
2380
275k
    int yo = image_transform_y(pie, y);
2381
275k
    int dw = image_transform_x(pie, pie->width) - xo;
2382
275k
    int dh = image_transform_y(pie, y + h) - yo;
2383
275k
    int rows_raster = pie->rows.raster;
2384
275k
    int offset_lastflippedstrip = 0;
2385
2386
275k
    if (pie->flipped) {
2387
498
        yo = -yo - dh;
2388
498
        if (!pie->icclink)
2389
498
            offset_lastflippedstrip =
2390
498
                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
498
    };
2396
2397
275k
    if (dw <= 0 || dh <= 0)
2398
96.0k
        return 0;
2399
179k
    pclxl_set_cursor(xdev, xo, yo);
2400
179k
    if (pie->bits_per_pixel == 24) {
2401
45.4k
        static const byte ci_[] = {
2402
45.4k
            DA(pxaColorDepth),
2403
45.4k
            DUB(eDirectPixel), DA(pxaColorMapping)
2404
45.4k
        };
2405
2406
45.4k
        px_put_ub(s, eBit_values[8]);
2407
45.4k
        PX_PUT_LIT(s, ci_);
2408
45.4k
        if (xdev->color_info.depth == 8) {
2409
2.15k
            rows_raster /= 3;
2410
2.15k
            if (!pie->icclink) {
2411
2.15k
                byte *in = pie->rows.data + offset_lastflippedstrip;
2412
2.15k
                byte *out = pie->rows.data + offset_lastflippedstrip;
2413
2.15k
                int i;
2414
2.15k
                int j;
2415
2416
184k
                for (j = 0; j < h; j++) {
2417
225M
                    for (i = 0; i < rows_raster; i++) {
2418
225M
                        *out =
2419
225M
                            (byte) (((*(in + 0) * (ulong) lum_red_weight) +
2420
225M
                                     (*(in + 1) * (ulong) lum_green_weight) +
2421
225M
                                     (*(in + 2) * (ulong) lum_blue_weight) +
2422
225M
                                     (lum_all_weights / 2)) /
2423
225M
                                    lum_all_weights);
2424
225M
                        in += 3;
2425
225M
                        out++;
2426
225M
                    }
2427
182k
                }
2428
2.15k
            }
2429
2.15k
        }
2430
134k
    } else if (pie->bits_per_pixel == 32) {
2431
393
        static const byte ci_[] = {
2432
393
            DA(pxaColorDepth),
2433
393
            DUB(eDirectPixel), DA(pxaColorMapping)
2434
393
        };
2435
2436
393
        px_put_ub(s, eBit_values[8]);
2437
393
        PX_PUT_LIT(s, ci_);
2438
393
        if (xdev->color_info.depth == 8) {
2439
            /* CMYK to Gray */
2440
199
            rows_raster /= 4;
2441
199
            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
199
        } else {
2464
            /* CMYK to RGB */
2465
194
            rows_raster /= 4;
2466
194
            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
194
            rows_raster *= 3;
2491
194
        }
2492
133k
    } else {
2493
133k
        static const byte ii_[] = {
2494
133k
            DA(pxaColorDepth),
2495
133k
            DUB(eIndexedPixel), DA(pxaColorMapping)
2496
133k
        };
2497
133k
        px_put_ub(s, eBit_values[pie->bits_per_pixel]);
2498
133k
        PX_PUT_LIT(s, ii_);
2499
133k
    }
2500
179k
    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
179k
    pclxl_write_image_data(xdev, pie->rows.data + offset_lastflippedstrip, 0,
2504
179k
                           rows_raster, rows_raster << 3, 0, h,
2505
179k
                           ((pie->bits_per_pixel == 24
2506
134k
                             || pie->bits_per_pixel == 32) ? true : false));
2507
179k
    pclxl_write_end_image(xdev);
2508
179k
    return 0;
2509
275k
}
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
19.0M
{
2517
19.0M
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2518
19.0M
    int data_bit = planes[0].data_x * info->plane_depths[0];
2519
19.0M
    int width_bits = pie->width * info->plane_depths[0];
2520
19.0M
    int i;
2521
2522
    /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
2523
19.0M
    if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
2524
48
        return_error(gs_error_rangecheck);
2525
19.0M
    if (height > pie->height - pie->y)
2526
143k
        height = pie->height - pie->y;
2527
42.0M
    for (i = 0; i < height; pie->y++, ++i) {
2528
22.9M
        int flipped_strip_offset;
2529
2530
22.9M
        if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
2531
52.6k
            int code = pclxl_image_write_rows(pie);
2532
2533
52.6k
            if (code < 0)
2534
0
                return code;
2535
52.6k
            pie->rows.first_y = pie->y;
2536
52.6k
        }
2537
22.9M
        flipped_strip_offset = (pie->flipped ?
2538
11.1k
                                (pie->rows.num_rows -
2539
11.1k
                                 (pie->y - pie->rows.first_y) -
2540
22.9M
                                 1) : (pie->y - pie->rows.first_y));
2541
22.9M
        if (!pie->icclink)
2542
22.8M
            memcpy(pie->rows.data +
2543
22.8M
                   pie->rows.raster * flipped_strip_offset,
2544
22.8M
                   planes[0].data + planes[0].raster * i + (data_bit >> 3),
2545
22.8M
                   pie->rows.raster);
2546
68.4k
        else {
2547
68.4k
            gsicc_bufferdesc_t input_buff_desc;
2548
68.4k
            gsicc_bufferdesc_t output_buff_desc;
2549
68.4k
            int pixels_per_row =
2550
68.4k
                pie->rows.raster / (pie->bits_per_pixel >> 3);
2551
68.4k
            int out_raster_stride =
2552
68.4k
                pixels_per_row * info->dev->color_info.num_components;
2553
68.4k
            gsicc_init_buffer(&input_buff_desc,
2554
68.4k
                              (pie->bits_per_pixel >> 3) /*num_chan */ ,
2555
68.4k
                              1 /*bytes_per_chan */ ,
2556
68.4k
                              false /*has_alpha */ , false /*alpha_first */ ,
2557
68.4k
                              false /*is_planar */ ,
2558
68.4k
                              0 /*plane_stride */ ,
2559
68.4k
                              pie->rows.raster /*row_stride */ ,
2560
68.4k
                              1 /*num_rows */ ,
2561
68.4k
                              pixels_per_row /*pixels_per_row */ );
2562
68.4k
            gsicc_init_buffer(&output_buff_desc,
2563
68.4k
                              info->dev->color_info.num_components, 1, false,
2564
68.4k
                              false, false, 0, out_raster_stride, 1,
2565
68.4k
                              pixels_per_row);
2566
68.4k
            gscms_transform_color_buffer(info->dev, pie->icclink,
2567
68.4k
                                         &input_buff_desc, &output_buff_desc,
2568
68.4k
                                         (void *)(planes[0].data +
2569
68.4k
                                                  planes[0].raster * i +
2570
68.4k
                                                  (data_bit >> 3)) /*src */ ,
2571
68.4k
                                         pie->rows.data + out_raster_stride * flipped_strip_offset      /*des */
2572
68.4k
                                         );
2573
68.4k
        }
2574
22.9M
    }
2575
19.0M
    *rows_used = height;
2576
19.0M
    return pie->y >= pie->height;
2577
19.0M
}
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
223k
{
2583
223k
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2584
223k
    int code = 0;
2585
2586
    /* Write the final strip, if any. */
2587
223k
    if (pie->y > pie->rows.first_y && draw_last)
2588
223k
        code = pclxl_image_write_rows(pie);
2589
223k
    if (draw_last) {
2590
223k
        gx_device_pclxl *xdev = (gx_device_pclxl *) info->dev;
2591
223k
        stream *s = pclxl_stream(xdev);
2592
2593
223k
        switch (xdev->state_rotated) {
2594
35.8k
            case 1:
2595
35.8k
                xdev->state_rotated = 0;
2596
35.8k
                px_put_ss(s, -90);
2597
35.8k
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2598
35.8k
                break;
2599
111
            case -1:
2600
111
                xdev->state_rotated = 0;
2601
111
                px_put_ss(s, +90);
2602
111
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2603
111
                break;
2604
14.0k
            case 2:
2605
14.0k
                xdev->state_rotated = 0;
2606
14.0k
                px_put_ss(s, -180);
2607
14.0k
                px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2608
14.0k
                break;
2609
173k
            case 0:
2610
173k
            default:
2611
                /* do nothing */
2612
173k
                break;
2613
223k
        }
2614
223k
    }
2615
223k
    if (pie->icclink)
2616
254
        gsicc_release_link(pie->icclink);
2617
223k
    gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
2618
223k
    gx_image_free_enum(&info);
2619
223k
    return code;
2620
223k
}
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
433k
{                               /* I - Parameter list */
2630
433k
    gx_device_pclxl *xdev;      /* PCL XL device */
2631
433k
    int code;                   /* Return code */
2632
433k
    gs_param_string s;          /* Temporary string value */
2633
2634
    /*
2635
     * First process the "standard" page device parameters...
2636
     */
2637
2638
433k
    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
433k
    xdev = (gx_device_pclxl *) dev;
2646
2647
433k
    if ((code = param_write_bool(plist, "Duplex", &(xdev->Duplex))) < 0)
2648
0
        return (code);
2649
2650
433k
    if ((code = param_write_bool(plist, "ManualFeed",
2651
433k
         &(xdev->ManualFeed))) < 0)
2652
0
        return (code);
2653
2654
433k
    if ((code = param_write_int(plist, "MediaPosition",
2655
433k
        &(xdev->MediaPosition))) < 0)
2656
0
        return (code);
2657
2658
433k
    param_string_from_string(s, xdev->MediaType);
2659
2660
433k
    if ((code = param_write_string(plist, "MediaType", &s)) < 0)
2661
0
        return (code);
2662
2663
433k
    if ((code = param_write_bool(plist, "Staple", &(xdev->Staple))) < 0)
2664
0
        return (code);
2665
2666
433k
    if ((code = param_write_bool(plist, "Tumble", &(xdev->Tumble))) < 0)
2667
0
        return (code);
2668
2669
433k
    if ((code = param_write_int(plist, "CompressMode",
2670
433k
                                &(xdev->CompressMode))) < 0)
2671
0
        return (code);
2672
2673
433k
    if ((code =
2674
433k
         param_write_bool(plist, "iccTransform", &(xdev->iccTransform))) < 0)
2675
0
        return (code);
2676
2677
433k
    return (0);
2678
433k
}
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
205k
{                               /* I - Parameter list */
2688
205k
    gx_device_pclxl *xdev;      /* PCL XL device */
2689
205k
    int code;                   /* Error code */
2690
205k
    int intval;                 /* Integer value */
2691
205k
    bool boolval;               /* Boolean value */
2692
205k
    gs_param_string stringval;  /* String value */
2693
205k
    bool ManualFeed;
2694
205k
    bool ManualFeed_set = false;
2695
205k
    int MediaPosition;
2696
205k
    bool MediaPosition_set = false;
2697
2698
    /*
2699
     * Process PCL-XL driver parameters...
2700
     */
2701
2702
205k
    xdev = (gx_device_pclxl *) dev;
2703
2704
205k
#define intoption(name, sname, type) \
2705
205k
  if ((code = param_read_int(plist, sname, &intval)) < 0) \
2706
205k
  { \
2707
0
    if_debug1('|', "Error setting %s\n", sname); \
2708
0
    param_signal_error(plist, sname, code); \
2709
0
    return (code); \
2710
0
  } \
2711
205k
  else if (code == 0) \
2712
205k
  { \
2713
18.3k
    if_debug2('|', "setting %s to %d\n", sname, intval); \
2714
18.3k
    xdev->name = (type)intval; \
2715
18.3k
  }
2716
2717
205k
#define booloption(name, sname) \
2718
820k
  if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
2719
820k
  { \
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
820k
  else if (code == 0) {                                   \
2731
73.5k
    if_debug2('|', "setting %s to %d\n", sname, boolval); \
2732
73.5k
    xdev->name = (bool)boolval; \
2733
73.5k
  }
2734
2735
205k
#define stringoption(name, sname)                                \
2736
205k
  if ((code = param_read_string(plist, sname, &stringval)) < 0)  \
2737
205k
    {                                                            \
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
205k
  else if (code == 0) {                                          \
2751
18.3k
    strncpy(xdev->name, (const char *)(stringval.data),          \
2752
18.3k
            stringval.size);                                     \
2753
18.3k
    xdev->name[stringval.size] = '\0';                           \
2754
18.3k
    if_debug2('|', "setting %s to %s\n", sname, xdev->name);     \
2755
18.3k
  }
2756
2757
    /* We need to have *_set to distinguish defaults from explicitly sets */
2758
205k
    booloption(Duplex, "Duplex");
2759
205k
    if (code == 0)
2760
18.3k
        if (xdev->Duplex) {
2761
0
            if_debug0('|', "round up page count\n");
2762
0
            xdev->page = (xdev->page + 1) & ~1;
2763
0
        }
2764
205k
    code = param_read_bool(plist, "ManualFeed", &ManualFeed);
2765
205k
    if (code == 0)
2766
18.3k
        ManualFeed_set = true;
2767
205k
    if (code >= 0) {
2768
205k
        code = param_read_int(plist, "MediaPosition", &MediaPosition);
2769
205k
        if (code == 0)
2770
46.1k
            MediaPosition_set = true;
2771
159k
        else if (code < 0) {
2772
0
            if (param_read_null(plist, "MediaPosition") == 0) {
2773
0
                code = 0;
2774
0
            }
2775
0
        }
2776
205k
    }
2777
205k
    stringoption(MediaType, "MediaType");
2778
205k
    if (code == 0) {
2779
18.3k
        xdev->MediaType_set = true;
2780
        /* round up for duplex */
2781
18.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
18.3k
    }
2787
205k
    booloption(Staple, "Staple");
2788
205k
    booloption(Tumble, "Tumble");
2789
205k
    intoption(CompressMode, "CompressMode", int);
2790
2791
205k
    booloption(iccTransform, "iccTransform");
2792
2793
    /*
2794
     * Then process standard page device parameters...
2795
     */
2796
2797
205k
    if (code >= 0)
2798
205k
        if ((code = gdev_vector_put_params(dev, plist)) < 0)
2799
409
            return (code);
2800
2801
204k
    if (code >= 0) {
2802
204k
        if (ManualFeed_set) {
2803
18.3k
            xdev->ManualFeed = ManualFeed;
2804
18.3k
            xdev->ManualFeed_set = true;
2805
18.3k
        }
2806
204k
        if (MediaPosition_set) {
2807
46.1k
            xdev->MediaPosition = MediaPosition;
2808
46.1k
            xdev->MediaPosition_set = true;
2809
46.1k
            if (xdev->MediaPosition_old != xdev->MediaPosition) {
2810
27.7k
                if_debug0('|', "round up page count\n");
2811
27.7k
                xdev->page = (xdev->page+1) & ~1 ;
2812
27.7k
                xdev->MediaPosition_old = xdev->MediaPosition;
2813
27.7k
            }
2814
46.1k
        }
2815
204k
    }
2816
2817
204k
    return (0);
2818
205k
}
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.82M
{
2825
2.82M
    font->dir->ccache.upper = 0;
2826
2.82M
    return gx_default_text_begin(dev, pgs, text, font, pcpath, ppte);
2827
2.82M
}