~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gdevpx.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 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, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: gdevpx.c 9239 2008-11-24 19:15:04Z till $ */
 
15
/* H-P PCL XL driver */
 
16
#include "math_.h"
 
17
#include "memory_.h"
 
18
#include "string_.h"
 
19
#include "gx.h"
 
20
#include "gserrors.h"
 
21
#include "gsccolor.h"
 
22
#include "gsdcolor.h"
 
23
#include "gxiparam.h"
 
24
#include "gxcspace.h"           /* for color mapping for images */
 
25
#include "gxdevice.h"
 
26
#include "gxpath.h"
 
27
#include "gdevvec.h"
 
28
#include "strimpl.h"
 
29
#include "srlx.h"
 
30
#include "gdevpxat.h"
 
31
#include "gdevpxen.h"
 
32
#include "gdevpxop.h"
 
33
#include "gdevpxut.h"
 
34
#include "gxlum.h"
 
35
 
 
36
 
 
37
/* ---------------- Device definition ---------------- */
 
38
 
 
39
/* Define the default resolution. */
 
40
#ifndef X_DPI
 
41
#  define X_DPI 600
 
42
#endif
 
43
#ifndef Y_DPI
 
44
#  define Y_DPI 600
 
45
#endif
 
46
 
 
47
/* Structure definition */
 
48
#define NUM_POINTS 40           /* must be >= 3 and <= 255 */
 
49
typedef enum {
 
50
    POINTS_NONE,
 
51
    POINTS_LINES,
 
52
    POINTS_CURVES
 
53
} point_type_t;
 
54
typedef struct gx_device_pclxl_s {
 
55
    gx_device_vector_common;
 
56
    /* Additional state information */
 
57
    pxeMediaSize_t media_size;
 
58
    bool ManualFeed;            /* map ps setpage commands to pxl */
 
59
    bool ManualFeed_set;         
 
60
    int MediaPosition;          /* MediaPosition attribute */
 
61
    int MediaPosition_set;
 
62
    int page;                   /* Page number starting at 0 */
 
63
    bool Duplex;                /* Duplex attribute */
 
64
    bool Tumble;                /* Tumble attribute */
 
65
    gx_path_type_t fill_rule;   /* ...winding_number or ...even_odd  */
 
66
    gx_path_type_t clip_rule;   /* ditto */
 
67
    pxeColorSpace_t color_space;
 
68
    struct pal_ {
 
69
        int size;               /* # of bytes */
 
70
        byte data[256 * 3];     /* up to 8-bit samples */
 
71
    } palette;
 
72
    struct pts_ {               /* buffer for accumulating path points */
 
73
        gs_int_point current;   /* current point as of start of data */
 
74
        point_type_t type;
 
75
        int count;
 
76
        gs_int_point data[NUM_POINTS];
 
77
    } points;
 
78
    struct ch_ {                /* cache for downloaded characters */
 
79
#define MAX_CACHED_CHARS 400
 
80
#define MAX_CHAR_DATA 500000
 
81
#define MAX_CHAR_SIZE 5000
 
82
#define CHAR_HASH_FACTOR 247
 
83
        ushort table[MAX_CACHED_CHARS * 3 / 2];
 
84
        struct cd_ {
 
85
            gs_id id;           /* key */
 
86
            uint size;
 
87
        } data[MAX_CACHED_CHARS];
 
88
        int next_in;            /* next data element to fill in */
 
89
        int next_out;           /* next data element to discard */
 
90
        int count;              /* of occupied data elements */
 
91
        ulong used;
 
92
    } chars;
 
93
    bool font_set;
 
94
} gx_device_pclxl;
 
95
 
 
96
gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
 
97
                               "gx_device_pclxl",
 
98
                               device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
 
99
                               gx_device_finalize, st_device_vector);
 
100
 
 
101
#define pclxl_device_body(dname, depth)\
 
102
  std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
 
103
                           DEFAULT_WIDTH_10THS * X_DPI / 10,\
 
104
                           DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
 
105
                           X_DPI, Y_DPI,\
 
106
                           (depth > 8 ? 3 : 1), depth,\
 
107
                           (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
 
108
                           (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
 
109
 
 
110
/* Driver procedures */
 
111
static dev_proc_open_device(pclxl_open_device);
 
112
static dev_proc_output_page(pclxl_output_page);
 
113
static dev_proc_close_device(pclxl_close_device);
 
114
static dev_proc_copy_mono(pclxl_copy_mono);
 
115
static dev_proc_copy_color(pclxl_copy_color);
 
116
static dev_proc_fill_mask(pclxl_fill_mask);
 
117
 
 
118
static dev_proc_get_params(pclxl_get_params);
 
119
static dev_proc_put_params(pclxl_put_params);
 
120
 
 
121
/*static dev_proc_draw_thin_line(pclxl_draw_thin_line); */
 
122
static dev_proc_begin_image(pclxl_begin_image);
 
123
static dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
 
124
 
 
125
#define pclxl_device_procs(map_rgb_color, map_color_rgb)\
 
126
{\
 
127
        pclxl_open_device,\
 
128
        NULL,                   /* get_initial_matrix */\
 
129
        NULL,                   /* sync_output */\
 
130
        pclxl_output_page,\
 
131
        pclxl_close_device,\
 
132
        map_rgb_color,          /* differs */\
 
133
        map_color_rgb,          /* differs */\
 
134
        gdev_vector_fill_rectangle,\
 
135
        NULL,                   /* tile_rectangle */\
 
136
        pclxl_copy_mono,\
 
137
        pclxl_copy_color,\
 
138
        NULL,                   /* draw_line */\
 
139
        NULL,                   /* get_bits */\
 
140
        pclxl_get_params,\
 
141
        pclxl_put_params,\
 
142
        NULL,                   /* map_cmyk_color */\
 
143
        NULL,                   /* get_xfont_procs */\
 
144
        NULL,                   /* get_xfont_device */\
 
145
        NULL,                   /* map_rgb_alpha_color */\
 
146
        gx_page_device_get_page_device,\
 
147
        NULL,                   /* get_alpha_bits */\
 
148
        NULL,                   /* copy_alpha */\
 
149
        NULL,                   /* get_band */\
 
150
        NULL,                   /* copy_rop */\
 
151
        gdev_vector_fill_path,\
 
152
        gdev_vector_stroke_path,\
 
153
        pclxl_fill_mask,\
 
154
        gdev_vector_fill_trapezoid,\
 
155
        gdev_vector_fill_parallelogram,\
 
156
        gdev_vector_fill_triangle,\
 
157
        NULL /****** WRONG ******/,     /* draw_thin_line */\
 
158
        pclxl_begin_image,\
 
159
        NULL,                   /* image_data */\
 
160
        NULL,                   /* end_image */\
 
161
        NULL,                   /* strip_tile_rectangle */\
 
162
        pclxl_strip_copy_rop\
 
163
}
 
164
 
 
165
const gx_device_pclxl gs_pxlmono_device = {
 
166
    pclxl_device_body("pxlmono", 8),
 
167
    pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
 
168
};
 
169
 
 
170
const gx_device_pclxl gs_pxlcolor_device = {
 
171
    pclxl_device_body("pxlcolor", 24),
 
172
    pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
 
173
};
 
174
 
 
175
/* ---------------- Other utilities ---------------- */
 
176
 
 
177
static inline stream *
 
178
pclxl_stream(gx_device_pclxl *xdev)
 
179
{
 
180
    return gdev_vector_stream((gx_device_vector *)xdev);
 
181
}
 
182
 
 
183
/* Initialize for a page. */
 
184
static void
 
185
pclxl_page_init(gx_device_pclxl * xdev)
 
186
{
 
187
    gdev_vector_init((gx_device_vector *)xdev);
 
188
    xdev->in_page = false;
 
189
    xdev->fill_rule = gx_path_type_winding_number;
 
190
    xdev->clip_rule = gx_path_type_winding_number;
 
191
    xdev->color_space = eNoColorSpace;
 
192
    xdev->palette.size = 0;
 
193
    xdev->font_set = false;
 
194
}
 
195
 
 
196
/* Test whether a RGB color is actually a gray shade. */
 
197
#define RGB_IS_GRAY(ci) ((ci) >> 8 == ((ci) & 0xffff))
 
198
 
 
199
/* Set the color space and (optionally) palette. */
 
200
static void
 
201
pclxl_set_color_space(gx_device_pclxl * xdev, pxeColorSpace_t color_space)
 
202
{
 
203
    if (xdev->color_space != color_space) {
 
204
        stream *s = pclxl_stream(xdev);
 
205
 
 
206
        px_put_ub(s, (byte)color_space);
 
207
        px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
 
208
        xdev->color_space = color_space;
 
209
    }
 
210
}
 
211
static void
 
212
pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
 
213
                        const byte * palette, uint palette_size)
 
214
{
 
215
    if (xdev->color_space != color_space ||
 
216
        xdev->palette.size != palette_size ||
 
217
        memcmp(xdev->palette.data, palette, palette_size)
 
218
        ) {
 
219
        stream *s = pclxl_stream(xdev);
 
220
        static const byte csp_[] = {
 
221
            DA(pxaColorSpace),
 
222
            DUB(e8Bit), DA(pxaPaletteDepth),
 
223
            pxt_ubyte_array
 
224
        };
 
225
 
 
226
        px_put_ub(s, (byte)color_space);
 
227
        PX_PUT_LIT(s, csp_);
 
228
        px_put_u(s, palette_size);
 
229
        px_put_bytes(s, palette, palette_size);
 
230
        px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
 
231
        xdev->color_space = color_space;
 
232
        xdev->palette.size = palette_size;
 
233
        memcpy(xdev->palette.data, palette, palette_size);
 
234
    }
 
235
}
 
236
 
 
237
/* Set a drawing RGB color. */
 
238
static int
 
239
pclxl_set_color(gx_device_pclxl * xdev, const gx_drawing_color * pdc,
 
240
                px_attribute_t null_source, px_tag_t op)
 
241
{
 
242
    stream *s = pclxl_stream(xdev);
 
243
 
 
244
    if (gx_dc_is_pure(pdc)) {
 
245
        gx_color_index color = gx_dc_pure_color(pdc);
 
246
 
 
247
        if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
 
248
            pclxl_set_color_space(xdev, eGray);
 
249
            px_put_uba(s, (byte) color, pxaGrayLevel);
 
250
        } else {
 
251
            pclxl_set_color_space(xdev, eRGB);
 
252
            spputc(s, pxt_ubyte_array);
 
253
            px_put_ub(s, 3);
 
254
            spputc(s, (byte) (color >> 16));
 
255
            spputc(s, (byte) (color >> 8));
 
256
            spputc(s, (byte) color);
 
257
            px_put_a(s, pxaRGBColor);
 
258
        }
 
259
    } else if (gx_dc_is_null(pdc) || !color_is_set(pdc))
 
260
        px_put_uba(s, 0, null_source);
 
261
    else
 
262
        return_error(gs_error_rangecheck);
 
263
    spputc(s, (byte)op);
 
264
    return 0;
 
265
}
 
266
 
 
267
/* Test whether we can handle a given color space in an image. */
 
268
/* We cannot handle ICCBased color spaces. */
 
269
static bool
 
270
pclxl_can_handle_color_space(const gs_color_space * pcs)
 
271
{
 
272
    gs_color_space_index index = gs_color_space_get_index(pcs);
 
273
 
 
274
    if (index == gs_color_space_index_Indexed) {
 
275
        if (pcs->params.indexed.use_proc)
 
276
            return false;
 
277
        index =
 
278
            gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
 
279
    }
 
280
    return !(index == gs_color_space_index_Separation ||
 
281
             index == gs_color_space_index_Pattern ||
 
282
             index == gs_color_space_index_CIEICC);
 
283
}
 
284
 
 
285
/* Set brush, pen, and mode for painting a path. */
 
286
static void
 
287
pclxl_set_paints(gx_device_pclxl * xdev, gx_path_type_t type)
 
288
{
 
289
    stream *s = pclxl_stream(xdev);
 
290
    gx_path_type_t rule = type & gx_path_type_rule;
 
291
 
 
292
    if (!(type & gx_path_type_fill) &&
 
293
        (color_is_set(&xdev->saved_fill_color.saved_dev_color) ||
 
294
        !gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color) 
 
295
        )
 
296
        ) {
 
297
        static const byte nac_[] = {
 
298
            DUB(0), DA(pxaNullBrush), pxtSetBrushSource
 
299
        };
 
300
 
 
301
        PX_PUT_LIT(s, nac_);
 
302
        color_set_null(&xdev->saved_fill_color.saved_dev_color);
 
303
        if (rule != xdev->fill_rule) {
 
304
            px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
 
305
                       eNonZeroWinding));
 
306
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
 
307
            xdev->fill_rule = rule;
 
308
        }
 
309
    }
 
310
    if (!(type & gx_path_type_stroke) &&
 
311
        (color_is_set(&xdev->saved_stroke_color.saved_dev_color) ||
 
312
        !gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color)
 
313
         )
 
314
        ) {
 
315
        static const byte nac_[] = {
 
316
            DUB(0), DA(pxaNullPen), pxtSetPenSource
 
317
        };
 
318
 
 
319
        PX_PUT_LIT(s, nac_);
 
320
        color_set_null(&xdev->saved_stroke_color.saved_dev_color);
 
321
    }
 
322
}
 
323
 
 
324
/* Set the cursor. */
 
325
static int
 
326
pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
 
327
{
 
328
    stream *s = pclxl_stream(xdev);
 
329
 
 
330
    px_put_ssp(s, x, y);
 
331
    px_put_ac(s, pxaPoint, pxtSetCursor);
 
332
    return 0;
 
333
}
 
334
 
 
335
/* ------ Paths ------ */
 
336
 
 
337
/* Flush any buffered path points. */
 
338
static void
 
339
px_put_np(stream * s, int count, pxeDataType_t dtype)
 
340
{
 
341
    px_put_uba(s, (byte)count, pxaNumberOfPoints);
 
342
    px_put_uba(s, (byte)dtype, pxaPointType);
 
343
}
 
344
static int
 
345
pclxl_flush_points(gx_device_pclxl * xdev)
 
346
{
 
347
    int count = xdev->points.count;
 
348
 
 
349
    if (count) {
 
350
        stream *s = pclxl_stream(xdev);
 
351
        px_tag_t op;
 
352
        int x = xdev->points.current.x, y = xdev->points.current.y;
 
353
        int uor = 0, sor = 0;
 
354
        pxeDataType_t data_type;
 
355
        int i, di;
 
356
        byte diffs[NUM_POINTS * 2];
 
357
 
 
358
        /*
 
359
         * Writing N lines using a point list requires 11 + 4*N or 11 +
 
360
         * 2*N bytes, as opposed to 8*N bytes using separate commands;
 
361
         * writing N curves requires 11 + 12*N or 11 + 6*N bytes
 
362
         * vs. 22*N.  So it's always shorter to write curves with a
 
363
         * list (except for N = 1 with full-size coordinates, but since
 
364
         * the difference is only 1 byte, we don't bother to ever use
 
365
         * the non-list form), but lines are shorter only if N >= 3
 
366
         * (again, with a 1-byte difference if N = 2 and byte
 
367
         * coordinates).
 
368
         */
 
369
        switch (xdev->points.type) {
 
370
            case POINTS_NONE:
 
371
                return 0;
 
372
            case POINTS_LINES:
 
373
                op = pxtLinePath;
 
374
                if (count < 3) {
 
375
                    for (i = 0; i < count; ++i) {
 
376
                        px_put_ssp(s, xdev->points.data[i].x,
 
377
                                xdev->points.data[i].y);
 
378
                        px_put_a(s, pxaEndPoint);
 
379
                        spputc(s, (byte)op);
 
380
                    }
 
381
                    goto zap;
 
382
                }
 
383
                /* See if we can use byte values. */
 
384
                for (i = di = 0; i < count; ++i, di += 2) {
 
385
                    int dx = xdev->points.data[i].x - x;
 
386
                    int dy = xdev->points.data[i].y - y;
 
387
 
 
388
                    diffs[di] = (byte) dx;
 
389
                    diffs[di + 1] = (byte) dy;
 
390
                    uor |= dx | dy;
 
391
                    sor |= (dx + 0x80) | (dy + 0x80);
 
392
                    x += dx, y += dy;
 
393
                }
 
394
                if (!(uor & ~0xff))
 
395
                    data_type = eUByte;
 
396
                else if (!(sor & ~0xff))
 
397
                    data_type = eSByte;
 
398
                else
 
399
                    break;
 
400
                op = pxtLineRelPath;
 
401
                /* Use byte values. */
 
402
              useb:px_put_np(s, count, data_type);
 
403
                spputc(s, (byte)op);
 
404
                px_put_data_length(s, count * 2);       /* 2 bytes per point */
 
405
                px_put_bytes(s, diffs, count * 2);
 
406
                goto zap;
 
407
            case POINTS_CURVES:
 
408
                op = pxtBezierPath;
 
409
                /* See if we can use byte values. */
 
410
                for (i = di = 0; i < count; i += 3, di += 6) {
 
411
                    int dx1 = xdev->points.data[i].x - x;
 
412
                    int dy1 = xdev->points.data[i].y - y;
 
413
                    int dx2 = xdev->points.data[i + 1].x - x;
 
414
                    int dy2 = xdev->points.data[i + 1].y - y;
 
415
                    int dx = xdev->points.data[i + 2].x - x;
 
416
                    int dy = xdev->points.data[i + 2].y - y;
 
417
 
 
418
                    diffs[di] = (byte) dx1;
 
419
                    diffs[di + 1] = (byte) dy1;
 
420
                    diffs[di + 2] = (byte) dx2;
 
421
                    diffs[di + 3] = (byte) dy2;
 
422
                    diffs[di + 4] = (byte) dx;
 
423
                    diffs[di + 5] = (byte) dy;
 
424
                    uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
 
425
                    sor |= (dx1 + 0x80) | (dy1 + 0x80) |
 
426
                        (dx2 + 0x80) | (dy2 + 0x80) |
 
427
                        (dx + 0x80) | (dy + 0x80);
 
428
                    x += dx, y += dy;
 
429
                }
 
430
                if (!(uor & ~0xff))
 
431
                    data_type = eUByte;
 
432
                else if (!(sor & ~0xff))
 
433
                    data_type = eSByte;
 
434
                else
 
435
                    break;
 
436
                op = pxtBezierRelPath;
 
437
                goto useb;
 
438
            default:            /* can't happen */
 
439
                return_error(gs_error_unknownerror);
 
440
        }
 
441
        px_put_np(s, count, eSInt16);
 
442
        spputc(s, (byte)op);
 
443
        px_put_data_length(s, count * 4);       /* 2 UInt16s per point */
 
444
        for (i = 0; i < count; ++i) {
 
445
            px_put_s(s, xdev->points.data[i].x);
 
446
            px_put_s(s, xdev->points.data[i].y);
 
447
        }
 
448
      zap:xdev->points.type = POINTS_NONE;
 
449
        xdev->points.count = 0;
 
450
    }
 
451
    return 0;
 
452
}
 
453
 
 
454
/* ------ Images ------ */
 
455
 
 
456
static image_enum_proc_plane_data(pclxl_image_plane_data);
 
457
static image_enum_proc_end_image(pclxl_image_end_image);
 
458
static const gx_image_enum_procs_t pclxl_image_enum_procs = {
 
459
    pclxl_image_plane_data, pclxl_image_end_image
 
460
};
 
461
 
 
462
/* Begin an image. */
 
463
static void
 
464
pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
 
465
                        uint dest_width, uint dest_height)
 
466
{
 
467
    stream *s = pclxl_stream(xdev);
 
468
 
 
469
    px_put_usa(s, width, pxaSourceWidth);
 
470
    px_put_usa(s, height, pxaSourceHeight);
 
471
    px_put_usp(s, dest_width, dest_height);
 
472
    px_put_ac(s, pxaDestinationSize, pxtBeginImage);
 
473
}
 
474
 
 
475
/* Write rows of an image. */
 
476
/****** IGNORES data_bit ******/
 
477
static void
 
478
pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data, int data_bit,
 
479
                       uint raster, uint width_bits, int y, int height)
 
480
{
 
481
    stream *s = pclxl_stream(xdev);
 
482
    uint width_bytes = (width_bits + 7) >> 3;
 
483
    uint num_bytes = ROUND_UP(width_bytes, 4) * height;
 
484
    bool compress = num_bytes >= 8;
 
485
    int i;
 
486
 
 
487
    px_put_usa(s, y, pxaStartLine);
 
488
    px_put_usa(s, height, pxaBlockHeight);
 
489
    if (compress) {
 
490
        stream_RLE_state rlstate;
 
491
        stream_cursor_write w;
 
492
        stream_cursor_read r;
 
493
 
 
494
        /*
 
495
         * H-P printers require that all the data for an operator be
 
496
         * contained in a single data block.  Thus, we must allocate a
 
497
         * temporary buffer for the compressed data.  Currently we don't go
 
498
         * to the trouble of doing two passes if we can't allocate a buffer
 
499
         * large enough for the entire transfer.
 
500
         */
 
501
        byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
 
502
                                   "pclxl_write_image_data");
 
503
 
 
504
        if (buf == 0)
 
505
            goto nc;
 
506
        s_RLE_set_defaults_inline(&rlstate);
 
507
        rlstate.EndOfData = false;
 
508
        s_RLE_init_inline(&rlstate);
 
509
        w.ptr = buf - 1;
 
510
        w.limit = w.ptr + num_bytes;
 
511
        /*
 
512
         * If we ever overrun the buffer, it means that the compressed
 
513
         * data was larger than the uncompressed.  If this happens,
 
514
         * write the data uncompressed.
 
515
         */
 
516
        for (i = 0; i < height; ++i) {
 
517
            r.ptr = data + i * raster - 1;
 
518
            r.limit = r.ptr + width_bytes;
 
519
            if ((*s_RLE_template.process)
 
520
                ((stream_state *) & rlstate, &r, &w, true) != 0 ||
 
521
                r.ptr != r.limit
 
522
                )
 
523
                goto ncfree;
 
524
            r.ptr = (const byte *)"\000\000\000\000\000";
 
525
            r.limit = r.ptr + (-(int)width_bytes & 3);
 
526
            if ((*s_RLE_template.process)
 
527
                ((stream_state *) & rlstate, &r, &w, true) != 0 ||
 
528
                r.ptr != r.limit
 
529
                )
 
530
                goto ncfree;
 
531
        }
 
532
        r.ptr = r.limit;
 
533
        if ((*s_RLE_template.process)
 
534
            ((stream_state *) & rlstate, &r, &w, true) != 0
 
535
            )
 
536
            goto ncfree;
 
537
        {
 
538
            uint count = w.ptr + 1 - buf;
 
539
 
 
540
            px_put_ub(s, eRLECompression);
 
541
            px_put_ac(s, pxaCompressMode, pxtReadImage);
 
542
            px_put_data_length(s, count);
 
543
            px_put_bytes(s, buf, count);
 
544
        }
 
545
        gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
 
546
        return;
 
547
      ncfree:gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
 
548
    }
 
549
 nc:
 
550
    /* Write the data uncompressed. */
 
551
    px_put_ub(s, eNoCompression);
 
552
    px_put_ac(s, pxaCompressMode, pxtReadImage);
 
553
    px_put_data_length(s, num_bytes);
 
554
    for (i = 0; i < height; ++i) {
 
555
        px_put_bytes(s, data + i * raster, width_bytes);
 
556
        px_put_bytes(s, (const byte *)"\000\000\000\000", -(int)width_bytes & 3);
 
557
    }
 
558
}
 
559
 
 
560
/* End an image. */
 
561
static void
 
562
pclxl_write_end_image(gx_device_pclxl * xdev)
 
563
{
 
564
    spputc(xdev->strm, pxtEndImage);
 
565
}
 
566
 
 
567
/* ------ Fonts ------ */
 
568
 
 
569
/* Write a string (single- or double-byte). */
 
570
static void
 
571
px_put_string(stream * s, const byte * data, uint len, bool wide)
 
572
{
 
573
    if (wide) {
 
574
        spputc(s, pxt_uint16_array);
 
575
        px_put_u(s, len);
 
576
        px_put_bytes(s, data, len * 2);
 
577
    } else {
 
578
        spputc(s, pxt_ubyte_array);
 
579
        px_put_u(s, len);
 
580
        px_put_bytes(s, data, len);
 
581
    }
 
582
}
 
583
 
 
584
/* Write a 16-bit big-endian value. */
 
585
static void
 
586
px_put_us_be(stream * s, uint i)
 
587
{
 
588
    spputc(s, (byte) (i >> 8));
 
589
    spputc(s, (byte) i);
 
590
}
 
591
 
 
592
/* Define a bitmap font.  The client must call px_put_string */
 
593
/* with the font name immediately before calling this procedure. */
 
594
static void
 
595
pclxl_define_bitmap_font(gx_device_pclxl * xdev)
 
596
{
 
597
    stream *s = pclxl_stream(xdev);
 
598
    static const byte bfh_[] = {
 
599
        DA(pxaFontName), DUB(0), DA(pxaFontFormat),
 
600
        pxtBeginFontHeader,
 
601
        DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
 
602
        pxtReadFontHeader,
 
603
        pxt_dataLengthByte, 8 + 6 + 4 + 6,
 
604
        0, 0, 0, 0,
 
605
        254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
 
606
        'B', 'R', 0, 0, 0, 4
 
607
    };
 
608
    static const byte efh_[] = {
 
609
        0xff, 0xff, 0, 0, 0, 0,
 
610
        pxtEndFontHeader
 
611
    };
 
612
 
 
613
    PX_PUT_LIT(s, bfh_);
 
614
    px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
 
615
    px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
 
616
    PX_PUT_LIT(s, efh_);
 
617
}
 
618
 
 
619
/* Set the font.  The client must call px_put_string */
 
620
/* with the font name immediately before calling this procedure. */
 
621
static void
 
622
pclxl_set_font(gx_device_pclxl * xdev)
 
623
{
 
624
    stream *s = pclxl_stream(xdev);
 
625
    static const byte sf_[] = {
 
626
        DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
 
627
        pxtSetFont
 
628
    };
 
629
 
 
630
    PX_PUT_LIT(s, sf_);
 
631
}
 
632
 
 
633
/* Define a character in a bitmap font.  The client must call px_put_string */
 
634
/* with the font name immediately before calling this procedure. */
 
635
static void
 
636
pclxl_define_bitmap_char(gx_device_pclxl * xdev, uint ccode,
 
637
               const byte * data, uint raster, uint width_bits, uint height)
 
638
{
 
639
    stream *s = pclxl_stream(xdev);
 
640
    uint width_bytes = (width_bits + 7) >> 3;
 
641
    uint size = 10 + width_bytes * height;
 
642
    uint i;
 
643
 
 
644
    px_put_ac(s, pxaFontName, pxtBeginChar);
 
645
    px_put_u(s, ccode);
 
646
    px_put_a(s, pxaCharCode);
 
647
    if (size > 0xffff) {
 
648
        spputc(s, pxt_uint32);
 
649
        px_put_l(s, (ulong) size);
 
650
    } else
 
651
        px_put_us(s, size);
 
652
    px_put_ac(s, pxaCharDataSize, pxtReadChar);
 
653
    px_put_data_length(s, size);
 
654
    px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
 
655
    px_put_us_be(s, width_bits);
 
656
    px_put_us_be(s, height);
 
657
    for (i = 0; i < height; ++i)
 
658
        px_put_bytes(s, data + i * raster, width_bytes);
 
659
    spputc(s, pxtEndChar);
 
660
}
 
661
 
 
662
/* Write the name of the only font we define. */
 
663
static void
 
664
pclxl_write_font_name(gx_device_pclxl * xdev)
 
665
{
 
666
    stream *s = pclxl_stream(xdev);
 
667
 
 
668
    px_put_string(s, (const byte *)"@", 1, false);
 
669
}
 
670
 
 
671
/* Look up a bitmap id, return the index in the character table. */
 
672
/* If the id is missing, return an index for inserting. */
 
673
static int
 
674
pclxl_char_index(gx_device_pclxl * xdev, gs_id id)
 
675
{
 
676
    int i, i_empty = -1;
 
677
    uint ccode;
 
678
 
 
679
    for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
 
680
         i = (i == 0 ? countof(xdev->chars.table) : i) - 1
 
681
        ) {
 
682
        ccode = xdev->chars.table[i];
 
683
        if (ccode == 0)
 
684
            return (i_empty >= 0 ? i_empty : i);
 
685
        else if (ccode == 1) {
 
686
            if (i_empty < 0)
 
687
                i_empty = i;
 
688
            else if (i == i_empty)      /* full table */
 
689
                return i;
 
690
        } else if (xdev->chars.data[ccode].id == id)
 
691
            return i;
 
692
    }
 
693
}
 
694
 
 
695
/* Remove the character table entry at a given index. */
 
696
static void
 
697
pclxl_remove_char(gx_device_pclxl * xdev, int index)
 
698
{
 
699
    uint ccode = xdev->chars.table[index];
 
700
    int i;
 
701
 
 
702
    if (ccode < 2)
 
703
        return;
 
704
    xdev->chars.count--;
 
705
    xdev->chars.used -= xdev->chars.data[ccode].size;
 
706
    xdev->chars.table[index] = 1;       /* mark as deleted */
 
707
    i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
 
708
    if (xdev->chars.table[i] == 0) {
 
709
        /* The next slot in probe order is empty. */
 
710
        /* Mark this slot and any deleted predecessors as empty. */
 
711
        for (i = index; xdev->chars.table[i] == 1;
 
712
             i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
 
713
            )
 
714
            xdev->chars.table[i] = 0;
 
715
    }
 
716
}
 
717
 
 
718
/* Write a bitmap as a text character if possible. */
 
719
/* The caller must set the color, cursor, and RasterOp. */
 
720
/* We know id != gs_no_id. */
 
721
static int
 
722
pclxl_copy_text_char(gx_device_pclxl * xdev, const byte * data,
 
723
                     int raster, gx_bitmap_id id, int w, int h)
 
724
{
 
725
    uint width_bytes = (w + 7) >> 3;
 
726
    uint size = width_bytes * h;
 
727
    int index;
 
728
    uint ccode;
 
729
    stream *s = pclxl_stream(xdev);
 
730
 
 
731
    if (size > MAX_CHAR_SIZE)
 
732
        return -1;
 
733
    index = pclxl_char_index(xdev, id);
 
734
    if ((ccode = xdev->chars.table[index]) < 2) {
 
735
        /* Enter the character in the table. */
 
736
        while (xdev->chars.used + size > MAX_CHAR_DATA ||
 
737
               xdev->chars.count >= MAX_CACHED_CHARS - 2
 
738
            ) {
 
739
            ccode = xdev->chars.next_out;
 
740
            index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
 
741
            pclxl_remove_char(xdev, index);
 
742
            xdev->chars.next_out =
 
743
                (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
 
744
        }
 
745
        index = pclxl_char_index(xdev, id);
 
746
        ccode = xdev->chars.next_in;
 
747
        xdev->chars.data[ccode].id = id;
 
748
        xdev->chars.data[ccode].size = size;
 
749
        xdev->chars.table[index] = ccode;
 
750
        xdev->chars.next_in =
 
751
            (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
 
752
        if (!xdev->chars.count++) {
 
753
            /* This is the very first character. */
 
754
            pclxl_write_font_name(xdev);
 
755
            pclxl_define_bitmap_font(xdev);
 
756
        }
 
757
        xdev->chars.used += size;
 
758
        pclxl_write_font_name(xdev);
 
759
        pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
 
760
    }
 
761
    if (!xdev->font_set) {
 
762
        pclxl_write_font_name(xdev);
 
763
        pclxl_set_font(xdev);
 
764
        xdev->font_set = true;
 
765
    } {
 
766
        byte cc_bytes[2];
 
767
 
 
768
        cc_bytes[0] = (byte) ccode;
 
769
        cc_bytes[1] = ccode >> 8;
 
770
        px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
 
771
    }
 
772
    px_put_ac(s, pxaTextData, pxtText);
 
773
    return 0;
 
774
}
 
775
 
 
776
/* ---------------- Vector implementation procedures ---------------- */
 
777
 
 
778
static int
 
779
pclxl_beginpage(gx_device_vector * vdev)
 
780
{
 
781
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
782
    /*
 
783
     * We can't use gdev_vector_stream here, because this may be called
 
784
     * from there before in_page is set.
 
785
     */
 
786
    stream *s = vdev->strm;
 
787
    byte media_source = eAutoSelect; /* default */
 
788
 
 
789
    xdev->page ++;
 
790
 
 
791
/*
 
792
    errprintf("PAGE: %d %d\n", xdev->page, xdev->NumCopies);
 
793
    errprintf("INFO: Printing page %d...\n", xdev->page);
 
794
    errflush();
 
795
*/
 
796
 
 
797
    px_write_page_header(s, (const gx_device *)vdev);
 
798
 
 
799
    if (xdev->ManualFeed_set && xdev->ManualFeed) 
 
800
        media_source = 2;
 
801
    else if (xdev->MediaPosition_set && xdev->MediaPosition >= 0 )
 
802
        media_source = xdev->MediaPosition;
 
803
 
 
804
    px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size,
 
805
                          &media_source,
 
806
                          xdev->page, xdev->Duplex, xdev->Tumble);
 
807
 
 
808
    spputc(s, pxtBeginPage);
 
809
    return 0;
 
810
}
 
811
 
 
812
static int
 
813
pclxl_setlinewidth(gx_device_vector * vdev, floatp width)
 
814
{
 
815
    stream *s = gdev_vector_stream(vdev);
 
816
 
 
817
    px_put_us(s, (uint) width);
 
818
    px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
 
819
    return 0;
 
820
}
 
821
 
 
822
static int
 
823
pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
 
824
{
 
825
    stream *s = gdev_vector_stream(vdev);
 
826
 
 
827
    /* The PCL XL cap styles just happen to be identical to PostScript. */
 
828
    px_put_ub(s, (byte) cap);
 
829
    px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
 
830
    return 0;
 
831
}
 
832
 
 
833
static int
 
834
pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
 
835
{
 
836
    stream *s = gdev_vector_stream(vdev);
 
837
 
 
838
    /* The PCL XL join styles just happen to be identical to PostScript. */
 
839
    px_put_ub(s, (byte) join);
 
840
    px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
 
841
    return 0;
 
842
}
 
843
 
 
844
static int
 
845
pclxl_setmiterlimit(gx_device_vector * vdev, floatp limit)
 
846
{
 
847
    stream *s = gdev_vector_stream(vdev);
 
848
    /*
 
849
     * Amazingly enough, the PCL XL specification doesn't allow real
 
850
     * numbers for the miter limit.
 
851
     */
 
852
    int i_limit = (int)(limit + 0.5);
 
853
 
 
854
    px_put_u(s, max(i_limit, 1));
 
855
    px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
 
856
    return 0;
 
857
}
 
858
 
 
859
static int
 
860
pclxl_setdash(gx_device_vector * vdev, const float *pattern, uint count,
 
861
              floatp offset)
 
862
{
 
863
    stream *s = gdev_vector_stream(vdev);
 
864
 
 
865
    if (count == 0) {
 
866
        static const byte nac_[] = {
 
867
            DUB(0), DA(pxaSolidLine)
 
868
        };
 
869
 
 
870
        PX_PUT_LIT(s, nac_);
 
871
    } else if (count > 255)
 
872
        return_error(gs_error_limitcheck);
 
873
    else {
 
874
        uint i;
 
875
 
 
876
        /*
 
877
         * Astoundingly, PCL XL doesn't allow real numbers here.
 
878
         * Do the best we can.
 
879
         */
 
880
        spputc(s, pxt_uint16_array);
 
881
        px_put_ub(s, (byte)count);
 
882
        for (i = 0; i < count; ++i)
 
883
            px_put_s(s, (uint)pattern[i]);
 
884
        px_put_a(s, pxaLineDashStyle);
 
885
        if (offset != 0)
 
886
            px_put_usa(s, (uint)offset, pxaDashOffset);
 
887
    }
 
888
    spputc(s, pxtSetLineDash);
 
889
    return 0;
 
890
}
 
891
 
 
892
static int
 
893
pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
 
894
               gs_logical_operation_t diff)
 
895
{
 
896
    stream *s = gdev_vector_stream(vdev);
 
897
 
 
898
    if (diff & lop_S_transparent) {
 
899
        px_put_ub(s, (byte)(lop & lop_S_transparent ? 1 : 0));
 
900
        px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
 
901
    }
 
902
    if (diff & lop_T_transparent) {
 
903
        px_put_ub(s, (byte)(lop & lop_T_transparent ? 1 : 0));
 
904
        px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
 
905
    }
 
906
    if (lop_rop(diff)) {
 
907
        px_put_ub(s, (byte)lop_rop(lop));
 
908
        px_put_ac(s, pxaROP3, pxtSetROP);
 
909
    }
 
910
    return 0;
 
911
}
 
912
 
 
913
static int
 
914
pclxl_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis, 
 
915
                   const gx_drawing_color * pdc)
 
916
{
 
917
    return false;
 
918
}
 
919
 
 
920
static int
 
921
pclxl_setfillcolor(gx_device_vector * vdev, const gs_imager_state * pis, 
 
922
                   const gx_drawing_color * pdc)
 
923
{
 
924
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
925
 
 
926
    return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
 
927
}
 
928
 
 
929
static int
 
930
pclxl_setstrokecolor(gx_device_vector * vdev, const gs_imager_state * pis, 
 
931
                     const gx_drawing_color * pdc)
 
932
{
 
933
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
934
 
 
935
    return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
 
936
}
 
937
 
 
938
static int
 
939
pclxl_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
 
940
             fixed y1, gx_path_type_t type)
 
941
{
 
942
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
943
    stream *s = gdev_vector_stream(vdev);
 
944
 
 
945
    /* Check for out-of-range points. */
 
946
#define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
 
947
    if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
 
948
        OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
 
949
        )
 
950
        return_error(gs_error_rangecheck);
 
951
#undef OUT_OF_RANGE
 
952
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
 
953
        pclxl_set_paints(xdev, type);
 
954
        px_put_usq_fixed(s, x0, y0, x1, y1);
 
955
        px_put_ac(s, pxaBoundingBox, pxtRectangle);
 
956
    }
 
957
    if (type & gx_path_type_clip) {
 
958
        static const byte cr_[] = {
 
959
            DA(pxaBoundingBox),
 
960
            DUB(eInterior), DA(pxaClipRegion),
 
961
            pxtSetClipRectangle
 
962
        };
 
963
 
 
964
        px_put_usq_fixed(s, x0, y0, x1, y1);
 
965
        PX_PUT_LIT(s, cr_);
 
966
    }
 
967
    return 0;
 
968
}
 
969
 
 
970
static int
 
971
pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
 
972
{
 
973
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
974
    stream *s = gdev_vector_stream(vdev);
 
975
 
 
976
    spputc(s, pxtNewPath);
 
977
    xdev->points.type = POINTS_NONE;
 
978
    xdev->points.count = 0;
 
979
    return 0;
 
980
}
 
981
 
 
982
static int
 
983
pclxl_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
 
984
             gx_path_type_t type)
 
985
{
 
986
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
987
    int code = pclxl_flush_points(xdev);
 
988
 
 
989
    if (code < 0)
 
990
        return code;
 
991
    return pclxl_set_cursor(xdev,
 
992
                            xdev->points.current.x = (int)x,
 
993
                            xdev->points.current.y = (int)y);
 
994
}
 
995
 
 
996
static int
 
997
pclxl_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
 
998
             gx_path_type_t type)
 
999
{
 
1000
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
1001
 
 
1002
    if (xdev->points.type != POINTS_LINES ||
 
1003
        xdev->points.count >= NUM_POINTS
 
1004
        ) {
 
1005
        if (xdev->points.type != POINTS_NONE) {
 
1006
            int code = pclxl_flush_points(xdev);
 
1007
 
 
1008
            if (code < 0)
 
1009
                return code;
 
1010
        }
 
1011
        xdev->points.current.x = (int)x0;
 
1012
        xdev->points.current.y = (int)y0;
 
1013
        xdev->points.type = POINTS_LINES;
 
1014
    } {
 
1015
        gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
 
1016
 
 
1017
        ppt->x = (int)x, ppt->y = (int)y;
 
1018
    }
 
1019
    return 0;
 
1020
}
 
1021
 
 
1022
static int
 
1023
pclxl_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
 
1024
           floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
 
1025
              gx_path_type_t type)
 
1026
{
 
1027
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
1028
 
 
1029
    if (xdev->points.type != POINTS_CURVES ||
 
1030
        xdev->points.count >= NUM_POINTS - 2
 
1031
        ) {
 
1032
        if (xdev->points.type != POINTS_NONE) {
 
1033
            int code = pclxl_flush_points(xdev);
 
1034
 
 
1035
            if (code < 0)
 
1036
                return code;
 
1037
        }
 
1038
        xdev->points.current.x = (int)x0;
 
1039
        xdev->points.current.y = (int)y0;
 
1040
        xdev->points.type = POINTS_CURVES;
 
1041
    }
 
1042
    {
 
1043
        gs_int_point *ppt = &xdev->points.data[xdev->points.count];
 
1044
 
 
1045
        ppt->x = (int)x1, ppt->y = (int)y1, ++ppt;
 
1046
        ppt->x = (int)x2, ppt->y = (int)y2, ++ppt;
 
1047
        ppt->x = (int)x3, ppt->y = (int)y3;
 
1048
    }
 
1049
    xdev->points.count += 3;
 
1050
    return 0;
 
1051
}
 
1052
 
 
1053
static int
 
1054
pclxl_closepath(gx_device_vector * vdev, floatp x, floatp y,
 
1055
                floatp x_start, floatp y_start, gx_path_type_t type)
 
1056
{
 
1057
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
1058
    stream *s = gdev_vector_stream(vdev);
 
1059
    int code = pclxl_flush_points(xdev);
 
1060
 
 
1061
    if (code < 0)
 
1062
        return code;
 
1063
    spputc(s, pxtCloseSubPath);
 
1064
    xdev->points.current.x = (int)x_start;
 
1065
    xdev->points.current.y = (int)y_start;
 
1066
    return 0;
 
1067
}
 
1068
 
 
1069
static int
 
1070
pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
 
1071
{
 
1072
    gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
 
1073
    stream *s = gdev_vector_stream(vdev);
 
1074
    int code = pclxl_flush_points(xdev);
 
1075
    gx_path_type_t rule = type & gx_path_type_rule;
 
1076
 
 
1077
    if (code < 0)
 
1078
        return code;
 
1079
    if (type & (gx_path_type_fill | gx_path_type_stroke)) {
 
1080
        if (rule != xdev->fill_rule) {
 
1081
            px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
 
1082
                       eNonZeroWinding));
 
1083
            px_put_ac(s, pxaFillMode, pxtSetFillMode);
 
1084
            xdev->fill_rule = rule;
 
1085
        }
 
1086
        pclxl_set_paints(xdev, type);
 
1087
        spputc(s, pxtPaintPath);
 
1088
    }
 
1089
    if (type & gx_path_type_clip) {
 
1090
        static const byte scr_[] = {
 
1091
            DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
 
1092
        };
 
1093
 
 
1094
        if (rule != xdev->clip_rule) {
 
1095
            px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
 
1096
                       eNonZeroWinding));
 
1097
            px_put_ac(s, pxaClipMode, pxtSetClipMode);
 
1098
            xdev->clip_rule = rule;
 
1099
        }
 
1100
        PX_PUT_LIT(s, scr_);
 
1101
    }
 
1102
    return 0;
 
1103
}
 
1104
 
 
1105
/* Vector implementation procedures */
 
1106
 
 
1107
static const gx_device_vector_procs pclxl_vector_procs = {
 
1108
        /* Page management */
 
1109
    pclxl_beginpage,
 
1110
        /* Imager state */
 
1111
    pclxl_setlinewidth,
 
1112
    pclxl_setlinecap,
 
1113
    pclxl_setlinejoin,
 
1114
    pclxl_setmiterlimit,
 
1115
    pclxl_setdash,
 
1116
    gdev_vector_setflat,
 
1117
    pclxl_setlogop,
 
1118
        /* Other state */
 
1119
    pclxl_can_handle_hl_color,
 
1120
    pclxl_setfillcolor,
 
1121
    pclxl_setstrokecolor,
 
1122
        /* Paths */
 
1123
    gdev_vector_dopath,
 
1124
    pclxl_dorect,
 
1125
    pclxl_beginpath,
 
1126
    pclxl_moveto,
 
1127
    pclxl_lineto,
 
1128
    pclxl_curveto,
 
1129
    pclxl_closepath,
 
1130
    pclxl_endpath
 
1131
};
 
1132
 
 
1133
/* ---------------- Driver procedures ---------------- */
 
1134
 
 
1135
/* ------ Open/close/page ------ */
 
1136
 
 
1137
/* Open the device. */
 
1138
static int
 
1139
pclxl_open_device(gx_device * dev)
 
1140
{
 
1141
    gx_device_vector *const vdev = (gx_device_vector *)dev;
 
1142
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1143
    int code;
 
1144
 
 
1145
    vdev->v_memory = dev->memory;       /****** WRONG ******/
 
1146
    vdev->vec_procs = &pclxl_vector_procs;
 
1147
    code = gdev_vector_open_file_options(vdev, 512,
 
1148
                                         VECTOR_OPEN_FILE_SEQUENTIAL);
 
1149
    if (code < 0)
 
1150
        return code;
 
1151
 
 
1152
    pclxl_page_init(xdev);
 
1153
    px_write_file_header(vdev->strm, dev);
 
1154
    xdev->media_size = pxeMediaSize_next;       /* no size selected */
 
1155
    memset(&xdev->chars, 0, sizeof(xdev->chars));
 
1156
    xdev->chars.next_in = xdev->chars.next_out = 2;
 
1157
    return 0;
 
1158
}
 
1159
 
 
1160
/* Wrap up ("output") a page. */
 
1161
/* We only support flush = true */
 
1162
static int
 
1163
pclxl_output_page(gx_device * dev, int num_copies, int flush)
 
1164
{
 
1165
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1166
    stream *s;
 
1167
 
 
1168
    /* Note that unlike close_device, end_page must not omit blank pages. */
 
1169
    if (!xdev->in_page)
 
1170
        pclxl_beginpage((gx_device_vector *)dev);
 
1171
    s = xdev->strm;
 
1172
    px_put_usa(s, (uint)num_copies, pxaPageCopies);     /* num_copies */
 
1173
    spputc(s, pxtEndPage);
 
1174
    sflush(s);
 
1175
    pclxl_page_init(xdev);
 
1176
    if (ferror(xdev->file))
 
1177
        return_error(gs_error_ioerror);
 
1178
    return gx_finish_output_page(dev, num_copies, flush);
 
1179
}
 
1180
 
 
1181
/* Close the device. */
 
1182
/* Note that if this is being called as a result of finalization, */
 
1183
/* the stream may no longer exist. */
 
1184
static int
 
1185
pclxl_close_device(gx_device * dev)
 
1186
{
 
1187
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1188
    FILE *file = xdev->file;
 
1189
 
 
1190
    if (xdev->in_page)
 
1191
        fputc(pxtEndPage, file);
 
1192
    px_write_file_trailer(file);
 
1193
    return gdev_vector_close_file((gx_device_vector *)dev);
 
1194
}
 
1195
 
 
1196
/* ------ One-for-one images ------ */
 
1197
 
 
1198
static const byte eBit_values[] = {
 
1199
    0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
 
1200
};
 
1201
 
 
1202
/* Copy a monochrome bitmap. */
 
1203
static int
 
1204
pclxl_copy_mono(gx_device * dev, const byte * data, int data_x, int raster,
 
1205
                gx_bitmap_id id, int x, int y, int w, int h,
 
1206
                gx_color_index zero, gx_color_index one)
 
1207
{
 
1208
    gx_device_vector *const vdev = (gx_device_vector *)dev;
 
1209
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1210
    int code;
 
1211
    stream *s;
 
1212
    gx_color_index color0 = zero, color1 = one;
 
1213
    gs_logical_operation_t lop;
 
1214
    byte palette[2 * 3];
 
1215
    int palette_size;
 
1216
    pxeColorSpace_t color_space;
 
1217
 
 
1218
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
 
1219
    code = gdev_vector_update_clip_path(vdev, NULL);
 
1220
    if (code < 0)
 
1221
        return code;
 
1222
 
 
1223
    if (data_x !=0 )
 
1224
        return gx_default_copy_mono(dev, data, data_x, raster, id, 
 
1225
                                    x, y, w, h, zero, one);
 
1226
 
 
1227
    pclxl_set_cursor(xdev, x, y);
 
1228
    if (id != gs_no_id && zero == gx_no_color_index &&
 
1229
        one != gx_no_color_index && data_x == 0
 
1230
        ) {
 
1231
        gx_drawing_color dcolor;
 
1232
 
 
1233
        set_nonclient_dev_color(&dcolor, one);
 
1234
        pclxl_setfillcolor(vdev, NULL, &dcolor);
 
1235
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
 
1236
            return 0;
 
1237
    }
 
1238
    /*
 
1239
     * The following doesn't work if we're writing white with a mask.
 
1240
     * We'll fix it eventually.
 
1241
     *
 
1242
     * This is a slightly better version than before (see bug 688372).
 
1243
     */
 
1244
    if (zero == one) {
 
1245
        if (zero == gx_no_color_index) {
 
1246
          /* one != gx_no_color_index */
 
1247
            lop = rop3_S | lop_S_transparent;
 
1248
            color0 = (1 << dev->color_info.depth) - 1;
 
1249
        } else if (one == gx_no_color_index) {
 
1250
          /* zero != gx_no_color_index */
 
1251
            lop = rop3_S | lop_S_transparent;
 
1252
            color1 = (1 << dev->color_info.depth) - 1;
 
1253
        } else {
 
1254
          /* both != no_color_index */
 
1255
            lop = rop3_S;
 
1256
        }
 
1257
    } else {
 
1258
        if_debug3('b', "zero %d one %d noidx %08X\n", zero, one, gx_no_color_index);
 
1259
        if ((zero == gx_no_color_index) &&
 
1260
            (one == gx_no_color_index))
 
1261
          return 0;
 
1262
        lop = lop_T_transparent  |rop3_S;
 
1263
        color1 = one;
 
1264
        color0 = one;
 
1265
    }
 
1266
 
 
1267
    if (dev->color_info.num_components == 1 ||
 
1268
        (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
 
1269
        ) {
 
1270
        palette[0] = (byte) color0;
 
1271
        palette[1] = (byte) color1;
 
1272
        palette_size = 2;
 
1273
        color_space = eGray;
 
1274
        if_debug2('b', "color palette %02X %02X\n", palette[0], palette[1]);
 
1275
    } else {
 
1276
        palette[0] = (byte) (color0 >> 16);
 
1277
        palette[1] = (byte) (color0 >> 8);
 
1278
        palette[2] = (byte) color0;
 
1279
        palette[3] = (byte) (color1 >> 16);
 
1280
        palette[4] = (byte) (color1 >> 8);
 
1281
        palette[5] = (byte) color1;
 
1282
        palette_size = 6;
 
1283
        color_space = eRGB;
 
1284
    }
 
1285
    code = gdev_vector_update_log_op(vdev, lop);
 
1286
    if (code < 0)
 
1287
        return 0;
 
1288
    pclxl_set_color_palette(xdev, color_space, palette, palette_size);
 
1289
    s = pclxl_stream(xdev);
 
1290
    {
 
1291
        static const byte mi_[] = {
 
1292
            DUB(e1Bit), DA(pxaColorDepth),
 
1293
            DUB(eIndexedPixel), DA(pxaColorMapping)
 
1294
        };
 
1295
 
 
1296
        PX_PUT_LIT(s, mi_);
 
1297
    }
 
1298
    pclxl_write_begin_image(xdev, w, h, w, h);
 
1299
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
 
1300
    pclxl_write_end_image(xdev);
 
1301
    return 0;
 
1302
}
 
1303
 
 
1304
/* Copy a color bitmap. */
 
1305
static int
 
1306
pclxl_copy_color(gx_device * dev,
 
1307
                 const byte * base, int sourcex, int raster, gx_bitmap_id id,
 
1308
                 int x, int y, int w, int h)
 
1309
{
 
1310
    gx_device_vector *const vdev = (gx_device_vector *)dev;
 
1311
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1312
    stream *s;
 
1313
    uint source_bit;
 
1314
    int code;
 
1315
 
 
1316
    fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
 
1317
    code = gdev_vector_update_clip_path(vdev, NULL);
 
1318
    if (code < 0)
 
1319
        return code;
 
1320
 
 
1321
 
 
1322
    source_bit = sourcex * dev->color_info.depth;
 
1323
    if ((source_bit & 7) != 0)
 
1324
        return gx_default_copy_color(dev, base, sourcex, raster, id,
 
1325
                                     x, y, w, h);
 
1326
    gdev_vector_update_log_op(vdev, rop3_S);
 
1327
    pclxl_set_cursor(xdev, x, y);
 
1328
    s = pclxl_stream(xdev);
 
1329
    {
 
1330
        static const byte ci_[] = {
 
1331
            DA(pxaColorDepth),
 
1332
            DUB(eDirectPixel), DA(pxaColorMapping)
 
1333
        };
 
1334
 
 
1335
        px_put_ub(s, eBit_values[dev->color_info.depth /
 
1336
                                 dev->color_info.num_components]);
 
1337
        PX_PUT_LIT(s, ci_);
 
1338
    }
 
1339
    pclxl_write_begin_image(xdev, w, h, w, h);
 
1340
    pclxl_write_image_data(xdev, base, source_bit, raster,
 
1341
                           w * dev->color_info.depth, 0, h);
 
1342
    pclxl_write_end_image(xdev);
 
1343
    return 0;
 
1344
}
 
1345
 
 
1346
/* Fill a mask. */
 
1347
static int
 
1348
pclxl_fill_mask(gx_device * dev,
 
1349
                const byte * data, int data_x, int raster, gx_bitmap_id id,
 
1350
                int x, int y, int w, int h,
 
1351
                const gx_drawing_color * pdcolor, int depth,
 
1352
                gs_logical_operation_t lop, const gx_clip_path * pcpath)
 
1353
{
 
1354
    gx_device_vector *const vdev = (gx_device_vector *)dev;
 
1355
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1356
    int code;
 
1357
    stream *s;
 
1358
 
 
1359
    fit_copy(dev, data, data_x, raster, id, x, y, w, h);
 
1360
    if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1)
 
1361
        return gx_default_fill_mask(dev, data, data_x, raster, id,
 
1362
                                    x, y, w, h, pdcolor, depth,
 
1363
                                    lop, pcpath);
 
1364
    code = gdev_vector_update_clip_path(vdev, pcpath);
 
1365
    if (code < 0)
 
1366
        return code;
 
1367
    code = gdev_vector_update_fill_color(vdev, NULL, pdcolor);
 
1368
    if (code < 0)
 
1369
        return 0;
 
1370
    pclxl_set_cursor(xdev, x, y);
 
1371
    if (id != gs_no_id && data_x == 0) {
 
1372
        code = gdev_vector_update_log_op(vdev, lop);
 
1373
        if (code < 0)
 
1374
            return 0;
 
1375
        if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
 
1376
            return 0;
 
1377
    }
 
1378
    code = gdev_vector_update_log_op(vdev,
 
1379
                                     lop | rop3_S | lop_S_transparent);
 
1380
    if (code < 0)
 
1381
        return 0;
 
1382
    pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
 
1383
    s = pclxl_stream(xdev);
 
1384
    {
 
1385
        static const byte mi_[] = {
 
1386
            DUB(e1Bit), DA(pxaColorDepth),
 
1387
            DUB(eIndexedPixel), DA(pxaColorMapping)
 
1388
        };
 
1389
 
 
1390
        PX_PUT_LIT(s, mi_);
 
1391
    }
 
1392
    pclxl_write_begin_image(xdev, w, h, w, h);
 
1393
    pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
 
1394
    pclxl_write_end_image(xdev);
 
1395
    return 0;
 
1396
}
 
1397
 
 
1398
/* Do a RasterOp. */
 
1399
static int
 
1400
pclxl_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex,
 
1401
                     uint sraster, gx_bitmap_id id,
 
1402
                     const gx_color_index * scolors,
 
1403
                     const gx_strip_bitmap * textures,
 
1404
                     const gx_color_index * tcolors,
 
1405
                     int x, int y, int width, int height,
 
1406
                     int phase_x, int phase_y, gs_logical_operation_t lop)
 
1407
{                               /* We can't do general RasterOps yet. */
 
1408
/****** WORK IN PROGRESS ******/
 
1409
    return 0;
 
1410
}
 
1411
 
 
1412
/* ------ High-level images ------ */
 
1413
 
 
1414
#define MAX_ROW_DATA 500000     /* arbitrary */
 
1415
typedef struct pclxl_image_enum_s {
 
1416
    gdev_vector_image_enum_common;
 
1417
    gs_matrix mat;
 
1418
    struct ir_ {
 
1419
        byte *data;
 
1420
        int num_rows;           /* # of allocated rows */
 
1421
        int first_y;
 
1422
        uint raster;
 
1423
    } rows;
 
1424
} pclxl_image_enum_t;
 
1425
gs_private_st_suffix_add1(st_pclxl_image_enum, pclxl_image_enum_t,
 
1426
                          "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
 
1427
                          pclxl_image_enum_reloc_ptrs, st_vector_image_enum,
 
1428
                          rows.data);
 
1429
 
 
1430
/* Start processing an image. */
 
1431
static int
 
1432
pclxl_begin_image(gx_device * dev,
 
1433
                  const gs_imager_state * pis, const gs_image_t * pim,
 
1434
                  gs_image_format_t format, const gs_int_rect * prect,
 
1435
                  const gx_drawing_color * pdcolor,
 
1436
                  const gx_clip_path * pcpath, gs_memory_t * mem,
 
1437
                  gx_image_enum_common_t ** pinfo)
 
1438
{
 
1439
    gx_device_vector *const vdev = (gx_device_vector *)dev;
 
1440
    gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
 
1441
    const gs_color_space *pcs = pim->ColorSpace;
 
1442
    pclxl_image_enum_t *pie;
 
1443
    byte *row_data;
 
1444
    int num_rows;
 
1445
    uint row_raster;
 
1446
    /*
 
1447
     * Following should divide by num_planes, but we only handle chunky
 
1448
     * images, i.e., num_planes = 1.
 
1449
     */
 
1450
    int bits_per_pixel =
 
1451
        (pim->ImageMask ? 1 :
 
1452
         pim->BitsPerComponent * gs_color_space_num_components(pcs));
 
1453
    gs_matrix mat;
 
1454
    int code;
 
1455
 
 
1456
    /*
 
1457
     * Check whether we can handle this image.  PCL XL 1.0 and 2.0 only
 
1458
     * handle orthogonal transformations.
 
1459
     */
 
1460
    gs_matrix_invert(&pim->ImageMatrix, &mat);
 
1461
    gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
 
1462
    /* Currently we only handle portrait transformations. */
 
1463
    if (mat.xx <= 0 || mat.xy != 0 || mat.yx != 0 || mat.yy <= 0 ||
 
1464
        (pim->ImageMask ?
 
1465
         (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
 
1466
         (!pclxl_can_handle_color_space(pim->ColorSpace) ||
 
1467
          (bits_per_pixel != 1 && bits_per_pixel != 4 &&
 
1468
           bits_per_pixel != 8 && bits_per_pixel !=24))) ||
 
1469
        format != gs_image_format_chunky ||
 
1470
        prect
 
1471
        )
 
1472
        goto use_default;
 
1473
    row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
 
1474
    num_rows = MAX_ROW_DATA / row_raster;
 
1475
    if (num_rows > pim->Height)
 
1476
        num_rows = pim->Height;
 
1477
    if (num_rows <= 0)
 
1478
        num_rows = 1;
 
1479
    pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
 
1480
                          "pclxl_begin_image");
 
1481
    row_data = gs_alloc_bytes(mem, num_rows * row_raster,
 
1482
                              "pclxl_begin_image(rows)");
 
1483
    if (pie == 0 || row_data == 0) {
 
1484
        code = gs_note_error(gs_error_VMerror);
 
1485
        goto fail;
 
1486
    }
 
1487
    code = gdev_vector_begin_image(vdev, pis, pim, format, prect,
 
1488
                                   pdcolor, pcpath, mem,
 
1489
                                   &pclxl_image_enum_procs,
 
1490
                                   (gdev_vector_image_enum_t *)pie);
 
1491
    if (code < 0)
 
1492
        return code;
 
1493
    pie->mat = mat;
 
1494
    pie->rows.data = row_data;
 
1495
    pie->rows.num_rows = num_rows;
 
1496
    pie->rows.first_y = 0;
 
1497
    pie->rows.raster = row_raster;
 
1498
    *pinfo = (gx_image_enum_common_t *) pie;
 
1499
    {
 
1500
        gs_logical_operation_t lop = pis->log_op;
 
1501
 
 
1502
        if (pim->ImageMask) {
 
1503
            const byte *palette = (const byte *)
 
1504
                (pim->Decode[0] ? "\377\000" : "\000\377");
 
1505
 
 
1506
            code = gdev_vector_update_fill_color(vdev, 
 
1507
                                     NULL, /* use process color */
 
1508
                                     pdcolor);
 
1509
            if (code < 0)
 
1510
                goto fail;
 
1511
            code = gdev_vector_update_log_op
 
1512
                (vdev, lop | rop3_S | lop_S_transparent);
 
1513
            if (code < 0)
 
1514
                goto fail;
 
1515
            pclxl_set_color_palette(xdev, eGray, palette, 2);
 
1516
        } else {
 
1517
            if (bits_per_pixel == 24 ) {
 
1518
                stream *s = pclxl_stream(xdev);
 
1519
                if (dev->color_info.num_components == 1) {
 
1520
                    pclxl_set_color_space(xdev, eGray);
 
1521
                    px_put_uba(s, (byte) 0x00, pxaGrayLevel);
 
1522
                } else {
 
1523
                    pclxl_set_color_space(xdev, eRGB);
 
1524
                    spputc(s, pxt_ubyte_array);
 
1525
                    px_put_ub(s, 3);
 
1526
                    spputc(s, (byte) 0x00);
 
1527
                    spputc(s, (byte) 0x00);
 
1528
                    spputc(s, (byte) 0x00);
 
1529
                    px_put_a(s, pxaRGBColor);
 
1530
                }
 
1531
                spputc(s, (byte) pxtSetBrushSource);
 
1532
            } else {
 
1533
            int bpc = pim->BitsPerComponent;
 
1534
            int num_components = pie->plane_depths[0] * pie->num_planes / bpc;
 
1535
            int sample_max = (1 << bpc) - 1;
 
1536
            byte palette[256 * 3];
 
1537
            int i;
 
1538
 
 
1539
            code = gdev_vector_update_log_op
 
1540
                (vdev, (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
 
1541
            if (code < 0)
 
1542
                goto fail;
 
1543
            for (i = 0; i < 1 << bits_per_pixel; ++i) {
 
1544
                gs_client_color cc;
 
1545
                gx_device_color devc;
 
1546
                int cv = i, j;
 
1547
                gx_color_index ci;
 
1548
 
 
1549
                for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
 
1550
                    cc.paint.values[j] = pim->Decode[j * 2] +
 
1551
                        (cv & sample_max) *
 
1552
                        (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
 
1553
                        sample_max;
 
1554
                (*pcs->type->remap_color)
 
1555
                    (&cc, pcs, &devc, pis, dev, gs_color_select_source);
 
1556
                if (!gx_dc_is_pure(&devc))
 
1557
                    return_error(gs_error_Fatal);
 
1558
                ci = gx_dc_pure_color(&devc);
 
1559
                if (dev->color_info.num_components == 1) {
 
1560
                    palette[i] = (byte)ci;
 
1561
                } else {
 
1562
                    byte *ppal = &palette[i * 3];
 
1563
 
 
1564
                    ppal[0] = (byte) (ci >> 16);
 
1565
                    ppal[1] = (byte) (ci >> 8);
 
1566
                    ppal[2] = (byte) ci;
 
1567
                }
 
1568
            }
 
1569
            if (dev->color_info.num_components == 1)
 
1570
                pclxl_set_color_palette(xdev, eGray, palette,
 
1571
                                        1 << bits_per_pixel);
 
1572
            else
 
1573
                pclxl_set_color_palette(xdev, eRGB, palette,
 
1574
                                        3 << bits_per_pixel);
 
1575
            }
 
1576
        }
 
1577
    }
 
1578
    return 0;
 
1579
 fail:
 
1580
    gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
 
1581
    gs_free_object(mem, pie, "pclxl_begin_image");
 
1582
 use_default:
 
1583
    if (dev->color_info.num_components == 1)
 
1584
        pclxl_set_color_space(xdev, eGray);
 
1585
    else
 
1586
        pclxl_set_color_space(xdev, eRGB);
 
1587
    return gx_default_begin_image(dev, pis, pim, format, prect,
 
1588
                                  pdcolor, pcpath, mem, pinfo);
 
1589
}
 
1590
 
 
1591
/* Write one strip of an image, from pie->rows.first_y to pie->y. */
 
1592
static int
 
1593
image_transform_x(const pclxl_image_enum_t *pie, int sx)
 
1594
{
 
1595
    return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
 
1596
                 ((const gx_device_pclxl *)pie->dev)->scale.x);
 
1597
}
 
1598
static int
 
1599
image_transform_y(const pclxl_image_enum_t *pie, int sy)
 
1600
{
 
1601
    return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
 
1602
                 ((const gx_device_pclxl *)pie->dev)->scale.y);
 
1603
}
 
1604
 
 
1605
static int
 
1606
pclxl_image_write_rows(pclxl_image_enum_t *pie)
 
1607
{
 
1608
    gx_device_pclxl *const xdev = (gx_device_pclxl *)pie->dev;
 
1609
    stream *s = pclxl_stream(xdev);
 
1610
    int y = pie->rows.first_y;
 
1611
    int h = pie->y - y;
 
1612
    int xo = image_transform_x(pie, 0);
 
1613
    int yo = image_transform_y(pie, y);
 
1614
    int dw = image_transform_x(pie, pie->width) - xo;
 
1615
    int dh = image_transform_y(pie, y + h) - yo;
 
1616
    int rows_raster=pie->rows.raster;
 
1617
 
 
1618
    if (dw <= 0 || dh <= 0)
 
1619
        return 0;
 
1620
    pclxl_set_cursor(xdev, xo, yo);
 
1621
    if (pie->bits_per_pixel==24) {
 
1622
        static const byte ci_[] = {
 
1623
            DA(pxaColorDepth),
 
1624
            DUB(eDirectPixel), DA(pxaColorMapping)
 
1625
        };
 
1626
 
 
1627
        px_put_ub(s, eBit_values[8]);
 
1628
        PX_PUT_LIT(s, ci_);
 
1629
        if (xdev->color_info.depth==8) {
 
1630
          byte *in=pie->rows.data;
 
1631
          byte *out=pie->rows.data;
 
1632
          int i;
 
1633
          int j;
 
1634
          rows_raster/=3;
 
1635
          for (j=0;  j<h;  j++) {
 
1636
            for (i=0;  i<rows_raster;  i++) {
 
1637
              *out = (byte)( ((*(in+0) * (ulong) lum_red_weight) + 
 
1638
                              (*(in+1) * (ulong) lum_green_weight) + 
 
1639
                              (*(in+3) * (ulong) lum_blue_weight) + 
 
1640
                              (lum_all_weights / 2)) / lum_all_weights);
 
1641
              in+=3;
 
1642
              out++;
 
1643
            }
 
1644
          }
 
1645
        }
 
1646
    } else {
 
1647
        static const byte ii_[] = {
 
1648
            DA(pxaColorDepth),
 
1649
            DUB(eIndexedPixel), DA(pxaColorMapping)
 
1650
        };
 
1651
        px_put_ub(s, eBit_values[pie->bits_per_pixel]);
 
1652
        PX_PUT_LIT(s, ii_);
 
1653
    }
 
1654
    pclxl_write_begin_image(xdev, pie->width, h, dw, dh);
 
1655
    pclxl_write_image_data(xdev, pie->rows.data, 0, rows_raster,
 
1656
                           rows_raster << 3, 0, h);
 
1657
    pclxl_write_end_image(xdev);
 
1658
    return 0;
 
1659
}
 
1660
 
 
1661
/* Process the next piece of an image. */
 
1662
static int
 
1663
pclxl_image_plane_data(gx_image_enum_common_t * info,
 
1664
                       const gx_image_plane_t * planes, int height,
 
1665
                       int *rows_used)
 
1666
{
 
1667
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
 
1668
    int data_bit = planes[0].data_x * info->plane_depths[0];
 
1669
    int width_bits = pie->width * info->plane_depths[0];
 
1670
    int i;
 
1671
 
 
1672
    /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
 
1673
    if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
 
1674
        return_error(gs_error_rangecheck);
 
1675
    if (height > pie->height - pie->y)
 
1676
        height = pie->height - pie->y;
 
1677
    for (i = 0; i < height; pie->y++, ++i) {
 
1678
        if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
 
1679
            int code = pclxl_image_write_rows(pie);
 
1680
 
 
1681
            if (code < 0)
 
1682
                return code;
 
1683
            pie->rows.first_y = pie->y;
 
1684
        }
 
1685
        memcpy(pie->rows.data +
 
1686
                 pie->rows.raster * (pie->y - pie->rows.first_y),
 
1687
               planes[0].data + planes[0].raster * i + (data_bit >> 3),
 
1688
               pie->rows.raster);
 
1689
    }
 
1690
    *rows_used = height;
 
1691
    return pie->y >= pie->height;
 
1692
}
 
1693
 
 
1694
/* Clean up by releasing the buffers. */
 
1695
static int
 
1696
pclxl_image_end_image(gx_image_enum_common_t * info, bool draw_last)
 
1697
{
 
1698
    pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
 
1699
    int code = 0;
 
1700
 
 
1701
    /* Write the final strip, if any. */
 
1702
    if (pie->y > pie->rows.first_y && draw_last)
 
1703
        code = pclxl_image_write_rows(pie);
 
1704
    gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
 
1705
    gx_image_free_enum(&info);
 
1706
    return code;
 
1707
}
 
1708
 
 
1709
/*
 
1710
 * 'pclxl_get_params()' - Get pagedevice parameters.
 
1711
 */
 
1712
 
 
1713
static int                              /* O - Error status */
 
1714
pclxl_get_params(gx_device     *dev,    /* I - Device info */
 
1715
                 gs_param_list *plist)  /* I - Parameter list */
 
1716
{
 
1717
  gx_device_pclxl       *xdev;          /* PCL XL device */
 
1718
  int                   code;           /* Return code */
 
1719
 
 
1720
 
 
1721
 /*
 
1722
  * First process the "standard" page device parameters...
 
1723
  */
 
1724
 
 
1725
  if ((code = gdev_vector_get_params(dev, plist)) < 0)
 
1726
    return (code);
 
1727
 
 
1728
 /*
 
1729
  * Then write the PCL-XL parameters...
 
1730
  */
 
1731
 
 
1732
  xdev = (gx_device_pclxl *)dev;
 
1733
 
 
1734
  if ((code = param_write_bool(plist, "Duplex", &(xdev->Duplex))) < 0)
 
1735
    return (code);
 
1736
 
 
1737
  if ((code = param_write_int(plist, "MediaPosition",
 
1738
                              &(xdev->MediaPosition))) < 0)
 
1739
    return (code);
 
1740
 
 
1741
  if ((code = param_write_bool(plist, "Tumble", &(xdev->Tumble))) < 0)
 
1742
    return (code);
 
1743
 
 
1744
  return (0);
 
1745
}
 
1746
 
 
1747
 
 
1748
/*
 
1749
 * 'pclxl_put_params()' - Set pagedevice parameters.
 
1750
 */
 
1751
 
 
1752
static int                              /* O - Error status */
 
1753
pclxl_put_params(gx_device     *dev,    /* I - Device info */
 
1754
                 gs_param_list *plist)  /* I - Parameter list */
 
1755
{
 
1756
  gx_device_pclxl       *xdev;          /* PCL XL device */
 
1757
  int                   code;           /* Error code */
 
1758
  int                   intval;         /* Integer value */
 
1759
  bool                  boolval;        /* Boolean value */
 
1760
 
 
1761
 
 
1762
 /*
 
1763
  * Process PCL-XL driver parameters...
 
1764
  */
 
1765
 
 
1766
  xdev = (gx_device_pclxl *)dev;
 
1767
 
 
1768
#define intoption(name, sname, type) \
 
1769
  if ((code = param_read_int(plist, sname, &intval)) < 0) \
 
1770
  { \
 
1771
    param_signal_error(plist, sname, code); \
 
1772
    return (code); \
 
1773
  } \
 
1774
  else if (code == 0) \
 
1775
  { \
 
1776
    xdev->name = (type)intval; \
 
1777
  }
 
1778
 
 
1779
#define booloption(name, sname) \
 
1780
  if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
 
1781
  { \
 
1782
    if ((code = param_read_null(plist, sname)) < 0) \
 
1783
    { \
 
1784
      param_signal_error(plist, sname, code); \
 
1785
      return (code); \
 
1786
    } \
 
1787
    if (code == 0) \
 
1788
      xdev->name = false; \
 
1789
  } \
 
1790
  else if (code == 0) \
 
1791
    xdev->name = (bool)boolval;
 
1792
 
 
1793
  booloption(Duplex, "Duplex")
 
1794
  intoption(MediaPosition, "MediaPosition", int)
 
1795
  if (code == 0) xdev->MediaPosition_set = true;
 
1796
  booloption(Tumble, "Tumble")
 
1797
 
 
1798
 /*
 
1799
  * Then process standard page device parameters...
 
1800
  */
 
1801
 
 
1802
  if ((code = gdev_vector_put_params(dev, plist)) < 0)
 
1803
    return (code);
 
1804
 
 
1805
  return (0);
 
1806
}