xref: /plan9/sys/src/cmd/gs/src/gxifast.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxifast.c,v 1.9 2003/08/18 21:21:57 dan Exp $ */
18 /* Fast monochrome image rendering */
19 #include "gx.h"
20 #include "memory_.h"
21 #include "gpcheck.h"
22 #include "gsbittab.h"
23 #include "gserrors.h"
24 #include "gxfixed.h"
25 #include "gxarith.h"
26 #include "gxmatrix.h"
27 #include "gsccolor.h"
28 #include "gspaint.h"
29 #include "gsutil.h"
30 #include "gxdevice.h"
31 #include "gxcmap.h"
32 #include "gxdcolor.h"
33 #include "gxistate.h"
34 #include "gxdevmem.h"
35 #include "gdevmem.h"		/* for mem_mono_device */
36 #include "gxcpath.h"
37 #include "gximage.h"
38 #include "gzht.h"
39 
40 /* Conditionally include statistics code. */
41 #ifdef DEBUG
42 #  define STATS
43 #endif
44 
45 /* ------ Strategy procedure ------ */
46 
47 /* Check the prototype. */
48 iclass_proc(gs_image_class_1_simple);
49 
50 /* Use special fast logic for portrait or landscape black-and-white images. */
51 private irender_proc(image_render_skip);
52 private irender_proc(image_render_simple);
53 private irender_proc(image_render_landscape);
54 irender_proc_t
gs_image_class_1_simple(gx_image_enum * penum)55 gs_image_class_1_simple(gx_image_enum * penum)
56 {
57     irender_proc_t rproc;
58     fixed ox = dda_current(penum->dda.pixel0.x);
59     fixed oy = dda_current(penum->dda.pixel0.y);
60 
61     if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
62 	return 0;
63     switch (penum->posture) {
64 	case image_portrait:
65 	    {			/* Use fast portrait algorithm. */
66 		long dev_width =
67 		    fixed2long_pixround(ox + penum->x_extent.x) -
68 		    fixed2long_pixround(ox);
69 
70 		if (dev_width != penum->rect.w) {
71 		    /*
72 		     * Add an extra align_bitmap_mod of padding so that
73 		     * we can align scaled rows with the device.
74 		     */
75 		    long line_size =
76 			bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;
77 
78 		    if (penum->adjust != 0 || line_size > max_uint)
79 			return 0;
80 		    /* Must buffer a scan line. */
81 		    penum->line_width = any_abs(dev_width);
82 		    penum->line_size = (uint) line_size;
83 		    penum->line = gs_alloc_bytes(penum->memory,
84 					    penum->line_size, "image line");
85 		    if (penum->line == 0) {
86 			gx_default_end_image(penum->dev,
87 					     (gx_image_enum_common_t *)penum,
88 					     false);
89 			return 0;
90 		    }
91 		}
92 		if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
93 			  penum->rect.w, dev_width);
94 		rproc = image_render_simple;
95 		break;
96 	    }
97 	case image_landscape:
98 	    {			/* Use fast landscape algorithm. */
99 		long dev_width =
100 		    fixed2long_pixround(oy + penum->x_extent.y) -
101 		    fixed2long_pixround(oy);
102 		long line_size =
103 		    (dev_width = any_abs(dev_width),
104 		     bitmap_raster(dev_width) * 8 +
105 		     ROUND_UP(dev_width, 8) * align_bitmap_mod);
106 
107 		if ((dev_width != penum->rect.w && penum->adjust != 0) ||
108 		    line_size > max_uint
109 		    )
110 		    return 0;
111 		/* Must buffer a group of 8N scan lines. */
112 		penum->line_width = dev_width;
113 		penum->line_size = (uint) line_size;
114 		penum->line = gs_alloc_bytes(penum->memory,
115 					     penum->line_size, "image line");
116 		if (penum->line == 0) {
117 		    gx_default_end_image(penum->dev,
118 					 (gx_image_enum_common_t *) penum,
119 					 false);
120 		    return 0;
121 		}
122 		penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
123 		if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
124 			  penum->rect.w, dev_width, line_size);
125 		rproc = image_render_landscape;
126 		/* Precompute values needed for rasterizing. */
127 		penum->dxy =
128 		    float2fixed(penum->matrix.xy +
129 				fixed2float(fixed_epsilon) / 2);
130 		break;
131 	    }
132 	default:
133 	    return 0;
134     }
135     /* Precompute values needed for rasterizing. */
136     penum->dxx =
137 	float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
138     /*
139      * We don't want to spread the samples, but we have to reset unpack_bps
140      * to prevent the buffer pointer from being incremented by 8 bytes per
141      * input byte.
142      */
143     penum->unpack = sample_unpack_copy;
144     penum->unpack_bps = 8;
145     if (penum->use_mask_color) {
146 	/*
147 	 * Set the masked color as 'no_color' to make it transparent
148 	 *  according to the mask color range and the decoding.
149 	 */
150 	penum->masked = true;
151 	if (penum->mask_color.values[0] == 1) {
152 	    /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */
153 	    set_nonclient_dev_color(penum->map[0].inverted ? &penum->icolor0 : &penum->icolor1,
154 			gx_no_color_index);
155 	} else if (penum->mask_color.values[1] == 0) {
156 	    /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */
157 	    set_nonclient_dev_color(penum->map[0].inverted ? &penum->icolor1 : &penum->icolor0,
158 			gx_no_color_index);
159 	} else {
160 	    /*
161 	     * The only other possible in-range value is v0 = 0, v1 = 1.
162 	     * The image is completely transparent!
163 	     */
164 	    rproc = image_render_skip;
165 	}
166 	penum->map[0].decoding = sd_none;
167     }
168     return rproc;
169 }
170 
171 /* ------ Rendering procedures ------ */
172 
173 #define DC_IS_NULL(pdc)\
174   (gx_dc_is_pure(pdc) && (pdc)->colors.pure == gx_no_color_index)
175 
176 /* Skip over a completely transparent image. */
177 private int
image_render_skip(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)178 image_render_skip(gx_image_enum * penum, const byte * buffer, int data_x,
179 		  uint w, int h, gx_device * dev)
180 {
181     return h;
182 }
183 
184 /*
185  * Scale (and possibly reverse) one scan line of a monobit image.
186  * This is used for both portrait and landscape image processing.
187  * We pass in an x offset (0 <= line_x < align_bitmap_mod * 8) so that
188  * we can align the result with the eventual device X.
189  *
190  * To be precise, the input to this routine is the w bits starting at
191  * bit data_x in buffer.  These w bits expand to abs(x_extent) bits,
192  * either inverted (zero = 0xff) or not (zero = 0), starting at bit
193  * line_x in line which corresponds to coordinate
194  * fixed2int_pixround(xcur + min(x_extent, 0)).  Note that the entire
195  * bytes containing the first and last output bits are affected: the
196  * other bits in those bytes are set to zero (i.e., the value of the
197  * 'zero' argument).
198  */
199 #ifdef STATS
200 struct stats_image_fast_s {
201     long
202          calls, all0s, all1s, runs, lbit0, byte00, byte01, byte02, byte03,
203          byte04, rbit0, lbit1, byte1, rbit1, thin, thin2, nwide, bwide,
204          nfill, bfill;
205 } stats_image_fast;
206 #  define INCS(stat) ++stats_image_fast.stat
207 #  define ADDS(stat, n) stats_image_fast.stat += n
208 #else
209 #  define INCS(stat) DO_NOTHING
210 #  define ADDS(stat, n) DO_NOTHING
211 #endif
212 inline private void
fill_row(byte * line,int line_x,uint raster,int value)213 fill_row(byte *line, int line_x, uint raster, int value)
214 {
215     memset(line + (line_x >> 3), value, raster - (line_x >> 3));
216 }
217 private void
image_simple_expand(byte * line,int line_x,uint raster,const byte * buffer,int data_x,uint w,fixed xcur,fixed x_extent,byte zero)218 image_simple_expand(byte * line, int line_x, uint raster,
219 		    const byte * buffer, int data_x, uint w,
220 		    fixed xcur, fixed x_extent, byte zero /* 0 or 0xff */ )
221 {
222     int dbitx = data_x & 7;
223     byte sbit = 0x80 >> dbitx;
224     byte sbitmask = 0xff >> dbitx;
225     uint wx = dbitx + w;
226     gx_dda_fixed xl;
227     gx_dda_step_fixed dxx4, dxx8, dxx16, dxx24, dxx32;
228     register const byte *psrc = buffer + (data_x >> 3);
229 
230     /*
231      * The following 3 variables define the end of the input data row.
232      * We would put them in a struct, except that no compiler that we
233      * know of will optimize individual struct members as though they
234      * were simple variables (e.g., by putting them in registers).
235      *
236      * endp points to the byte that contains the bit just beyond the
237      * end of the row.  endx gives the bit number of this bit within
238      * the byte, with 0 being the *least* significant bit.  endbit is
239      * a mask for this bit.
240      */
241     const byte *endp = psrc + (wx >> 3);
242     int endx = ~wx & 7;
243     byte endbit = 1 << endx;
244 
245     /*
246      * The following 3 variables do the same for start of the last run
247      * of the input row (think of it as a pointer to just beyond the
248      * end of the next-to-last run).
249      */
250     const byte *stop = endp;
251     int stopx;
252     byte stopbit = endbit;
253     byte data;
254     byte one = ~zero;
255     fixed xl0;
256 
257     if (w == 0)
258 	return;
259     INCS(calls);
260 
261     /* Scan backward for the last transition. */
262     if (stopbit == 0x80)
263 	--stop, stopbit = 1;
264     else
265 	stopbit <<= 1;
266     /* Now (stop, stopbit) give the last bit of the row. */
267     {
268 	byte stopmask = -stopbit << 1;
269 	byte last = *stop;
270 
271 	if (stop == psrc)	/* only 1 input byte */
272 	    stopmask &= sbitmask;
273 	if (last & stopbit) {
274 	    /* The last bit is a 1: look for a 0-to-1 transition. */
275 	    if (~last & stopmask) {	/* Transition in last byte. */
276 		last |= stopbit - 1;
277 	    } else {		/* No transition in the last byte. */
278 		while (stop > psrc && stop[-1] == 0xff)
279 		    --stop;
280 		if (stop == psrc ||
281 		    (stop == psrc + 1 && !(~*psrc & sbitmask))
282 		    ) {
283 		    /* The input is all 1s.  Clear the row and exit. */
284 		    INCS(all1s);
285 		    fill_row(line, line_x, raster, one);
286 		    return;
287 		}
288 		last = *--stop;
289 	    }
290 	    stopx = byte_bit_run_length_0[byte_reverse_bits[last]] - 1;
291 	} else {
292 	    /* The last bit is a 0: look for a 1-to-0 transition. */
293 	    if (last & stopmask) {	/* Transition in last byte. */
294 		last &= -stopbit;
295 	    } else {		/* No transition in the last byte. */
296 		while (stop > psrc && stop[-1] == 0)
297 		    --stop;
298 		if (stop == psrc ||
299 		    (stop == psrc + 1 && !(*psrc & sbitmask))
300 		    ) {
301 		    /* The input is all 0s.  Clear the row and exit. */
302 		    INCS(all0s);
303 		    fill_row(line, line_x, raster, zero);
304 		    return;
305 		}
306 		last = *--stop;
307 	    }
308 	    stopx = byte_bit_run_length_0[byte_reverse_bits[last ^ 0xff]] - 1;
309 	}
310 	if (stopx < 0)
311 	    stopx = 7, ++stop;
312 	stopbit = 1 << stopx;
313     }
314 
315     /* Pre-clear the row. */
316     fill_row(line, line_x, raster, zero);
317 
318     /* Set up the DDAs. */
319     xl0 =
320 	(x_extent >= 0 ?
321 	 fixed_fraction(fixed_pre_pixround(xcur)) :
322 	 fixed_fraction(fixed_pre_pixround(xcur + x_extent)) - x_extent);
323     xl0 += int2fixed(line_x);
324     dda_init(xl, xl0, x_extent, w);
325     dxx4 = xl.step;
326     dda_step_add(dxx4, xl.step);
327     /* egcc - 2.91.66 generates incorrect code for
328      * dda_step_add(dxx4, dxx4);
329      * Using the temp variable.
330      */
331     dxx8 = dxx4;
332     dda_step_add(dxx4, dxx8);
333     dxx8 = dxx4;
334     dda_step_add(dxx8, dxx4);
335     dxx16 = dxx8;
336     dda_step_add(dxx16, dxx8);
337     dxx24 = dxx16;
338     dda_step_add(dxx24, dxx8);
339     dxx32 = dxx24;
340     dda_step_add(dxx32, dxx8);
341 
342     /*
343      * Loop invariants:
344      *      data = *psrc;
345      *      sbit = 1 << n, 0<=n<=7.
346      */
347     for (data = *psrc;;) {
348 	int x0, n, bit;
349 	byte *bp;
350 	static const byte lmasks[9] = {
351 	    0xff, 0x7f, 0x3f, 0x1f, 0xf, 7, 3, 1, 0
352 	};
353 	static const byte rmasks[9] = {
354 	    0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
355 	};
356 
357 	INCS(runs);
358 
359 	/* Scan a run of zeros. */
360 	data ^= 0xff;		/* invert */
361 	while (data & sbit) {
362 	    dda_next(xl);
363 	    sbit >>= 1;
364 	    INCS(lbit0);
365 	}
366 	if (!sbit) {		/* Scan a run of zero bytes. */
367 sw:	    if ((data = psrc[1]) != 0) {
368 		psrc++;
369 		INCS(byte00);
370 	    } else if ((data = psrc[2]) != 0) {
371 		dda_state_next(xl.state, dxx8);
372 		psrc += 2;
373 		INCS(byte01);
374 	    } else if ((data = psrc[3]) != 0) {
375 		dda_state_next(xl.state, dxx16);
376 		psrc += 3;
377 		INCS(byte02);
378 	    } else if ((data = psrc[4]) != 0) {
379 		dda_state_next(xl.state, dxx24);
380 		psrc += 4;
381 		INCS(byte03);
382 	    } else {
383 		dda_state_next(xl.state, dxx32);
384 		psrc += 4;
385 		INCS(byte04);
386 		goto sw;
387 	    }
388 	    if (data > 0xf)
389 		sbit = 0x80;
390 	    else {
391 		sbit = 0x08;
392 		dda_state_next(xl.state, dxx4);
393 	    }
394 	    data ^= 0xff;	/* invert */
395 	    while (data & sbit) {
396 		dda_next(xl);
397 		sbit >>= 1;
398 		INCS(rbit0);
399 	    }
400 	}
401 	x0 = dda_current_fixed2int(xl);
402 	if (psrc >= stop && sbit == stopbit) {
403 	    /*
404 	     * We've scanned the last run of 0s.
405 	     * Prepare to fill the final run of 1s.
406 	     */
407 	    n = fixed2int(xl0 + x_extent) - x0;
408 	} else {		/* Scan a run of ones. */
409 	    /* We know the current bit is a one. */
410 	    data ^= 0xff;	/* un-invert */
411 	    do {
412 		dda_next(xl);
413 		sbit >>= 1;
414 		INCS(lbit1);
415 	    }
416 	    while (data & sbit);
417 	    if (!sbit) {	/* Scan a run of 0xff bytes. */
418 		while ((data = *++psrc) == 0xff) {
419 		    dda_state_next(xl.state, dxx8);
420 		    INCS(byte1);
421 		}
422 		if (data < 0xf0)
423 		    sbit = 0x80;
424 		else {
425 		    sbit = 0x08;
426 		    dda_state_next(xl.state, dxx4);
427 		}
428 		while (data & sbit) {
429 		    dda_next(xl);
430 		    sbit >>= 1;
431 		    INCS(rbit1);
432 		}
433 	    }
434 	    n = dda_current_fixed2int(xl) - x0;
435 	}
436 
437 	/* Fill the run in the scan line. */
438 	if (n < 0)
439 	    x0 += n, n = -n;
440 	bp = line + (x0 >> 3);
441 	bit = x0 & 7;
442 	if ((n += bit) <= 8) {
443 	    *bp ^= lmasks[bit] - lmasks[n];
444 	    INCS(thin);
445 	} else if ((n -= 8) <= 8) {
446 	    *bp ^= lmasks[bit];
447 	    bp[1] ^= rmasks[n];
448 	    INCS(thin2);
449 	} else {
450 	    *bp++ ^= lmasks[bit];
451 	    if (n >= 56) {
452 		int nb = n >> 3;
453 
454 		memset(bp, one, nb);
455 		bp += nb;
456 		INCS(nwide);
457 		ADDS(bwide, nb);
458 	    } else {
459 		ADDS(bfill, n >> 3);
460 		while ((n -= 8) >= 0)
461 		    *bp++ = one;
462 		INCS(nfill);
463 	    }
464 	    *bp ^= rmasks[n & 7];
465 	}
466 	if (psrc >= stop && sbit == stopbit)
467 	    break;
468     }
469 }
470 
471 /* Copy one rendered scan line to the device. */
472 private int
copy_portrait(gx_image_enum * penum,const byte * data,int dx,int raster,int x,int y,int w,int h,gx_device * dev)473 copy_portrait(gx_image_enum * penum, const byte * data, int dx, int raster,
474 	      int x, int y, int w, int h, gx_device * dev)
475 {
476     const gx_device_color *pdc0;
477     const gx_device_color *pdc1;
478     uint align = ALIGNMENT_MOD(data, align_bitmap_mod);
479 
480     /*
481      * We know that the lookup table maps 1 bit to 1 bit,
482      * so it can only have 2 states: straight-through or invert.
483      */
484     if (penum->map[0].table.lookup4x1to32[0])
485 	pdc0 = &penum->icolor1, pdc1 = &penum->icolor0;
486     else
487 	pdc0 = &penum->icolor0, pdc1 = &penum->icolor1;
488     data -= align;
489     dx += align << 3;
490     if (gx_dc_is_pure(pdc0) && gx_dc_is_pure(pdc1)) {
491 	/* Just use copy_mono. */
492 	dev_proc_copy_mono((*copy_mono)) =
493 	    (h == 1 || (raster & (align_bitmap_mod - 1)) == 0 ?
494 	     dev_proc(dev, copy_mono) : gx_copy_mono_unaligned);
495 	return (*copy_mono)
496 	    (dev, data, dx, raster, gx_no_bitmap_id,
497 	     x, y, w, h, pdc0->colors.pure, pdc1->colors.pure);
498     }
499     /*
500      * At least one color isn't pure: if the other one is transparent, use
501      * the opaque color's fill_masked procedure.  Note that we use a
502      * slightly unusual representation for transparent here (per
503      * gx_begin_image1): a pure color with pixel value gx_no_color_index.
504      */
505     {
506 	const gx_device_color *pdc;
507 	bool invert;
508 
509 	if (DC_IS_NULL(pdc1)) {
510 	    pdc = pdc0;
511 	    invert = true;
512 	} else {
513 	    if (!DC_IS_NULL(pdc0)) {
514 		int code = gx_device_color_fill_rectangle
515 		    (pdc0, x, y, w, h, dev, lop_default, NULL);
516 
517 		if (code < 0)
518 		    return code;
519 	    }
520 	    pdc = pdc1;
521 	    invert = false;
522 	}
523 	return (*pdc->type->fill_masked)
524 	    (pdc, data, dx, raster, gx_no_bitmap_id, x, y, w, h,
525 	     dev, lop_default, invert);
526 
527     }
528 }
529 
530 /* Rendering procedure for a monobit image with no */
531 /* skew or rotation and pure colors. */
532 private int
image_render_simple(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)533 image_render_simple(gx_image_enum * penum, const byte * buffer, int data_x,
534 		    uint w, int h, gx_device * dev)
535 {
536     dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
537     const fixed dxx = penum->dxx;
538     const byte *line;
539     uint line_width, line_size;
540     int line_x;
541     fixed xcur = dda_current(penum->dda.pixel0.x);
542     int ix = fixed2int_pixround(xcur);
543     int ixr;
544     const int iy = penum->yci, ih = penum->hci;
545     gx_device_color * const pdc0 = &penum->icolor0;
546     gx_device_color * const pdc1 = &penum->icolor1;
547     int dy;
548     int code;
549 
550     if (h == 0)
551 	return 0;
552     if ((!DC_IS_NULL(pdc0) &&
553 	 (code = gx_color_load(pdc0, penum->pis, dev)) < 0) ||
554 	(!DC_IS_NULL(pdc1) &&
555 	 (code = gx_color_load(pdc1, penum->pis, dev)) < 0)
556 	)
557 	return code;
558     if (penum->line == 0) {	/* A direct BitBlt is possible. */
559 	line = buffer;
560 	line_size = (w + 7) >> 3;
561 	line_width = w;
562 	line_x = 0;
563     } else if (copy_mono == dev_proc(&mem_mono_device, copy_mono) &&
564 	       dxx > 0 && gx_dc_is_pure(pdc1) && gx_dc_is_pure(pdc0) &&
565 	       /* We know the colors must be (0,1) or (1,0). */
566 	       (pdc0->colors.pure ^ pdc1->colors.pure) == 1 &&
567 	       !penum->clip_image &&
568 	       /*
569 		* Even if clip_image is false, the clipping rectangle
570 		* might lie partly outside the device coordinate space
571 		* if the Margins values are non-zero.
572 		*/
573 	       ix >= 0 &&
574 	       (ixr = fixed2int_pixround(xcur + penum->x_extent.x) - 1) <
575 	         dev->width &&
576 	       iy >= 0 && iy + ih <= dev->height
577 	) {
578 	/* Do the operation directly into the memory device bitmap. */
579 	int line_ix;
580 	int ib_left = ix >> 3, ib_right = ixr >> 3;
581 	byte *scan_line = scan_line_base((gx_device_memory *) dev, iy);
582 	byte save_left, save_right, mask;
583 
584 	line_x = ix & (align_bitmap_mod * 8 - 1);
585 	line_ix = ix - line_x;
586 	line_size = (ixr >> 3) + 1 - (line_ix >> 3);
587 	line_width = ixr + 1 - ix;
588 	/* We must save and restore any unmodified bits in */
589 	/* the two edge bytes. */
590 	save_left = scan_line[ib_left];
591 	save_right = scan_line[ib_right];
592 	image_simple_expand(scan_line + (line_ix >> 3), line_x,
593 			    line_size, buffer, data_x, w, xcur,
594 			    penum->x_extent.x,
595 			    (byte)((pdc0->colors.pure == 0) !=
596 			     (penum->map[0].table.lookup4x1to32[0] == 0) ?
597 			     0xff : 0));
598 	if (ix & 7)
599 	    mask = (byte) (0xff00 >> (ix & 7)),
600 		scan_line[ib_left] =
601 		(save_left & mask) + (scan_line[ib_left] & ~mask);
602 	if ((ixr + 1) & 7)
603 	    mask = (byte) (0xff00 >> ((ixr + 1) & 7)),
604 		scan_line[ib_right] =
605 		(scan_line[ib_right] & mask) + (save_right & ~mask);
606 	if (ih <= 1)
607 	    return 1;
608 	/****** MAY BE UNALIGNED ******/
609 	line = scan_line + (line_ix >> 3);
610 	if (dxx < 0)
611 	    ix -= line_width;
612 	for (dy = 1; dy < ih; dy++) {
613 	    int code = (*copy_mono)
614 		(dev, line, line_x, line_size, gx_no_bitmap_id,
615 		 ix, iy + dy, line_width, 1,
616 		 (gx_color_index)0, (gx_color_index)1);
617 
618 	    if (code < 0)
619 		return code;
620 	}
621 	return 0;
622     } else {
623 	line = penum->line;
624 	line_size = penum->line_size;
625 	line_width = penum->line_width;
626 	line_x = ix & (align_bitmap_mod * 8 - 1);
627 	image_simple_expand(penum->line, line_x, line_size,
628 			    buffer, data_x, w, xcur,
629 			    penum->x_extent.x, 0);
630     }
631 
632     /* Finally, transfer the scan line to the device. */
633     if (dxx < 0)
634 	ix -= line_width;
635     for (dy = 0; dy < ih; dy++) {
636 	int code = copy_portrait(penum, line, line_x, line_size,
637 				 ix, iy + dy, line_width, 1, dev);
638 
639 	if (code < 0)
640 	    return code;
641     }
642 
643     return 1;
644 }
645 
646 /* Rendering procedure for a 90 degree rotated monobit image */
647 /* with pure colors.  We buffer and then flip 8 scan lines at a time. */
648 private int copy_landscape(gx_image_enum *, int, int, bool, gx_device *);
649 private int
image_render_landscape(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)650 image_render_landscape(gx_image_enum * penum, const byte * buffer, int data_x,
651 		       uint w, int h, gx_device * dev)
652 {
653     byte *line = penum->line;
654     uint raster = bitmap_raster(penum->line_width);
655     int ix = penum->xci, iw = penum->wci;
656     int xinc, xmod;
657     byte *row;
658     const byte *orig_row = 0;
659     bool y_neg = penum->dxy < 0;
660 
661     if (is_fneg(penum->matrix.yx))
662 	ix += iw, iw = -iw, xinc = -1;
663     else
664 	xinc = 1;
665     /*
666      * Because of clipping, there may be discontinuous jumps in the values
667      * of ix (xci).  If this happens, or if we are at the end of the data or
668      * a client has requested flushing, flush the flipping buffer.
669      */
670     if (ix != penum->xi_next || h == 0) {
671 	int xi = penum->xi_next;
672 	int code =
673 	    (xinc > 0 ?
674 	     copy_landscape(penum, penum->line_xy, xi, y_neg, dev) :
675 	     copy_landscape(penum, xi, penum->line_xy, y_neg, dev));
676 
677 	if (code < 0)
678 	    return code;
679 	penum->line_xy = penum->xi_next = ix;
680 	if (h == 0)
681 	    return code;
682     }
683     for (; iw != 0; iw -= xinc) {
684 	if (xinc < 0)
685 	    --ix;
686 	xmod = ix & 7;
687 	row = line + xmod * raster;
688 	if (orig_row == 0) {
689 	    image_simple_expand(row, 0, raster,
690 				buffer, data_x, w,
691 				dda_current(penum->dda.pixel0.y),
692 				penum->x_extent.y, 0);
693 	    orig_row = row;
694 	} else
695 	    memcpy(row, orig_row, raster);
696 	if (xinc > 0) {
697 	    ++ix;
698 	    if (xmod == 7) {
699 		int code =
700 		    copy_landscape(penum, penum->line_xy, ix, y_neg, dev);
701 
702 		if (code < 0)
703 		    return code;
704 		orig_row = 0;
705 		penum->line_xy = ix;
706 	    }
707 	} else {
708 	    if (xmod == 0) {
709 		int code =
710 		    copy_landscape(penum, ix, penum->line_xy, y_neg, dev);
711 
712 		if (code < 0)
713 		    return code;
714 		orig_row = 0;
715 		penum->line_xy = ix;
716 	    }
717 	}
718     }
719     penum->xi_next = ix;
720     return 0;
721 }
722 
723 /* Flip and copy one group of scan lines. */
724 private int
copy_landscape(gx_image_enum * penum,int x0,int x1,bool y_neg,gx_device * dev)725 copy_landscape(gx_image_enum * penum, int x0, int x1, bool y_neg,
726 	       gx_device * dev)
727 {
728     byte *line = penum->line;
729     uint line_width = penum->line_width;
730     uint raster = bitmap_raster(line_width);
731     byte *flipped = line + raster * 8;
732     int w = x1 - x0;
733     int y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
734 
735     if (w == 0 || line_width == 0)
736 	return 0;
737     /* Flip the buffered data from raster x 8 to align_bitmap_mod x */
738     /* line_width. */
739     if (line_width > 0) {
740 	int i;
741 
742 	for (i = (line_width - 1) >> 3; i >= 0; --i)
743 	    memflip8x8(line + i, raster,
744 		       flipped + (i << (log2_align_bitmap_mod + 3)),
745 		       align_bitmap_mod);
746     }
747     /* Transfer the scan lines to the device. */
748     if (w < 0)
749 	x0 = x1, w = -w;
750     if (y_neg)
751 	y -= line_width;
752     return copy_portrait(penum, flipped, x0 & 7, align_bitmap_mod,
753 			 x0, y, w, line_width, dev);
754 }
755