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