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