1/*
2 * "$Id: print-weave.c,v 1.76 2010/08/04 00:33:57 rlk Exp $"
3 *
4 *   Softweave calculator for Gutenprint.
5 *
6 *   Copyright 2000 Charles Briscoe-Smith <cpbs@debian.org>
7 *
8 *   This program is free software; you can redistribute it and/or modify it
9 *   under the terms of the GNU General Public License as published by the Free
10 *   Software Foundation; either version 2 of the License, or (at your option)
11 *   any later version.
12 *
13 *   This program is distributed in the hope that it will be useful, but
14 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 *   for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23/*
24 * This file must include only standard C header files.  The core code must
25 * compile on generic platforms that don't support glib, gimp, gtk, etc.
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <string.h>
32#include <gutenprint/gutenprint.h>
33#include "gutenprint-internal.h"
34#include <gutenprint/gutenprint-intl-internal.h>
35#ifdef HAVE_LIMITS_H
36#include <limits.h>
37#endif
38
39static int
40gcd(int x, int y)
41{
42	if (y == 0)
43		return x;
44	while (x != 0) {
45		if (y > x) {
46			int t = x;
47			x = y;
48			y = t;
49		}
50		x %= y;
51	}
52	return y;
53}
54
55typedef struct stpi_softweave
56{
57  stp_linebufs_t *linebases;	/* Base address of each row buffer */
58  stp_lineoff_t *lineoffsets;	/* Offsets within each row buffer */
59  stp_lineactive_t *lineactive;	/* Does this line have anything printed? */
60  stp_linecount_t *linecounts;	/* How many rows we've printed this pass */
61  stp_linebounds_t *linebounds;	/* Starting and ending print column */
62  stp_pass_t *passes;		/* Circular list of pass numbers */
63  int last_pass_offset;		/* Starting row (offset from the start of */
64				/* the page) of the most recently printed */
65				/* pass (so we can determine how far to */
66				/* advance the paper) */
67  int last_pass;		/* Number of the most recently printed pass */
68
69  int jets;			/* Number of jets per color */
70  int virtual_jets;		/* Number of jets per color, taking into */
71				/* account the head offset */
72  int separation;		/* Offset from one jet to the next in rows */
73  void *weaveparm;		/* Weave calculation parameter block */
74
75  int horizontal_weave;		/* Number of horizontal passes required */
76				/* This is > 1 for some of the ultra-high */
77				/* resolution modes */
78  int vertical_subpasses;	/* Number of passes per line (for better */
79				/* quality) */
80  int vmod;			/* Number of banks of passes */
81  int oversample;		/* Excess precision per row */
82  int repeat_count;		/* How many times a pass is repeated */
83  int ncolors;			/* How many colors */
84  int linewidth;		/* Line width in input pixels */
85  int vertical_height;		/* Image height in output pixels */
86  int firstline;		/* Actual first line (referenced to paper) */
87
88  int bitwidth;			/* Bits per pixel */
89  int lineno;
90  int vertical_oversample;	/* Vertical oversampling */
91  int current_vertical_subpass;
92  int horizontal_width;		/* Horizontal width, in bits */
93  int *head_offset;		/* offset of printheads */
94  unsigned char *s[STP_MAX_WEAVE];
95  unsigned char *fold_buf;
96  unsigned char *comp_buf;
97  stp_weave_t wcache;
98  int rcache;
99  int vcache;
100  stp_flushfunc *flushfunc;
101  stp_fillfunc *fillfunc;
102  stp_packfunc *pack;
103  stp_compute_linewidth_func *compute_linewidth;
104} stpi_softweave_t;
105
106/* RAW WEAVE */
107
108typedef struct raw {
109	int separation;
110	int jets;
111	int oversampling;
112	int advancebasis;
113	int subblocksperpassblock;
114	int passespersubblock;
115	stp_weave_strategy_t strategy;
116	stp_vars_t *v;
117} raw_t;
118
119/*
120 * Strategy types currently defined:
121 *
122 *  0: zig-zag type pass block filling
123 *  1: ascending pass block filling
124 *  2: descending pass block filling
125 *  3: ascending fill with 2x expansion
126 *  4: staggered zig-zag neighbour-avoidance fill
127 *  5: ascending fill with 3x expansion
128 *
129 * In theory, strategy 0 should be optimal; in practice, it can lead
130 * to visible areas of banding.  If it's necessary to avoid filling
131 * neighbouring rows in neighbouring passes, strategy 4 should be optimal,
132 * at least for some weaves.
133 */
134
135static void
136initialize_raw_weave(raw_t *w,	/* I - weave struct to be filled in */
137                     int separation,	/* I - jet separation */
138                     int jets,	/* I - number of jets */
139                     int oversample,	/* I - oversampling factor */
140                     stp_weave_strategy_t strat,	/* I - weave pattern variation to use */
141		     stp_vars_t *v)
142{
143	w->separation = separation;
144	w->jets = jets;
145	w->oversampling = oversample;
146	w->advancebasis = jets / oversample;
147	if (w->advancebasis == 0)
148	  w->advancebasis++;
149	w->subblocksperpassblock = gcd(separation, w->advancebasis);
150	w->passespersubblock = separation / w->subblocksperpassblock;
151	w->strategy = strat;
152	w->v = v;
153}
154
155static void
156calculate_raw_pass_parameters(raw_t *w,		/* I - weave parameters */
157                              int pass,		/* I - pass number ( >= 0) */
158                              int *startrow,	/* O - print head position */
159                              int *subpass)	/* O - subpass number */
160{
161	int band, passinband, subpassblock, subpassoffset;
162
163	band = pass / (w->separation * w->oversampling);
164	passinband = pass % (w->separation * w->oversampling);
165	subpassblock = pass % w->separation
166	                 * w->subblocksperpassblock / w->separation;
167
168	switch (w->strategy) {
169	case STP_WEAVE_ZIGZAG:
170		if (subpassblock * 2 < w->subblocksperpassblock)
171			subpassoffset = 2 * subpassblock;
172		else
173			subpassoffset = 2 * (w->subblocksperpassblock
174			                      - subpassblock) - 1;
175		break;
176	case STP_WEAVE_ASCENDING:
177		subpassoffset = subpassblock;
178		break;
179	case STP_WEAVE_DESCENDING:
180		subpassoffset = w->subblocksperpassblock - 1 - subpassblock;
181		break;
182	case STP_WEAVE_ASCENDING_2X:
183		if (subpassblock * 2 < w->subblocksperpassblock)
184			subpassoffset = 2 * subpassblock;
185		else
186			subpassoffset = 1 + 2 * (subpassblock
187			                          - (w->subblocksperpassblock
188			                              + 1) / 2);
189		break;
190	case STP_WEAVE_ASCENDING_3X:
191		if (subpassblock * 3 < w->subblocksperpassblock)
192			subpassoffset = 3 * subpassblock;
193		else if (3 * (subpassblock - (w->subblocksperpassblock + 2) / 3)
194		          < w->subblocksperpassblock - 2)
195			subpassoffset = 2 + 3 * (subpassblock
196			                          - (w->subblocksperpassblock
197			                              + 2) / 3);
198		else
199			subpassoffset = 1 + 3 * (subpassblock
200			                          - (w->subblocksperpassblock
201			                              + 2) / 3
202						  - w->subblocksperpassblock
203						      / 3);
204		break;
205	case STP_WEAVE_STAGGERED:
206		if (subpassblock * 2 < w->subblocksperpassblock)
207			subpassoffset = 2 * subpassblock;
208		else if (subpassblock * 2 < w->subblocksperpassblock + 2)
209			subpassoffset = 1;
210		else
211			subpassoffset = 2 * (w->subblocksperpassblock
212			                      - subpassblock) + 1;
213		break;
214	default:
215		subpassoffset = subpassblock;
216		break;
217	}
218
219	*startrow = w->separation * w->jets * band
220	              + w->advancebasis * passinband + subpassoffset;
221	*subpass = passinband / w->separation;
222}
223
224static void
225calculate_raw_row_parameters(raw_t *w,		/* I - weave parameters */
226                             int row,		/* I - row number */
227                             int subpass,	/* I - subpass number */
228                             int *pass,		/* O - pass number */
229                             int *jet,		/* O - jet number in pass */
230                             int *startrow)	/* O - starting row of pass */
231{
232	int subblockoffset, subpassblock, band, baserow, passinband, offset;
233	int pass_div_separation;
234	int pass_mod_separation;
235	int off_mod_separation;
236
237	subblockoffset = row % w->subblocksperpassblock;
238	switch (w->strategy) {
239	case STP_WEAVE_ZIGZAG:
240		if (subblockoffset % 2 == 0)
241			subpassblock = subblockoffset / 2;
242		else
243			subpassblock = w->subblocksperpassblock
244			                 - (subblockoffset + 1) / 2;
245		break;
246	case STP_WEAVE_ASCENDING:
247		subpassblock = subblockoffset;
248		break;
249	case STP_WEAVE_DESCENDING:
250		subpassblock = w->subblocksperpassblock - 1 - subblockoffset;
251		break;
252	case STP_WEAVE_ASCENDING_2X:
253		if (subblockoffset % 2 == 0)
254			subpassblock = subblockoffset / 2;
255		else
256			subpassblock = (subblockoffset - 1) / 2
257			               + (w->subblocksperpassblock + 1) / 2;
258		break;
259	case STP_WEAVE_ASCENDING_3X:
260		if (subblockoffset % 3 == 0)
261			subpassblock = subblockoffset / 3;
262		else if (subblockoffset % 3 == 1)
263			subpassblock = (subblockoffset - 1) / 3
264			                 + (w->subblocksperpassblock + 2) / 3;
265		else
266			subpassblock = (subblockoffset - 2) / 3
267			                 + (w->subblocksperpassblock + 2) / 3
268			                 + (w->subblocksperpassblock + 1) / 3;
269		break;
270	case STP_WEAVE_STAGGERED:
271		if (subblockoffset % 2 == 0)
272			subpassblock = subblockoffset / 2;
273		else if (subblockoffset == 1)
274			subpassblock = (w->subblocksperpassblock + 1) / 2;
275		else
276			subpassblock = w->subblocksperpassblock
277			                 - (subblockoffset - 1) / 2;
278		break;
279	default:
280		subpassblock = subblockoffset;
281		break;
282	}
283
284	band = row / (w->separation * w->jets);
285	baserow = row - subblockoffset - band * w->separation * w->jets;
286	passinband = baserow / w->advancebasis;
287	offset = baserow % w->advancebasis;
288	pass_div_separation = passinband / w->separation;
289	pass_mod_separation = passinband % w->separation;
290	off_mod_separation = offset % w->separation;
291
292	while (off_mod_separation != 0
293	       || pass_div_separation != subpass
294	       || pass_mod_separation / w->passespersubblock
295	            != subpassblock)
296	  {
297	    offset += w->advancebasis;
298	    passinband--;
299	    if (passinband >= 0)
300	      {
301		pass_mod_separation--;
302		if (pass_mod_separation < 0)
303		  {
304		    pass_mod_separation += w->separation;
305		    pass_div_separation--;
306		  }
307		if (w->advancebasis < w->separation)
308		  {
309		    off_mod_separation += w->advancebasis;
310		    if (off_mod_separation >= w->separation)
311		      off_mod_separation -= w->separation;
312		  }
313		else if (w->advancebasis > w->separation)
314		  off_mod_separation = offset % w->separation;
315	      }
316	    else
317	      {
318		const int roundedjets =
319		  (w->advancebasis * w->oversampling) % w->jets;
320		band--;
321		passinband += w->separation * w->oversampling;
322		offset += w->separation * (w->jets - roundedjets);
323		pass_div_separation = passinband / w->separation;
324		pass_mod_separation = passinband % w->separation;
325		off_mod_separation = offset % w->separation;
326	      }
327	  }
328
329	*pass = band * w->oversampling * w->separation + passinband;
330	*jet = (offset / w->separation) % w->jets;
331	*startrow = row - (*jet * w->separation);
332}
333
334/* COOKED WEAVE */
335
336typedef struct cooked {
337	raw_t rw;
338	int first_row_printed;
339	int last_row_printed;
340
341	int first_premapped_pass;	/* First raw pass used by this page */
342	int first_normal_pass;
343	int first_postmapped_pass;
344	int first_unused_pass;
345
346	int *pass_premap;
347	int *stagger_premap;
348	int *pass_postmap;
349	int *stagger_postmap;
350} cooked_t;
351
352typedef struct startmap {
353  int startrow;
354  int map;
355  int pos;			/* Secondary key for stable sort */
356} startmap_t;
357
358static int
359smap_compare(const void *p1, const void *p2)
360{
361  const startmap_t *s1 = (const startmap_t *)p1;
362  const startmap_t *s2 = (const startmap_t *)p2;
363  if (s1->startrow < s2->startrow)
364    return -1;
365  else if (s1->startrow > s2->startrow)
366    return 1;
367  else if (s1->pos < s2->pos)
368    return -1;
369  else
370    return 1;
371}
372
373static void
374sort_by_start_row(int *map, int *startrows, int count)
375{
376  startmap_t *smap = stp_malloc(sizeof(startmap_t) * count);
377  int i;
378  for (i = 0; i < count; i++)
379    {
380      smap[i].startrow = startrows[i];
381      smap[i].map = map[i];
382      smap[i].pos = i;
383    }
384  qsort(smap, count, sizeof(startmap_t), smap_compare);
385  for (i = 0; i < count; i++)
386    {
387      startrows[i] = smap[i].startrow;
388      map[i] = smap[i].map;
389    }
390  stp_free(smap);
391}
392
393static void
394calculate_stagger(raw_t *w, int *map, int *startrows_stagger, int count)
395{
396	int i;
397
398	for (i = 0; i < count; i++) {
399		int startrow, subpass;
400		calculate_raw_pass_parameters(w, map[i], &startrow, &subpass);
401		startrow -= w->separation * w->jets;
402		startrows_stagger[i] = (startrows_stagger[i] - startrow)
403		                         / w->separation;
404	}
405}
406
407static void
408invert_map(int *map, int *stagger, int count, int oldfirstpass,
409           int newfirstpass)
410{
411	int i;
412	int *newmap, *newstagger;
413	newmap = stp_malloc(count * sizeof(int));
414	newstagger = stp_malloc(count * sizeof(int));
415
416	for (i = 0; i < count; i++) {
417		newmap[map[i] - oldfirstpass] = i + newfirstpass;
418		newstagger[map[i] - oldfirstpass] = stagger[i];
419	}
420
421	memcpy(map, newmap, count * sizeof(int));
422	memcpy(stagger, newstagger, count * sizeof(int));
423	stp_free(newstagger);
424	stp_free(newmap);
425}
426
427static void
428make_passmap(raw_t *w, int **map, int **starts, int first_pass_number,
429             int first_pass_to_map, int first_pass_after_map,
430             int first_pass_to_stagger, int first_pass_after_stagger,
431             int first_row_of_maximal_pass, int separations_to_distribute)
432{
433	int *passmap, *startrows;
434	int passes_to_map = first_pass_after_map - first_pass_to_map;
435	int i;
436
437	STPI_ASSERT(first_pass_to_map <= first_pass_after_map, w->v);
438	STPI_ASSERT(first_pass_to_stagger <= first_pass_after_stagger, w->v);
439
440	*map = passmap = stp_malloc(passes_to_map * sizeof(int));
441	*starts = startrows = stp_malloc(passes_to_map * sizeof(int));
442
443	for (i = 0; i < passes_to_map; i++) {
444		int startrow, subpass;
445		int pass = i + first_pass_to_map;
446		calculate_raw_pass_parameters(w, pass, &startrow, &subpass);
447		passmap[i] = pass;
448		if (first_row_of_maximal_pass >= 0)
449			startrow = first_row_of_maximal_pass - startrow
450			             + w->separation * w->jets;
451		else
452			startrow -= w->separation * w->jets;
453		while (startrow < 0)
454			startrow += w->separation;
455		startrows[i] = startrow;
456	}
457
458	sort_by_start_row(passmap, startrows, passes_to_map);
459
460	separations_to_distribute++;
461
462	for (i = 0; i < first_pass_after_stagger - first_pass_to_stagger; i++) {
463		int offset = first_pass_to_stagger - first_pass_to_map;
464		if (startrows[i + offset] / w->separation
465		      < i % separations_to_distribute)
466		{
467			startrows[i + offset]
468			  = startrows[i + offset] % w->separation
469			     + w->separation * (i % separations_to_distribute);
470		}
471	}
472
473	if (first_row_of_maximal_pass >= 0) {
474		for (i = 0; i < passes_to_map; i++) {
475			startrows[i] = first_row_of_maximal_pass - startrows[i];
476		}
477	}
478
479	sort_by_start_row(passmap, startrows, passes_to_map);
480	calculate_stagger(w, passmap, startrows, passes_to_map);
481
482	invert_map(passmap, startrows, passes_to_map, first_pass_to_map,
483		   first_pass_to_map - first_pass_number);
484}
485
486static void
487calculate_pass_map(stp_vars_t *v,
488		   cooked_t *w,		/* I - weave parameters */
489                   int pageheight,	/* I - number of rows on page */
490                   int firstrow,	/* I - first printed row */
491                   int lastrow)		/* I - last printed row */
492{
493	int startrow, subpass;
494	int pass = -1;
495
496	w->first_row_printed = firstrow;
497	w->last_row_printed = lastrow;
498
499	if (pageheight <= lastrow)
500		pageheight = lastrow + 1;
501
502	do {
503		calculate_raw_pass_parameters(&w->rw, ++pass,
504		                              &startrow, &subpass);
505	} while (startrow - w->rw.separation < firstrow);
506
507	w->first_premapped_pass = pass;
508
509	while (startrow < w->rw.separation * w->rw.jets
510	       && startrow - w->rw.separation < pageheight
511	       && startrow <= lastrow + w->rw.separation * w->rw.jets)
512	{
513		calculate_raw_pass_parameters(&w->rw, ++pass,
514		                              &startrow, &subpass);
515	}
516	w->first_normal_pass = pass;
517
518	while (startrow - w->rw.separation < pageheight
519	       && startrow <= lastrow + w->rw.separation * w->rw.jets)
520	{
521		calculate_raw_pass_parameters(&w->rw, ++pass,
522		                              &startrow, &subpass);
523	}
524	w->first_postmapped_pass = pass;
525
526	while (startrow <= lastrow + w->rw.separation * w->rw.jets) {
527		calculate_raw_pass_parameters(&w->rw, ++pass,
528		                              &startrow, &subpass);
529	}
530	w->first_unused_pass = pass;
531
532	stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
533		    "first premapped %d first normal %d first postmapped %d "
534		    "first unused %d\n",
535		    w->first_premapped_pass, w->first_normal_pass,
536		    w->first_postmapped_pass, w->first_unused_pass);
537	/*
538	 * FIXME: make sure first_normal_pass doesn't advance beyond
539	 * first_postmapped_pass, or first_postmapped_pass doesn't
540	 * retreat before first_normal_pass.
541	 */
542
543	if (w->first_normal_pass > w->first_premapped_pass) {
544		int spread, separations_to_distribute, normal_passes_mapped;
545		separations_to_distribute = firstrow / w->rw.separation;
546		spread = (separations_to_distribute + 1) * w->rw.separation;
547		normal_passes_mapped = (spread + w->rw.advancebasis - 1)
548		                            / w->rw.advancebasis;
549		w->first_normal_pass += normal_passes_mapped;
550		make_passmap(&w->rw, &w->pass_premap, &w->stagger_premap,
551		             w->first_premapped_pass,
552		             w->first_premapped_pass, w->first_normal_pass,
553			     w->first_premapped_pass,
554			     w->first_normal_pass - normal_passes_mapped,
555		             -1, separations_to_distribute);
556	} else {
557		w->pass_premap = 0;
558		w->stagger_premap = 0;
559	}
560
561	if (w->first_unused_pass >= w->first_postmapped_pass) {
562		int spread, separations_to_distribute, normal_passes_mapped;
563		separations_to_distribute = (pageheight - lastrow - 1)
564		                                     / w->rw.separation;
565		spread = (separations_to_distribute + 1) * w->rw.separation;
566		normal_passes_mapped = (spread + w->rw.advancebasis)
567		                             / w->rw.advancebasis;
568		w->first_postmapped_pass -= normal_passes_mapped;
569		make_passmap(&w->rw, &w->pass_postmap, &w->stagger_postmap,
570		             w->first_premapped_pass,
571		             w->first_postmapped_pass, w->first_unused_pass,
572			     w->first_postmapped_pass + normal_passes_mapped,
573			     w->first_unused_pass,
574		             pageheight - 1
575		                 - w->rw.separation * (w->rw.jets - 1),
576			     separations_to_distribute);
577	} else {
578		w->pass_postmap = 0;
579		w->stagger_postmap = 0;
580	}
581}
582
583static void *				/* O - weave parameter block */
584initialize_weave_params(int separation,		/* I - jet separation */
585                        int jets,		/* I - number of jets */
586                        int oversample,		/* I - oversampling factor */
587                        int firstrow,	/* I - first row number to print */
588                        int lastrow,	/* I - last row number to print */
589                        int pageheight,	/* I - number of rows on the whole
590                        		       page, without using any
591                        		       expanded margin facilities */
592                        stp_weave_strategy_t strategy,	/* I - weave pattern variant to use */
593			stp_vars_t *v)
594{
595	cooked_t *w = stp_malloc(sizeof(cooked_t));
596	if (w) {
597		initialize_raw_weave(&w->rw, separation, jets, oversample, strategy, v);
598		calculate_pass_map(v, w, pageheight, firstrow, lastrow);
599	}
600	return w;
601}
602
603static void
604stpi_destroy_weave_params(void *vw)
605{
606	cooked_t *w = (cooked_t *) vw;
607
608	if (w->pass_premap) stp_free(w->pass_premap);
609	if (w->stagger_premap) stp_free(w->stagger_premap);
610	if (w->pass_postmap) stp_free(w->pass_postmap);
611	if (w->stagger_postmap) stp_free(w->stagger_postmap);
612	stp_free(w);
613}
614
615static void
616stpi_calculate_row_parameters(void *vw,		/* I - weave parameters */
617			      int row,		/* I - row number */
618			      int subpass,	/* I - subpass */
619			      int *pass,	/* O - pass containing row */
620			      int *jetnum,	/* O - jet number of row */
621			      int *startingrow,	/* O - phys start of pass */
622			      int *ophantomrows, /* O - missing rows @ start */
623			      int *ojetsused)	/* O - jets used by pass */
624{
625	cooked_t *w = (cooked_t *) vw;
626	int raw_pass, jet, startrow, phantomrows, jetsused;
627	int stagger = 0;
628	int extra;
629
630	STPI_ASSERT(row >= w->first_row_printed, w->rw.v);
631	STPI_ASSERT(row <= w->last_row_printed, w->rw.v);
632	calculate_raw_row_parameters(&w->rw,
633	                             row + w->rw.separation * w->rw.jets,
634	                             subpass, &raw_pass, &jet, &startrow);
635	startrow -= w->rw.separation * w->rw.jets;
636	jetsused = w->rw.jets;
637	phantomrows = 0;
638
639	if (raw_pass < w->first_normal_pass) {
640	        STPI_ASSERT(raw_pass >= w->first_premapped_pass, w->rw.v);
641		*pass = w->pass_premap[raw_pass - w->first_premapped_pass];
642		stagger = w->stagger_premap[raw_pass - w->first_premapped_pass];
643	} else if (raw_pass >= w->first_postmapped_pass) {
644	        STPI_ASSERT(raw_pass >= w->first_postmapped_pass, w->rw.v);
645		*pass = w->pass_postmap[raw_pass - w->first_postmapped_pass];
646		stagger = w->stagger_postmap[raw_pass
647		                             - w->first_postmapped_pass];
648	} else {
649		*pass = raw_pass - w->first_premapped_pass;
650	}
651
652	startrow += stagger * w->rw.separation;
653	*jetnum = jet - stagger;
654	if (stagger < 0) {
655		stagger = -stagger;
656		phantomrows += stagger;
657	}
658	jetsused -= stagger;
659
660	extra = w->first_row_printed
661	             - (startrow + w->rw.separation * phantomrows);
662	if (extra > 0) {
663		extra = (extra + w->rw.separation - 1) / w->rw.separation;
664		jetsused -= extra;
665		phantomrows += extra;
666	}
667
668	extra = startrow + w->rw.separation * (phantomrows + jetsused - 1)
669	          - w->last_row_printed;
670	if (extra > 0) {
671		extra = (extra + w->rw.separation - 1) / w->rw.separation;
672		jetsused -= extra;
673	}
674
675	*startingrow = startrow;
676	*ophantomrows = phantomrows;
677	*ojetsused = jetsused;
678}
679
680/*
681 * "Soft" weave
682 *
683 * The Epson Stylus Color/Photo printers don't have memory to print
684 * using all of the nozzles in the print head.  For example, the Stylus Photo
685 * 700/EX has 32 nozzles.  At 720 dpi, with an 8" wide image, a single line
686 * requires (8 * 720 * 6 / 8) bytes, or 4320 bytes (because the Stylus Photo
687 * printers have 6 ink colors).  To use 32 nozzles would require 138240 bytes.
688 * It's actually worse than that, though, because the nozzles are spaced 8
689 * rows apart.  Therefore, in order to store enough data to permit sending the
690 * page as a simple raster, the printer would require enough memory to store
691 * 256 rows, or 1105920 bytes.  Considering that the Photo EX can print
692 * 11" wide, we're looking at more like 1.5 MB.  In fact, these printers are
693 * capable of 1440 dpi horizontal resolution.  This would require 3 MB.  The
694 * printers actually have 64K-256K.
695 *
696 * With the newer (740/750 and later) printers it's even worse, since these
697 * printers support multiple dot sizes.  But that's neither here nor there.
698 *
699 * Older Epson printers had a mode called MicroWeave (tm).  In this mode, the
700 * host fed the printer individual rows of dots, and the printer bundled them
701 * up and sent them to the print head in the correct order to achieve high
702 * quality.  This MicroWeave mode still works in new printers, but the
703 * implementation is very minimal: the printer uses exactly one nozzle of
704 * each color (the first one).  This makes printing extremely slow (more than
705 * 30 minutes for one 8.5x11" page), although the quality is extremely high
706 * with no visible banding whatsoever.  It's not good for the print head,
707 * though, since no ink is flowing through the other nozzles.  This leads to
708 * drying of ink and possible permanent damage to the print head.
709 *
710 * By the way, although the Epson manual says that microweave mode should be
711 * used at 720 dpi, 360 dpi continues to work in much the same way.  At 360
712 * dpi, data is fed to the printer one row at a time on all Epson printers.
713 * The pattern that the printer uses to print is very prone to banding.
714 * However, 360 dpi is inherently a low quality mode; if you're using it,
715 * presumably you don't much care about quality.
716 *
717 * Printers from roughly the Stylus Color 600 and later do not have the
718 * capability to do MicroWeave correctly.  Instead, the host must arrange
719 * the output in the order that it will be sent to the print head.  This
720 * is a very complex process; the jets in the print head are spaced more
721 * than one row (1/720") apart, so we can't simply send consecutive rows
722 * of dots to the printer.  Instead, we have to pass e. g. the first, ninth,
723 * 17th, 25th... rows in order for them to print in the correct position on
724 * the paper.  This interleaving process is called "soft" weaving.
725 *
726 * This decision was probably made to save money on memory in the printer.
727 * It certainly makes the driver code far more complicated than it would
728 * be if the printer could arrange the output.  Is that a bad thing?
729 * Usually this takes far less CPU time than the dithering process, and it
730 * does allow us more control over the printing process, e. g. to reduce
731 * banding.  Conceivably, we could even use this ability to map out bad
732 * jets.
733 *
734 * Interestingly, apparently the Windows (and presumably Macintosh) drivers
735 * for most or all Epson printers still list a "microweave" mode.
736 * Experiments have demonstrated that this does not in fact use the
737 * "microweave" mode of the printer.  Possibly it does nothing, or it uses
738 * a different weave pattern from what the non-"microweave" mode does.
739 * This is unnecessarily confusing.
740 *
741 * What makes this interesting is that there are many different ways of
742 * of accomplishing this goal.  The naive way would be to divide the image
743 * up into groups of 256 rows, and print all the mod8=0 rows in the first pass,
744 * mod8=1 rows in the second, and so forth.  The problem with this approach
745 * is that the individual ink jets are not perfectly uniform; some emit
746 * slightly bigger or smaller drops than others.  Since each group of 8
747 * adjacent rows is printed with the same nozzle, that means that there will
748 * be distinct streaks of lighter and darker bands within the image (8 rows
749 * is 1/90", which is visible; 1/720" is not).  Possibly worse is that these
750 * patterns will repeat every 256 rows.  This creates banding patterns that
751 * are about 1/3" wide.
752 *
753 * So we have to do something to break up this patterning.
754 *
755 * Epson does not publish the weaving algorithms that they use in their
756 * bundled drivers.  Indeed, their developer web site
757 * (http://www.ercipd.com/isv/edr_docs.htm) does not even describe how to
758 * do this weaving at all; it says that the only way to achieve 720 dpi
759 * is to use MicroWeave.  It does note (correctly) that 1440 dpi horizontal
760 * can only be achieved by the driver (i. e. in software).  The manual
761 * actually makes it fairly clear how to do this (it requires two passes
762 * with horizontal head movement between passes), and it is presumably
763 * possible to do this with MicroWeave.
764 *
765 * The information about how to do this is apparently available under NDA.
766 * It's actually easy enough to reverse engineer what's inside a print file
767 * with a simple Perl script.  There are presumably other printer commands
768 * that are not documented and may not be as easy to reverse engineer.
769 *
770 * I considered a few algorithms to perform the weave.  The first one I
771 * devised let me use only (jets - distance_between_jets + 1) nozzles, or
772 * 25.  This is OK in principle, but it's slower than using all nozzles.
773 * By playing around with it some more, I came up with an algorithm that
774 * lets me use all of the nozzles, except near the top and bottom of the
775 * page.
776 *
777 * This still produces some banding, though.  Even better quality can be
778 * achieved by using multiple nozzles on the same line.  How do we do this?
779 * In 1440x720 mode, we're printing two output lines at the same vertical
780 * position.  However, if we want four passes, we have to effectively print
781 * each line twice.  Actually doing this would increase the density, so
782 * what we do is print half the dots on each pass.  This produces near-perfect
783 * output, and it's far faster than using (pseudo) "MicroWeave".
784 *
785 * The current algorithm is not completely general.  The number of passes
786 * is limited to (nozzles / gap).  On the Photo EX class printers, that limits
787 * it to 4 -- 32 nozzles, an inter-nozzle gap of 8 lines.  Furthermore, there
788 * are a number of routines that are only coded up to 8 passes.  Fortunately,
789 * this is enough passes to get rid of most banding.  What's left is a very
790 * fine pattern that is sometimes described as "corduroy", since the pattern
791 * looks like that kind of fabric.
792 *
793 * Newer printers (those that support variable dot sizes, such as the 740,
794 * 1200, etc.) have an additional complication: when used in softweave mode,
795 * they operate at 360 dpi horizontal resolution.  This requires FOUR passes
796 * to achieve 1440x720 dpi.  Thus, to enable us to break up each row
797 * into separate sub-rows, we have to actually print each row eight times.
798 * Fortunately, all such printers have 48 nozzles and a gap of 6 rows,
799 * except for the high-speed 900, which uses 96 nozzles and a gap of 2 rows.
800 *
801 * I cannot let this entirely pass without commenting on the Stylus Color 440.
802 * This is a very low-end printer with 21 (!) nozzles and a separation of 8.
803 * The weave routine works correctly with single-pass printing, which is enough
804 * to minimally achieve 720 dpi output (it's physically a 720 dpi printer).
805 * However, the routine does not work correctly at more than one pass per row.
806 * Therefore, this printer bands badly.
807 *
808 * Yet another complication is how to get near the top and bottom of the page.
809 * This algorithm lets us print to within one head width of the top of the
810 * page, and a bit more than one head width from the bottom.  That leaves a
811 * lot of blank space.  Doing the weave properly outside of this region is
812 * increasingly difficult as we get closer to the edge of the paper; in the
813 * interior region, any nozzle can print any line, but near the top and
814 * bottom edges, only some nozzles can print.  We've handled this for now by
815 * using the naive way mentioned above near the borders, and switching over
816 * to the high quality method in the interior.  Unfortunately, this means
817 * that the quality is quite visibly degraded near the top and bottom of the
818 * page.  Algorithms that degrade more gracefully are more complicated.
819 * Epson does not advertise that the printers can print at the very top of the
820 * page, although in practice most or all of them can.  I suspect that the
821 * quality that can be achieved very close to the top is poor enough that
822 * Epson does not want to allow printing there.  That is a valid decision,
823 * although we have taken another approach.
824 *
825 * To compute the weave information, we need to start with the following
826 * information:
827 *
828 * 1) The number of jets the print head has for each color;
829 *
830 * 2) The separation in rows between the jets;
831 *
832 * 3) The horizontal resolution of the printer;
833 *
834 * 4) The desired horizontal resolution of the output;
835 *
836 * 5) The desired extra passes to reduce banding.
837 *
838 * As discussed above, each row is actually printed in one or more passes
839 * of the print head; we refer to these as subpasses.  For example, if we're
840 * printing at 1440(h)x720(v) on a printer with true horizontal resolution of
841 * 360 dpi, and we wish to print each line twice with different nozzles
842 * to reduce banding, we need to use 8 subpasses.  The dither routine
843 * will feed us a complete row of bits for each color; we have to split that
844 * up, first by round robining the bits to ensure that they get printed at
845 * the right micro-position, and then to split up the bits that are actually
846 * turned on into two equal chunks to reduce banding.
847 *
848 * Given the above information, and the desired row index and subpass (which
849 * together form a line number), we can compute:
850 *
851 * 1) Which pass this line belongs to.  Passes are numbered consecutively,
852 *    and each pass must logically (see #3 below) start at no smaller a row
853 *    number than the previous pass, as the printer cannot advance by a
854 *    negative amount.
855 *
856 * 2) Which jet will print this line.
857 *
858 * 3) The "logical" first line of this pass.  That is, what line would be
859 *    printed by jet 0 in this pass.  This number may be less than zero.
860 *    If it is, there are ghost lines that don't actually contain any data.
861 *    The difference between the logical first line of this pass and the
862 *    logical first line of the preceding pass tells us how many lines must
863 *    be advanced.
864 *
865 * 4) The "physical" first line of this pass.  That is, the first line index
866 *    that is actually printed in this pass.  This information lets us know
867 *    when we must prepare this pass.
868 *
869 * 5) The last line of this pass.  This lets us know when we must actually
870 *    send this pass to the printer.
871 *
872 * 6) The number of ghost rows this pass contains.  We must still send the
873 *    ghost data to the printer, so this lets us know how much data we must
874 *    fill in prior to the start of the pass.
875 *
876 * The bookkeeping to keep track of all this stuff is quite hairy, and needs
877 * to be documented separately.
878 *
879 * The routine initialize_weave calculates the basic parameters, given
880 * the number of jets and separation between jets, in rows.
881 *
882 * -- Robert Krawitz <rlk@alum.mit.edu) November 3, 1999
883 */
884
885static stp_lineoff_t *
886allocate_lineoff(int count, int ncolors)
887{
888  int i;
889  stp_lineoff_t *retval = stp_malloc(count * sizeof(stp_lineoff_t));
890  for (i = 0; i < count; i++)
891    {
892      retval[i].ncolors = ncolors;
893      retval[i].v = stp_zalloc(ncolors * sizeof(unsigned long));
894    }
895  return (retval);
896}
897
898static stp_lineactive_t *
899allocate_lineactive(int count, int ncolors)
900{
901  int i;
902  stp_lineactive_t *retval = stp_malloc(count * sizeof(stp_lineactive_t));
903  for (i = 0; i < count; i++)
904    {
905      retval[i].ncolors = ncolors;
906      retval[i].v = stp_zalloc(ncolors * sizeof(char));
907    }
908  return (retval);
909}
910
911static stp_linecount_t *
912allocate_linecount(int count, int ncolors)
913{
914  int i;
915  stp_linecount_t *retval = stp_malloc(count * sizeof(stp_linecount_t));
916  for (i = 0; i < count; i++)
917    {
918      retval[i].ncolors = ncolors;
919      retval[i].v = stp_zalloc(ncolors * sizeof(int));
920    }
921  return (retval);
922}
923
924static stp_linebounds_t *
925allocate_linebounds(int count, int ncolors)
926{
927  int i;
928  stp_linebounds_t *retval = stp_malloc(count * sizeof(stp_linebounds_t));
929  for (i = 0; i < count; i++)
930    {
931      retval[i].ncolors = ncolors;
932      retval[i].start_pos = stp_zalloc(ncolors * sizeof(int));
933      retval[i].end_pos = stp_zalloc(ncolors * sizeof(int));
934    }
935  return (retval);
936}
937
938static stp_linebufs_t *
939allocate_linebuf(int count, int ncolors)
940{
941  int i;
942  stp_linebufs_t *retval = stp_malloc(count * sizeof(stp_linebufs_t));
943  for (i = 0; i < count; i++)
944    {
945      retval[i].ncolors = ncolors;
946      retval[i].v = stp_zalloc(ncolors * sizeof(unsigned char *));
947    }
948  return (retval);
949}
950
951/*
952 * Initialize the weave parameters
953 *
954 * Rules:
955 *
956 * 1) Currently, osample * v_subpasses * v_subsample <= 8, and no one
957 *    of these variables may exceed 4.
958 *
959 * 2) first_line >= 0
960 *
961 * 3) line_height < physlines
962 *
963 * 4) page_height >= 2 * jets * sep
964 */
965
966static void
967stpi_destroy_weave(void *vsw)
968{
969  int i, j;
970  stpi_softweave_t *sw = (stpi_softweave_t *) vsw;
971  stp_free(sw->passes);
972  if (sw->fold_buf)
973    stp_free(sw->fold_buf);
974  if (sw->comp_buf)
975    stp_free(sw->comp_buf);
976  for (i = 0; i < STP_MAX_WEAVE; i++)
977    if (sw->s[i])
978      stp_free(sw->s[i]);
979  for (i = 0; i < sw->vmod; i++)
980    {
981      for (j = 0; j < sw->ncolors; j++)
982	{
983	  if (sw->linebases[i].v[j])
984	    stp_free(sw->linebases[i].v[j]);
985	}
986      stp_free(sw->linecounts[i].v);
987      stp_free(sw->linebases[i].v);
988      stp_free(sw->lineactive[i].v);
989      stp_free(sw->lineoffsets[i].v);
990      stp_free(sw->linebounds[i].start_pos);
991      stp_free(sw->linebounds[i].end_pos);
992    }
993  stp_free(sw->linecounts);
994  stp_free(sw->lineactive);
995  stp_free(sw->lineoffsets);
996  stp_free(sw->linebases);
997  stp_free(sw->linebounds);
998  stp_free(sw->head_offset);
999  stpi_destroy_weave_params(sw->weaveparm);
1000  stp_free(vsw);
1001}
1002
1003void
1004stp_initialize_weave(stp_vars_t *v,
1005		     int jets,	/* Width of print head */
1006		     int sep,	/* Separation in rows between jets */
1007		     int osample,	/* Horizontal oversample */
1008		     int v_subpasses, /* Vertical passes */
1009		     int v_subsample, /* Vertical oversampling */
1010		     int ncolors,
1011		     int bitwidth,	/* bits/pixel */
1012		     int linewidth,	/* Width of a line, in pixels */
1013		     int line_count, /* Lines that will be printed */
1014		     int first_line, /* First line that will be printed */
1015		     int page_height, /* Total height of the page in rows */
1016		     const int *head_offset,
1017		     stp_weave_strategy_t weave_strategy,
1018		     stp_flushfunc flushfunc,
1019		     stp_fillfunc fillfunc,
1020		     stp_packfunc pack,
1021		     stp_compute_linewidth_func compute_linewidth)
1022{
1023  int i;
1024  int last_line, maxHeadOffset;
1025  stpi_softweave_t *sw = stp_zalloc(sizeof (stpi_softweave_t));
1026
1027  if (jets < 1)
1028    jets = 1;
1029  if (jets == 1 || sep < 1)
1030    sep = 1;
1031  if (v_subpasses < 1)
1032    v_subpasses = 1;
1033  if (v_subsample < 1)
1034    v_subsample = 1;
1035
1036  sw->separation = sep;
1037  sw->jets = jets;
1038  sw->horizontal_weave = osample;
1039  sw->oversample = osample * v_subpasses * v_subsample;
1040  if (sw->oversample > jets)
1041    {
1042      int found = 0;
1043      for (i = 2; i <= osample; i++)
1044	{
1045	  if ((osample % i == 0) && (sw->oversample / i <= jets))
1046	    {
1047	      sw->repeat_count = i;
1048	      osample /= i;
1049	      found = 1;
1050	      break;
1051	    }
1052	}
1053      if (!found)
1054	{
1055	  stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
1056		      sw->oversample, jets);
1057	  stp_free(sw);
1058	  return;
1059	}
1060    }
1061  else
1062    sw->repeat_count = 1;
1063
1064  sw->vertical_oversample = v_subsample;
1065  sw->vertical_subpasses = v_subpasses;
1066  sw->oversample = osample * v_subpasses * v_subsample;
1067  sw->firstline = first_line;
1068  sw->lineno = first_line;
1069  sw->flushfunc = flushfunc;
1070
1071  if (sw->oversample > jets)
1072    {
1073      stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
1074		  sw->oversample, jets);
1075      stp_free(sw);
1076      return;
1077    }
1078
1079  /*
1080   * setup printhead offsets.
1081   * for monochrome (bw) printing, the offsets are 0.
1082   */
1083  sw->head_offset = stp_zalloc(ncolors * sizeof(int));
1084  if (ncolors > 1)
1085    for(i = 0; i < ncolors; i++)
1086      sw->head_offset[i] = head_offset[i];
1087
1088  maxHeadOffset = 0;
1089  for (i = 0; i < ncolors; i++)
1090    if (sw->head_offset[i] > maxHeadOffset)
1091      maxHeadOffset = sw->head_offset[i];
1092
1093  sw->virtual_jets = sw->jets;
1094  if (maxHeadOffset > 0)
1095    sw->virtual_jets += (maxHeadOffset + sw->separation - 1) / sw->separation;
1096  last_line = first_line + line_count - 1 + maxHeadOffset;
1097
1098  sw->weaveparm = initialize_weave_params(sw->separation, sw->jets,
1099                                          sw->oversample, first_line, last_line,
1100                                          page_height, weave_strategy, v);
1101  /*
1102   * The value of vmod limits how many passes may be unfinished at a time.
1103   * If pass x is not yet printed, pass x+vmod cannot be started.
1104   *
1105   * The multiplier of 2: 1 for the normal passes, 1 for the special passes
1106   * at the start or end.
1107   */
1108  sw->vmod = 2 * sw->separation * sw->oversample * sw->repeat_count;
1109  if (sw->virtual_jets > sw->jets)
1110    sw->vmod *= (sw->virtual_jets + sw->jets - 1) / sw->jets;
1111
1112  sw->bitwidth = bitwidth;
1113  sw->last_pass_offset = 0;
1114  sw->last_pass = -1;
1115  sw->current_vertical_subpass = 0;
1116  sw->ncolors = ncolors;
1117  sw->linewidth = linewidth;
1118  sw->vertical_height = line_count;
1119  sw->lineoffsets = allocate_lineoff(sw->vmod, ncolors);
1120  sw->lineactive = allocate_lineactive(sw->vmod, ncolors);
1121  sw->linebases = allocate_linebuf(sw->vmod, ncolors);
1122  sw->linebounds = allocate_linebounds(sw->vmod, ncolors);
1123  sw->passes = stp_zalloc(sw->vmod * sizeof(stp_pass_t));
1124  sw->linecounts = allocate_linecount(sw->vmod, ncolors);
1125  sw->rcache = -2;
1126  sw->vcache = -2;
1127  sw->fillfunc = fillfunc;
1128  sw->compute_linewidth = compute_linewidth;
1129  sw->pack = pack;
1130  sw->horizontal_width =
1131    (sw->compute_linewidth)(v, ((sw->linewidth + sw->horizontal_weave - 1) /
1132				 sw->horizontal_weave));
1133  stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1134	      "Computing linewidth for linewidth %d weave %d => %d (%d)\n",
1135	      sw->linewidth, sw->horizontal_weave, sw->horizontal_width,
1136	      ((sw->horizontal_width + 7) / 8));
1137  sw->horizontal_width = ((sw->horizontal_width + 7) / 8);
1138
1139  for (i = 0; i < sw->vmod; i++)
1140    {
1141      int j;
1142      sw->passes[i].pass = -1;
1143      for (j = 0; j < sw->ncolors; j++)
1144	{
1145	  sw->linebases[i].v[j] = NULL;
1146	}
1147    }
1148  stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1149	      "Weave parameters: separation %d jets %d (%d) h %d v %d v_sub %d\n",
1150	      sw->separation, sw->jets, sw->virtual_jets, osample,
1151	      v_subpasses, v_subsample);
1152  stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1153	      "      ncolors %d bpp %d width %d (%d) line_count %d first %d last %d max_offset %d\n",
1154	      sw->ncolors, sw->bitwidth, linewidth, sw->horizontal_width,
1155	      sw->vertical_height, first_line, last_line, maxHeadOffset);
1156  stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1157	      "      oversample %d line buffer count %d total buffer %d, page_height %d\n",
1158	      sw->oversample, sw->vmod,
1159	      sw->vmod * sw->virtual_jets * sw->bitwidth *
1160	      sw->ncolors * sw->horizontal_width, page_height);
1161  stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1162	      "      ***Buffer limit %d (vj %d bw %d hw %d)\n",
1163	      sw->virtual_jets * sw->bitwidth * sw->horizontal_width,
1164	      sw->virtual_jets, sw->bitwidth, sw->horizontal_width);
1165  stp_allocate_component_data(v, "Weave", NULL, stpi_destroy_weave, sw);
1166  return;
1167}
1168
1169static void
1170weave_parameters_by_row(const stp_vars_t *v, stpi_softweave_t *sw,
1171			int row, int vertical_subpass, stp_weave_t *w)
1172{
1173  int jetsused;
1174  int sub_repeat_count = vertical_subpass % sw->repeat_count;
1175  /*
1176   * Conceptually, this does not modify the softweave state.  We cache
1177   * the results, but this cache is considered hidden.
1178   */
1179  vertical_subpass /= sw->repeat_count;
1180
1181  if (sw->rcache == row && sw->vcache == vertical_subpass)
1182    {
1183      memcpy(w, &sw->wcache, sizeof(stp_weave_t));
1184      w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
1185      return;
1186    }
1187  sw->rcache = row;
1188  sw->vcache = vertical_subpass;
1189
1190  w->row = row;
1191  stpi_calculate_row_parameters(sw->weaveparm, row, vertical_subpass,
1192				&w->pass, &w->jet, &w->logicalpassstart,
1193				&w->missingstartrows, &jetsused);
1194
1195  w->physpassstart = w->logicalpassstart + sw->separation * w->missingstartrows;
1196  w->physpassend = w->physpassstart + sw->separation * (jetsused - 1);
1197
1198  memcpy(&(sw->wcache), w, sizeof(stp_weave_t));
1199  w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
1200  stp_dprintf(STP_DBG_ROWS, v, "row %d, jet %d of pass %d "
1201	      "(pos %d, start %d, end %d, missing rows %d)\n",
1202	      w->row, w->jet, w->pass, w->logicalpassstart, w->physpassstart,
1203	      w->physpassend, w->missingstartrows);
1204}
1205
1206static stpi_softweave_t *
1207get_sw(const stp_vars_t *v)
1208{
1209  return (stpi_softweave_t *) stp_get_component_data(v, "Weave");
1210}
1211
1212void
1213stp_weave_parameters_by_row(const stp_vars_t *v, int row,
1214			    int vertical_subpass, stp_weave_t *w)
1215{
1216  stpi_softweave_t *sw = get_sw(v);
1217  weave_parameters_by_row(v, sw, row, vertical_subpass, w);
1218}
1219
1220
1221static stp_lineoff_t *
1222stpi_get_lineoffsets(const stp_vars_t *v, stpi_softweave_t *sw,
1223		     int row, int subpass, int offset)
1224{
1225  stp_weave_t w;
1226  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1227  return &(sw->lineoffsets[w.pass % sw->vmod]);
1228}
1229
1230static stp_lineactive_t *
1231stpi_get_lineactive(const stp_vars_t *v, stpi_softweave_t *sw,
1232		    int row, int subpass, int offset)
1233{
1234  stp_weave_t w;
1235  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1236  return &(sw->lineactive[w.pass % sw->vmod]);
1237}
1238
1239static stp_linecount_t *
1240stpi_get_linecount(const stp_vars_t *v, stpi_softweave_t *sw,
1241		   int row, int subpass, int offset)
1242{
1243  stp_weave_t w;
1244  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1245  return &(sw->linecounts[w.pass % sw->vmod]);
1246}
1247
1248static stp_linebufs_t *
1249stpi_get_linebases(const stp_vars_t *v, stpi_softweave_t *sw,
1250		   int row, int subpass, int offset)
1251{
1252  stp_weave_t w;
1253  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1254  return &(sw->linebases[w.pass % sw->vmod]);
1255}
1256
1257static stp_linebounds_t *
1258stpi_get_linebounds(const stp_vars_t *v, stpi_softweave_t *sw,
1259		    int row, int subpass, int offset)
1260{
1261  stp_weave_t w;
1262  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1263  return &(sw->linebounds[w.pass % sw->vmod]);
1264}
1265
1266static stp_pass_t *
1267stpi_get_pass_by_row(stp_vars_t *v, stpi_softweave_t *sw,
1268		     int row, int subpass,int offset)
1269{
1270  stp_weave_t w;
1271  weave_parameters_by_row(v, sw, row + offset, subpass, &w);
1272  return &(sw->passes[w.pass % sw->vmod]);
1273}
1274
1275stp_lineoff_t *
1276stp_get_lineoffsets_by_pass(const stp_vars_t *v, int pass)
1277{
1278  const stpi_softweave_t *sw = get_sw(v);
1279  return &(sw->lineoffsets[pass % sw->vmod]);
1280}
1281
1282stp_lineactive_t *
1283stp_get_lineactive_by_pass(const stp_vars_t *v, int pass)
1284{
1285  const stpi_softweave_t *sw = get_sw(v);
1286  return &(sw->lineactive[pass % sw->vmod]);
1287}
1288
1289stp_linecount_t *
1290stp_get_linecount_by_pass(const stp_vars_t *v, int pass)
1291{
1292  const stpi_softweave_t *sw = get_sw(v);
1293  return &(sw->linecounts[pass % sw->vmod]);
1294}
1295
1296const stp_linebufs_t *
1297stp_get_linebases_by_pass(const stp_vars_t *v, int pass)
1298{
1299  const stpi_softweave_t *sw = get_sw(v);
1300  return &(sw->linebases[pass % sw->vmod]);
1301}
1302
1303stp_pass_t *
1304stp_get_pass_by_pass(const stp_vars_t *v, int pass)
1305{
1306  const stpi_softweave_t *sw = get_sw(v);
1307  return &(sw->passes[pass % sw->vmod]);
1308}
1309
1310static void
1311check_linebases(stp_vars_t *v, stpi_softweave_t *sw,
1312		int row, int cpass, int head_offset, int color)
1313{
1314  stp_linebufs_t *bufs =
1315    (stp_linebufs_t *) stpi_get_linebases(v, sw, row, cpass, head_offset);
1316  if (!(bufs->v[color]))
1317    bufs->v[color] =
1318      stp_zalloc (sw->virtual_jets * sw->bitwidth * sw->horizontal_width);
1319}
1320
1321/*
1322 * If there are phantom rows at the beginning of a pass, fill them in so
1323 * that the printer knows exactly what it doesn't have to print.  We're
1324 * using RLE compression here.  Each line must be specified independently,
1325 * so we have to compute how many full blocks (groups of 128 bytes, or 1024
1326 * "off" pixels) and how much leftover is needed.  Note that we can only
1327 * RLE-encode groups of 2 or more bytes; single bytes must be specified
1328 * with a count of 1.
1329 */
1330
1331void
1332stp_fill_tiff(stp_vars_t *v, int row, int subpass,
1333	      int width, int missingstartrows, int color)
1334{
1335  stpi_softweave_t *sw = get_sw(v);
1336  stp_lineoff_t *lineoffs;
1337  stp_linecount_t *linecount;
1338  const stp_linebufs_t *bufs;
1339  int i = 0;
1340  int k = 0;
1341
1342  width = sw->bitwidth * width * 8;
1343  for (k = 0; k < missingstartrows; k++)
1344    {
1345      int bytes_to_fill = width;
1346      int full_blocks = bytes_to_fill / (128 * 8);
1347      int leftover = (7 + (bytes_to_fill % (128 * 8))) / 8;
1348      int l = 0;
1349      bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
1350
1351      while (l < full_blocks)
1352	{
1353	  (bufs->v[color][2 * i]) = 129;
1354	  (bufs->v[color][2 * i + 1]) = 0;
1355	  i++;
1356	  l++;
1357	}
1358      if (leftover == 1)
1359	{
1360	  (bufs->v[color][2 * i]) = 1;
1361	  (bufs->v[color][2 * i + 1]) = 0;
1362	  i++;
1363	}
1364      else if (leftover > 0)
1365	{
1366	  (bufs->v[color][2 * i]) = 257 - leftover;
1367	  (bufs->v[color][2 * i + 1]) = 0;
1368	  i++;
1369	}
1370    }
1371
1372  lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
1373  linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
1374  lineoffs->v[color] = 2 * i;
1375  linecount->v[color] = missingstartrows;
1376}
1377
1378void
1379stp_fill_uncompressed(stp_vars_t *v, int row, int subpass,
1380		      int width, int missingstartrows, int color)
1381{
1382  stpi_softweave_t *sw = get_sw(v);
1383  stp_lineoff_t *lineoffs;
1384  stp_linecount_t *linecount;
1385  const stp_linebufs_t *bufs;
1386
1387  bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
1388  lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
1389  linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
1390  width *= sw->bitwidth * missingstartrows;
1391  memset(bufs->v[color], 0, width);
1392  lineoffs->v[color] = width;
1393  linecount->v[color] = missingstartrows;
1394}
1395
1396int
1397stp_compute_tiff_linewidth(stp_vars_t *v, int n)
1398{
1399  /*
1400   * It's possible for the "compression" to actually expand the line by
1401   * roughly one part in 128.
1402   */
1403  return ((n + 128 + 7) * 129 / 128);
1404}
1405
1406int
1407stp_compute_uncompressed_linewidth(stp_vars_t *v, int n)
1408{
1409  return (8 * ((n + 7) / 8));
1410}
1411
1412static void
1413initialize_row(stp_vars_t *v, stpi_softweave_t *sw,
1414	       int row, int width, unsigned char *const cols[])
1415{
1416  stp_weave_t w;
1417  int i, j, jj;
1418  stp_pass_t *pass;
1419
1420  for (i = 0; i < sw->oversample; i++)
1421    {
1422      for (j = 0; j < sw->ncolors; j++)
1423	{
1424	  if (cols[j])
1425	    {
1426	      stp_lineoff_t *lineoffs =
1427		stpi_get_lineoffsets(v, sw, row, i, sw->head_offset[j]);
1428	      stp_lineactive_t *lineactive =
1429		stpi_get_lineactive(v, sw, row, i, sw->head_offset[j]);
1430	      stp_linecount_t *linecount =
1431		stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
1432	      stp_linebounds_t *linebounds =
1433		stpi_get_linebounds(v, sw, row, i, sw->head_offset[j]);
1434	      check_linebases(v, sw, row, i, sw->head_offset[j], j);
1435	      weave_parameters_by_row(v, sw, row+sw->head_offset[j], i, &w);
1436	      pass = stpi_get_pass_by_row(v, sw, row, i, sw->head_offset[j]);
1437
1438	      /* initialize pass if not initialized yet */
1439	      if (pass->pass < 0)
1440		{
1441		  pass->pass = w.pass;
1442		  pass->missingstartrows = w.missingstartrows;
1443		  pass->logicalpassstart = w.logicalpassstart;
1444		  pass->physpassstart = w.physpassstart;
1445		  pass->physpassend = w.physpassend;
1446		  pass->subpass = i;
1447
1448		  for(jj=0; jj<sw->ncolors; jj++)
1449		    {
1450		      if (lineoffs->v[jj] != 0)
1451			stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
1452				    "lineoffs %ld should be zero!\n",
1453				    w.pass, i, row, lineoffs->v[jj]);
1454		      lineoffs->v[jj] = 0;
1455		      lineactive->v[jj] = 0;
1456		      if (linecount->v[jj] != 0)
1457			stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
1458				    "linecount %d should be zero!\n",
1459				    w.pass, i, row, linecount->v[jj]);
1460		      linecount->v[jj] = 0;
1461		      linebounds->start_pos[jj] = INT_MAX;
1462		      linebounds->end_pos[jj] = -1;
1463		    }
1464		}
1465
1466	      if((linecount->v[j] == 0) && (w.jet > 0))
1467		{
1468		  (sw->fillfunc)(v, row, i, width, w.jet, j);
1469		}
1470	    }
1471	}
1472    }
1473}
1474
1475static void
1476add_to_row(stp_vars_t *v, stpi_softweave_t *sw, int row, unsigned char *buf,
1477	   size_t nbytes, int color, int setactive, int h_pass)
1478{
1479  const stp_linebufs_t *bufs =
1480    stpi_get_linebases(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
1481  stp_lineoff_t *lineoffs =
1482    stpi_get_lineoffsets(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
1483  stp_lineactive_t *lineactive =
1484    stpi_get_lineactive(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
1485  stp_linecount_t *linecount =
1486    stpi_get_linecount(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
1487  size_t place = lineoffs->v[color];
1488  size_t count = linecount->v[color];
1489  if (place + nbytes > sw->virtual_jets * sw->bitwidth * sw->horizontal_width)
1490    {
1491      int i;
1492      stp_eprintf(v, "ERROR: %s\n", _("Fatal error!"));
1493      stp_eprintf(v, "ERROR: Static weave data follows:\n");
1494      stp_eprintf(v, "ERROR:    jets: %d\n", sw->jets);
1495      stp_eprintf(v, "ERROR:    virtual_jets: %d\n", sw->virtual_jets);
1496      stp_eprintf(v, "ERROR:    separation: %d\n", sw->separation);
1497      stp_eprintf(v, "ERROR:    horizontal_weave: %d\n", sw->horizontal_weave);
1498      stp_eprintf(v, "ERROR:    vertical_subpasses: %d\n", sw->vertical_subpasses);
1499      stp_eprintf(v, "ERROR:    vmod: %d\n", sw->vmod);
1500      stp_eprintf(v, "ERROR:    oversample: %d\n", sw->oversample);
1501      stp_eprintf(v, "ERROR:    repeat_count: %d\n", sw->repeat_count);
1502      stp_eprintf(v, "ERROR:    ncolors: %d\n", sw->ncolors);
1503      stp_eprintf(v, "ERROR:    linewidth: %d\n", sw->linewidth);
1504      stp_eprintf(v, "ERROR:    vertical_height: %d\n", sw->vertical_height);
1505      stp_eprintf(v, "ERROR:    firstline: %d\n", sw->firstline);
1506      stp_eprintf(v, "ERROR:    bitwidth: %d\n", sw->bitwidth);
1507      stp_eprintf(v, "ERROR:    vertical_oversample: %d\n", sw->vertical_oversample);
1508      stp_eprintf(v, "ERROR:    horizontal_width: %d\n", sw->horizontal_width);
1509      if (sw->head_offset)
1510	{
1511	  stp_eprintf(v, "ERROR:    head_offset:\n");
1512	  for (i = 0; i < sw->ncolors; i++)
1513	    stp_eprintf(v, "ERROR:      head %d: %d\n", i, sw->head_offset[i]);
1514	}
1515      stp_eprintf(v, "ERROR: Dynamic weave data follows:\n");
1516      stp_eprintf(v, "ERROR:    last_pass_offset: %d\n", sw->last_pass_offset);
1517      stp_eprintf(v, "ERROR:    last_pass: %d\n", sw->last_pass);
1518      stp_eprintf(v, "ERROR:    lineno: %d\n", sw->lineno);
1519      stp_eprintf(v, "ERROR:    current_vertical_subpass: %d\n", sw->current_vertical_subpass);
1520      stp_eprintf(v, "ERROR:    rcache: %d\n", sw->rcache);
1521      stp_eprintf(v, "ERROR:    vcache: %d\n", sw->vcache);
1522      stp_eprintf(v, "ERROR: Other parameters: row %d color %d setactive %d hpass %d\n",
1523		  row, color, setactive, h_pass);
1524      stp_eprintf(v, "ERROR: Buffer overflow: limit %d (jets %d bits %d horizontal %d), actual %ld (current %d added %d), count %ld\n",
1525		  sw->virtual_jets * sw->bitwidth * sw->horizontal_width,
1526		  sw->virtual_jets, sw->bitwidth, sw->horizontal_width,
1527		  (long) (place + nbytes), (int) place, (int) nbytes, (long) count);
1528      stp_eprintf(v, "ERROR: %s\n", _("Please report the above information to gimp-print-devel@lists.sourceforge.net"));
1529      stp_abort();
1530    }
1531  memcpy(bufs->v[color] + lineoffs->v[color], buf, nbytes);
1532  lineoffs->v[color] += nbytes;
1533  if (setactive)
1534    lineactive->v[color] = 1;
1535}
1536
1537static void
1538stpi_flush_passes(stp_vars_t *v, int flushall)
1539{
1540  stpi_softweave_t *sw = get_sw(v);
1541  while (1)
1542    {
1543      stp_pass_t *pass = stp_get_pass_by_pass(v, sw->last_pass + 1);
1544      /*
1545       * This ought to be   pass->physpassend >  sw->lineno
1546       * but that causes rubbish to be output for some reason.
1547       */
1548      if (pass->pass < 0 || (!flushall && pass->physpassend >= sw->lineno))
1549	return;
1550      (sw->flushfunc)(v, pass->pass, pass->subpass);
1551      sw->last_pass = pass->pass;
1552      pass->pass = -1;
1553    }
1554}
1555
1556void
1557stp_flush_all(stp_vars_t *v)
1558{
1559  stpi_flush_passes(v, 1);
1560}
1561
1562static void
1563finalize_row(stp_vars_t *v, int row)
1564{
1565  stpi_softweave_t *sw = get_sw(v);
1566  int i,j;
1567  stp_dprintf(STP_DBG_ROWS, v, "Finalizing row %d...\n", row);
1568  for (i = 0; i < sw->oversample; i++)
1569    {
1570      stp_weave_t w;
1571      stp_linecount_t *lines;
1572
1573      for(j=0; j<sw->ncolors; j++)
1574        {
1575	  lines = stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
1576	  lines->v[j]++;
1577        }
1578
1579      weave_parameters_by_row(v, sw, row, i, &w);
1580      if (w.physpassend == row)
1581	{
1582	  stp_dprintf(STP_DBG_ROWS, v,
1583		      "Pass=%d, physpassend=%d, row=%d, lineno=%d, flush..\n",
1584		      w.pass, w.physpassend, row, sw->lineno);
1585	  stpi_flush_passes(v, 0);
1586	}
1587    }
1588}
1589
1590void
1591stp_write_weave(stp_vars_t *v, unsigned char *const cols[])
1592{
1593  stpi_softweave_t *sw = get_sw(v);
1594  int length = (sw->linewidth + 7) / 8;
1595  stp_lineoff_t *lineoffs[STP_MAX_WEAVE];
1596  stp_lineactive_t *lineactives[STP_MAX_WEAVE];
1597  stp_linecount_t *linecounts[STP_MAX_WEAVE];
1598  stp_linebounds_t *linebounds[STP_MAX_WEAVE];
1599  const stp_linebufs_t *bufs[STP_MAX_WEAVE];
1600  int xlength = (length + sw->horizontal_weave - 1) / sw->horizontal_weave;
1601  int ylength = xlength * sw->horizontal_weave;
1602  unsigned char *comp_ptr;
1603  int i, j;
1604  int setactive;
1605  int h_passes = sw->horizontal_weave * sw->vertical_subpasses;
1606  int cpass = sw->current_vertical_subpass * h_passes;
1607
1608  if (!sw->fold_buf)
1609    {
1610      stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1611		  "fold buffer allocation: length %d lw %d weave %d xlength %d ylength %d\n",
1612		  length, sw->linewidth, sw->horizontal_weave, xlength, ylength);
1613      stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1614		  "Allocating fold buf %d * %d (%d)\n", ylength, sw->bitwidth,
1615		  sw->bitwidth * ylength);
1616      sw->fold_buf = stp_zalloc(sw->bitwidth * ylength);
1617    }
1618  if (!sw->comp_buf)
1619    {
1620      stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
1621		  "Allocating compression buffer based on %d, %d\n",
1622		  sw->bitwidth, ylength);
1623      sw->comp_buf = stp_zalloc(sw->bitwidth *
1624				(sw->compute_linewidth)(v,ylength));
1625    }
1626  if (sw->current_vertical_subpass == 0)
1627    initialize_row(v, sw, sw->lineno, xlength, cols);
1628
1629  for (j = 0; j < sw->ncolors; j++)
1630    {
1631      if (cols[j])
1632	{
1633	  const unsigned char *in;
1634	  int idx;
1635
1636	  for (i = 0; i < h_passes; i++)
1637	    {
1638	      int offset = sw->head_offset[j];
1639	      int pass = cpass + i;
1640	      if (!sw->s[i])
1641		sw->s[i] = stp_zalloc(sw->bitwidth *
1642				      (sw->compute_linewidth)(v, ylength));
1643	      lineoffs[i] =
1644		stpi_get_lineoffsets(v, sw, sw->lineno, pass, offset);
1645	      linecounts[i] =
1646		stpi_get_linecount(v, sw, sw->lineno, pass, offset);
1647	      lineactives[i] =
1648		stpi_get_lineactive(v, sw, sw->lineno, pass,offset);
1649	      linebounds[i] =
1650		stpi_get_linebounds(v, sw, sw->lineno, pass, offset);
1651	      bufs[i] =
1652		stpi_get_linebases(v, sw, sw->lineno, pass, offset);
1653	    }
1654
1655	  if (sw->bitwidth == 2)
1656	    {
1657	      stp_fold(cols[j], length, sw->fold_buf);
1658	      in = sw->fold_buf;
1659	    }
1660	  else
1661	    in = cols[j];
1662	  if (sw->horizontal_weave == 1)
1663	    memcpy(sw->s[0], in, length * sw->bitwidth);
1664	  else
1665	    stp_unpack(length, sw->bitwidth, sw->horizontal_weave, in, sw->s);
1666	  if (sw->vertical_subpasses > 1)
1667	    {
1668	      for (idx = 0; idx < sw->horizontal_weave; idx++)
1669		stp_split(length, sw->bitwidth, sw->vertical_subpasses,
1670			  sw->s[idx], sw->horizontal_weave, &(sw->s[idx]));
1671	    }
1672	  for (i = 0; i < h_passes; i++)
1673	    {
1674	      int first, last;
1675	      setactive = (sw->pack)(v, sw->s[i], sw->bitwidth * xlength,
1676				     sw->comp_buf, &comp_ptr, &first, &last);
1677	      if (first < linebounds[i]->start_pos[j])
1678		linebounds[i]->start_pos[j] = first;
1679	      if (last > linebounds[i]->end_pos[j])
1680		linebounds[i]->end_pos[j] = last;
1681	      add_to_row(v, sw, sw->lineno, sw->comp_buf,
1682			 comp_ptr - sw->comp_buf, j, setactive, cpass + i);
1683	    }
1684	}
1685    }
1686  sw->current_vertical_subpass++;
1687  if (sw->current_vertical_subpass >= sw->vertical_oversample)
1688    {
1689      finalize_row(v, sw->lineno);
1690      sw->lineno++;
1691      sw->current_vertical_subpass = 0;
1692    }
1693}
1694
1695#if 0
1696#define TEST_RAW
1697#endif
1698#if 0
1699#define TEST_COOKED
1700#endif
1701#if 0
1702#define ACCUMULATE
1703#endif
1704
1705#if defined(TEST_RAW) || defined(TEST_COOKED)
1706#define TEST
1707#endif
1708
1709#ifdef TEST
1710#define MAXCOLLECT (1000)
1711#endif
1712
1713#ifdef TEST_COOKED
1714static void
1715calculate_pass_parameters(cooked_t *w,		/* I - weave parameters */
1716                          int pass,		/* I - pass number ( >= 0) */
1717                          int *startrow,	/* O - print head position */
1718                          int *subpass,		/* O - subpass number */
1719			  int *phantomrows,	/* O - missing rows */
1720			  int *jetsused)	/* O - jets used to print */
1721{
1722	int raw_pass = pass + w->first_premapped_pass;
1723	int stagger = 0;
1724	int extra;
1725
1726	if (raw_pass < w->first_normal_pass) {
1727		int i = 0;
1728		while (i + w->first_premapped_pass < w->first_normal_pass) {
1729			if (w->pass_premap[i] == pass) {
1730				raw_pass = i + w->first_premapped_pass;
1731				stagger = w->stagger_premap[i];
1732				break;
1733			}
1734			i++;
1735		}
1736	} else if (raw_pass >= w->first_postmapped_pass) {
1737		int i = 0;
1738		while (i + w->first_postmapped_pass < w->first_unused_pass) {
1739			if (w->pass_postmap[i] == pass) {
1740				raw_pass = i + w->first_postmapped_pass;
1741				stagger = w->stagger_postmap[i];
1742				break;
1743			}
1744			i++;
1745		}
1746	}
1747
1748	calculate_raw_pass_parameters(&w->rw, raw_pass, startrow, subpass);
1749	*startrow -= w->rw.separation * w->rw.jets;
1750	*jetsused = w->rw.jets;
1751	*phantomrows = 0;
1752
1753	*startrow += stagger * w->rw.separation;
1754	if (stagger < 0) {
1755		stagger = -stagger;
1756		*phantomrows += stagger;
1757	}
1758	*jetsused -= stagger;
1759
1760	extra = w->first_row_printed - (*startrow + w->rw.separation * *phantomrows);
1761	extra = (extra + w->rw.separation - 1) / w->rw.separation;
1762	if (extra > 0) {
1763		*jetsused -= extra;
1764		*phantomrows += extra;
1765	}
1766
1767	extra = *startrow + w->rw.separation * (*phantomrows + *jetsused - 1)
1768	          - w->last_row_printed;
1769	extra = (extra + w->rw.separation - 1) / w->rw.separation;
1770	if (extra > 0) {
1771		*jetsused -= extra;
1772	}
1773}
1774#endif /* TEST_COOKED */
1775
1776#ifdef TEST
1777
1778#ifdef ACCUMULATE
1779#define PUTCHAR(x) /* nothing */
1780#else
1781#define PUTCHAR(x) putchar(x)
1782#endif
1783
1784static void
1785plotpass(int startrow, int phantomjets, int jetsused, int totaljets,
1786         int separation, int subpass, int *collect, int *prints)
1787{
1788	int hpos, i;
1789
1790	for (hpos = 0; hpos < startrow; hpos++)
1791		PUTCHAR(' ');
1792
1793	for (i = 0; i < phantomjets; i++) {
1794		int j;
1795		PUTCHAR('X');
1796		hpos++;
1797		for (j = 1; j < separation; j++) {
1798			PUTCHAR(' ');
1799			hpos++;
1800		}
1801	}
1802
1803	for (; i < phantomjets + jetsused; i++) {
1804		if (i > phantomjets) {
1805			int j;
1806			for (j = 1; j < separation; j++) {
1807				PUTCHAR('-');
1808				hpos++;
1809			}
1810		}
1811		if (hpos < MAXCOLLECT) {
1812			if (collect[hpos] & 1 << subpass)
1813				PUTCHAR('^');
1814			else if (subpass < 10)
1815				PUTCHAR('0' + subpass);
1816			else
1817				PUTCHAR('A' + subpass - 10);
1818			collect[hpos] |= 1 << subpass;
1819			prints[hpos]++;
1820		} else {
1821			PUTCHAR('0' + subpass);
1822		}
1823		hpos++;
1824	}
1825
1826	while (i++ < totaljets) {
1827		int j;
1828		for (j = 1; j < separation; j++) {
1829			PUTCHAR(' ');
1830			hpos++;
1831		}
1832		PUTCHAR('X');
1833	}
1834#ifdef ACCUMULATE
1835	for (i=0; i<=MAXCOLLECT; i++) {
1836		if (collect[i] == 0)
1837			putchar(' ');
1838		else if (collect[i] < 10)
1839			putchar('0'+collect[i]);
1840		else
1841			putchar('A'+collect[i]-10);
1842	}
1843#endif
1844	putchar('\n');
1845}
1846#endif /* TEST */
1847
1848#ifdef TEST_COOKED
1849int
1850main(int ac, char *av[])
1851{
1852	int S         =ac>1 ? atoi(av[1]) : 4;
1853	int J         =ac>2 ? atoi(av[2]) : 12;
1854	int H         =ac>3 ? atoi(av[3]) : 1;
1855	int firstrow  =ac>4 ? atoi(av[4]) : 1;
1856	int lastrow   =ac>5 ? atoi(av[5]) : 100;
1857	int pageheight=ac>6 ? atoi(av[6]) : 1000;
1858	stp_weave_strategy_t strategy  =ac>7 ? atoi(av[7]) : 1;
1859	cooked_t *weave;
1860	int passes;
1861
1862	int pass, x;
1863	int collect[MAXCOLLECT];
1864	int prints[MAXCOLLECT];
1865
1866	memset(collect, 0, MAXCOLLECT*sizeof(int));
1867	memset(prints, 0, MAXCOLLECT*sizeof(int));
1868	printf("S=%d  J=%d  H=%d  firstrow=%d  lastrow=%d  "
1869	       "pageheight=%d  strategy=%d\n",
1870	       S, J, H, firstrow, lastrow, pageheight, strategy);
1871
1872	weave = initialize_weave_params(S, J, H, firstrow, lastrow,
1873	                                pageheight, strategy);
1874	passes = weave->first_unused_pass - weave->first_premapped_pass;
1875
1876	for (pass = 0; pass < passes; pass++) {
1877		int startrow, subpass, phantomjets, jetsused;
1878
1879		calculate_pass_parameters(weave, pass, &startrow, &subpass,
1880		                          &phantomjets, &jetsused);
1881
1882		plotpass(startrow, phantomjets, jetsused, J, S, subpass,
1883		         collect, prints);
1884	}
1885
1886	for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
1887		;
1888
1889	for (x=0; x<=pass; x++) {
1890		if (collect[x] < 10)
1891			putchar('0'+collect[x]);
1892		else
1893			putchar('A'+collect[x]-10);
1894	}
1895	putchar('\n');
1896
1897	for (x=0; x<=pass; x++) {
1898		if (prints[x] < 10)
1899			putchar('0'+prints[x]);
1900		else
1901			putchar('A'+prints[x]-10);
1902	}
1903	putchar('\n');
1904
1905	return 0;
1906}
1907#endif /* TEST_COOKED */
1908
1909#ifdef TEST_RAW
1910int
1911main(int ac, char *av[])
1912{
1913	int S     =ac>1 ? atoi(av[1]) : 4;
1914	int J     =ac>2 ? atoi(av[2]) : 12;
1915	int h_pos =ac>3 ? atoi(av[3]) : 1;
1916	int h_over=ac>4 ? atoi(av[4]) : 1;
1917	int v_over=ac>5 ? atoi(av[5]) : 1;
1918	int H = h_pos * h_over * v_over;
1919
1920	int pass, passes, x;
1921	int collect[MAXCOLLECT];
1922	int prints[MAXCOLLECT];
1923	raw_t raw;
1924
1925	memset(collect, 0, MAXCOLLECT*sizeof(int));
1926	memset(prints, 0, MAXCOLLECT*sizeof(int));
1927	printf("S=%d  J=%d  H=%d\n", S, J, H);
1928
1929	if (H > J) {
1930		printf("H > J, so this weave will not work!\n");
1931	}
1932	passes = S * H * 3;
1933
1934	initialize_raw_weave(&raw, S, J, H);
1935
1936	for (pass=0; pass<passes + S * H; pass++) {
1937		int startrow, subpass, phantomjets, jetsused;
1938
1939		calculate_raw_pass_parameters(&raw, pass, &startrow, &subpass);
1940		phantomjets = 0;
1941		jetsused = J;
1942
1943		plotpass(startrow, phantomjets, jetsused, J, S, subpass,
1944		         collect, prints);
1945	}
1946	for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
1947		;
1948
1949	for (x=0; x<=pass; x++) {
1950		if (collect[x] < 10)
1951			putchar('0'+collect[x]);
1952		else
1953			putchar('A'+collect[x]-10);
1954	}
1955	putchar('\n');
1956
1957	for (x=0; x<=pass; x++) {
1958		if (prints[x] < 10)
1959			putchar('0'+prints[x]);
1960		else
1961			putchar('A'+prints[x]-10);
1962	}
1963	putchar('\n');
1964
1965	printf("  A  first row given by pass lookup doesn't match row lookup\n"
1966	       "  B  jet out of range\n"
1967	       "  C  given jet number of pass doesn't print this row\n"
1968	       "  D  subpass given by reverse lookup doesn't match requested subpass\n");
1969
1970	for (x = S * J; x < S * J * 20; x++) {
1971		int h;
1972		for (h = 0; h < H; h++) {
1973			int pass, jet, start, first, subpass, z;
1974			int a=0, b=0, c=0, d=0;
1975			calculate_raw_row_parameters(&raw, x, h, &pass, &jet, &start);
1976			for (z=0; z < pass; z++) {
1977				putchar(' ');
1978			}
1979			printf("%d", jet);
1980			calculate_raw_pass_parameters(&raw, pass, &first, &subpass);
1981			if (first != start)
1982				a=1;
1983			if (jet < 0 || jet >= J)
1984				b=1;
1985			if (x != first + jet * S)
1986				c=1;
1987			if (subpass != h)
1988				d=1;
1989			if (a || b || c || d) {
1990				printf("    (");
1991				if (a) putchar('A');
1992				if (b) putchar('B');
1993				if (c) putchar('C');
1994				if (d) putchar('D');
1995				putchar(')');
1996				printf("\npass=%d first=%d start=%d jet=%d subpass=%d", pass, first, start, jet, subpass);
1997			}
1998			putchar('\n');
1999		}
2000		/* putchar('\n'); */
2001	}
2002
2003	return 0;
2004}
2005
2006#endif /* TEST_RAW */
2007