1 /*
2 
3    Copyright (C) 1999,2000  Peter B. West <pbwest@netscape.net>
4    Portions Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 U.S.A.
19 
20    This program may also be distributed as part of Aladdin Ghostscript,
21    under the terms of the Aladdin Free Public License (the "License").
22 
23    Every copy of Aladdin Ghostscript must include a copy of the
24    License, normally in a plain ASCII text file named PUBLIC.  The
25    License grants you the right to copy, modify and redistribute
26    Aladdin Ghostscript, but only under certain conditions described in
27    the License.  Among other things, the License requires that the
28    copyright notice and this notice be preserved on all copies.
29 
30   The author, Peter B. West, may be contacted via e-mail as
31   pbwest@netscape.net
32   or by post at
33   1/32 Bent Street
34   Toowong, Brisbane,
35   QLD, AUSTRALIA. 4066
36 
37   http://www.powerup.com.au/~pbwest
38 
39   Based on the driver for the Lexmark 5700, pioneered by
40     Stephen Taylor  setaylor@ma.ultranet.com  staylor@cs.wpi.edu
41   and on other pioneering work on the Lexmark 7000 by
42     Henryk Paluch <paluch@bimbo.fjfi.cvut.cz>
43 
44   My heartfelt thanks to these blokes (i.e. guys, fellows).
45 
46   I should also like to thank Marija Svilans, through whom I discovered the
47   work of Stephen and Henryk.
48 
49   My deepest praise and thanksgiving is reserved for the Author of all that
50   is Good, Beautiful and True; my Lord and my God, Jesus Christ.
51   "...all things were made through Him, and without Him was not anything
52    made that was made."  John 1:3
53 
54   Peter B. West pbwest@netscape.net
55   (First release: Friday, 8th October, 1999.)
56 
57 */
58 
59 /*$Id: gdevlx50.c,v 1.41 2000-04-18 14:35:41+10 pbw Exp pbw $*/
60 /*
61  * Lexmark 5000 ink-jet printer driver for Ghostscript
62  *
63  * Black and colour cartridges supported - NO PHOTO CARTRIDGE support yet.
64  *
65  * defines the lx5000 device for printing in black-and-white and colour
66  * at 600x600 (default), 1200x600 & 300x600 dpi, unidirectional.
67  *
68  * I use the command
69  * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 file.ps
70  *
71  * For black-only printing, use
72  * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 -dBitsPerPixel=1 file.ps
73  * For compatibility with earlier versions of the code, the following
74  *  equivalent command is still supported.
75  * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 -dCMYK=false file.ps
76  *
77  * For 1200x600 printing, add the argument
78  * -r1200x600
79  * For 300x600 printing, add the argument
80  * -r300x600
81  *
82  * A number of integer valued options are available.
83  * These options are accessed as arguments of the form
84  *	-doptionname=optionvalue
85  * 	Optionname		Optionvalue range
86  *	BitsPerPixel		1 or 4
87  *	HeadSeparation		1 - 30
88  *	AlignA			0 - 30
89  *	AlignB			0 - 15
90  *	DryingTime		0 - 60
91  *
92  * BitsPerPixel currently only defines Black-only (1) or CMYK (4).
93  *  -dBitsPerPixel=4 is the default, and is eauivalent to the older form
94  *  -dCMYK=true
95  * [ HeadSeparation varies from print-cartridge to print-cartridge and
96  *  16 (the default) usually works fine. Stephen Taylor]
97  *
98  * AlignA is the horizontal alignment adjustment between the colour and
99  *  the black pens.  This distance will vary with each pair of cartridges.
100  *
101  * AlignB is the vertical alignment distance between the colour and black
102  *  pens, and will also vary with each pair of cartridges.
103  *
104  * These values can be determined by running the alignment test; i.e,
105  * by writing the printer data file blckalgn.out to the device.
106  *
107  *  cat blckalgn.out >/dev/lp0
108  *
109  * This file is now part of the distribution for the driver.
110  *
111  * DryingTime is used to include a delay after printing a page, to allow the
112  * page to dry to some extent before a subsequent page is printed and fed on
113  * top of it.  The range of values is 0-60.
114  *
115  * Ancilliary files:
116  *
117  * blckalgn.out		As mentioned above,this is a file of printer commands
118  *			which will print the allignment page for the 5000.
119  *   Usage:  cat blckalgn.out >/dev/lp0 (or appropriate printer device)
120  *
121  * blckhcln.out		This is a file of printer commands to print the head
122  *			cleaning sequences.
123  *   Usage:  cat blckhcln.out >/dev/lp0
124  *
125  * showcarts.out	This is a file with the printer command to move the
126  *			printer cartridges into position for changing a
127  *			cartridge.
128  *   Usage:  cat showcarts.out >/dev/lp0
129  *
130  * parkcarts.out	This is a file with the printer command to move the
131  *			printer cartridges back to a parked position.
132  *   Usage:  cat parkcarts.out >/dev/lp0
133  *
134  ==================   K N O W N   P R O B L E M S   =======================
135 
136   PROBLEMS WITH 1200dpi horizontally
137 
138   This release was delayed by a bug in the production of black output
139   (including black pixels in colour output) at 1200 Xdpi which
140   manifested as the truncation of black swipes.  In the RedHat test
141   page, for example, the black background to the hat in the RedHat
142   logo would abruptly halt, and no more of the black swipe would be
143   printed.  This was difficult to track down, because of the sheer
144   size of the otuput file produced, and I ran out of time to find and
145   fix it, although I was beginning to suspect a problem with the
146   parallel driver.  (It is always tempting to blame someone else.)
147 
148   When I recently returned to this problem, and tried the test print
149   again on the unchanged binary, the bug had disappeared.  In the
150   meantime, I had added more physical memory to the system, and
151   upgraded my 6.0 system to the 6.1 kernel (2.2.12), the 6.1 glibc
152   version (2.1.2-11) and miscellaneous other 6.1 rpms.
153 
154   All was not lost, however.  When I tested black-only printing at
155   1200dpi, the problem re-appeared.  I have come to the conclusion
156   that the 5000 simply cannot print at 1200dpi.  I have tested this by
157   printing solid bars of black at 600 and 1200 dpi.  The 600dpi bar
158   (all nozzles on for most of the width of the paper) produces the
159   expected bar.  Doing the same thing at 1200dpi produces movement of
160   the printhead, but only the beginnings of a bar.  Reducing the
161   demand by printing from only every second nozzle get an intermediate
162   result; the printing of the bar starts, but the nozzle lines trail
163   off and dry up at various points in the traversal of the
164   page. leaving an effect somthing like a tattered flag.
165 
166   How does the Windows driver do it?  When printing a high density
167   black-only page, the driver prints repeated overlays offset by half
168   the height of the print swathe.  Although I have not analysed these
169   swathes in detail, I suspect that the function of this "halving" is
170   simply to halve the printed pixel density, and thereby eliminate the
171   problem discussed above.
172 
173   I have taken the "half-height" printing method for granted ever
174   since I read a passing reference to it in the H-P Jounal articles on
175   PPA, but I misunderstood it.  I had thought that it was a way of
176   performing a pseudo-doubling of the VERTICAL print density by
177   overprinting adjacent pairs of lines.  I was originally unaware that
178   the 5000 supported native 1200x600 resolution.  The problem, as far
179   as I can determine, is that the 5000 does NOT support such printing.
180   And if the printer is not going to support 1200dpi horizontally,
181   neither am I.
182 
183   PROBLEMS WITH PRINTER DATA "JAMMING"
184 
185   I am experiencing an annoying problem with my 5000 on my AST Bravo
186   P100 (yes, really) system under RedHat linux (6.0 with kernel
187   2.2.12-20 and glibc 2.1.2-11).  The printer frequently fails to
188   respond between print jobs, and sometimes between pages of the same
189   print job.  The only way to wake it up is to power cycle the
190   printer.  I have no idea why this is, of whether it is a general
191   problem.  I would appreciate all feedback on this problem.
192 
193   I have received feedback on this from Bob Clark
194   <rlc@c317689-a.scllg1.pa.home.com>.  He realised that the printer
195   was queueing status data to be read from the same device.  When this
196   queue (which appears to be 64 bytes long) fills up, the printer
197   stalls until it is reset (by a power cycle or by some as yet
198   undiscovered escape sequence), or until the status data is read.
199   That's the problem, but I do not have a clean solution yet.
200 
201  *=================================================
202    Other requirements for compiling this driver:-
203   =================================================
204    The Ghostscript 6.0 source distribution, available from
205       http://www.cs.wisc.edu/~ghost/aladdin/get600.html
206 
207    This includes reasonable html documentation on compiling GS.
208 
209    For users of RPM-based systems like Red Hat, I have a source RPM
210    available which automates most of the process of compiling and
211    installing Ghostscript.  A discussion of the details of compiling
212    and installing with this source RPM is available on my web page at
213    <http://localhost:80/~pbw/ghostscript/compileGS.html>.
214 
215    The RPM includes a number of patch files which are applied to the
216    pristine Ghostscript 6.0 sources.  Users of non-RPM systems can
217    extract these patches from the cpio archive which is also noted in
218    the instructions.
219 
220    I have compiled and tested on a RedHat 6.0 i386 system, using
221    egcs-2.91.66 19990314/Linux (egcs-1.1.2 release), so the relevant
222    system-specific .mak file for me was unix-gcc.mak.  The .mak file
223    of general application is contrib.mak.
224 
225  */
226 
227 /************************************************************************
228  *			I N C L U D E   F I L E S			*
229  ************************************************************************/
230 #include "gdevprn.h"
231 #include "gsparam.h"
232 
233 /************************************************************************
234  *		     R C S   I D E N T   S T R I N G S			*
235  ************************************************************************/
236 const char Id[]		=
237 	"$Id: gdevlx50.c,v 1.41 2000-04-18 14:35:41+10 pbw Exp pbw $";
238 const char RCSFile[]	= "$RCSFile$";
239 const char Revision[]	= "$Revision: 1.41 $";
240 const char Author[]	=
241 	"Peter B. West   pbwest@netscape.net\n"
242 	"$Author: pbw $\n";
243 /*===========================================================================
244  In gxdevice.h, the default width and height are expressed in 10ths of an
245  inch.  The conversion to mm will therefore, not be exact.
246 
247  These values are immediately converted to (x,y) pixels for storage in the
248  width and height fields defined in the gx_device_common macro which is
249  defined in gxdevcli.h.  These in turn are converted to points and stored
250  in the float MediaSize[2] array in gx_device_common by the
251  std_device_part_2_ macro in gxdevice.h.
252 
253  The same macro stores the (x,y)dpi values in the float arrays
254  HWResolution[2] and MarginsHWResolution[2].
255 
256  The macro prn_device_std_margins_body in gdevprn.h provides for X and Y
257  offsets, as well as left, bottom, right and top margin values.  X & Y are
258  expressed in inches, as are all the other margin values.
259 
260  The X & Y offsets are known as Margins in gx_device_common.	They provide
261  the offset from the physical page corner (presumably top left, but may
262  depend on the position of 0,0) to 0,0 in the device co-ordinate system.
263  These values are converted by prn_device_std_margins_body into _negated_
264  (x,y)dpi and stored in the float Margins[2] array.
265 
266  The left, bottom, right and top margin values are converted to points,
267  and stored in the float HWMargins[4] array.  Note that these values are
268  defined relative to the physical paper, not the co-ordinate system.  The
269  Margins array is used to transform from physical page offsets to the
270  device co-ordinate system.
271 
272  The implications of this are that the X & Y offset from page corner to
273  0,0 should be defined as accurately as possible.  The other four margins
274  should then be defined for a comprehensive coverage of the physical page.
275  The definitions of paper size given in 10ths of an inch in gxdevice.h are
276  a constraint.
277 
278  I presume that the intention of the transformation from 0,0 to
279  the physical page is to leave the defined width and height mapped
280  onto the physical page, and for the left and top margins to then restore
281  those two dimensions of the accessible page.  The result would be, if the
282  values of X & Y offset precisely reversed the values of left and top
283  HWMargins, that the top left hand printable point would be at device
284  co-ordinates 0,0.  The bottom and right HWMargins would then provide the
285  necessary clipping of the co-ordinate system to keep output within the
286  printable area.
287 
288  In fact, this is the way the x, Y offsets and the left and top margin
289  values are set up in the default prn_device_std_body macro in gdevprn.h.
290  In that macro, the X, Y offset values (expressed in inches) are simply
291  copied from the left and top margins.
292 
293  What I have found with my 5000, is that it can print on virtually the
294  whole area of the paper.  This shows some remarkable paper handling cap-
295  ability.  This capability almost demands that 0,0 in the device co-ordin-
296  ate system be _outside_ the paper area.  It is.  On my printer, the X
297  offset from the physical page top left corner is 48 600ths of an inch -
298  a little less than 6 points.
299 
300  The physical paper is a little narrower than 8.3 inches (210.82 mm), so
301  the attempt to print right to the 8.3" margin falls short by about 16
302  600ths, or about 2 points.  When 0,0 falls _within_ the page, the combin-
303  ed margin clipping ensures that the driver will never issue printer com-
304  mands which exceed the defined width and height of the page.  What
305  happens when 0,0 is outside the page?  This implies, especially when the
306  hardware is capable of printing to the edges of the paper, that the
307  driver may issue print commands whose offsets exceed the defined width of
308  the page, in order to print to the right edge of the paper.	I don't know
309  whether Ghostscript will allow this.
310 
311                    Print width
312               |<------------ 8.3" ----------->|
313               |                               |
314               |                               |
315               +-------------- ~ --------------+
316                                               |<-->| 2 pts
317               |      |<----- Paper width --------->|
318         6 pts |<---->|                             |
319                      +-------------- ~ ------------+
320 
321  In this case, the X offset is going to be negative, and the device co-
322  ordinate value of X for the left edge of the paper is going to almost 50
323  600ths.  It is a good idea to apply some restrictions on printing to the
324  edge of the paper, so a HWMargin should be applied.
325 
326  The problem with setting the margins is this: Ghostscript knows where the
327  top and left sides of the page are relative to 0,0, because it is spec-
328  ifically informed of these values.  It has no way of knowing where the
329  bottom and right of the page are, except from the height and width values.
330  These are only provided to an accuracy of a tenth of an inch, so the
331  assumed right and bottom margins may fall short of or overrun the edge of
332  the paper.
333 
334  In these circumstances, it seems a good idea to provide HWMargin values
335  designed to enforce a uniform margin around all of the edges.  The left &
336  top margins can be given directly; the others must be worked out so that
337  when applied with reference to the height and width parameters, they
338  result in the same margin.
339 
340  For example, on my 5000, 0,0 is approximately 48/600" (about 6 points) to
341  the left of the physical page.  When I print at an offset from 0 of
342  8.3", the default A4 width, the print is approximately 32/600" (about 4
343  points) inside the right edge of the page.  That is, 8.3" is (48-32)/600"
344  too wide for the physical page.
345 
346  4 points (4/72") is 0.05555", and 32/600" is 0.053333".  If I set a left
347  HWMargin of 0.053", and Ghostscript obliges by mapping a new printable
348  origin 4 points inside the left edge of the paper, with 8.3" of print-
349  able line to the right of it, my left margin will need to account for the
350  extra 16/600" that GS thinks exists on the right, and for the actual
351  margin of 0.053" that I want to establish on the right.  I think.
352 
353  The interest in the top margin is that it seems to be keyed to the colour
354  pens.  These form three blocks of nozzles vertically aligned in the
355  colour print head.
356 
357  ---    -- +-----+                 v Alignment B
358   ^     ^  |     | v              --- +-----+ ---
359   |     64 |  C  | -- --- +-----+ --- |     |  ^
360   |  v  v  |     | 40  ^  |     |  ^  |     |  |
361   |  -- -- +-----+ --  |  |     |     |     |  |
362   |  24            ^   |  |     |     |     |  |
363   |  -- -- +-----+     |  |     |     |     |  |
364   |  ^  ^  |     |     |  |     |     |     |
365  240    64 |  M  |    192 |  K  |     |  K  | 208
366   |  v  v  |     |     |  |     |     |     |
367   |  -- -- +-----+     |  |     |     |     |  |
368   |  24            v   |  |     |     |     |  |
369   |  -- -- +-----+ --  |  |     |     |     |  |
370   |  ^  ^  |     | 40  v  |     |     |     |  |
371   |     64 |  Y  | -- --- +-----+     |     |  v
372   v     v  |     | ^                  +-----+ ---
373  ---    -- +-----+
374 
375  The colour pens have 64 nozzles each, and the black has 208.  Black can
376  also be driven in colour compatibility mode, when it uses 192 nozzles
377  only, the same as the total number of colour nozzles.  In order to align
378  the black nozzles with the colour, an alignment value is specified in the
379  initialization sequence for the page.  This value is in turn determined
380  by printing an alignment page under control of the printer driver (See
381  ancilliary files above.)
382 
383  Note that when an odd number is specified as Alignment B, an odd numbered
384  nozzle will be mapped as nozzle 0 of the 192 nozzle black pen, so the
385  even/odd association of nozzle numbers will be reversed; i.e., nozzle 0
386  will become and ODD nozzle.
387 
388  The paper handler seems to assume that the paper load position is with
389  the page lined up immediately before the lowest nozzle of the YELLOW pen.
390  (Note that the paper is being fed in from the bottom of the printheads.)
391  When I issue a paper feed instruction of 480 (240x2) 1200ths, and print a
392  three-colour bar, the top of the CYAN pen is just on the physical page.
393  Efectively, the Y component of 0,0 is right at the top of the page, with
394  respect to the YELLOW pen.  Y=0 with respect to the 192 nozzle black pen
395  is always constant, and with respect to the 208 pen, can be determined
396  from Alignment B.
397 
398 
399  *===========================================================================*/
400 
401 /************************************************************************
402  *			B A S I C   M A C R O S				*
403  ************************************************************************/
404 
405 #define A5_11_5000	1
406 #define A5_11_5700	2
407 
408 
409 #define ALIGN_A_DEF	15
410 #define ALIGN_A_OFFSET	5	/* in pageinit escape sequence */
411 #define ALIGN_B_DEF	8
412 #define ALIGN_B_OFFSET	6	/* in pageinit escape sequence */
413 
414 #define HEADSEP_DEF	16
415 				/* number of pixels between even columns in */
416 				/* output and odd ones */
417 #define DRY_TIME_DEF	0	/* Default pause for page to dry */
418 
419 
420 /************************************************************************
421  *	     P R I N T E R   T Y P E   D E F I N I T I O N S	 	*
422  ************************************************************************/
423 
424 #ifndef LX_BI
425 #   define LX_UNI
426 				/* or define LX_BI */
427 #endif
428 #define MIN_LX5000_X	300
429 #define MAX_LX5000_X	1200
430 #define DEF_LX5000_X	600
431 #define MIN_LX5000_Y	600
432 #define MAX_LX5000_Y	1200
433 #define DEF_LX5000_Y	MIN_LX5000_Y
434 
435 #ifndef LX5000_XDPI
436 #   define LX5000_XDPI	DEF_LX5000_X
437 #endif
438 #ifndef LX5000_YDPI
439 #   define LX5000_YDPI	DEF_LX5000_Y
440 #endif
441 
442 				/* Multiply lines by FEED_FACTOR when feeding
443 				   paper.  The 5000 feeds in 1200ths. */
444 #define FEED_FACTOR	( 1200/LX5000_YDPI )
445 
446 #define LX5000_XOFFSET_TO_0_0_XDPI	(-48.0)
447 #define LX5000_YOFFSET_TO_0_0_YDPI	(0.0)
448 
449 #define LX5000_XOFFSET_TO_0_0	( LX5000_XOFFSET_TO_0_0_XDPI/LX5000_XDPI )
450 #define LX5000_YOFFSET_TO_0_0	( LX5000_YOFFSET_TO_0_0_YDPI/LX5000_YDPI )
451 
452 /* The theory */
453 #define LX5000_LEFT_HWMARGIN_INS	0.053
454 #define LX5000_BOTTOM_HWMARGIN_INS	0.067
455 #define LX5000_RIGHT_HWMARGIN_INS	0.08
456 #define LX5000_TOP_HWMARGIN_INS		0.053
457 /**/
458 /* The practice
459 ??
460 */
461 
462 #define LINE_PAD_BYTES	8
463 				/* number of bytes of padding on each end of */
464 				/* scan line to account for head separation */
465 				/* N.B. Keep this value 16-bit aligned.  */
466 
467 #define RIGHTWARD	0
468 #define LEFTWARD	1
469 
470 #define SWIPE_WORD_BITS	16
471 				/* Bits per directory word */
472 #define BLACK_NOZZLES	208
473 				/* height of printhead in pixels */
474 #define _1COLOUR_NOZZLES 64
475 				/* Height of one colour pen in pixels */
476 
477 				/* Height of colour compatible black swipe */
478 #define BLK_COLOUR_NOZZLES	(_1COLOUR_NOZZLES * 3)
479 
480 				/* number of shorts described by each */
481 				/* full black column directory */
482 #define BLK_SWIPE_WORDS		( BLACK_NOZZLES / SWIPE_WORD_BITS )
483 #define COLOUR_SWIPE_WORDS	( BLK_COLOUR_NOZZLES / SWIPE_WORD_BITS )
484 				/* and for a colour swipe command */
485 #define _1COLOUR_WORDS		( _1COLOUR_NOZZLES / SWIPE_WORD_BITS )
486 				/* and for a single colour pen */
487 
488 #define BLK_DIRECTORY_MASK	(( ~0 << BLK_SWIPE_WORDS ) ^ ~0 )
489 #define COLOUR_DIRECTORY_MASK	(( ~0 << COLOUR_SWIPE_WORDS ) ^ ~0 )
490 #define DIRECTORY_TYPE_BIT	0x2000
491 				/* Directory type: Set = normal;
492 					   unset = repeat compression */
493 
494 #define COLOUR_PEN_GAP	24	/* Defined in equivalent nozzles.  This will */
495 				/* also be the offset from the top of the */
496 				/* first colour pen to the top of the colour */
497 				/* compatible black pen. */
498 #define COLOUR_PEN_DIFF	( _1COLOUR_NOZZLES + COLOUR_PEN_GAP )
499 				/* The difference between corresponding */
500 				/* nozzle positions (e.g. bottom nozzle) on */
501 				/* contiguous colour pens. */
502 
503 				/* The intial pen scanline positions are */
504 				/* defined with reference to the first */
505 				/* printable line (line 0) on the page.  The */
506 				/* initial colour cartridge position is */
507 				/* immediately above line 0. */
508 #define INITIAL_YELLOW_BOTTOM_LINE	( -1 )
509 
510 				/*  The pen buffer size must be a power of */
511 				/*  2, so that the index into the buffer */
512 				/*  will either wrap within that size on */
513 				/*  increment, or be able to be masked to */
514 				/*  force a wrap of the index into the */
515 				/*  circular pen buffers.  See discussion */
516 				/*  of pen buffers in lx5000_print_page(). */
517 #define COLOUR_BUF_MASK		0xff
518 				/* 2^8 - 1 */
519 #define COLOUR_BUF_LINES	( COLOUR_BUF_MASK + 1 )
520 
521 /************************************************************************
522  *		S W I P E   C O M M A N D   M A C R O S			*
523  ************************************************************************/
524 
525 #define SWIPE_LEADER	0x1b, '*', 4
526 				/* Lead-in bytes for swipe command */
527 
528 #define CMDLEN_X	3
529 				/* Index in swipe command of 4 byte */
530 
531 #define DIRECTION_X	7
532 				/* Index in swipe cmd of direction flag */
533 
534 #define UNIDIRECTIONAL	0
535 #define BIDIRECTIONAL	1
536 
537 #define HEADSPEED_X	8
538 				/* Index in swipe cmd of head speed */
539 				/* Head speeds for various densities */
540 #define _300X		1
541 #define _600X		2
542 #define _1200X		5
543 
544 #define PEN_X		9
545 				/* Index of 2 byte pen selectors */
546 #define BLACK0		1
547 #define BLACK1		1
548 #define COLOUR0		2
549 #define COLOUR1		0
550 
551 #define NOZZLE_COUNT_X	11
552 				/* Index of nozzle count selector */
553 #define _192NOZZLES	0x18
554 #define _208NOZZLES	0x1a
555 
556 #define UNKNOWN1_X	12
557 				/* Index of an unknown byte */
558 #define UNKNOWN1VAL	0
559 #define NUM_COLUMNS_X	13
560 				/* Index in swipe command of 2 byte */
561 				/* column count				*/
562 #define _1ST_COLUMN_X	15
563 				/* Index in swipe command of 2 byte */
564 				/* first column horizontal offset */
565 #define LAST_COLUMN_X	17
566 				/* Index in swipe command of 2 byte */
567 				/* last column horizontal offset	*/
568 
569 #define SWIPE_HDR_END_X	19
570 #define SWIPE_HDR_END_LEN	7
571 #define SWIPE_HDR_END	0, 0, '+', 'p', 'b', 'w', 1
572 				/* Final byte sequence of swipe cmd header */
573 
574 #define SWIPE_HDR_LEN	( SWIPE_HDR_END_X + SWIPE_HDR_END_LEN )
575 
576 /************************************************************************
577  *		C O L O U R   H A N D L I N G   M A C R O S		*
578  ************************************************************************/
579 /* Macros for the relative position on the colour components in */
580 /* gx_color_index, the driver defined representation of individual */
581 /* colours. */
582 
583 #define BLACK_X		0
584 #define YELLOW_X	1
585 #define MAGENTA_X	2
586 #define CYAN_X		3
587 
588 #define LO_PEN		0
589 #define HI_PEN		1
590 
591 				/* Colour defines for lx5000 black printer */
592 
593 #   define NUM_COMPONENTS_BLK	1
594 #   define BITS_PER_PIXEL_BLK	1
595 #   define MAX_GREY_BLK		1
596 #   define MAX_RGB_BLK		0
597 #   define DITHER_GREYS_BLK	2
598 #   define DITHER_COLOURS_BLK	0
599 
600 				/* Colour defines for lx5000 colour printer */
601 #   define NUM_COMPONENTS_CMY	4
602 #   define BITS_PER_PIXEL_CMY	4
603 #   define MAX_GREY_CMY		1
604 #   define MAX_RGB_CMY		1
605 #   define DITHER_GREYS_CMY	2
606 #   define DITHER_COLOURS_CMY	2
607 
608 #   define MIN_COLOUR		BLACK_X
609 #   define MAX_COLOUR		CYAN_X
610 #   define BLACK_PEN		BLACK_X
611 #   define _1ST_CMY_COLOUR	YELLOW_X
612 #   define LAST_CMY_COLOUR	CYAN_X
613 
614 #define BPP			BITS_PER_PIXEL_CMY
615 				/* N.B. This is only required for
616 				   processCMYKline */
617 #   define PIXEL_MASK		(( 1 << BPP ) - 1 )
618 #   define INITIAL_PIXEL_SHIFT	( ( sizeof( uchar ) * 8 ) - BPP )
619 
620 #define NUM_COLOURS		( MAX_COLOUR - MIN_COLOUR + 1 )
621 #define PENS_PER_COLOUR	2
622 #define NUM_PENS		( NUM_COLOURS * PENS_PER_COLOUR )
623 
624 #define BITS_PER_COLOUR		(BITS_PER_PIXEL_CMY / NUM_COMPONENTS_CMY)
625 
626 #define DEF_NUM_COLOURS		NUM_COLOURS
627 #define DEF_PENS_PER_COLOUR	1
628 #define DEF_LINE_INCREMENT	1
629 
630 /* !!!!!!!!!!!!!!!!!!!!! WARNING, WARNING, WILL ROBINSON !!!!!!!!!!!!!!!!!!!!*/
631 				/* If BPP ever exceeds 8, this will break
632 				   badly, as will the whole of processCMYKline.
633 				   PIXELS_PER_BYTE is used when skipping over
634 				   empty bytes in processCMYKline().  Each
635 				   empty scanline byte skips over this many
636 				   bits in the colourBufs.	*/
637 #define PIXELS_PER_BYTE		(8 / BPP)
638 
639 #define COLOUR_MASK	(( 1 << ( BITS_PER_COLOUR ) ) - 1 )
640 
641 /************************************************************************
642  *			Memory allocation macros			*
643  *	    ( For use with getColourBufs & releaseAllocations )		*
644  ************************************************************************/
645 #define ALLOCATE	true
646 #define DEALLOCATE	false
647 
648 /************************************************************************
649  *		" F U N C T I O N A L "   M A C R O S			*
650  ************************************************************************/
651 /************************************************************************
652  *			Macro to fill the swipe header			*
653  ************************************************************************/
654 
655 #define FILL_SWIPE_HEADER( swipeHdr, len, dir, speed, pen0, pen1, nozzles, \
656 	unknown, numcols, firstcol, lastcol ) \
657 	    swipeHdr[ CMDLEN_X ]	= ( ( len >> 24 ) & 0xff ); \
658 	    swipeHdr[ CMDLEN_X + 1 ]	= ( ( len >> 16 ) & 0xff ); \
659 	    swipeHdr[ CMDLEN_X + 2 ]	= ( ( len >> 8 ) & 0xff ); \
660 	    swipeHdr[ CMDLEN_X + 3 ]	= ( len & 0xff ); \
661 	    swipeHdr[ DIRECTION_X ]	= dir; \
662 	    swipeHdr[ HEADSPEED_X ]	= speed; \
663 	    swipeHdr[ PEN_X ]		= pen0; \
664 	    swipeHdr[ PEN_X + 1 ]	= pen1; \
665 	    swipeHdr[ NOZZLE_COUNT_X ]	= nozzles; \
666 	    swipeHdr[ UNKNOWN1_X ]	= unknown; \
667 	    swipeHdr[ NUM_COLUMNS_X ]	= ( numcols >> 8 ); \
668 	    swipeHdr[ NUM_COLUMNS_X + 1 ] = ( numcols & 0xff ); \
669 	    swipeHdr[ _1ST_COLUMN_X ]      = ( firstcol >> 8 ); \
670 	    swipeHdr[ _1ST_COLUMN_X + 1 ]  = ( firstcol & 0xff ); \
671 	    swipeHdr[ LAST_COLUMN_X ]      = ( lastcol >> 8 ); \
672 	    swipeHdr[ LAST_COLUMN_X + 1 ]  = ( lastcol & 0xff )
673 
674 
675 /************************************************************************
676  *   Macros to manipulate bit pointers in bitBuf & scanPixels structs	*
677  ************************************************************************/
678 #define BIT_TO_MASK( n ) ( 0x80 >> ( n ) )
679 #define INC_BIT( bitPtr ) \
680 do { \
681     if ( ! ((bitPtr).xBit >>= 1 )) \
682 	    { (bitPtr).xByte++ ; (bitPtr).xBit = 0x80; } \
683 } while (0)
684 
685 #define DEC_BIT( bitPtr ) \
686 do { \
687     if ( ! ( (bitPtr).xBit = (( (bitPtr).xBit << 1 ) & 0xff ))) \
688 	{ (bitPtr).xByte-- ; (bitPtr).xBit = 1; } \
689 } while (0)
690 
691 /************************************************************************
692  *		Macro for defining gx_device_procs structure		*
693  ************************************************************************/
694 
695 #define lx5000_proctab(get_params, put_params, map_color_rgb, map_cmyk_color)\
696 {	gdev_prn_open,\
697 	gx_default_get_initial_matrix,\
698 	NULL,	/* sync_output */\
699 	gdev_prn_output_page,\
700 	gdev_prn_close,\
701 	NULL,	/* map_rgb_color */\
702 	map_color_rgb,\
703 	NULL,	/* fill_rectangle */\
704 	NULL,	/* tile_rectangle */\
705 	NULL,	/* copy_mono */\
706 	NULL,	/* copy_color */\
707 	NULL,	/* draw_line */\
708 	NULL,	/* get_bits */\
709 	get_params,\
710 	put_params,\
711 	map_cmyk_color,\
712 	NULL,	/* get_xfont_procs */\
713 	NULL,	/* get_xfont_device */\
714 	NULL,	/* map_rgb_alpha_color */\
715 	gx_page_device_get_page_device	/* get_page_device */\
716 }
717 
718 /************************************************************************
719  *   T Y P E D E F S   E N U M S   &   E X T E R N A L   S T O R A G E	*
720  ************************************************************************/
721 				/* The procedure descriptors */
722 				/* declare functions */
723 private dev_proc_print_page(lx5000_print_page);
724 private dev_proc_get_params(lx5000_get_params);
725 private dev_proc_put_params(lx5000_put_params);
726 
727 private dev_proc_map_cmyk_color(lx5000_map_cmyk_color);
728 private dev_proc_map_color_rgb(lx5000_map_color_rgb);
729 
730 private const gx_device_procs lx5000_procs =
731     lx5000_proctab(
732                      lx5000_get_params,
733 		     lx5000_put_params,
734 		     lx5000_map_color_rgb,
735 		     lx5000_map_cmyk_color
736 		     );
737 
738 				/* The device descriptors */
739 				/* define a subclass containing useful state */
740 				/* a sub-class of gx_device_printer */
741 typedef struct lx5000_device_s {
742     gx_device_common;
743     gx_prn_device_common;
744     int		alignA;
745     int		alignB;
746     int		headSeparation;
747     int		dryTime;	/* Seconds delay at end of page for drying */
748     int		pensPerColour;	/* 1 for 600Y; 2 for 1200Y */
749     int		lineIncrement;	/* 1 for 600Y; 2 for 1200Y */
750     int		scanLineBytes;	/* Returned by GS */
751     int		penLineBytes;	/* When scanline colour elements are each
752 				   reduced to a single bit, this is the result-
753 				   ing line length in bytes.	*/
754     int		penLineLen;	/* penLineBytes + BOL + EOL padding */
755     int		penBufSize;	/* penLineLen * no. of lines */
756     int		swipeBufSize;	/* calculated size of a swipe command buffer */
757     bool	isCMYK;
758 } lx5000_device;
759 
760 				/* Define a structure for a pointer to an */
761 				/* individual bit in a scanline	 */
762 typedef struct bufBit_s {
763     byte 	*xByte;		/* Pointer to byte in buffer */
764     uchar	xBit;		/* Mask for invidual bit in byte */
765 } bufBit;
766 
767 
768 typedef struct penData_s {
769     int		topLine;	/* Top printable line of this pen */
770     int		bottomLine;	/* Bottom printable line of this pen */
771     int		nextPrintLine;	/* Next line to be printed, this pen */
772 
773     int		initialBottomLine;
774     int		bottomToBottomYellow;
775     int		topToBottomYellow;
776     int		finalLine;
777 } penData;
778 
779 				/* Structure for extracting pixels from the
780 				   initial scan line, which must be int
781 				   aligned.			*/
782 typedef struct scanPixels_s {
783     uchar	*scanByte;	/* Pointer to a byte in the scan buffer */
784     int		pixShift;	/* Shift required to get next pixel to */
785 } scanPixels;			/* the LSBits of the word. */
786 
787 				/* Standard lx5000 device */
788 lx5000_device far_data gs_lx5000_device = {
789     prn_device_margins_body
790     	( lx5000_device,
791 	  lx5000_procs,
792 	  "lx5000",
793 	  DEFAULT_WIDTH_10THS,
794 	  DEFAULT_HEIGHT_10THS,
795 	  LX5000_XDPI,		/* x dpi */
796 	  LX5000_YDPI,		/* y dpi */
797 				/* Offset inches from page left to 0,0 */
798 	  LX5000_XOFFSET_TO_0_0,
799 				/* Offset inches from page top to 0,0 */
800 	  LX5000_YOFFSET_TO_0_0,
801 	  LX5000_LEFT_HWMARGIN_INS,	/* margins */
802 	  LX5000_BOTTOM_HWMARGIN_INS,
803 	  LX5000_RIGHT_HWMARGIN_INS,
804 	  LX5000_TOP_HWMARGIN_INS,
805 	  NUM_COMPONENTS_CMY,	/* colour info  */
806 	  BITS_PER_PIXEL_CMY,	/*	"	*/
807 	  MAX_GREY_CMY,		/*	"	*/
808 	  MAX_RGB_CMY,		/*	"	*/
809 	  DITHER_GREYS_CMY,	/*	"	*/
810 	  DITHER_COLOURS_CMY,	/*	"	*/
811 	  lx5000_print_page
812 	  ),
813     ALIGN_A_DEF,		/* default(!) horizontal pen alignment	*/
814     ALIGN_B_DEF,		/* default(!) vertical pen alignment	*/
815     HEADSEP_DEF,		/* default headSeparation value */
816     DRY_TIME_DEF,		/* Default page drying time */
817     DEF_PENS_PER_COLOUR,
818     DEF_LINE_INCREMENT,
819     0,				/* scanLineBytes */
820     0,				/* penLineBytes */
821     0,				/* penLineLen */
822     0,				/* penBufSize */
823     0,				/* swipeBufSize */
824     true			/* isCMYK - defaults to using colour	*/
825 };
826 
827 private const gx_device_color_info color_info_cmy =
828 {
829     NUM_COMPONENTS_CMY,
830     BITS_PER_PIXEL_CMY,
831     MAX_GREY_CMY,
832     MAX_RGB_CMY,
833     DITHER_GREYS_CMY,
834     DITHER_COLOURS_CMY
835 };
836 
837 private const gx_device_color_info color_info_blk =
838 {
839     NUM_COMPONENTS_BLK,
840     BITS_PER_PIXEL_BLK,
841     MAX_GREY_BLK,
842     MAX_RGB_BLK,
843     DITHER_GREYS_BLK,
844     DITHER_COLOURS_BLK
845 };
846 
847 
848 /************************************************************************
849  ************************************************************************
850  *		     D R I V E R   P R O C E D U R E S			*
851  ************************************************************************
852  ************************************************************************/
853 
854 /************************************************************************
855  *		    U T I L I T Y   P R O C E D U R E S			*
856  ************************************************************************/
857 
858 /*----------------------------------------------------------------------*
859  *	i n i t P e n C o n s t a n t s ( )				*
860  *----------------------------------------------------------------------*
861  *----------------------------------------------------------------------*/
862 private void
initPenConstants(lx5000_device * lx5000dev,penData pens[NUM_COLOURS][PENS_PER_COLOUR])863 initPenConstants( lx5000_device *lx5000dev,
864 		  penData pens[NUM_COLOURS][PENS_PER_COLOUR] )
865 {
866 				/* Indexed by pensPerColour.  */
867     static const int	nozzleCount[ NUM_COLOURS ][ PENS_PER_COLOUR + 1 ] =
868     {
869 	{ -1, BLACK_NOZZLES, (BLACK_NOZZLES / 2) },
870 	{ -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) },
871 	{ -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) },
872 	{ -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) }
873     };
874 
875     int		colour, pen;
876     int		pensPerColour	= lx5000dev->pensPerColour;
877 
878     pens[YELLOW_X][LO_PEN].initialBottomLine	= -1;
879     pens[MAGENTA_X][LO_PEN].initialBottomLine =
880 				pens[YELLOW_X][LO_PEN].initialBottomLine
881 							- COLOUR_PEN_DIFF;
882     pens[CYAN_X][LO_PEN].initialBottomLine =
883 				pens[MAGENTA_X][LO_PEN].initialBottomLine
884 							- COLOUR_PEN_DIFF;
885     pens[BLACK_X][LO_PEN].initialBottomLine =
886 				pens[YELLOW_X][LO_PEN].initialBottomLine
887 						- COLOUR_PEN_GAP
888 				+ ( SWIPE_WORD_BITS - lx5000dev->alignB );
889 
890     for ( colour = 0; colour < NUM_COLOURS; colour++ )
891     {
892 	pens[colour][LO_PEN].bottomToBottomYellow
893 				= pens[YELLOW_X][LO_PEN].initialBottomLine
894 	    			- pens[colour][LO_PEN].initialBottomLine;
895     }
896 
897     if ( pensPerColour == 1 )
898     {
899 	pens[BLACK_X][LO_PEN].topToBottomYellow =
900 					BLK_COLOUR_NOZZLES + COLOUR_PEN_GAP
901 						+ lx5000dev->alignB - 1;
902 	pens[YELLOW_X][LO_PEN].topToBottomYellow =  _1COLOUR_NOZZLES - 1;
903 	pens[MAGENTA_X][LO_PEN].topToBottomYellow =
904 				pens[YELLOW_X][LO_PEN].topToBottomYellow
905 						+ COLOUR_PEN_DIFF;
906 	pens[CYAN_X][LO_PEN].topToBottomYellow =
907 				pens[MAGENTA_X][LO_PEN].topToBottomYellow
908 						+ COLOUR_PEN_DIFF;
909 
910 	for ( colour = 0; colour < NUM_COLOURS; colour++ )
911 	{
912 	    pens[colour][HI_PEN].topToBottomYellow
913 				= pens[colour][LO_PEN].topToBottomYellow;
914 	    pens[colour][HI_PEN].initialBottomLine
915 				= pens[colour][LO_PEN].initialBottomLine;
916 	    pens[colour][HI_PEN].bottomToBottomYellow
917 				= pens[colour][LO_PEN].bottomToBottomYellow;
918 	}
919     }
920     else			/* pensPerColour > 1 */
921     {
922 	pens[BLACK_X][HI_PEN].topToBottomYellow =
923 					BLK_COLOUR_NOZZLES + COLOUR_PEN_GAP
924 						+ lx5000dev->alignB - 1;
925 	pens[BLACK_X][LO_PEN].topToBottomYellow =
926 					pens[BLACK_X][HI_PEN].topToBottomYellow
927 					- nozzleCount[BLACK_X][pensPerColour];
928 	pens[YELLOW_X][HI_PEN].topToBottomYellow =  _1COLOUR_NOZZLES - 1;
929 	pens[YELLOW_X][LO_PEN].topToBottomYellow =
930 				pens[YELLOW_X][HI_PEN].topToBottomYellow
931 					- nozzleCount[YELLOW_X][pensPerColour];
932 	pens[MAGENTA_X][HI_PEN].topToBottomYellow =
933 				pens[YELLOW_X][HI_PEN].topToBottomYellow
934 						+ COLOUR_PEN_DIFF;
935 	pens[MAGENTA_X][LO_PEN].topToBottomYellow =
936 				pens[MAGENTA_X][HI_PEN].topToBottomYellow
937 					-nozzleCount[MAGENTA_X][pensPerColour];
938 	pens[CYAN_X][HI_PEN].topToBottomYellow =
939 				pens[MAGENTA_X][HI_PEN].topToBottomYellow
940 						+ COLOUR_PEN_DIFF;
941 	pens[CYAN_X][LO_PEN].topToBottomYellow =
942 				pens[CYAN_X][HI_PEN].topToBottomYellow
943 					- nozzleCount[CYAN_X][pensPerColour];
944 
945 	for ( colour = 0; colour < NUM_COLOURS; colour++ )
946 	{
947 	    pens[colour][HI_PEN].bottomToBottomYellow =
948 				    pens[colour][LO_PEN].bottomToBottomYellow
949 				    + nozzleCount[colour][pensPerColour];
950 	    pens[colour][HI_PEN].initialBottomLine =
951 				    pens[colour][LO_PEN].initialBottomLine
952 				    - nozzleCount[colour][pensPerColour];
953 	}
954     }
955 
956     for ( colour = 0; colour < NUM_COLOURS; colour++ )
957     {
958 	for ( pen = 0; pen < PENS_PER_COLOUR; pen++ )
959 	{
960 	    pens[colour][pen].finalLine =
961 		( lx5000dev->height ) + pens[colour][pen].topToBottomYellow;
962 	}
963     }
964 }
965 
966 /*----------------------------------------------------------------------*
967  *	p a g e I n i t ( )						*
968  *----------------------------------------------------------------------*
969  *----------------------------------------------------------------------*/
970 private void
pageInit(unsigned int alignA,unsigned int alignB,FILE * prn_stream)971 pageInit( unsigned int alignA, unsigned int alignB, FILE *prn_stream )
972 {
973     static char page_init[] = {
974         0x1b, '*', 'm', 0, 0x40, ALIGN_A_DEF, ALIGN_B_DEF, 0xf, 0xf
975     };
976 
977     page_init[ALIGN_A_OFFSET] = (uchar)alignA;
978     page_init[ALIGN_B_OFFSET] = (uchar)alignB;
979 
980     fwrite( page_init, 1, sizeof( page_init ), prn_stream );
981 }
982 
983 /*----------------------------------------------------------------------*
984  *	p a g e E n d ( )						*
985  *----------------------------------------------------------------------*
986  *----------------------------------------------------------------------*/
987 private void
pageEnd(FILE * prn_stream)988 pageEnd( FILE *prn_stream )
989 {
990     static const char page_end[] = {
991 	0x1b,'*', 7, 0x65
992     };
993 
994     fwrite( page_end, 1, sizeof( page_end ), prn_stream );
995 				/* Do it twice - that's what the Windows */
996 				/* driver for the 5000 does	*/
997     fwrite( page_end, 1, sizeof( page_end ), prn_stream );
998 }
999 
1000 /*----------------------------------------------------------------------*
1001  *	f e e d P a p e r ( )						*
1002  *----------------------------------------------------------------------*
1003  *----------------------------------------------------------------------*/
1004 private void
feedPaper(lx5000_device * lx5000dev,int newLine,int * currentLine,penData pens[NUM_COLOURS][PENS_PER_COLOUR],FILE * prn_stream)1005 feedPaper( lx5000_device *lx5000dev, int newLine, int *currentLine,
1006 	   penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1007 	   FILE *prn_stream )
1008 {
1009     static const char feed_paper[] = {
1010 	0x1b, '*', 3
1011     };
1012 
1013     ushort	_1200ths;
1014     int		colour, pen;
1015 
1016     if ( newLine >= *currentLine )
1017     {
1018 	_1200ths = (ushort)(( newLine - *currentLine ) * FEED_FACTOR );
1019 	fwrite( feed_paper, 1, sizeof( feed_paper ), prn_stream );
1020 	putc( _1200ths >> 8 , prn_stream);
1021 	putc( _1200ths & 0xff, prn_stream );
1022 
1023 	*currentLine			= newLine;
1024 
1025 	for ( colour = 0;
1026 	      colour < lx5000dev->color_info.num_components;
1027 	      colour++ )
1028 	    for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1029 	    {
1030 		pens[colour][pen].topLine =
1031 		    newLine - pens[colour][pen].topToBottomYellow;
1032 		pens[colour][pen].bottomLine =
1033 		    newLine - pens[colour][pen].bottomToBottomYellow;
1034 	    }
1035 
1036     }
1037 }
1038 
1039 
1040 /*----------------------------------------------------------------------*
1041  *	g e t C o l o u r B u f s ( )					*
1042  *----------------------------------------------------------------------*
1043   Return pointers to the allocated buffers in those pointers whose addresses
1044   have been passed as parameters, or release the allocations.
1045 
1046   Allocation is indicated by a true value of the argument `allocate'.
1047 
1048   The buffers themselves are allocated and the pointers to them are kept
1049   in static storage.  On the first call, the buffers are allocated, and the
1050   pointers to them are maintained in static storage.  On all subsequent
1051   calls, the pointer contents are simply returned.
1052 
1053   Deallocation is indicated by a false value of the argument `allocate'.
1054 
1055   If the pointers are non-null, the allocated memory is released, and
1056   the pointer values are set to NULL.
1057 
1058   N.B.  The arrays are defined in terms of the maximum values for the array
1059   dimensions, even though the actual usage of each dimension is dynamically
1060   determined.  E.g. colourBufs is dimensioned [NUM_COLOURS],
1061   even though the number of colour dimensions actually used is determined
1062   by the variable numColours, which will be 1 if the driver is being used
1063   in black-only mode.
1064  *----------------------------------------------------------------------*/
1065 int
getColourBufs(lx5000_device * lx5000dev,byte ** lineBufferPtr,byte * colourBufPtrs[],byte ** swipeBufPtr,bool allocate)1066 getColourBufs( lx5000_device *lx5000dev,
1067 	       byte **lineBufferPtr, byte *colourBufPtrs[],
1068 	       byte **swipeBufPtr, bool allocate )
1069 {
1070     static byte  	*colourBufs[ NUM_COLOURS ];
1071 				/* Only an array of pointers; OK if too big */
1072     static byte 	*lineBuffer	= NULL;
1073     static byte 	*swipeBuf	= NULL;
1074 
1075     int	colour;
1076     int	colourBufNull	= 0;
1077     int	numColours	= lx5000dev->color_info.num_components;
1078 
1079     if ( allocate )
1080     {
1081 	if ( lineBuffer == NULL )
1082 	{
1083 				/*  Initialise the pen buffers	*/
1084 	    for ( colour = 0; colour < numColours; colour++ )
1085 		colourBufs[ colour ] = NULL;
1086 
1087 	    /*---------------------------------------------------------------*
1088 	      Derive the size of a colour buffer line:  If the number of
1089 	      components is one and the number of bits per pixel is one, then
1090 	      there is only one bit per pixel in the scan line, so the colour
1091 	      buffer line is the same size.
1092 
1093 	      Otherwise, reduce each gx_color_index element in the scan line to
1094 	      one bit in the penprint buffer.
1095 	      *--------------------------------------------------------------*/
1096 
1097 	    lx5000dev->scanLineBytes = gdev_mem_bytes_per_scan_line(
1098 						(gx_device *)lx5000dev );
1099 	    lx5000dev->penLineBytes	=
1100 		( lx5000dev->color_info.num_components == 1
1101 			    && lx5000dev->color_info.depth == 1 )
1102 		? lx5000dev->scanLineBytes
1103 		: ( lx5000dev->scanLineBytes / sizeof( gx_color_index ));
1104 
1105 	    lx5000dev->penLineLen =
1106 			lx5000dev->penLineBytes + ( LINE_PAD_BYTES * 2);
1107 
1108 	    lx5000dev->penBufSize
1109 				= lx5000dev->penLineLen * COLOUR_BUF_LINES;
1110 
1111 	    /* swipeBuf size:
1112 	     * No. of columns = No. of bits in the linebuf
1113 	     * Bits per column = maximum swipe height
1114 	     * Bytes per column = Bits per column / 8 + 2 byte directory
1115 	     * Total bytes = Bytes/column * no. of columns + header bytes
1116 	     */
1117 	    lx5000dev->swipeBufSize	=
1118 		((lx5000dev->penLineLen * 8)
1119 		 * ((BLACK_NOZZLES / 8) + 2) + SWIPE_HDR_LEN);
1120 
1121 				/* Allocate a buffer for a single scan line */
1122 	    lineBuffer	= (byte *)gs_alloc_byte_array
1123 		( &gs_memory_default, lx5000dev->scanLineBytes, 1,
1124 		  "lx5000_print_page(lineBuffer)" );
1125 
1126 	    swipeBuf	= (byte *)gs_alloc_byte_array
1127 		( &gs_memory_default, lx5000dev->swipeBufSize, 1,
1128 		  "lx5000_print_page(swipeBuf)" );
1129 
1130 	    for ( colour = 0 ; colour < numColours; colour++ )
1131 	    {
1132 		if ( ( colourBufs[colour] =
1133 		       (byte *)gs_alloc_byte_array
1134 		       ( &gs_memory_default, lx5000dev->penBufSize, 1,
1135 			 "lx5000_print_page(colourBufs)"
1136 			 )
1137 		       ) == NULL )
1138 		{
1139 		    colourBufNull = 1;
1140 		    colour = numColours;
1141 		}
1142 	    }
1143 				/* Check allocations */
1144 	    if ( lineBuffer == NULL || colourBufNull || swipeBuf == NULL ) {
1145 		getColourBufs( lx5000dev, lineBufferPtr, colourBufPtrs,
1146 				    swipeBufPtr, DEALLOCATE );
1147 		return_error( gs_error_VMerror );
1148 	    }
1149 	}
1150 	/* Clear the black buffer, iff ! isCMYK.  If CMYK, scan lines are
1151 	   processed by processCMYKlines(), and buffer lines are cleared
1152 	   individually, before a new scan line is processed.  As part of this
1153 	   clearing, the line EOL and BOL pads are also cleared.
1154 	   If ! CMYK, the black-only scan line is read or copied directly
1155 	   into the black buffer, without clearing the buffer.  Therefore, the
1156 	   line pad regions must either be cleared individually for each line
1157 	   processed, or cleared once when the buffer is allocated.
1158 	*/
1159 	if ( ! lx5000dev->isCMYK )
1160 	    memset( colourBufs[BLACK_X], 0, lx5000dev->penBufSize );
1161 
1162 				/* Return the values */
1163 	*lineBufferPtr	= lineBuffer;
1164 	*swipeBufPtr	= swipeBuf;
1165 	for ( colour = 0; colour < numColours; colour++ )
1166 	    colourBufPtrs[colour] = colourBufs[colour];
1167 
1168 	return 0;
1169     }
1170     else			/* Deallocate the buffers */
1171     {
1172 	for ( colour = 0; colour < numColours; colour++ )
1173 	{
1174 	    if ( colourBufs[colour] != NULL )
1175 		gs_free_object( &gs_memory_default,
1176 				(char *)colourBufs[colour],
1177 				"lx5000_print_page(colourBufs)" );
1178 	    colourBufs[ colour ]	= NULL;
1179 	    colourBufPtrs[ colour ]	= NULL;
1180 	}
1181 	if ( swipeBuf != NULL )
1182 	    gs_free_object( &gs_memory_default,
1183 			    (char *)swipeBuf, "lx5000_print_page(swipeBuf)" );
1184 	swipeBuf	= NULL;
1185 	*swipeBufPtr	= NULL;
1186 	if ( lineBuffer != NULL )
1187 	    gs_free_object( &gs_memory_default,
1188 		    (char *)lineBuffer, "lx5000_print_page(lineBuffer)" );
1189 	lineBuffer	= NULL;
1190 	*lineBufferPtr	= NULL;
1191 	return 0;
1192     }
1193 }
1194 
1195 
1196 /*----------------------------------------------------------------------*
1197  *	p r o c e s s C M Y K l i n e ( )				*
1198  *----------------------------------------------------------------------*
1199   Given a scan line number, a pointer to a scan line, an array of pointers to
1200   individual colour buffers, and an array of the individual pen scanBit
1201   arrays, distribute the scan line elements into the colour buffers.
1202 
1203   N.B. The empty indicator for each line for each pen buffer must also be
1204   set by this procedure.
1205 
1206   Things like dithering may well end up in here.
1207  *----------------------------------------------------------------------*/
1208 private void
processCMYKline(lx5000_device * lx5000dev,int linenum,byte * lineBuffer,byte * scanLine,byte * colourBufs[NUM_COLOURS],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES])1209 processCMYKline( lx5000_device *lx5000dev, int linenum,
1210 		 byte *lineBuffer, byte *scanLine,
1211 		 byte *colourBufs[NUM_COLOURS],
1212 		 bufBit
1213 		 colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1214 		 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1215 		 bool lineEmpty[NUM_COLOURS][ COLOUR_BUF_LINES ] )
1216 {
1217     int		colour;
1218     int		numColours = lx5000dev->color_info.num_components;
1219 
1220     uchar	colourBits[ numColours ];
1221     uchar	lineIndex;
1222     uchar	scanPixel;
1223     scanPixels	nextPixel;
1224     bufBit	nextBit[ numColours ];
1225 				/* The end of the (scan)line. */
1226     uchar	*scanEnd	= scanLine + lx5000dev->scanLineBytes;
1227 
1228     nextPixel.scanByte	= scanLine;  /* Set up the moving pixel pointer. */
1229     nextPixel.pixShift	= INITIAL_PIXEL_SHIFT;
1230     lineIndex		= (uchar)( linenum & COLOUR_BUF_MASK );
1231 
1232     for ( colour = 0; colour < numColours; colour++ )
1233     {
1234 				/* Set up the moving output bit pointer for
1235 				   each of the colours.	*/
1236 	nextBit[ colour ].xByte	= colourBufs[ colour ] + LINE_PAD_BYTES
1237 				+ ( lineIndex * lx5000dev->penLineLen );
1238 	nextBit[ colour ].xBit	= BIT_TO_MASK( 0 );
1239 				/* Clear the colourBuf line if necessary */
1240 	if ( ! lineEmpty[ colour ][ lineIndex ] )
1241 	{
1242 	    memset( nextBit[ colour ].xByte - LINE_PAD_BYTES,
1243 		    0, lx5000dev->penLineLen );
1244 	    lineEmpty[ colour ][ lineIndex ] = true;
1245 	}
1246     }
1247 				/* Is the line empty? */
1248     if (( ! *scanLine ) &&
1249 	! memcmp( scanLine, scanLine + 1, lx5000dev->scanLineBytes - 1 ))
1250 	return;			/* N.B. empty flag is pre-set to true */
1251 
1252     while ( nextPixel.scanByte < scanEnd )
1253     {
1254 	int	colour;
1255 	int	cmy;		/* Used to detect if C+M+Y set */
1256 	int	skipPixels, skipBytes, skipBits;
1257 				/* Number of consecutive empty pixels, equiv-
1258 				   alent bytes and remainder bits just skipped
1259 				   over in the CMYK line being processed. */
1260 
1261 				/* Get next pixel and increment the pointer */
1262 	scanPixel =
1263 	    ( ( *(nextPixel.scanByte) >> nextPixel.pixShift ) & PIXEL_MASK );
1264 
1265 		/* pixShift is the number of bits to right-shift the scanByte
1266 		   before applying PIXEL_MASK.  When we attempt to decrement
1267 		   it past 0, it's time to look at the next scanByte.
1268 		   N.B.  We assume that the subtraction of BPP will end with
1269 		   zero, i.e., that there are an integral number of BPPs in
1270 		   INITIAL_PIXEL_SHIFT.  We test for <= 0 just
1271 		   in case this condition gets violated.
1272 		*/
1273 	skipPixels = 0;
1274 	if (  nextPixel.pixShift <= 0 )
1275 	{
1276 	    nextPixel.scanByte++;
1277 	    nextPixel.pixShift = INITIAL_PIXEL_SHIFT;
1278 				/* If the next byte is empty, skip it */
1279 	    while (( ! *nextPixel.scanByte ) && nextPixel.scanByte < scanEnd )
1280 	    {
1281 		nextPixel.scanByte++;
1282 		skipPixels += PIXELS_PER_BYTE;
1283 	    }
1284 	}
1285 	else
1286 	    nextPixel.pixShift -= BPP;
1287 				/* Get the black bit(s) */
1288 	colourBits[ BLACK_X ]	= scanPixel & COLOUR_MASK;
1289 	scanPixel		>>= BITS_PER_COLOUR;
1290 				/* Set to catch all ANDed bits from colours */
1291 	cmy			= ~0;
1292 	for ( colour = YELLOW_X; colour <= CYAN_X; colour++ )
1293 	{
1294 	    colourBits[ colour ] = scanPixel & COLOUR_MASK;
1295 	    cmy			&= scanPixel & COLOUR_MASK;
1296 	    scanPixel		>>= BITS_PER_COLOUR;
1297 	}
1298 	if ( ( cmy ^ COLOUR_MASK ) == 0 ) /* C, M & Y all set == COLOUR_MASK */
1299 	{
1300 	    colourBits[ YELLOW_X ] =
1301 		colourBits[ MAGENTA_X ] = colourBits[ CYAN_X ] = 0;
1302 	    colourBits[ BLACK_X ] = COLOUR_MASK;
1303 	}
1304 				/* Now set the colourBuf bits */
1305 	skipBytes = skipPixels >> 3;
1306 	skipBits  = skipPixels & 7;
1307 	for ( colour = 0; colour < numColours; colour++ )
1308 	{
1309 	    if ( colourBits[ colour ] )
1310 	    {
1311 		*( nextBit[ colour ].xByte )	|= nextBit[ colour ].xBit;
1312 		lineEmpty[ colour ][ lineIndex ] = false;
1313 	    }
1314 	    INC_BIT( nextBit[ colour ] );
1315 	    if ( skipPixels )
1316 	    {
1317 		int	bitSkip = skipBits;
1318 
1319 		nextBit[ colour ].xByte += skipBytes;
1320 		while ( bitSkip-- )
1321 		{
1322 		    INC_BIT( nextBit[ colour ] );
1323 		}
1324 	    }
1325 	}
1326     }
1327 }
1328 
1329 
1330 /*----------------------------------------------------------------------*
1331  *	r e f r e s h B u f f e r ( )					*
1332  *----------------------------------------------------------------------*
1333  Given pointers to the values of the next line to retrieve from GS, and
1334  the next printable line, the GS line buffer, the per colour bit buffers,
1335  the per colour arrays containing the per line `empty'
1336  indicators, and the per pen penData structs, containing the next print
1337  line for each pen, refresh the buffer, and perform initial processing on
1338  the lines read from GS.
1339 
1340  When the scan line is for a black-only device, the line bits can be read
1341  directly into the appropriate colour buffer at the appropriate place.
1342 
1343  When the scan lines hold colour info, each line must undergo CMYK pro-
1344  cessing to derive the individual arrays of single-colour bits.
1345 
1346  Refreshing the buffers involves reading lines into the circular colour
1347  buffers until COLOUR_BUF_LINES have been read, or until the available
1348  lines have been exhausted.
1349 
1350  On return, nextLineToPrint must be set to the said line number, or beyond
1351  the end of the page, if no more remain to be printed.
1352  *----------------------------------------------------------------------*/
1353 private void
refreshBuffer(lx5000_device * lx5000dev,int * nextLineToGet,int * nextLineToPrint,byte * lineBuffer,byte * colourBufs[],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES])1354 refreshBuffer( lx5000_device *lx5000dev,
1355 	       int *nextLineToGet, int *nextLineToPrint,
1356 	       byte *lineBuffer, byte *colourBufs[],
1357 	       bufBit
1358 	       colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1359 	       penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1360 	       bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES] )
1361 {
1362     byte	*lineBuf;
1363     uchar	nextToGet;	/* Circular buffer pointer, 0 to ff */
1364     int		bufferOffset;
1365     int		colour, pen;
1366     int		_1stPrintable;	/* Across all pens */
1367     int		numColours = lx5000dev->color_info.num_components;
1368 
1369 				/* Establish the next line to print, if it
1370 				   is already in the buffer.		*/
1371     _1stPrintable		= pens[YELLOW_X][LO_PEN].finalLine;
1372     for ( colour = 0; colour < numColours; colour++ )
1373     {
1374 	for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1375 	    if ( pens[ colour ][ pen ].nextPrintLine < _1stPrintable)
1376 		_1stPrintable = pens[ colour ][ pen ].nextPrintLine;
1377     }
1378     *nextLineToPrint = _1stPrintable;
1379 
1380     nextToGet = (uchar)(*nextLineToGet & COLOUR_BUF_MASK);
1381 				/* nextLineToPrint may be set high (i.e. not
1382 				   known), or may be a known print line. */
1383     while (  ( *nextLineToGet < *nextLineToPrint
1384 	       || ( *nextLineToGet - *nextLineToPrint ) < COLOUR_BUF_LINES )
1385 	     && *nextLineToGet < lx5000dev->height )
1386     {
1387 	bufferOffset = LINE_PAD_BYTES + ( lx5000dev->penLineLen * nextToGet );
1388 
1389 	if ( ! lx5000dev->isCMYK )
1390 	{
1391 				/* For black-only, read the bits directly into
1392 				   the colour buffer. */
1393 	    gdev_prn_get_bits( (gx_device_printer *)lx5000dev, *nextLineToGet,
1394 			       colourBufs[BLACK_X] + bufferOffset, &lineBuf );
1395 				/* If necessary, copy the bits into the actual
1396 				   buffer.		*/
1397 	    if ( lineBuf != colourBufs[BLACK_X] + bufferOffset )
1398 		memcpy(colourBufs[BLACK_X] + bufferOffset,
1399 		       lineBuf, lx5000dev->penLineBytes);
1400 				/* Check for a printing line */
1401 	    if ( *(colourBufs[BLACK_X] + bufferOffset) != 0
1402 		 || memcmp( colourBufs[BLACK_X] + bufferOffset,
1403 			    colourBufs[BLACK_X] + bufferOffset + 1,
1404 			    lx5000dev->scanLineBytes - 1 ))
1405 		lineEmpty[ BLACK_X ][  nextToGet ] = false;
1406 	    else
1407 		lineEmpty[ BLACK_X ][  nextToGet ] = true;
1408 	}
1409 	else			/* CMYK printing */
1410 	{
1411 				/* Process a CMYK line from GS */
1412 	    gdev_prn_get_bits( (gx_device_printer *)lx5000dev,
1413 			       *nextLineToGet, lineBuffer, &lineBuf );
1414 	    processCMYKline( lx5000dev, *nextLineToGet, lineBuffer, lineBuf,
1415 			     colourBufs, colourLines, pens, lineEmpty );
1416 	}
1417 	for (colour = 0; colour < numColours; colour++ )
1418 	{
1419 				/* Check for printing line -
1420 				   N.B. For two-pen colour, this becomes more
1421 				   complicated.  The relationship between the
1422 				   first print line of the lower and of the
1423 				   upper pen is determined by odd/even line
1424 				   numbers, although this is not an essential
1425 				   relationship.  Blank lines at the top of
1426 				   the lower pen could be skipped, and the
1427 				   first available line could be printed by
1428 				   the lower pen. */
1429 	    if ( ! lineEmpty[colour][nextToGet] )
1430 	    {
1431 		if ( pens[colour][LO_PEN].nextPrintLine > *nextLineToGet )
1432 		    pens[colour][LO_PEN].nextPrintLine = *nextLineToGet;
1433 		if ( *nextLineToPrint > *nextLineToGet )
1434 		    *nextLineToPrint = *nextLineToGet;
1435 	    }
1436 	}
1437 	++*nextLineToGet;
1438 	nextToGet = ( *nextLineToGet & COLOUR_BUF_MASK ); /* N.B. This is safer
1439 				   than just doing the increment, in case the
1440 				   buffer length changes.		*/
1441     }
1442 				/* Check that no buffer padding is necessary */
1443     if ( *nextLineToPrint < lx5000dev->height )
1444     {
1445 	while ( ( *nextLineToGet - *nextLineToPrint ) < COLOUR_BUF_LINES )
1446 	{			/* Last refresh fell short of COLOUR_BUF_LINES
1447 				   because last line of page was reached.
1448 				   Pad the buffer to COLOUR_BUF_LINES with 0
1449 					   (no print) bytes.  */
1450 	    for ( colour = 0; colour < numColours; colour++ )
1451 	    {			/* Fill the colour line buffer, incl pad */
1452 		memset( colourBufs[colour]
1453 			+ ( lx5000dev->penLineLen * nextToGet ),
1454 			0, lx5000dev->penLineLen );
1455 				/* Set empty indicator - note that firstBit
1456 				   is NOT set here. */
1457 		lineEmpty[colour][nextToGet] = true;
1458 	    }
1459 	    ++*nextLineToGet;
1460 	    nextToGet = ( *nextLineToGet & COLOUR_BUF_MASK );
1461 	}
1462     }
1463 }
1464 
1465 /*----------------------------------------------------------------------*
1466  *	c a r t r i d g e M o v e T o ( )				*
1467  *----------------------------------------------------------------------*
1468   Given the array of penBits structures for each pen, containing the
1469   nextPrintLine value for the pen, return the line position to
1470   which the colour cartridge must be moved to print that line with the
1471   TOP nozzle of the required pen.
1472   If the print line for any pen is within the current range of that pen,
1473   a line less than the current colour head position will be returned.
1474   If colour is not defined, return a value off the end of the page.
1475  *----------------------------------------------------------------------*/
1476 private int
cartridgeMoveTo(lx5000_device * lx5000dev,penData pens[NUM_COLOURS][PENS_PER_COLOUR],int _1stColour,int lastColour)1477 cartridgeMoveTo( lx5000_device *lx5000dev,
1478 		 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1479 		 int _1stColour, int lastColour )
1480 {
1481     if ( _1stColour != BLACK_X && ! lx5000dev->isCMYK )
1482 				/* Send back an off-the-page value */
1483 	return pens[CYAN_X][LO_PEN].finalLine;
1484     else
1485     {
1486 	int	colour, pen, minLine;
1487 
1488 	minLine	= pens[CYAN_X][LO_PEN].finalLine; /* Initialise high  */
1489 				/* For each pen, calculate a moveto value
1490 				   which will print the next line with the
1491 				   first nozzle of that pen.
1492 				   Return the minimum of these values. */
1493 	for ( colour = _1stColour; colour <= lastColour; colour++ )
1494 	    for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1495 		if ( ( pens[colour][pen].nextPrintLine
1496 		       + pens[colour][pen].topToBottomYellow )
1497 		     < minLine )
1498 		    minLine =
1499 			pens[colour][pen].nextPrintLine
1500 			+ pens[colour][pen].topToBottomYellow;
1501 
1502 	return minLine;
1503     }
1504 }
1505 /*----------------------------------------------------------------------*
1506  *	s e t C o l o u r C o l u m n E x t e n t ( )			*
1507  *----------------------------------------------------------------------*
1508   Given a colour buffer, a single array of colourBits structures,
1509   1st and last lines, 1st nozzle, and the addresses of
1510   _1stColumn, lastColumn and columnExtent variables, calculate and set
1511   these column variables after stripping leading and trailing white space.
1512  *----------------------------------------------------------------------*/
1513 private void
setColourColumnExtent(lx5000_device * lx5000dev,byte * colourBuf,bool lineEmpty[COLOUR_BUF_LINES],int _1stLine,int _1stNozzle,int lastLine,int * _1stColumn,int * lastColumn,int * columnExtent)1514 setColourColumnExtent( lx5000_device *lx5000dev, byte *colourBuf,
1515 		       bool lineEmpty[COLOUR_BUF_LINES],
1516 		       int _1stLine, int _1stNozzle, int lastLine,
1517 		       int *_1stColumn, int *lastColumn, int *columnExtent )
1518 {
1519     uchar	_1stIndex;
1520     int		firstPrintByte, lastPrintByte;
1521     int		line;
1522 
1523     line		= _1stLine;
1524     firstPrintByte	= lx5000dev->penLineBytes;
1525     lastPrintByte	= 0;
1526 
1527     for ( ; line <= lastLine; line += lx5000dev->lineIncrement )
1528     {				/* For each active line in swipe */
1529 	int	columnByte;
1530 
1531 	_1stIndex	= line & COLOUR_BUF_MASK;
1532 	if ( lineEmpty[ _1stIndex ] )
1533 	    continue;		/* If the line is empty, skip it. */
1534 				/* Otherwise, scan from the beginning to any
1535 				   previously found non-zero byte for the
1536 				   beginning of the active column extent. */
1537 	for ( columnByte = 0; columnByte < firstPrintByte; columnByte++ )
1538 	    if ( colourBuf[ _1stIndex * lx5000dev->penLineLen
1539 			  + LINE_PAD_BYTES + columnByte ] )
1540 	    {
1541 		firstPrintByte = columnByte;
1542 		break;
1543 	    }
1544 				/* Scan from the end of the line to any pre-
1545 				   viously found non-zero byte for the end of
1546 				   the active column extent.		*/
1547 	for ( columnByte = lx5000dev->penLineBytes;
1548 	      columnByte > lastPrintByte; columnByte-- )
1549 	    if ( colourBuf[ _1stIndex * lx5000dev->penLineLen
1550 			  + LINE_PAD_BYTES + columnByte ] )
1551 	    {
1552 		lastPrintByte = columnByte;
1553 		break;
1554 	    }
1555     }
1556 				/* If we have no extent, there are no
1557 				   printable lines for this pen.	*/
1558     if ( firstPrintByte > lastPrintByte )
1559     {
1560 	*_1stColumn	= firstPrintByte * 8;
1561 	*lastColumn	= lastPrintByte * 8;
1562 	*columnExtent	= 0;
1563 	return;
1564     }
1565 
1566     *_1stColumn		= firstPrintByte * 8;
1567     *lastColumn		= lastPrintByte * 8 + 7 + lx5000dev->headSeparation;
1568     *columnExtent	= ( *lastColumn - *_1stColumn ) + 1;
1569 
1570 }
1571 
1572 /*----------------------------------------------------------------------*
1573  *	s e t C o l o u r L i n e s ( )					*
1574  *----------------------------------------------------------------------*
1575   Given a single colour/pen buffer, a single array of bufBit structures,
1576   1st and last lines, 1st nozzle, print direction, and
1577   _1stColumn, lastColumn and columnExtent variables, set up the pointers
1578   to the first actual column of each line, taking account of even and odd
1579   nozzle numbers.
1580  *----------------------------------------------------------------------*/
1581 private void
setColourLines(lx5000_device * lx5000dev,byte * colourBuf,bufBit colourLines[COLOUR_BUF_LINES],int _1stLine,int _1stNozzle,int lastLine,int direction,int _1stColumn,int lastColumn)1582 setColourLines( lx5000_device *lx5000dev,
1583 		byte *colourBuf, bufBit colourLines[COLOUR_BUF_LINES],
1584 		int _1stLine, int _1stNozzle, int lastLine, int direction,
1585 		int _1stColumn, int lastColumn )
1586 {
1587     uchar	_1stIndex;
1588     int		line, nozzle, bit, headSep, headSepBytes, headSepBits;
1589     int		firstPrintByte, lastPrintByte, lastPrintBit;
1590     bufBit	startPtr;
1591 
1592     /* Now initialize the penBits bufBit structures to point to the
1593        beginning and end of the extent for each of the active lines in
1594        this swipe
1595 
1596        Adjust the beginning for all EVEN nozzles by moving it to the
1597        left by HeadSeparation bits.
1598     */
1599 
1600     headSep		= lx5000dev->headSeparation;
1601     if ( lx5000dev->x_pixels_per_inch == 300.0 )
1602 	headSep		= headSep >> 1;	/* Halve the value at 300 dpi */
1603     if ( lx5000dev->x_pixels_per_inch == 1200.0 )
1604 	headSep		= headSep << 1; /* Double the value at 1200dpi */
1605     headSepBytes	= headSep / 8;
1606     headSepBits		= headSep % 8;
1607 
1608     firstPrintByte	= _1stColumn / 8;
1609     lastPrintByte	= lastColumn / 8;
1610     lastPrintBit	= lastColumn % 8;
1611 
1612     if ( direction == RIGHTWARD )
1613     {
1614 				/* Set up the ODD columns first */
1615 	startPtr.xByte	= colourBuf + LINE_PAD_BYTES + firstPrintByte;
1616 	startPtr.xBit	= BIT_TO_MASK( 0 );
1617 	line		= _1stLine;
1618 	nozzle		= _1stNozzle;	/* Is 1st nozzle effectively odd? */
1619 	if ( ! ( nozzle & 1 ) )	/* Nozzle is even, so increment */
1620 	    line += lx5000dev->lineIncrement;
1621 	for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1622 	{
1623 	    _1stIndex	= (uchar)( line & COLOUR_BUF_MASK );
1624 	    colourLines[_1stIndex].xByte	=
1625 		startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1626 	    colourLines[_1stIndex].xBit	= startPtr.xBit;
1627 	}
1628 				/* Set up EVEN columns */
1629 	startPtr.xByte -= headSepBytes;
1630 	for ( bit = 0; bit < headSepBits; bit++ )
1631 	{
1632 	    DEC_BIT( startPtr );
1633 	}
1634 	line	= _1stLine;
1635 	nozzle	= _1stNozzle;	/* Is 1st nozzle effectively even? */
1636 	if ( nozzle & 1 )	/* Nozzle is odd, so increment */
1637 	    line += lx5000dev->lineIncrement;
1638 	for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1639 	{
1640 	    _1stIndex	= (uchar)( line & COLOUR_BUF_MASK );
1641 	    colourLines[_1stIndex].xByte	=
1642 		startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1643 	    colourLines[_1stIndex].xBit	= startPtr.xBit;
1644 	}
1645     }
1646     else			/* direction == LEFTWARD */
1647     {
1648 				/* Set up the ODD columns first */
1649 	startPtr.xByte	= colourBuf + LINE_PAD_BYTES + lastPrintByte;
1650 	startPtr.xBit	= BIT_TO_MASK( lastPrintBit );
1651 	line		= _1stLine;
1652 	nozzle		= _1stNozzle;	/* Is 1st nozzle effectively odd? */
1653 	if ( ! ( nozzle & 1 ) )	/* Nozzle is even, so increment */
1654 	    line += lx5000dev->lineIncrement;
1655 	for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1656 	{
1657 	    _1stIndex	= (uchar)( line & COLOUR_BUF_MASK );
1658 	    colourLines[_1stIndex].xByte	=
1659 		startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1660 	    colourLines[_1stIndex].xBit	= startPtr.xBit;
1661 	}
1662 				/* Set up EVEN columns */
1663 	startPtr.xByte -= headSepBytes;
1664 	for ( bit = 0; bit < headSepBits; bit++ )
1665 	{
1666 	    DEC_BIT( startPtr );
1667 	}
1668 	line	= _1stLine;
1669 	nozzle	= _1stNozzle;	/* Is 1st nozzle effectively even? */
1670 	if ( nozzle & 1 ) /* Nozzle is odd, so increment */
1671 	    line += lx5000dev->lineIncrement;
1672 	for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1673 	{
1674 	    _1stIndex	= (uchar)( line & COLOUR_BUF_MASK );
1675 	    colourLines[_1stIndex].xByte	=
1676 		startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1677 	    colourLines[_1stIndex].xBit	= startPtr.xBit;
1678 	}
1679     }
1680 }
1681 
1682 /*----------------------------------------------------------------------*
1683  *	p r i n t S w i p e ( )						*
1684  *----------------------------------------------------------------------*
1685  *----------------------------------------------------------------------*/
1686 private void
printSwipe(lx5000_device * lx5000dev,byte * colourBufs[NUM_COLOURS],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES],byte * swipeBuf,int * nextLineToPrint,int * nextLineToGet,int direction,int _1stColour,int lastColour,FILE * prn_stream)1687 printSwipe( lx5000_device *lx5000dev, byte *colourBufs[NUM_COLOURS],
1688 	     bufBit
1689 	     colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1690 	     penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1691 	     bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES], byte *swipeBuf,
1692 	     int *nextLineToPrint, int *nextLineToGet, int direction,
1693 	     int _1stColour, int lastColour, FILE *prn_stream )
1694 {
1695     /*--------------------------------------------------------------------*
1696       For unidirectional colour swathes, the effective print direction on
1697       a 5000 is reversed.  The implication of this is that, once the extent
1698       of the printing columns has been determined, the data for the colour
1699       pens must be fed to the head bit-reversed; i.e., set the bit pointer
1700       to the last column to be printed, and decrement the bit pointer until
1701       all of the columns have been printed.
1702      *--------------------------------------------------------------------*/
1703 
1704     static const char swipeHeader[SWIPE_HDR_LEN] = {
1705 	SWIPE_LEADER,
1706 	0, 0, 0, 0,			/* command length */
1707 	0,				/* direction */
1708 	0,				/* head speed */
1709 	0, 0,			/* pen selector */
1710 	0,				/* nozzle count */
1711 	0,				/* don't know */
1712 	0, 0,			/* number of columns */
1713 	0, 0,			/* 1st column */
1714 	0, 0,			/* last column */
1715 	SWIPE_HDR_END
1716     };
1717 
1718     static const int	wordsPerPen[NUM_COLOURS][PENS_PER_COLOUR + 1] =
1719     {
1720 	{ -1,
1721 	  BLACK_NOZZLES / SWIPE_WORD_BITS,
1722 	  BLACK_NOZZLES / SWIPE_WORD_BITS / 2
1723 	},
1724 	{ -1,
1725 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1726 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1727 	},
1728 	{ -1,
1729 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1730 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1731 	},
1732 	{ -1,
1733 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1734 	  _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1735 	}
1736     };
1737 
1738     int		_1stNozzle[NUM_COLOURS][PENS_PER_COLOUR];
1739 				/* 1st active nozzle for pen */
1740     int		lastNozzle[NUM_COLOURS][PENS_PER_COLOUR];
1741 				/* Last nozzle of this pen */
1742     int		_1stLine[NUM_COLOURS][PENS_PER_COLOUR];
1743 				/* Line no. of first print line for pen */
1744     int		_1stPenColumn[NUM_COLOURS][PENS_PER_COLOUR];
1745     int		lastPenColumn[NUM_COLOURS][PENS_PER_COLOUR];
1746 				/* Per-pen values... */
1747     int		penExtent[NUM_COLOURS][PENS_PER_COLOUR];
1748     int		_1stColumn;	/* ...and overall values of... */
1749     int		lastColumn;
1750     int		columnExtent;	/* Column range after */
1751 				/* stripping leading and trailing white space*/
1752     int		column;		/* Loop variable - current column */
1753     int		line;		/* Loop variables - line corresponding to
1754 				   current nozzle & temp line variable.  */
1755     uchar	lineIndex;	/* Circular index into pen buffer,
1756 				   corresponding to current line. */
1757     int		swipeCmdLen;	/* Length of the swipe command */
1758     int		colour, pen;
1759     byte 	*outp;
1760     int		x_dpi		= (int)( lx5000dev->x_pixels_per_inch + 0.1 );
1761 
1762 				/* Initialize worst case values for column
1763 				   extremities.		*/
1764     _1stColumn	= lx5000dev->penLineBytes * 8
1765 					+ 7 + lx5000dev->headSeparation;
1766     lastColumn	= 0;
1767 				/* Set up extents on a per-colour basis. */
1768     for ( colour = _1stColour; colour <= lastColour; colour++ )
1769 	for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1770 	{
1771 	    _1stLine[colour][pen]	= pens[colour][pen].nextPrintLine;
1772 	    _1stNozzle[colour][pen]	= _1stLine[colour][pen]
1773 						- pens[colour][pen].topLine;
1774 	    lastNozzle[colour][pen]	= pens[colour][pen].bottomLine
1775 	 					- pens[colour][pen].topLine;
1776 
1777 	    setColourColumnExtent( lx5000dev, colourBufs[colour],
1778 				   lineEmpty[colour], _1stLine[colour][pen],
1779 				   _1stNozzle[colour][pen],
1780 				   pens[colour][pen].bottomLine,
1781 				   &_1stPenColumn[colour][pen],
1782 				   &lastPenColumn[colour][pen],
1783 				   &penExtent[colour][pen] );
1784 				/* Get the overall extents for the swipe */
1785 	    if ( _1stPenColumn[colour][pen] < _1stColumn )
1786 		_1stColumn = _1stPenColumn[colour][pen];
1787 	    if ( lastPenColumn[colour][pen] > lastColumn )
1788 		lastColumn = lastPenColumn[colour][pen];
1789 	}
1790 				/* Set overall extent */
1791     columnExtent	= ( lastColumn - _1stColumn ) + 1;
1792 
1793 				/* Set the column range for each of the colour
1794 				   pens now that the full extent is known. */
1795     for ( colour = _1stColour; colour <= lastColour; colour++ )
1796 	for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1797 	{
1798 	    setColourLines( lx5000dev, colourBufs[colour],
1799 			    colourLines[colour][pen],
1800 			    _1stLine[colour][pen], _1stNozzle[colour][pen],
1801 			    pens[colour][pen].bottomLine, direction,
1802 			    _1stColumn, lastColumn );
1803 	}
1804 
1805     memcpy( swipeBuf, swipeHeader, SWIPE_HDR_LEN );
1806     outp	= swipeBuf + SWIPE_HDR_LEN;
1807 				/* For each column of the output, build two
1808 				   stripes.  One uses the standard directory
1809 				   scheme, and the other uses the repeat
1810 				   compression scheme.  Output the more
1811 				   compact result. */
1812     for ( column = _1stColumn; column <= lastColumn; column++ )
1813     {
1814 	ushort	dataword;	/* Loop transient - contents of swipe data
1815 				   word currently under construction. */
1816 	ushort	lastWord;	/* Last data word constructed for repeat
1817 				   compression directory method.	*/
1818 	int	nozzle;		/* Loop variable - current nozzle */
1819 				/* The arrays of the two sets of data words
1820 				   generated by each of the swipe construction
1821 				   methods for a single swipe.  Does not
1822 				   include the 16 bit directory word. */
1823 	int	wordCount1;	/* The count of words in the column arrays, */
1824 	int	wordCount2;	/* below.			*/
1825 	ushort	column1[BLK_SWIPE_WORDS];
1826 	ushort	column2[BLK_SWIPE_WORDS];
1827 	int	columnWord;	/* Current word within column. */
1828 	bufBit *lineBit;	/* Loop transient - current scan line bit */
1829 	ushort	wordBit;	/* Current bit within swipe word - incremented
1830 				   by right shifts. */
1831 	ushort	directoryBit;	/* Current bit within directory word.  It
1832 				   indicates the currently active set of 16
1833 				   nozzles.  Incremented by left shifts. */
1834 	ushort	directory1;	/* The directories for the two methods. Each */
1835 	ushort	directory2;	/* bit controls one following 16bit word. */
1836 
1837 	if ( _1stColour == BLACK_X )
1838 	{
1839 	    directory1	= (ushort)(BLK_DIRECTORY_MASK); /* empty */
1840 	    directory2	= (ushort)(BLK_DIRECTORY_MASK); /* empty */
1841 	}
1842 	else
1843 	{
1844 	    directory1	= (ushort)(COLOUR_DIRECTORY_MASK); /* empty */
1845 	    directory2	= (ushort)(COLOUR_DIRECTORY_MASK); /* empty */
1846 	}
1847 	directory1	|= DIRECTORY_TYPE_BIT; /* Normal directory */
1848 	directory2	&= ~DIRECTORY_TYPE_BIT; /* Repeat compression
1849 						   directory */
1850 				/* LSBit of directory refers to 1st following
1851 				   word */
1852 	directoryBit	= 1;
1853 	lastWord	= 0;
1854 	wordCount1	= 0;
1855 	wordCount2	= 0;
1856 				/* Note that the order of the pens in the
1857 				   datawords (top nozzle to bottom) is
1858 				   CMY, the reverse of the numbering */
1859 				/*------------------------------------------
1860 				  N.B. What are the implications of this for
1861 				  pen processing within a colour?
1862 				  -----------------------------------------*/
1863 	for ( colour = lastColour; colour >= _1stColour; colour-- )
1864 	    for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1865 	    {
1866 		dataword	= 0;
1867 		nozzle	= 0;
1868 		line	= _1stLine[colour][pen];
1869 				/* If there are any non-printing nozzles at
1870 				   the top of the printhead, set up the entries
1871 				   for them here.		*/
1872 		while ( ( (  _1stNozzle[colour][pen] - nozzle )
1873 			  >= SWIPE_WORD_BITS )
1874 			&& ( nozzle <= lastNozzle[colour][pen] ) )
1875 		{
1876 		    if ( lastWord != 0 )
1877 		    {
1878 			directory2		&= ~directoryBit;
1879 			column2[ wordCount2++ ]	=  dataword;
1880 			lastWord		=  dataword;
1881 		    }
1882 		    nozzle		+= SWIPE_WORD_BITS;
1883 		    directoryBit	<<= 1;
1884 		}
1885 				/* Shift over any remaining empty bits in
1886 				   the current column word.  */
1887 		wordBit = ( 1 << ( SWIPE_WORD_BITS - 1 ));
1888 		wordBit >>= ( _1stNozzle[colour][pen] - nozzle );
1889 
1890 		for ( columnWord = _1stNozzle[colour][pen] / SWIPE_WORD_BITS;
1891 		      columnWord <
1892 			  wordsPerPen[colour][lx5000dev->pensPerColour];
1893 		      columnWord++ )
1894 		{
1895 		    while ( wordBit )
1896 		    {
1897 			lineIndex = (uchar)( line & COLOUR_BUF_MASK );
1898 				/* Get the bit from the next line */
1899 			lineBit   = &colourLines[colour][pen][lineIndex];
1900 			if ( *(lineBit->xByte) & lineBit->xBit )
1901 			    dataword |= wordBit;
1902 			wordBit >>= 1;
1903 			if ( direction == LEFTWARD )
1904 			{
1905 			    DEC_BIT( *lineBit );
1906 			}
1907 			else
1908 			{
1909 			    INC_BIT( *lineBit );
1910 			}
1911 			line += lx5000dev->lineIncrement;
1912 		    }
1913 				/* Do we have a non-null dataword? */
1914 		    if ( dataword )/* For normal compression, every nonempty */
1915 		    {		/* dataword is noted and sent to printer */
1916 			directory1		&= ~directoryBit;
1917 			column1[ wordCount1++ ]	=  dataword;
1918 		    }
1919 		    if ( dataword != lastWord ) /* For repeat compression, */
1920 		    {		/* only datawords which change are recorded */
1921 			directory2		&= ~directoryBit;
1922 			column2[ wordCount2++ ]	=  dataword;
1923 			lastWord		=  dataword;
1924 		    }
1925 				/* Look at next set of nozzles */
1926 		    directoryBit <<= 1;
1927 		    dataword	= 0;
1928 				/* Reset dataword bit mask to 1st bit */
1929 		    wordBit	= ( 1 << ( SWIPE_WORD_BITS - 1 ));
1930 		}
1931 	    }
1932 				/* Output the smaller array of column words -
1933 				   is it normal or repeat compressed? */
1934 	if ( wordCount1 < wordCount2 )
1935 	{			/* A normal directory + data */
1936 	    int		i;
1937 
1938 	    *outp++	= directory1 >> 8;
1939 	    *outp++	= directory1 & 0xff;
1940 	    for ( i = 0; i < wordCount1; i++ )
1941 	    {
1942 		*outp++	= column1[ i ] >> 8;
1943 		*outp++	= column1[ i ] & 0xff;
1944 	    }
1945 	}
1946 	else
1947 	{			/* A repeat compression directory + data */
1948 	    int		i;
1949 
1950 	    *outp++	= directory2 >> 8;
1951 	    *outp++	= directory2 & 0xff;
1952 	    for ( i = 0; i < wordCount2; i++ )
1953 	    {
1954 		*outp++	= column2[ i ] >> 8;
1955 		*outp++	= column2[ i ] & 0xff;
1956 	    }
1957 	}
1958     }
1959 				/* Set up the header and output the swipe */
1960     swipeCmdLen	= outp - swipeBuf;
1961     {
1962 	int	ps1, ps2, direction, density, nozzles;
1963 
1964 	direction	= UNIDIRECTIONAL;
1965 	if ( x_dpi == 300 )
1966 	{
1967 	    density	= _300X;
1968 	}
1969 	else
1970 	{
1971 	    if ( x_dpi == 1200 )
1972 		density	= _1200X;
1973 	    else
1974 		density	= _600X;
1975 	}
1976 
1977 	if ( _1stColour == BLACK_X )
1978 	{
1979 	    ps1		= BLACK0;
1980 	    ps2		= BLACK1;
1981 	    nozzles	= _208NOZZLES;
1982 	}
1983 	else
1984 	{
1985 	    ps1		= COLOUR0;
1986 	    ps2		= COLOUR1;
1987 	    nozzles	= _192NOZZLES;
1988 	}
1989 	FILL_SWIPE_HEADER( swipeBuf, swipeCmdLen, direction, density,
1990 			   ps1, ps2, nozzles, UNKNOWN1VAL,
1991 			   columnExtent, _1stColumn, lastColumn );
1992     }
1993     fwrite( swipeBuf,1, outp - swipeBuf, prn_stream );
1994 
1995     for ( colour = _1stColour; colour <= lastColour; colour++ )
1996 	for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1997 	{
1998 				/* Scan the buffer for the next print line,
1999 				   if present.  If not, set sentinel value. */
2000 	    if ( pens[colour][pen].nextPrintLine
2001 		 <= pens[colour][pen].bottomLine
2002 		 || pens[colour][pen].nextPrintLine >= *nextLineToGet )
2003 	    {
2004 		pens[colour][pen].nextPrintLine =
2005 		    			pens[YELLOW_X][LO_PEN].finalLine;
2006 		line = pens[colour][pen].bottomLine + 1;
2007 		while ( line < *nextLineToGet )
2008 		{
2009 		    lineIndex	= (uchar)( line & COLOUR_BUF_MASK );
2010 		    if ( ! lineEmpty[colour][ lineIndex ] )
2011 		    {
2012 			pens[colour][pen].nextPrintLine = line;
2013 			break;
2014 		    }
2015 		    line += lx5000dev->lineIncrement;
2016 		}
2017 	    }
2018 	}
2019 }
2020 
2021 /*----------------------------------------------------------------------*
2022  *	l x 5 0 0 0 _ p r i n t _ p a g e ( )				*
2023  *----------------------------------------------------------------------*
2024   Send the page to the printer.
2025  *----------------------------------------------------------------------*/
2026 private int
lx5000_print_page(gx_device_printer * pdev,FILE * prn_stream)2027 lx5000_print_page( gx_device_printer *pdev, FILE *prn_stream )
2028 {
2029     /*
2030      Data structures for the buffer:
2031 
2032      ------------------------------------------------------------------*
2033      			C O L O U R   B U F F E R S
2034      ------------------------------------------------------------------*
2035      The colour buffers contain the individual colour bits that will
2036      actually be passed to the print heads; therefore, there is one bit
2037      per printable element.  So far, the correspondence between the
2038      gx_color_index elements in the scan line and the individual print
2039      bits is 1-to-1.
2040 
2041      For the colour driver, the colour buffers will be:
2042      		Cbuffer, Mbuffer, Ybuffer and Kbuffer
2043      while for the black driver, only Kbuffer is used.
2044      (See BUFFER HANDLING MACROS.)
2045 
2046      ------------------------------------------------------------------*
2047      		D E T E R M I N I N G   B U F F E R   S I Z E
2048      ------------------------------------------------------------------*
2049      The colour buffers are circular buffers: in order to implement this
2050      characteristic, the size of the buffer must be 2^n.  The buffers may
2051      then be indexed by the scan line number, masked by 2^n - 1.
2052 
2053      The buffer must be able to accommodate the maximum range of scan
2054      lines that might be affected by a single swipe command.  For colour
2055      pens this is 240 ( 3 x 64 pens + 2 x 24 inter-pen gaps).  For the
2056      black pen, this is 208.  Therefore, the minimum buffer size is 256.
2057      In fact, this is probably also the optimal buffer size, as there seems
2058      to be no advantage in buffering twice the number of scan line required
2059      to hold any individual swipe.
2060 
2061      ------------------------------------------------------------------*
2062      	   S T R U C T U R E   O F   T H E   C O L O U R   B U F F E R S
2063      ------------------------------------------------------------------*
2064      The colour buffers hold the data for individual colour printheads,
2065      extracted from the original data provided as scan lines.  When the
2066      data for each colour is extracted from the scan line, it is placed
2067      into a line of the colour buffer corresponding to the scan line.
2068 
2069      Within each line of the colour buffer, the data is structured like so:
2070      +-------+------------------- ~ ---------------------+-------+
2071      |  Pad  |    Scan line data bits for one colour     |  Pad  |
2072      | bytes |                                           | bytes |
2073      +-------+-------------------------------------------+-------+
2074 
2075      When the scan line data is first processed, the colour data is copied
2076      into the colour buffer in the position indicated above.  This line of
2077      data is padded on both ends.  The size of the pad is sufficient to
2078      account for the number of bits of head separation between the EVEN
2079      and ODD rows of nozzles in each print head; by default 16.
2080 
2081      The individual lines are accessed through an array of colourLines struct-
2082      ures.  This is defined in the TYPEDEFS & EXTERNAL STORAGE secion above.
2083 
2084      The colourLines structure contains a byte pointer which points to one of
2085      the bytes of an individual colour buffer line, and an unsigned char
2086      which is a single bit mask isolating one bit of the byte pointed to by
2087      the other element.
2088      		typedef struct bufBit_s {
2089      			byte *	xByte;
2090      			uchar	xBit;
2091      		} bufBit;
2092 
2093      The colourLines structure holds one instance of a bufBit; it points to
2094      the first bit of the scan line.  In general, the bit pointers for the
2095      first bit of the EVEN columns will point to the beginning of the
2096      extracted scan line data.  For the ODD columns, the first bit
2097      will point into the leading PAD bytes by 16 bits before the start of
2098      the actual scan line data.
2099 
2100      In this way, all of the complications of managing the separation
2101      between the EVEN and ODD columns on the heads is contained in the
2102      set-up procedures for the pointers in the scanLines array.  If it is
2103      required to reverse the adjustments of EVEN and ODD columns (for bi-
2104      directional printing, for example) this is achieved by adjusting the
2105      firstBit entries in this array.
2106 
2107      That, at any rate, is the theory.  It seemed like a good idea at the
2108      time.
2109 
2110      */
2111 
2112     static const char init_string[] = {
2113 	0xa5, 0, 6, 0x40, 3, 3, 0xc0, 0x0f, 0x0f,
2114 	0xa5, 0, 3, 0x40, 4, 5,
2115 	0xa5, 0, 3, 0x40, 4, 6,
2116 	0xa5, 0, 3, 0x40, 4, 7,
2117 	0xa5, 0, 3, 0x40, 4, 8,
2118 	0xa5, 0, 4, 0x40, 0xe0, 0xb, 3,
2119 	0xa5, 0, 11, 0x40, 0xe0, 0x41, 0, 0, 0, 0, 0, 0, 0, A5_11_5000,
2120 	0xa5, 0, 6, 0x40, 5, 0, 0, 0x80, 0,
2121 	0x1b, '*', 7, 0x73, 0x30,
2122 	0x1b, '*', 'm', 0, 0x14, 3, 0x84, 2, 0, 1, 0xf4,
2123 	0x1b, '*', 7, 0x63,
2124 	0x1b, '*', 'm', 0, 0x42, 0, 0,
2125 	0xa5, 0, 5, 0x40, 0xe0, 0x80, 8, 7
2126     };
2127 
2128     byte 	*lineBuffer;
2129     byte 	*swipeBuffer;
2130     byte 	*colourBufs[ NUM_COLOURS ];
2131     bufBit	colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES];
2132     bool	lineEmpty[ NUM_COLOURS ][ COLOUR_BUF_LINES ];
2133     penData	pens[ NUM_COLOURS ][ PENS_PER_COLOUR ];
2134 				/* nextLineToPrint is the top unprinted line
2135 				   in the buffers.  It is adjusted as lines
2136 				   are processed and printed.  Its sentinel
2137 				   value is pens[YELLOW_X][LO_PEN].finalLine.
2138 				   When any line
2139 				   which is not blank is read from GS &
2140 				   processed, nextLineToPrint will be set to
2141 				   this line if it is less than the current
2142 				   value.
2143 
2144 				   nextLineToGet is the next scanline to read
2145 				   from GS.				*/
2146     int		nextLineToPrint;
2147     int		nextLineToGet	= 0;
2148 				/* The current bottom line position of
2149 					  the colour cartridge.		*/
2150     int		bottomYellowLine;
2151     int		retval;
2152 
2153     lx5000_device *lx5000dev	= (lx5000_device *)pdev;
2154 
2155     nextLineToPrint	= pens[YELLOW_X][LO_PEN].finalLine;
2156     bottomYellowLine	= INITIAL_YELLOW_BOTTOM_LINE;
2157 				/* Allocate the buffer storage */
2158     if ( ( retval = getColourBufs( lx5000dev, &lineBuffer, colourBufs,
2159 				   &swipeBuffer, ALLOCATE ) ))
2160 	return retval;
2161 
2162     initPenConstants( lx5000dev, pens );
2163 			/* Initialize the lineEmpty[] and pens[] arrays -
2164 			   should happen during parameter setup process */
2165     {
2166 	int	colour, pen, line;
2167 
2168 	for ( colour = 0;
2169 	      colour < lx5000dev->color_info.num_components;
2170 	      colour++ )
2171 	{
2172 	    for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
2173 	    {
2174 		pens[colour][pen].nextPrintLine =
2175 		    			pens[YELLOW_X][LO_PEN].finalLine;
2176 
2177 		pens[colour][pen].bottomLine	=
2178 					pens[colour][pen].initialBottomLine;
2179 		pens[colour][pen].topLine	=
2180 			bottomYellowLine
2181 			- pens[colour][pen].topToBottomYellow;
2182 	    }
2183 	    for ( line = 0; line < COLOUR_BUF_LINES; line++ )
2184 		/* Force the zeroing of the line first time through */
2185 		lineEmpty[colour][line]	= false;
2186 	}
2187     }
2188 
2189 				/* Initialize the printer and reset margins. */
2190     pageInit( (uchar)lx5000dev->alignA, (uchar)lx5000dev->alignB, prn_stream );
2191     fwrite( init_string, 1, sizeof( init_string ), prn_stream );
2192 
2193 	/*--------------------------------------------------------------*
2194 	 Assume that COLOUR_BUF_LINES of data are available, starting with
2195 	 nextLineToPrint.  Work out which cartridge will be doing the
2196 	 printing, and how far it will have to move.
2197 
2198 	 Something is available to be printed.  This may (should?) involve
2199 	 initial paper movement to line up the appropriate pen.  Deciding
2200 	 on when to move the paper and by how much is tricky.  One aim is
2201 	 to minimize paper movements.
2202 
2203 	 Check for black vs colour printing first.  If the required
2204 	 movement for any of the colour pens is less than the required
2205 	 movement for the black pen, print a colour swathe, adjust all of
2206 	 the colour buffer values, and the nextLineToPrint value if
2207 	 necessary.
2208 
2209 	 Then refreshBuffer() and take another look.  Sooner or later,
2210 	 the next required movement of the colour cartridge will exceed
2211 	 the movement required of the black cartridge.  Print a black
2212 	 swathe.  Whether to move the black cartridge for this print is
2213 	 determined by checking on the subsequent colour cartridge
2214 	 movement.
2215 
2216 	 If the difference between the required movement for the black
2217 	 and the required movement for the colour is less than or equal
2218 	 to one colour pen depth, do not move the pen before printing the
2219 	 black swathe.
2220 
2221 	 Adjust black buffer values, including nextLineToPrint, which will
2222 	 (almost?) certainly change after a black print.  refreshBuffer()
2223 	 and try again.
2224 
2225 	 A note on 192 vs 208 black swathes.  I can see the reasons for
2226 	 using the 192 swathes.  When printing solid blocks with some of
2227 	 each colour and black on each scan line, use of 192 nozzles
2228 	 obviates the need for any black-related head movement.  A black
2229 	 swathe can be printed on every third movement of the heads, and,
2230 	 in the circumstances sketched above, will use all 192 nozzles.
2231 
2232 	 Obviously, the same simple algorithm can be used when the colours
2233 	 are less densely packed.  The Alignment B value, coded into the
2234 	 header of every swipe command, automatically adjusts the first
2235 	 pen of the set of 192 within a range of 0-15, so that the 192
2236 	 nozzles are symmetrically arranged with respect to the colour
2237 	 pens.  The complication is that the EVEN/ODD status of the
2238 	 nozzles in the 208 set is unaffected, even though the numbering
2239 	 may change.
2240 
2241 	 It originally seemed to me that it was completely unnecessary
2242 	 to use the 192 nozzle set.  The alignment value was needed to
2243 	 get the positioning right, but for all other purposes, the
2244 	 208 set could be used, and adjustments made on the fly.
2245 	 However, I when considering the printing of pseudo 1200Y
2246 	 pages, which involves the use of half-height pseudo-pens, it
2247 	 became clear that the calculation of the half-height of a
2248 	 pens would be greatly simplified by the use of 192 nozzles.
2249 	 This would leave the height of a pseudo-pen at an integral
2250 	 number of 16-bit datawords.
2251 
2252 	 As a result, I will use 192 nozzles only when printing at
2253 	 Nx1200Ydpi.
2254 
2255 	 *--------------------------------------------------------------*/
2256     refreshBuffer( lx5000dev, &nextLineToGet, &nextLineToPrint,
2257 		   lineBuffer, colourBufs, colourLines, pens, lineEmpty );
2258     while ( nextLineToPrint < pdev->height )
2259     {
2260 	int	blackDirection	= RIGHTWARD;
2261 	int	colourDirection	= LEFTWARD;
2262 				/* Target of next move of colour cartridge */
2263 	int	nextColourLine;
2264 	int	nextBlack208Line = cartridgeMoveTo( lx5000dev, pens,
2265 							  BLACK_X,
2266 							  BLACK_X );
2267 
2268 				/* In Black-only mode, cartridgeMoveTo
2269 				   will return an off-page value for the
2270 				   colour pens.			*/
2271 	nextColourLine = cartridgeMoveTo( lx5000dev, pens,
2272 						   _1ST_CMY_COLOUR,
2273 						   LAST_CMY_COLOUR );
2274 	if (  lx5000dev->isCMYK  && nextColourLine <= nextBlack208Line )
2275 	{			/* Move the head & print a 3-colour swathe */
2276 	    feedPaper( lx5000dev, nextColourLine, &bottomYellowLine, pens,
2277 		       prn_stream );
2278 	    printSwipe( lx5000dev, colourBufs, colourLines, pens,
2279 			 lineEmpty, swipeBuffer,
2280 			 &nextLineToPrint, &nextLineToGet, colourDirection,
2281 			 _1ST_CMY_COLOUR, LAST_CMY_COLOUR,
2282 			 prn_stream );
2283 	}
2284 	else
2285 	{
2286 	    feedPaper( lx5000dev, nextBlack208Line, &bottomYellowLine,
2287 			   pens, prn_stream );
2288 	    printSwipe( lx5000dev, colourBufs, colourLines, pens,
2289 			lineEmpty, swipeBuffer,
2290 			&nextLineToPrint, &nextLineToGet, blackDirection,
2291 			BLACK_X, BLACK_X,
2292 			prn_stream );
2293 	}
2294 	refreshBuffer( lx5000dev, &nextLineToGet, &nextLineToPrint,
2295 		       lineBuffer, colourBufs, colourLines, pens, lineEmpty );
2296     } /* ends the loop for swipes of the print head.*/
2297 
2298 				/* Eject the page, reinitialize the printer */
2299     pageEnd( prn_stream );
2300     fflush( prn_stream );
2301     getColourBufs( lx5000dev, &lineBuffer, colourBufs, &swipeBuffer,
2302 		   DEALLOCATE );
2303     if ( lx5000dev->dryTime )
2304 	sleep( lx5000dev->dryTime );
2305 
2306     return 0;
2307 }
2308 
2309 /*
2310  * There are a number of parameters which can differ between ink cartridges.
2311  * The Windows driver asks you to recalibrate every time you load a new
2312  * cartridge.
2313  *
2314  * [The Lexmark 5700 black
2315  * cartridge has two columns of dots, separated by about 16 pixels.
2316  * This `head separation' distance can vary between cartridges, so
2317  * we provide a parameter to set it.  In my small experience I've not
2318  * set the corresponding parameter in windows to anything greater than 17
2319  * or smaller than 15, but it would seem that it can vary from 1 to 32,
2320  * based on the calibration choices offered.
2321  *		Stephen Taylor's comment on the 5700 ]
2322  *
2323  * N.B.  The above discussion relates to the 5700.  On the 5000, in the
2324  *  Windows driver at any rate, there is no adjustment for the pixel
2325  *  distance between the rows of jets on the one print head.
2326  *
2327  * There are, however, two values which are always encoded into the initial
2328  *  escape sequence that the Windows driver sends to the printer for each
2329  *  new page: alignA the horizontal alignment between the colour and the
2330  *  black pens, and alignB, the vertical alignment between the same pens.
2331  *
2332  * AlignC is a black-only alignment, which seems to have something to do
2333  *  with bi-directional alignment.
2334  *
2335  * AlignD is a colour-only alignment, corresponding to AlignC.
2336  *
2337  * [As I understand the rules laid out in gsparams.h,
2338  * lx5000_get_params is supposed to return the current values of parameters
2339  * and lx5000_put_params is supposed to set up values in the lx5000_device
2340  * structure which can be used by the lx5000_print_page routine.
2341  * I've copied my routines from gdevcdj.c
2342  *		Stephen Taylor]
2343  *
2344  * DryingTime is a delay to allow page drying before a new page is fed
2345  * through.
2346  *
2347  * CMYK is a boolean parameter which specifies colour capability.  Set
2348  *  -dCMYK=false for black-only printing.
2349  *
2350  * See lx5000_put_params() for the legal ranges of values for these parameters.
2351  *
2352  */
2353 
2354 /*----------------------------------------------------------------------*
2355  *	l x 5 0 0 0 b _ g e t _ p a r a m s ( )				*
2356  *----------------------------------------------------------------------*/
2357 private int
lx5000_get_params(gx_device * pdev,gs_param_list * plist)2358 lx5000_get_params( gx_device *pdev, gs_param_list *plist )
2359 /*----------------------------------------------------------------------*/
2360 {
2361     lx5000_device *lx5000dev	= (lx5000_device *)pdev;
2362     int code			= gdev_prn_get_params( pdev, plist );
2363 
2364     if ( code < 0 ||
2365 	 ( code =
2366 	  param_write_int( plist, "HeadSeparation",
2367 			  &lx5000dev->headSeparation )) < 0 ||
2368 	 ( code = param_write_int(plist, "AlignA", &lx5000dev->alignA)) < 0 ||
2369 	 ( code = param_write_int(plist, "AlignB", &lx5000dev->alignB)) < 0 ||
2370 	 ( code = param_write_bool( plist, "CMYK", &lx5000dev->isCMYK )) < 0 ||
2371 	 ( code = param_write_bool( plist,
2372 				    "DryingTime", &lx5000dev->dryTime )) < 0
2373 	 )
2374 	return code;
2375 
2376     return code;
2377 }
2378 
2379 /*----------------------------------------------------------------------*
2380  *	l x 5 0 0 0 b _ p u t _ p a r a m _ i n t ( )			*
2381  *----------------------------------------------------------------------*/
2382 private int
lx5000_put_param_int(gs_param_list * plist,gs_param_name pname,int * pvalue,int minval,int maxval,int ecode)2383 lx5000_put_param_int(
2384 		      gs_param_list *plist, gs_param_name pname,
2385 		      int *pvalue,  int minval, int maxval, int ecode
2386 		      )
2387 /*----------------------------------------------------------------------*/
2388 {
2389     int code, value;
2390 
2391     switch ( code = param_read_int( plist, pname, &value ) )
2392     {
2393     default:
2394 	return code;
2395     case 0:
2396 	if ( value < minval || value > maxval )
2397 	{
2398 	    code =
2399 		param_signal_error( plist, pname, gs_error_rangecheck );
2400 	    ecode = ( code < 0 ? code : ecode );
2401 	}
2402 	else
2403 	    *pvalue = value;
2404     case 1:
2405 	return ecode;
2406     }
2407 }
2408 
2409 /*----------------------------------------------------------------------*
2410  *	l x 5 0 0 0 b _ p u t _ p a r a m _ b o o l ( )			*
2411  *----------------------------------------------------------------------*/
2412 private int
lx5000_put_param_bool(gs_param_list * plist,gs_param_name pname,bool * pvalue,int ecode)2413 lx5000_put_param_bool(
2414 		      gs_param_list *plist, gs_param_name pname,
2415 		      bool *pvalue,  int ecode
2416 		      )
2417 /*----------------------------------------------------------------------*/
2418 {
2419     int 	code;
2420 
2421     switch ( code = param_read_bool( plist, pname, pvalue ) )
2422     {
2423     default:
2424 	ecode = code;
2425 	param_signal_error(plist, pname, ecode);
2426 	return code;
2427     case 1:
2428     case 0:
2429 	return ecode;
2430     }
2431 }
2432 
2433 /*----------------------------------------------------------------------*
2434  *	l x 5 0 0 0 b _ p u t _ p a r a m s ( )				*
2435  *----------------------------------------------------------------------*/
2436 private int
lx5000_put_params(gx_device * pdev,gs_param_list * plist)2437 lx5000_put_params( gx_device *pdev, gs_param_list *plist )
2438 /*----------------------------------------------------------------------*/
2439 /* put_params is supposed to check all the parameters before setting any. */
2440 /*----------------------------------------------------------------------*/
2441 {
2442     lx5000_device	*lx5000dev = (lx5000_device *)pdev;
2443 
2444     int 	ecode, code	= 0;
2445     int 	headSeparation	= lx5000dev->headSeparation;
2446     int 	alignA		= lx5000dev->alignA;
2447     int 	alignB		= lx5000dev->alignB;
2448     int		dryTime		= lx5000dev->dryTime;
2449     int		bitsPerPixel	= lx5000dev->isCMYK ? 4 : 1;
2450     int		oldBPP		= bitsPerPixel;
2451     bool	isCMYK		= lx5000dev->isCMYK;
2452     bool	isCMYK_old	= isCMYK;
2453 
2454     code = lx5000_put_param_int( plist, "HeadSeparation", &headSeparation,
2455 				 8, 24, code ); /* 8 - 24 columns */
2456 
2457     code = lx5000_put_param_int( plist, "AlignA", &alignA, 0, 30, code );
2458 				/* 0 - 30 columns */
2459 
2460     code = lx5000_put_param_int( plist, "AlignB", &alignB, 0, 15, code );
2461 				/* 0 -15 nozzles */
2462 
2463     code = lx5000_put_param_int( plist, "DryingTime", &dryTime, 0, 60, code );
2464 				/* 0 -60 seconds */
2465 
2466     code = lx5000_put_param_int
2467 	( plist, "BitsPerPixel", &bitsPerPixel, 1, 4, code );
2468 				/* Black cartridge only */
2469 
2470     code = lx5000_put_param_bool( plist, "CMYK", &isCMYK, code );
2471 				/* Black cartridge only */
2472 
2473     /* Take precautions against input errors */
2474     if ( bitsPerPixel != 1 ) { bitsPerPixel = 4; }
2475 
2476     if ( isCMYK != isCMYK_old || bitsPerPixel != oldBPP )
2477     {
2478 	bool	isCMYK_new;
2479 	/* What has changed?  Assume that initial values were consistent,
2480 	   and set isCMYK to a value consistent with the changed args
2481 	   If both have changed, give precedence to isCMYK
2482 	*/
2483 	if ( bitsPerPixel != oldBPP )
2484 	{
2485 	    if ( bitsPerPixel == 1 )
2486 	    { isCMYK_new = false; }
2487 	    else
2488 	    { isCMYK_new = true; };
2489 	}
2490 	if ( isCMYK != isCMYK_old )
2491 	{ isCMYK_new = isCMYK; }
2492 
2493 	isCMYK = isCMYK_new;
2494 	bitsPerPixel = isCMYK ? 4 : 1;
2495 
2496 	if ( isCMYK )
2497 	{
2498 	    lx5000dev->color_info = color_info_cmy;
2499 	    dev_proc(pdev, map_cmyk_color) = lx5000_map_cmyk_color;
2500 	    dev_proc(pdev, map_rgb_color) = NULL;
2501 	    dev_proc(pdev, map_color_rgb) = lx5000_map_color_rgb;
2502 	}
2503 	else
2504 	{
2505 	    lx5000dev->color_info = color_info_blk;
2506 	    dev_proc(pdev, map_cmyk_color) = NULL;
2507 	    dev_proc(pdev, map_rgb_color) = gdev_prn_map_rgb_color;
2508 	    dev_proc(pdev, map_color_rgb) = gdev_prn_map_color_rgb;
2509 	}
2510 	if ( pdev->is_open )
2511 	    gs_closedevice(pdev);
2512     }
2513 
2514 				/* call super class put_params */
2515     ecode = gdev_prn_put_params( pdev, plist );
2516 
2517     if ( ecode < 0 || code < 0 )
2518     {
2519 	if ( isCMYK != isCMYK_old )
2520 	{
2521 	    if ( ! isCMYK )
2522 	    {
2523 		lx5000dev->color_info = color_info_cmy;
2524 		dev_proc(pdev, map_cmyk_color) = lx5000_map_cmyk_color;
2525 		dev_proc(pdev, map_rgb_color) = NULL;
2526 		dev_proc(pdev, map_color_rgb) = lx5000_map_color_rgb;
2527 	    }
2528 	    else
2529 	    {
2530 		lx5000dev->color_info = color_info_blk;
2531 		dev_proc(pdev, map_cmyk_color) = NULL;
2532 		dev_proc(pdev, map_rgb_color) = gdev_prn_map_rgb_color;
2533 		dev_proc(pdev, map_color_rgb) = gdev_prn_map_color_rgb;
2534 	    }
2535 	    if ( pdev->is_open )
2536 		gs_closedevice(pdev);
2537 	}
2538 	return ecode < 0 ? ecode : code;
2539     }
2540 
2541 				/* looks like everything okay; */
2542 				/* go ahead and set parameters */
2543     lx5000dev->headSeparation = headSeparation;
2544     lx5000dev->alignA = alignA;
2545     lx5000dev->alignB = alignB;
2546     lx5000dev->dryTime = dryTime;
2547     lx5000dev->isCMYK = isCMYK;
2548 				/* N.B. I am only setting these values here -
2549 				   should they also be set as part of the "two
2550 				   phase commit" of parameter changes?  My
2551 				   code is the only place these things are
2552 				   accessed.	*/
2553     if ( lx5000dev->y_pixels_per_inch == MAX_LX5000_Y )
2554     {
2555 	lx5000dev->pensPerColour	= 2;
2556 	lx5000dev->lineIncrement	= 2;
2557     }
2558     else
2559     {
2560 	lx5000dev->pensPerColour	= 1;
2561 	lx5000dev->lineIncrement	= 1;
2562     }
2563     if ( code == 1 ) return ecode;
2564     return 0;
2565 }
2566 
2567 
2568 /*----------------------------------------------------------------------*
2569  * The following colour handling procedures are lifted from gdevbit.c
2570  *----------------------------------------------------------------------*/
2571 /* Map color to RGB.  This has 3 separate cases, but since it is rarely */
2572 /* used, we do a case test rather than providing 3 separate routines. */
2573 private int
lx5000_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value rgb[3])2574 lx5000_map_color_rgb(gx_device * dev, gx_color_index color,
2575 		     gx_color_value rgb[3])
2576 {
2577     int depth = dev->color_info.depth;
2578     int ncomp = dev->color_info.num_components;
2579     int bpc = depth / ncomp;
2580     uint mask = (1 << bpc) - 1;
2581 
2582 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
2583 
2584     /* Map CMYK back to RGB. */
2585 
2586     gx_color_index cshift = color;
2587     uint c, m, y, k;
2588 
2589     k = cshift & mask;
2590     cshift >>= bpc;
2591     y = cshift & mask;
2592     cshift >>= bpc;
2593     m = cshift & mask;
2594     c = cshift >> bpc;
2595     /* We use our improved conversion rule.... */
2596     rgb[0] = cvalue((mask - c) * (mask - k) / mask);
2597     rgb[1] = cvalue((mask - m) * (mask - k) / mask);
2598     rgb[2] = cvalue((mask - y) * (mask - k) / mask);
2599 
2600     return 0;
2601 #undef cvalue
2602 }
2603 
2604 /* Map CMYK to color. */
2605 private gx_color_index
lx5000_map_cmyk_color(gx_device * dev,gx_color_value cyan,gx_color_value magenta,gx_color_value yellow,gx_color_value black)2606 lx5000_map_cmyk_color(gx_device * dev, gx_color_value cyan,
2607 	gx_color_value magenta, gx_color_value yellow, gx_color_value black)
2608 {
2609     int bpc = dev->color_info.depth / 4;
2610     int drop = sizeof(gx_color_value) * 8 - bpc;
2611     gx_color_index color =
2612     ((((((cyan >> drop) << bpc) +
2613 	(magenta >> drop)) << bpc) +
2614       (yellow >> drop)) << bpc) +
2615     (black >> drop);
2616 
2617     return (color == gx_no_color_index ? color ^ 1 : color);
2618 }
2619 
2620 /*=============== Clean up my #define's =================*/
2621 #undef A5_11_5000
2622 #undef A5_11_5700
2623 #undef ALIGN_A_DEF
2624 #undef ALIGN_A_OFFSET
2625 #undef ALIGN_B_DEF
2626 #undef ALIGN_B_OFFSET
2627 #undef HEADSEP_DEF
2628 #undef DRY_TIME_DEF
2629 #undef LX_UNI
2630 #undef MIN_LX5000_X
2631 #undef MAX_LX5000_X
2632 #undef DEF_LX5000_X
2633 #undef MIN_LX5000_Y
2634 #undef MAX_LX5000_Y
2635 #undef DEF_LX5000_Y
2636 #undef LX5000_XDPI
2637 #undef LX5000_YDPI
2638 #undef FEED_FACTOR
2639 #undef LX5000_XOFFSET_TO_0_0_XDPI
2640 #undef LX5000_YOFFSET_TO_0_0_YDPI
2641 #undef LX5000_XOFFSET_TO_0_0
2642 #undef LX5000_YOFFSET_TO_0_0
2643 #undef LX5000_LEFT_HWMARGIN_INS
2644 #undef LX5000_BOTTOM_HWMARGIN_INS
2645 #undef LX5000_RIGHT_HWMARGIN_INS
2646 #undef LX5000_TOP_HWMARGIN_INS
2647 #undef LINE_PAD_BYTES
2648 #undef RIGHTWARD
2649 #undef LEFTWARD
2650 #undef SWIPE_WORD_BITS
2651 #undef BLACK_NOZZLES
2652 #undef _1COLOUR_NOZZLES
2653 #undef BLK_COLOUR_NOZZLES
2654 #undef BLK_SWIPE_WORDS
2655 #undef COLOUR_SWIPE_WORDS
2656 #undef _1COLOUR_WORDS
2657 #undef BLK_DIRECTORY_MASK
2658 #undef COLOUR_DIRECTORY_MASK
2659 #undef DIRECTORY_TYPE_BIT
2660 #undef COLOUR_PEN_GAP
2661 #undef COLOUR_PEN_DIFF
2662 #undef INITIAL_YELLOW_BOTTOM_LINE
2663 #undef COLOUR_BUF_MASK
2664 #undef COLOUR_BUF_LINES
2665 #undef SWIPE_LEADER
2666 #undef CMDLEN_X
2667 #undef DIRECTION_X
2668 #undef UNIDIRECTIONAL
2669 #undef BIDIRECTIONAL
2670 #undef HEADSPEED_X
2671 #undef _300X
2672 #undef _600X
2673 #undef _1200Y
2674 #undef PEN_X
2675 #undef BLACK0
2676 #undef BLACK1
2677 #undef COLOUR0
2678 #undef COLOUR1
2679 #undef NOZZLE_COUNT_X
2680 #undef _192NOZZLES
2681 #undef _208NOZZLES
2682 #undef UNKNOWN1_X
2683 #undef UNKNOWN1VAL
2684 #undef NUM_COLUMNS_X
2685 #undef _1ST_COLUMN_X
2686 #undef LAST_COLUMN_X
2687 #undef SWIPE_HDR_END_X
2688 #undef SWIPE_HDR_END_LEN
2689 #undef SWIPE_HDR_END
2690 #undef SWIPE_HDR_LEN
2691 #undef BLACK_X
2692 #undef YELLOW_X
2693 #undef MAGENTA_X
2694 #undef CYAN_X
2695 #undef LO_PEN
2696 #undef HI_PEN
2697 #undef NUM_COMPONENTS_BLK
2698 #undef BITS_PER_PIXEL_BLK
2699 #undef MAX_GREY_BLK
2700 #undef MAX_RGB_BLK
2701 #undef DITHER_GREYS_BLK
2702 #undef DITHER_COLOURS_BLK
2703 #undef NUM_COMPONENTS_CMY
2704 #undef BITS_PER_PIXEL_CMY
2705 #undef MAX_GREY_CMY
2706 #undef MAX_RGB_CMY
2707 #undef DITHER_GREYS_CMY
2708 #undef DITHER_COLOURS_CMY
2709 #undef MIN_COLOUR
2710 #undef MAX_COLOUR
2711 #undef BLACK_PEN
2712 #undef _1ST_CMY_COLOUR
2713 #undef LAST_CMY_COLOUR
2714 #undef BPP
2715 #undef PIXEL_MASK
2716 #undef INITIAL_PIXEL_SHIFT
2717 #undef NUM_COLOURS
2718 #undef PENS_PER_COLOUR
2719 #undef NUM_PENS
2720 #undef BITS_PER_COLOUR
2721 #undef DEF_NUM_COLOURS
2722 #undef DEF_PENS_PER_COLOUR
2723 #undef DEF_LINE_INCREMENT
2724 #undef PIXELS_PER_BYTE
2725 #undef COLOUR_MASK
2726 #undef ALLOCATE
2727 #undef DEALLOCATE
2728 #undef FILL_SWIPE_HEADER
2729 #undef BIT_TO_MASK
2730 #undef INC_BIT
2731 #undef DEC_BIT
2732 #undef lx5000_proctab
2733