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