~ubuntu-branches/ubuntu/utopic/ghostscript/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/1002_pxl-make-dicctransform-default.patch/devices/vector/gdevpx.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2014-03-31 18:24:33 UTC
  • Revision ID: package-import@ubuntu.com-20140331182433-h4hi1ud2b70gu2jj
Tags: 9.10~dfsg-0ubuntu10
* debian/patches/1001_pxlcolor-support-jpeg-in-output.patch,
  debian/patches/020140331-4b44b41-pxlcolor-support-jpeg-in-output.patch:
  Replaced preliminary patch by what got actually committed upstream
  (Upstream bug #691880).
* debian/patches/020140331-41ab485-pxl-transform-deep-images-with-icc-transform-to-emit-high-level-images.patch,
  debian/patches/020140331-8ae4ee2-fixes-pxl-segfault-with-trying-to-set-up-icc-transform-for-bitmasks.patch:
  Transform deep (24-bit) images with an ICC transform to emit high-level
  images (Upstream bug #691880).
* debian/patches/1002_pxl-make-dicctransform-default.patch: Make deep iamge
  ICC transform default (Upstream bug #695124).

Show diffs side-by-side

added added

removed removed

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