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