Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/base/gxifast.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, 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 "gxgstate.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
#include "valgrind.h"
40
41
/* Conditionally include statistics code. */
42
#if defined(DEBUG) && !defined(GS_THREADSAFE)
43
#  define STATS
44
#endif
45
46
/* ------ Strategy procedure ------ */
47
48
/* Check the prototype. */
49
iclass_proc(gs_image_class_1_simple);
50
51
/* Use special fast logic for portrait or landscape black-and-white images. */
52
static irender_proc(image_render_skip);
53
static irender_proc(image_render_simple);
54
static irender_proc(image_render_landscape);
55
56
int
57
gs_image_class_1_simple(gx_image_enum * penum, irender_proc_t *render_fn)
58
0
{
59
0
    fixed ox = dda_current(penum->dda.pixel0.x);
60
0
    fixed oy = dda_current(penum->dda.pixel0.y);
61
62
0
    if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
63
0
        return 0;
64
0
    switch (penum->posture) {
65
0
        case image_portrait:
66
0
            {     /* Use fast portrait algorithm. */
67
0
                long dev_width =
68
0
                    fixed2long_pixround(ox + penum->x_extent.x) -
69
0
                    fixed2long_pixround(ox);
70
71
0
                if (dev_width != penum->rect.w) {
72
                    /*
73
                     * Add an extra align_bitmap_mod of padding so that
74
                     * we can align scaled rows with the device.
75
                     */
76
0
                    long line_size =
77
0
                        bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;
78
79
0
                    if (penum->adjust != 0 || line_size > max_uint)
80
0
                        return 0;
81
                    /* Must buffer a scan line. */
82
0
                    penum->line_width = any_abs(dev_width);
83
0
                    penum->line_size = (uint) line_size;
84
0
                    penum->line = gs_alloc_bytes(penum->memory,
85
0
                                            penum->line_size, "image line");
86
0
                    if (penum->line == 0) {
87
0
                        return gs_error_VMerror;
88
0
                    }
89
0
                }
90
0
                if_debug2m('b', penum->memory, "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
91
0
                           penum->rect.w, dev_width);
92
0
                *render_fn = image_render_simple;
93
0
                break;
94
0
            }
95
0
        case image_landscape:
96
0
            {     /* Use fast landscape algorithm. */
97
0
                long dev_width =
98
0
                    fixed2long_pixround(oy + penum->x_extent.y) -
99
0
                    fixed2long_pixround(oy);
100
0
                long line_size =
101
0
                    (dev_width = any_abs(dev_width),
102
0
                     bitmap_raster(dev_width) * 8 +
103
0
                     ROUND_UP(dev_width, 8) * align_bitmap_mod);
104
105
0
                if ((dev_width != penum->rect.w && penum->adjust != 0) ||
106
0
                    line_size > max_uint
107
0
                    )
108
0
                    return 0;
109
                /* Must buffer a group of 8N scan lines. */
110
0
                penum->line_width = dev_width;
111
0
                penum->line_size = (uint) line_size;
112
0
                penum->line = gs_alloc_bytes(penum->memory,
113
0
                                             penum->line_size, "image line");
114
0
                if (penum->line == 0) {
115
0
                    return gs_error_VMerror;
116
0
                }
117
#ifdef PACIFY_VALGRIND
118
                memset(penum->line, 0, penum->line_size); /* For the number of scan lined < 8 */
119
#endif
120
0
                penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
121
0
                if_debug3m('b', penum->memory,
122
0
                           "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
123
0
                           penum->rect.w, dev_width, line_size);
124
0
                *render_fn = image_render_landscape;
125
                /* Precompute values needed for rasterizing. */
126
0
                penum->dxy =
127
0
                    float2fixed(penum->matrix.xy +
128
0
                                fixed2float(fixed_epsilon) / 2);
129
0
                break;
130
0
            }
131
0
        default:
132
0
            return 0;
133
0
    }
134
    /* Precompute values needed for rasterizing. */
135
0
    penum->dxx =
136
0
        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
0
    penum->unpack = sample_unpack_copy;
143
0
    penum->unpack_bps = 8;
144
0
    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
0
        penum->masked = true;
150
0
        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
0
            set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1,
153
0
                        gx_no_color_index);
154
0
        } 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
0
            set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0,
157
0
                        gx_no_color_index);
158
0
        } else {
159
            /*
160
             * The only other possible in-range value is v0 = 0, v1 = 1.
161
             * The image is completely transparent!
162
             */
163
0
            *render_fn = image_render_skip;
164
0
        }
165
0
        penum->map[0].decoding = sd_none;
166
0
    }
167
0
    return 0;
168
0
}
169
170
/* ------ Rendering procedures ------ */
171
172
#define DC_IS_NULL(pdc)\
173
0
  (gx_dc_is_pure(pdc) && (pdc)->colors.pure == gx_no_color_index)
174
175
/* Skip over a completely transparent image. */
176
static int
177
image_render_skip(gx_image_enum * penum, const byte * buffer, int data_x,
178
                  uint w, int h, gx_device * dev)
179
0
{
180
0
    return h;
181
0
}
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
0
#  define INCS(stat) DO_NOTHING
209
0
#  define ADDS(stat, n) DO_NOTHING
210
#endif
211
static inline void
212
fill_row(byte *line, int line_x, uint raster, int value)
213
0
{
214
0
    memset(line + (line_x >> 3), value, raster - (line_x >> 3));
215
0
}
216
217
static 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
0
{
222
0
    int dbitx = data_x & 7;
223
0
    byte sbit = 0x80 >> dbitx;
224
0
    byte sbitmask = 0xff >> dbitx;
225
0
    uint wx = dbitx + w;
226
0
    gx_dda_fixed xl;
227
0
    gx_dda_step_fixed dxx4, dxx8, dxx16, dxx24, dxx32;
228
0
    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
0
    const byte *endp = psrc + (wx >> 3);
242
0
    int endx = ~wx & 7;
243
0
    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
0
    const byte *stop = endp;
251
0
    int stopx;
252
0
    byte stopbit = endbit;
253
0
    byte data;
254
0
    byte one = ~zero;
255
0
    fixed xl0;
256
#ifdef PACIFY_VALGRIND
257
    byte vbits;
258
#endif
259
260
0
    if (w == 0)
261
0
        return;
262
0
    INCS(calls);
263
264
    /* Scan backward for the last transition. */
265
0
    if (stopbit == 0x80)
266
0
        --stop, stopbit = 1;
267
0
    else
268
0
        stopbit <<= 1;
269
    /* Now (stop, stopbit) give the last bit of the row. */
270
#ifdef PACIFY_VALGRIND
271
    /* Here, we are dealing with a row of bits, rather than bytes.
272
     * If the width of the bits is not a multiple of 8, we don't
273
     * fill out the last byte, and valgrind (correctly) tracks the
274
     * bits in that last byte as being a mix of defined and undefined.
275
     * When we are scanning through the row bitwise, everything works
276
     * fine, but our "skip whole bytes" code can confuse valgrind.
277
     * We know that we won't match the "data == 0xff" for the final
278
     * byte (i.e. the undefinedness of some of the bits doesn't matter
279
     * to the correctness of the routine), but valgrind is not smart
280
     * enough to realise that we know this. Accordingly, we get a false
281
     * positive "undefined memory read".
282
     * How do we fix this? Well, one way would be to read in the
283
     * partial last byte, and explicitly set the undefined bits to
284
     * be 0.
285
     *   *stop &= ~(stopbit-1);
286
     * Unfortunately, stop is a const *, so we can't do that (we could
287
     * break const, but it is just conceivable that the caller might
288
     * pass the next string of bits out in a later call, and so we
289
     * might be corrupting valid data).
290
     * Instead, we make a call to a valgrind helper. */
291
    VALGRIND_GET_VBITS(stop,&vbits,1);
292
    if ((vbits & stopbit)==0) { /* At least our stop bit must be addressable already! */
293
      byte zero = 0;
294
      VALGRIND_SET_VBITS(stop,&zero,1);
295
    }
296
#endif
297
0
    {
298
0
        byte stopmask = -stopbit << 1;
299
0
        byte last = *stop;
300
301
0
        if (stop == psrc) /* only 1 input byte */
302
0
            stopmask &= sbitmask;
303
0
        if (last & stopbit) {
304
            /* The last bit is a 1: look for a 0-to-1 transition. */
305
0
            if (~last & stopmask) { /* Transition in last byte. */
306
0
                last |= stopbit - 1;
307
0
            } else {   /* No transition in the last byte. */
308
0
                while (stop > psrc && stop[-1] == 0xff)
309
0
                    --stop;
310
0
                if (stop == psrc ||
311
0
                    (stop == psrc + 1 && !(~*psrc & sbitmask))
312
0
                    ) {
313
                    /* The input is all 1s.  Clear the row and exit. */
314
0
                    INCS(all1s);
315
0
                    fill_row(line, line_x, raster, one);
316
0
                    goto end;
317
0
                }
318
0
                last = *--stop;
319
0
            }
320
0
            stopx = byte_bit_run_length_0[byte_reverse_bits[last]] - 1;
321
0
        } else {
322
            /* The last bit is a 0: look for a 1-to-0 transition. */
323
0
            if (last & stopmask) { /* Transition in last byte. */
324
0
                last &= -stopbit;
325
0
            } else {   /* No transition in the last byte. */
326
0
                while (stop > psrc && stop[-1] == 0)
327
0
                    --stop;
328
0
                if (stop == psrc ||
329
0
                    (stop == psrc + 1 && !(*psrc & sbitmask))
330
0
                    ) {
331
                    /* The input is all 0s.  Clear the row and exit. */
332
0
                    INCS(all0s);
333
0
                    fill_row(line, line_x, raster, zero);
334
0
                    goto end;
335
0
                }
336
0
                last = *--stop;
337
0
            }
338
0
            stopx = byte_bit_run_length_0[byte_reverse_bits[last ^ 0xff]] - 1;
339
0
        }
340
0
        if (stopx < 0)
341
0
            stopx = 7, ++stop;
342
0
        stopbit = 1 << stopx;
343
0
    }
344
345
    /* Pre-clear the row. */
346
0
    fill_row(line, line_x, raster, zero);
347
348
349
    /* Extreme negative values of x_extent cause the xl0 calculation
350
     * to explode. Workaround this here. */
351
0
    if (x_extent < min_int + 0x100)
352
0
      x_extent += 0x100;
353
354
    /* Set up the DDAs. */
355
0
    xl0 =
356
0
        (x_extent >= 0 ?
357
0
         fixed_fraction(fixed_pre_pixround(xcur)) :
358
0
         fixed_fraction(fixed_pre_pixround(xcur + x_extent)) - x_extent);
359
0
    xl0 += int2fixed(line_x);
360
    /* We should never get a negative x10 here. If we do, all bets are off. */
361
0
    if (xl0 < 0)
362
0
        xl0 = 0, x_extent = 0;
363
0
    dda_init(xl, xl0, x_extent, w);
364
0
    dxx4 = xl.step;
365
0
    dda_step_add(dxx4, xl.step);
366
    /* egcc - 2.91.66 generates incorrect code for
367
     * dda_step_add(dxx4, dxx4);
368
     * Using the temp variable.
369
     */
370
0
    dxx8 = dxx4;
371
0
    dda_step_add(dxx4, dxx8);
372
0
    dxx8 = dxx4;
373
0
    dda_step_add(dxx8, dxx4);
374
0
    dxx16 = dxx8;
375
0
    dda_step_add(dxx16, dxx8);
376
0
    dxx24 = dxx16;
377
0
    dda_step_add(dxx24, dxx8);
378
0
    dxx32 = dxx24;
379
0
    dda_step_add(dxx32, dxx8);
380
381
    /*
382
     * Loop invariants:
383
     *      data = *psrc;
384
     *      sbit = 1 << n, 0<=n<=7.
385
     */
386
0
    for (data = *psrc;;) {
387
0
        int x0, n, bit;
388
0
        byte *bp;
389
0
        static const byte lmasks[9] = {
390
0
            0xff, 0x7f, 0x3f, 0x1f, 0xf, 7, 3, 1, 0
391
0
        };
392
0
        static const byte rmasks[9] = {
393
0
            0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
394
0
        };
395
396
0
        INCS(runs);
397
398
        /* Scan a run of zeros. */
399
0
        data ^= 0xff;   /* invert */
400
0
        while (data & sbit) {
401
0
            dda_next(xl);
402
0
            sbit >>= 1;
403
0
            INCS(lbit0);
404
0
        }
405
0
        if (!sbit) {   /* Scan a run of zero bytes. */
406
0
sw:     if ((data = psrc[1]) != 0) {
407
0
                psrc++;
408
0
                INCS(byte00);
409
0
            } else if ((data = psrc[2]) != 0) {
410
0
                dda_state_next(xl.state, dxx8);
411
0
                psrc += 2;
412
0
                INCS(byte01);
413
0
            } else if ((data = psrc[3]) != 0) {
414
0
                dda_state_next(xl.state, dxx16);
415
0
                psrc += 3;
416
0
                INCS(byte02);
417
0
            } else if ((data = psrc[4]) != 0) {
418
0
                dda_state_next(xl.state, dxx24);
419
0
                psrc += 4;
420
0
                INCS(byte03);
421
0
            } else {
422
0
                dda_state_next(xl.state, dxx32);
423
0
                psrc += 4;
424
0
                INCS(byte04);
425
0
                goto sw;
426
0
            }
427
0
            if (data > 0xf)
428
0
                sbit = 0x80;
429
0
            else {
430
0
                sbit = 0x08;
431
0
                dda_state_next(xl.state, dxx4);
432
0
            }
433
0
            data ^= 0xff; /* invert */
434
0
            while (data & sbit) {
435
0
                dda_next(xl);
436
0
                sbit >>= 1;
437
0
                INCS(rbit0);
438
0
            }
439
0
        }
440
0
        x0 = dda_current_fixed2int(xl);
441
0
        if (psrc >= stop && sbit == stopbit) {
442
            /*
443
             * We've scanned the last run of 0s.
444
             * Prepare to fill the final run of 1s.
445
             * Use int64_t to avoid overflow.
446
             */
447
0
            n = fixed2int((int64_t)xl0 + (int64_t)x_extent) - x0;
448
0
        } else {   /* Scan a run of ones. */
449
            /* We know the current bit is a one. */
450
0
            data ^= 0xff; /* un-invert */
451
0
            do {
452
0
                dda_next(xl);
453
0
                sbit >>= 1;
454
0
                INCS(lbit1);
455
0
            }
456
0
            while (data & sbit);
457
0
            if (!sbit) { /* Scan a run of 0xff bytes. */
458
0
                while ((data = *++psrc) == 0xff) {
459
0
                    dda_state_next(xl.state, dxx8);
460
0
                    INCS(byte1);
461
0
                }
462
0
                if (data < 0xf0)
463
0
                    sbit = 0x80;
464
0
                else {
465
0
                    sbit = 0x08;
466
0
                    dda_state_next(xl.state, dxx4);
467
0
                }
468
0
                while (data & sbit) {
469
0
                    dda_next(xl);
470
0
                    sbit >>= 1;
471
0
                    INCS(rbit1);
472
0
                }
473
0
            }
474
0
            n = dda_current_fixed2int(xl) - x0;
475
0
        }
476
477
        /* Fill the run in the scan line. */
478
0
        if (n < 0)
479
0
            x0 += n, n = -n;
480
0
        bp = line + (x0 >> 3);
481
0
        bit = x0 & 7;
482
0
        if ((n += bit) <= 8) {
483
0
            *bp ^= lmasks[bit] - lmasks[n];
484
0
            INCS(thin);
485
0
        } else if ((n -= 8) <= 8) {
486
0
            *bp ^= lmasks[bit];
487
0
            bp[1] ^= rmasks[n];
488
0
            INCS(thin2);
489
0
        } else {
490
0
            *bp++ ^= lmasks[bit];
491
0
            if (n >= 56) {
492
0
                int nb = n >> 3;
493
494
0
                memset(bp, one, nb);
495
0
                bp += nb;
496
0
                INCS(nwide);
497
0
                ADDS(bwide, nb);
498
0
            } else {
499
0
                ADDS(bfill, n >> 3);
500
0
                while ((n -= 8) >= 0)
501
0
                    *bp++ = one;
502
0
                INCS(nfill);
503
0
            }
504
0
            *bp ^= rmasks[n & 7];
505
0
        }
506
0
        if (psrc >= stop && sbit == stopbit)
507
0
            break;
508
0
    }
509
0
 end:
510
0
    VALGRIND_SET_VBITS(stop,&vbits,1);
511
0
}
512
513
/* Copy one rendered scan line to the device. */
514
static int
515
copy_portrait(gx_image_enum * penum, const byte * data, int dx, int raster,
516
              int x, int y, int w, int h, gx_device * dev)
517
0
{
518
0
    const gx_device_color *pdc0;
519
0
    const gx_device_color *pdc1;
520
0
    uint align = ALIGNMENT_MOD(data, align_bitmap_mod);
521
522
    /*
523
     * We know that the lookup table maps 1 bit to 1 bit,
524
     * so it can only have 2 states: straight-through or invert.
525
     */
526
0
    if (penum->map[0].table.lookup4x1to32[0])
527
0
        pdc0 = penum->icolor1, pdc1 = penum->icolor0;
528
0
    else
529
0
        pdc0 = penum->icolor0, pdc1 = penum->icolor1;
530
0
    data -= align;
531
0
    dx += align << 3;
532
0
    if (gx_dc_is_pure(pdc0) && gx_dc_is_pure(pdc1)) {
533
        /* Just use copy_mono. */
534
0
        dev_proc_copy_mono((*copy_mono)) =
535
0
            (h == 1 || (raster & (align_bitmap_mod - 1)) == 0 ?
536
0
             dev_proc(dev, copy_mono) : gx_copy_mono_unaligned);
537
0
        return (*copy_mono)
538
0
            (dev, data, dx, raster, gx_no_bitmap_id,
539
0
             x, y, w, h, pdc0->colors.pure, pdc1->colors.pure);
540
0
    }
541
    /*
542
     * At least one color isn't pure: if the other one is transparent, use
543
     * the opaque color's fill_masked procedure.  Note that we use a
544
     * slightly unusual representation for transparent here (per
545
     * gx_begin_image1): a pure color with pixel value gx_no_color_index.
546
     */
547
0
    {
548
0
        const gx_device_color *pdc;
549
0
        bool invert;
550
551
0
        if (DC_IS_NULL(pdc1)) {
552
0
            pdc = pdc0;
553
0
            invert = true;
554
0
        } else {
555
0
            if (!DC_IS_NULL(pdc0)) {
556
0
                int code = gx_device_color_fill_rectangle
557
0
                    (pdc0, x, y, w, h, dev, lop_default, NULL);
558
559
0
                if (code < 0)
560
0
                    return code;
561
0
            }
562
0
            pdc = pdc1;
563
0
            invert = false;
564
0
        }
565
0
        return (*pdc->type->fill_masked)
566
0
            (pdc, data, dx, raster, gx_no_bitmap_id, x, y, w, h,
567
0
             dev, lop_default, invert);
568
569
0
    }
570
0
}
571
572
/* Rendering procedure for a monobit image with no */
573
/* skew or rotation and pure colors. */
574
static int
575
image_render_simple(gx_image_enum * penum, const byte * buffer, int data_x,
576
                    uint w, int h, gx_device * dev)
577
0
{
578
0
    dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
579
0
    const fixed dxx = penum->dxx;
580
0
    const byte *line;
581
0
    uint line_width, line_size;
582
0
    int line_x;
583
0
    fixed xcur = dda_current(penum->dda.pixel0.x);
584
0
    int ix = fixed2int_pixround(xcur);
585
0
    int ixr;
586
0
    const int iy = penum->yci, ih = penum->hci;
587
0
    gx_device_color * const pdc0 = penum->icolor0;
588
0
    gx_device_color * const pdc1 = penum->icolor1;
589
0
    int dy;
590
0
    int code;
591
592
0
    if (h == 0)
593
0
        return 0;
594
0
    if ((!DC_IS_NULL(pdc0) &&
595
0
         (code = gx_color_load(pdc0, penum->pgs, dev)) < 0) ||
596
0
        (!DC_IS_NULL(pdc1) &&
597
0
         (code = gx_color_load(pdc1, penum->pgs, dev)) < 0)
598
0
        )
599
0
        return code;
600
0
    if (penum->line == 0) { /* A direct BitBlt is possible. */
601
0
        line = buffer;
602
0
        line_size = (w + 7) >> 3;
603
0
        line_width = w;
604
0
        line_x = 0;
605
0
    } else if (copy_mono == dev_proc(&mem_mono_device, copy_mono) &&
606
0
               dxx > 0 && gx_dc_is_pure(pdc1) && gx_dc_is_pure(pdc0) &&
607
               /* We know the colors must be (0,1) or (1,0). */
608
0
               (pdc0->colors.pure ^ pdc1->colors.pure) == 1 &&
609
0
               !penum->clip_image &&
610
               /*
611
                * Even if clip_image is false, the clipping rectangle
612
                * might lie partly outside the device coordinate space
613
                * if the Margins values are non-zero.
614
                */
615
0
               ix >= 0 &&
616
0
               (ixr = fixed2int_pixround(xcur + penum->x_extent.x) - 1) <
617
0
                 dev->width &&
618
0
               iy >= 0 && iy + ih <= dev->height
619
0
        ) {
620
        /* Do the operation directly into the memory device bitmap. */
621
0
        int line_ix;
622
0
        int ib_left = ix >> 3, ib_right = ixr >> 3;
623
0
        byte *scan_line = scan_line_base((gx_device_memory *) dev, iy);
624
0
        byte save_left, save_right, mask;
625
626
0
        line_x = ix & (align_bitmap_mod * 8 - 1);
627
0
        line_ix = ix - line_x;
628
0
        line_size = (ixr >> 3) + 1 - (line_ix >> 3);
629
0
        line_width = ixr + 1 - ix;
630
        /* We must save and restore any unmodified bits in */
631
        /* the two edge bytes. */
632
0
        save_left = scan_line[ib_left];
633
0
        save_right = scan_line[ib_right];
634
0
        image_simple_expand(scan_line + (line_ix >> 3), line_x,
635
0
                            line_size, buffer, data_x, w, xcur,
636
0
                            penum->x_extent.x,
637
0
                            (byte)((pdc0->colors.pure == 0) !=
638
0
                             (penum->map[0].table.lookup4x1to32[0] == 0) ?
639
0
                             0xff : 0));
640
0
        if (ix & 7)
641
0
            mask = (byte) (0xff00 >> (ix & 7)),
642
0
                scan_line[ib_left] =
643
0
                (save_left & mask) + (scan_line[ib_left] & ~mask);
644
0
        if ((ixr + 1) & 7)
645
0
            mask = (byte) (0xff00 >> ((ixr + 1) & 7)),
646
0
                scan_line[ib_right] =
647
0
                (scan_line[ib_right] & mask) + (save_right & ~mask);
648
0
        if (ih <= 1)
649
0
            return 1;
650
        /****** MAY BE UNALIGNED ******/
651
0
        line = scan_line + (line_ix >> 3);
652
0
        for (dy = 1; dy < ih; dy++) {
653
0
            int code = (*copy_mono)
654
0
                (dev, line, line_x, line_size, gx_no_bitmap_id,
655
0
                 ix, iy + dy, line_width, 1,
656
0
                 (gx_color_index)0, (gx_color_index)1);
657
658
0
            if (code < 0)
659
0
                return code;
660
0
        }
661
0
        return 0;
662
0
    } else {
663
0
        line = penum->line;
664
0
        line_size = penum->line_size;
665
0
        line_width = penum->line_width;
666
0
        line_x = ix & (align_bitmap_mod * 8 - 1);
667
0
        image_simple_expand(penum->line, line_x, line_size,
668
0
                            buffer, data_x, w, xcur,
669
0
                            penum->x_extent.x, 0);
670
0
    }
671
672
    /* Finally, transfer the scan line to the device. */
673
0
    if (dxx < 0)
674
0
        ix -= line_width;
675
0
    for (dy = 0; dy < ih; dy++) {
676
0
        int code = copy_portrait(penum, line, line_x, line_size,
677
0
                                 ix, iy + dy, line_width, 1, dev);
678
679
0
        if (code < 0)
680
0
            return code;
681
0
    }
682
683
0
    return 1;
684
0
}
685
686
/* Rendering procedure for a 90 degree rotated monobit image */
687
/* with pure colors.  We buffer and then flip 8 scan lines at a time. */
688
static int copy_landscape(gx_image_enum *, int, int, bool, gx_device *);
689
static int
690
image_render_landscape(gx_image_enum * penum, const byte * buffer, int data_x,
691
                       uint w, int h, gx_device * dev)
692
0
{
693
0
    byte *line = penum->line;
694
0
    uint raster = bitmap_raster(penum->line_width);
695
0
    int ix = penum->xci, iw = penum->wci;
696
0
    int xinc, xmod;
697
0
    byte *row;
698
0
    const byte *orig_row = 0;
699
0
    bool y_neg = penum->dxy < 0;
700
701
0
    if (is_fneg(penum->matrix.yx))
702
0
        ix += iw, iw = -iw, xinc = -1;
703
0
    else
704
0
        xinc = 1;
705
    /*
706
     * Because of clipping, there may be discontinuous jumps in the values
707
     * of ix (xci).  If this happens, or if we are at the end of the data or
708
     * a client has requested flushing, flush the flipping buffer.
709
     */
710
0
    if (ix != penum->xi_next || h == 0) {
711
0
        int xi = penum->xi_next;
712
0
        int code =
713
0
            (xinc > 0 ?
714
0
             copy_landscape(penum, penum->line_xy, xi, y_neg, dev) :
715
0
             copy_landscape(penum, xi, penum->line_xy, y_neg, dev));
716
717
0
        if (code < 0)
718
0
            return code;
719
0
        penum->line_xy = penum->xi_next = ix;
720
0
        if (h == 0)
721
0
            return code;
722
0
    }
723
0
    for (; iw != 0; iw -= xinc) {
724
0
        if (xinc < 0)
725
0
            --ix;
726
0
        xmod = ix & 7;
727
0
        row = line + xmod * raster;
728
0
        if (orig_row == 0) {
729
0
            image_simple_expand(row, 0, raster,
730
0
                                buffer, data_x, w,
731
0
                                dda_current(penum->dda.pixel0.y),
732
0
                                penum->x_extent.y, 0);
733
0
            orig_row = row;
734
0
        } else
735
0
            memcpy(row, orig_row, raster);
736
0
        if (xinc > 0) {
737
0
            ++ix;
738
0
            if (xmod == 7) {
739
0
                int code =
740
0
                    copy_landscape(penum, penum->line_xy, ix, y_neg, dev);
741
742
0
                if (code < 0)
743
0
                    return code;
744
0
                orig_row = 0;
745
0
                penum->line_xy = ix;
746
0
            }
747
0
        } else {
748
0
            if (xmod == 0) {
749
0
                int code =
750
0
                    copy_landscape(penum, ix, penum->line_xy, y_neg, dev);
751
752
0
                if (code < 0)
753
0
                    return code;
754
0
                orig_row = 0;
755
0
                penum->line_xy = ix;
756
0
            }
757
0
        }
758
0
    }
759
0
    penum->xi_next = ix;
760
0
    return 0;
761
0
}
762
763
/* Flip and copy one group of scan lines. */
764
static int
765
copy_landscape(gx_image_enum * penum, int x0, int x1, bool y_neg,
766
               gx_device * dev)
767
0
{
768
0
    byte *line = penum->line;
769
0
    uint line_width = penum->line_width;
770
0
    uint raster = bitmap_raster(line_width);
771
0
    byte *flipped = line + raster * 8;
772
0
    int w = x1 - x0;
773
0
    int y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
774
775
0
    if (w == 0 || line_width == 0)
776
0
        return 0;
777
    /* Flip the buffered data from raster x 8 to align_bitmap_mod x */
778
    /* line_width. */
779
0
    if (line_width > 0) {
780
0
        int i = (line_width-1)>>3;
781
782
#ifdef PACIFY_VALGRIND
783
        if (line_width & 7) {
784
            memflip8x8_eol(line + i, raster,
785
                           flipped + (i << (log2_align_bitmap_mod + 3)),
786
                           align_bitmap_mod,
787
                           line_width & 7);
788
            i--;
789
        }
790
#endif
791
792
0
        for (; i >= 0; --i)
793
0
            memflip8x8(line + i, raster,
794
0
                       flipped + (i << (log2_align_bitmap_mod + 3)),
795
0
                       align_bitmap_mod);
796
0
    }
797
    /* Transfer the scan lines to the device. */
798
0
    if (w < 0)
799
0
        x0 = x1, w = -w;
800
0
    if (y_neg)
801
0
        y -= line_width;
802
0
    return copy_portrait(penum, flipped, x0 & 7, align_bitmap_mod,
803
0
                         x0, y, w, line_width, dev);
804
0
}