Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
}