Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxp1fill.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* PatternType 1 filling algorithms */
18
#include "string_.h"
19
#include "math_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsrop.h"
23
#include "gsmatrix.h"
24
#include "gxcspace.h"           /* for gscolor2.h */
25
#include "gxcolor2.h"
26
#include "gxdcolor.h"
27
#include "gxdevcli.h"
28
#include "gxdevmem.h"
29
#include "gxclip2.h"
30
#include "gxpcolor.h"
31
#include "gxp1impl.h"
32
#include "gxcldev.h"
33
#include "gxblend.h"
34
#include "gsicc_cache.h"
35
#include "gxdevsop.h"
36
#include <limits.h>             /* For INT_MAX etc */
37
#include "gpcheck.h"
38
39
#include "gdevp14.h"
40
41
128M
#define fastfloor(x) (((int)(x)) - (((x)<0) && ((x) != (float)(int)(x))))
42
43
/* Define the state for tile filling. */
44
typedef struct tile_fill_state_s {
45
46
    /* Original arguments */
47
48
    const gx_device_color *pdevc;       /* pattern color */
49
    int x0, y0, w0, h0;
50
    gs_logical_operation_t lop;
51
    const gx_rop_source_t *source;
52
53
    /* Variables set at initialization */
54
55
    gx_device_tile_clip *cdev;
56
    gx_device *pcdev;           /* original device or cdev */
57
    const gx_strip_bitmap *tmask;
58
    gs_int_point phase;
59
    int num_planes;    /* negative if not planar */
60
61
62
    /* Following are only for uncolored patterns */
63
64
    dev_color_proc_fill_rectangle((*fill_rectangle));
65
66
    /* Following are only for colored patterns */
67
68
    gx_device *orig_dev;
69
    int xoff, yoff;             /* set dynamically */
70
71
} tile_fill_state_t;
72
73
/* Define the state for tile filling.
74
   This is used for when we have
75
   transparency */
76
typedef struct tile_fill_trans_state_s {
77
78
    /* Original arguments */
79
80
    const gx_device_color *pdevc;       /* pattern color */
81
    int x0, y0, w0, h0;
82
83
    /* Variables set at initialization */
84
85
    gx_device *pcdev;           /* original device or &cdev */
86
    gs_int_point phase;
87
88
    int xoff, yoff;             /* set dynamically */
89
90
} tile_fill_trans_state_t;
91
92
/* we need some means of detecting if a forwarding clipping device was
93
   installed.  If the tile state cdev pointer is non-NULL, then the
94
   target output device must be the clipping device. */
95
1.12M
#define CLIPDEV_INSTALLED (state.cdev != NULL)
96
97
/* Initialize the filling state. */
98
static int
99
tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc,
100
               gx_device * dev, bool set_mask_phase)
101
778k
{
102
778k
    gx_color_tile *m_tile = pdevc->mask.m_tile;
103
778k
    int px, py;
104
778k
    int num_planar_planes;
105
106
778k
    ptfs->pdevc = pdevc;
107
778k
    num_planar_planes = dev->num_planar_planes;
108
778k
    if (num_planar_planes) {
109
89.4k
        ptfs->num_planes = dev->num_planar_planes;
110
689k
    } else {
111
689k
        ptfs->num_planes = -1;
112
689k
    }
113
778k
    if (m_tile == 0) {          /* no clipping */
114
415k
        ptfs->cdev = NULL;
115
415k
        ptfs->pcdev = dev;
116
415k
        ptfs->phase = pdevc->phase;
117
415k
        return 0;
118
415k
    }
119
363k
    if ((ptfs->cdev = (gx_device_tile_clip *)gs_alloc_struct(dev->memory,
120
363k
                                                 gx_device_tile_clip,
121
363k
                                                 &st_device_tile_clip,
122
363k
                                                 "tile_fill_init(cdev)")) == NULL) {
123
0
        return_error(gs_error_VMerror);
124
0
    }
125
363k
    ptfs->cdev->finalize = NULL;
126
363k
    ptfs->pcdev = (gx_device *)ptfs->cdev;
127
363k
    ptfs->tmask = &m_tile->tmask;
128
363k
    ptfs->phase.x = pdevc->mask.m_phase.x;
129
363k
    ptfs->phase.y = pdevc->mask.m_phase.y;
130
    /*
131
     * For non-simple tiles, the phase will be reset on each pass of the
132
     * tile_by_steps loop, but for simple tiles, we must set it now.
133
     */
134
363k
    if (set_mask_phase && m_tile->is_simple) {
135
83.6k
        px = imod(-(int)fastfloor(m_tile->step_matrix.tx - ptfs->phase.x + 0.5),
136
83.6k
                  m_tile->tmask.rep_width);
137
83.6k
        py = imod(-(int)fastfloor(m_tile->step_matrix.ty - ptfs->phase.y + 0.5),
138
83.6k
                  m_tile->tmask.rep_height);
139
83.6k
    } else
140
279k
        px = py = 0;
141
363k
    return tile_clip_initialize(ptfs->cdev, ptfs->tmask, dev, px, py);
142
363k
}
143
144
static int
145
threshold_ceil(float f, float e)
146
614k
{
147
614k
    int i = (int)fastfloor(f);
148
149
614k
    if (f - i < e)
150
13.6k
        return i;
151
601k
    return i+1;
152
614k
}
153
static int
154
threshold_floor(float f, float e)
155
614k
{
156
614k
    int i = (int)fastfloor(f);
157
158
614k
    if (f - i > 1-e)
159
765
        return i+1;
160
614k
    return i;
161
614k
}
162
163
/* Return a conservative approximation to the maximum expansion caused by
164
 * a given matrix. */
165
static float
166
matrix_expansion(gs_matrix *m)
167
307k
{
168
307k
    float e, f;
169
170
307k
    e = fabs(m->xx);
171
307k
    f = fabs(m->xy);
172
307k
    if (f > e)
173
56.8k
        e = f;
174
307k
    f = fabs(m->yx);
175
307k
    if (f > e)
176
0
        e = f;
177
307k
    f = fabs(m->yy);
178
307k
    if (f > e)
179
531
        e = f;
180
181
307k
    return e*e;
182
307k
}
183
/*
184
 * Fill with non-standard X and Y stepping.
185
 * ptile is pdevc->colors.pattern.{m,p}_tile.
186
 * tbits_or_tmask is whichever of tbits and tmask is supplying
187
 * the tile size.
188
 * This implementation could be sped up considerably!
189
 */
190
static int
191
tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0,
192
              const gx_color_tile * ptile,
193
              const gx_strip_bitmap * tbits_or_tmask,
194
              int (*fill_proc) (const tile_fill_state_t * ptfs,
195
                                int x, int y, int w, int h))
196
307k
{
197
307k
    int x1 = x0 + w0, y1 = y0 + h0;
198
307k
    int i0, i1, j0, j1, i, j;
199
307k
    gs_matrix step_matrix;      /* translated by phase */
200
307k
    int code;
201
307k
    int check_timeout;
202
#ifdef DEBUG
203
    const gs_memory_t *mem = ptfs->pcdev->memory;
204
#endif
205
206
307k
    ptfs->x0 = x0, ptfs->w0 = w0;
207
307k
    ptfs->y0 = y0, ptfs->h0 = h0;
208
307k
    step_matrix = ptile->step_matrix;
209
307k
    step_matrix.tx -= ptfs->phase.x;
210
307k
    step_matrix.ty -= ptfs->phase.y;
211
307k
    {
212
307k
        gs_rect bbox;           /* bounding box in device space */
213
307k
        gs_rect ibbox;          /* bounding box in stepping space */
214
307k
        double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
215
307k
        double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
216
307k
        double u0, v0, u1, v1;
217
        /* Any difference smaller than error is guaranteed to result in
218
         * less than a pixels difference in the output. Use this as a
219
         * threshold when rounding to allow for inaccuracies in
220
         * floating point maths. This enables us to avoid doing more
221
         * repeats than we need to. */
222
307k
        float error = 1/matrix_expansion(&step_matrix);
223
224
307k
        bbox.p.x = x0, bbox.p.y = y0;
225
307k
        bbox.q.x = x1, bbox.q.y = y1;
226
307k
        if_debug4m('T', mem,
227
307k
          "[T]bbox=(%d,%d) (%d,%d)\n",
228
307k
                    x0, y0, x1, y1);
229
307k
        if_debug6m('T', mem,
230
307k
          "[T]step_matrix=(%g,%g,%g,%g,%g,%g)\n",
231
307k
                    step_matrix.xx, step_matrix.xy, step_matrix.yx, step_matrix.yy, step_matrix.tx, step_matrix.ty);
232
307k
        code = gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
233
307k
        if (code < 0)
234
0
            return code;
235
307k
        if_debug10m('T', mem,
236
307k
          "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
237
307k
                    x0, y0, w0, h0,
238
307k
                    ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
239
307k
                    step_matrix.tx, step_matrix.ty);
240
        /*
241
         * If the pattern is partly transparent and XStep/YStep is smaller
242
         * than the device space BBox, we need to ensure that we cover
243
         * each pixel of the rectangle being filled with *every* pattern
244
         * that overlaps it, not just *some* pattern copy.
245
         */
246
307k
        u0 = ibbox.p.x - max(ptile->bbox.p.x, 0);
247
307k
        v0 = ibbox.p.y - max(ptile->bbox.p.y, 0);
248
307k
        u1 = ibbox.q.x - min(ptile->bbox.q.x, 0);
249
307k
        v1 = ibbox.q.y - min(ptile->bbox.q.y, 0);
250
307k
        if (!ptile->is_simple)
251
307k
            u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
252
307k
        i0 = threshold_floor(u0, error);
253
307k
        j0 = threshold_floor(v0, error);
254
307k
        i1 = threshold_ceil(u1, error);
255
307k
        j1 = threshold_ceil(v1, error);
256
307k
    }
257
307k
    if_debug4m('T', mem, "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
258
319k
#define CHECK_INTERRUPT_THRESHOLD 1024
259
307k
    check_timeout = CHECK_INTERRUPT_THRESHOLD;
260
2.64M
    for (i = i0; i < i1; i++)
261
53.1M
        for (j = j0; j < j1; j++) {
262
50.7M
            int x = (int)fastfloor(step_matrix.xx * i +
263
50.7M
                          step_matrix.yx * j + step_matrix.tx);
264
50.7M
            int y = (int)fastfloor(step_matrix.xy * i +
265
50.7M
                          step_matrix.yy * j + step_matrix.ty);
266
50.7M
            int w = tbits_or_tmask->size.x;
267
50.7M
            int h = tbits_or_tmask->size.y;
268
50.7M
            int xoff, yoff;
269
270
50.7M
            check_timeout--;
271
50.7M
            if (check_timeout == 0) {
272
12.3k
                return_if_interrupt(ptfs->pcdev->memory);
273
12.3k
                check_timeout = CHECK_INTERRUPT_THRESHOLD;
274
12.3k
            }
275
276
50.7M
            if_debug4m('T', mem, "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
277
50.7M
            if (x == INT_MIN || y == INT_MIN) {
278
2
                if_debug0m('T', mem, " underflow!\n");
279
2
                continue;
280
2
            }
281
50.7M
            if (x < x0)
282
17.7M
                xoff = x0 - x, x = x0, w -= xoff;
283
33.0M
            else
284
33.0M
                xoff = 0;
285
50.7M
            if (y < y0)
286
19.3M
                yoff = y0 - y, y = y0, h -= yoff;
287
31.4M
            else
288
31.4M
                yoff = 0;
289
            /* Check for overflow */
290
50.7M
            if (h > 0 && max_int - h < y)
291
0
                h = max_int - y;
292
50.7M
            if (w > 0 && max_int - w < x)
293
0
                w = max_int - x;
294
50.7M
            if (x + w > x1)
295
27.2M
                w = x1 - x;
296
50.7M
            if (y + h > y1)
297
43.7M
                h = y1 - y;
298
50.7M
            if_debug6m('T', mem, "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
299
50.7M
                       x, y, w, h, xoff, yoff);
300
50.7M
            if (w > 0 && h > 0) {
301
5.50M
                if (ptfs->pcdev == (gx_device *)ptfs->cdev)
302
5.46M
                    tile_clip_set_phase(ptfs->cdev,
303
5.46M
                                imod(xoff - x, ptfs->tmask->rep_width),
304
5.46M
                                imod(yoff - y, ptfs->tmask->rep_height));
305
                /* Set the offsets for colored pattern fills */
306
5.50M
                ptfs->xoff = xoff;
307
5.50M
                ptfs->yoff = yoff;
308
5.50M
                code = (*fill_proc) (ptfs, x, y, w, h);
309
5.50M
                if (code < 0)
310
0
                    return code;
311
5.50M
            }
312
50.7M
        }
313
307k
    return 0;
314
307k
}
315
316
/* Fill a rectangle with a colored Pattern. */
317
/* Note that we treat this as "texture" for RasterOp. */
318
static int
319
tile_colored_fill(const tile_fill_state_t * ptfs,
320
                  int x, int y, int w, int h)
321
5.42M
{
322
5.42M
    gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
323
5.42M
    gs_logical_operation_t lop = ptfs->lop;
324
5.42M
    const gx_rop_source_t *source = ptfs->source;
325
5.42M
    gx_device *dev = ptfs->orig_dev;
326
5.42M
    int xoff = ptfs->xoff, yoff = ptfs->yoff;
327
5.42M
    gx_strip_bitmap *bits = &ptile->tbits;
328
5.42M
    const byte *data = bits->data;
329
5.42M
    bool full_transfer = (w == ptfs->w0 && h == ptfs->h0);
330
5.42M
    int code = 0;
331
332
5.42M
    if (source == NULL && lop_no_S_is_T(lop) && dev_proc(dev, copy_planes) != gx_default_copy_planes &&
333
4.06M
        ptfs->num_planes > 0) {
334
834k
            code = (*dev_proc(ptfs->pcdev, copy_planes))
335
834k
                    (ptfs->pcdev, data + bits->raster * yoff, xoff,
336
834k
                     bits->raster,
337
834k
                     (full_transfer ? bits->id : gx_no_bitmap_id),
338
834k
                     x, y, w, h, ptile->tbits.rep_height);
339
4.59M
    } else if (source == NULL && lop_no_S_is_T(lop)) {
340
4.59M
            code = (*dev_proc(ptfs->pcdev, copy_color))
341
4.59M
                    (ptfs->pcdev, data + bits->raster * yoff, xoff,
342
4.59M
                     bits->raster,
343
4.59M
                     (full_transfer ? bits->id : gx_no_bitmap_id),
344
4.59M
                     x, y, w, h);
345
4.59M
    } else {
346
0
        gx_strip_bitmap data_tile;
347
0
        gx_bitmap_id source_id;
348
0
        gx_rop_source_t no_source;
349
350
0
        if (source == NULL)
351
0
            set_rop_no_source(source, no_source, dev);
352
0
        source_id = (full_transfer ? source->id : gx_no_bitmap_id);
353
0
        data_tile.data = (byte *) data;         /* actually const */
354
0
        data_tile.raster = bits->raster;
355
0
        data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x;
356
0
        data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y;
357
0
        data_tile.id = bits->id;
358
0
        data_tile.shift = data_tile.rep_shift = 0;
359
0
        data_tile.num_planes = (ptfs->num_planes > 1 ? ptfs->num_planes : 1);
360
0
        code = (*dev_proc(ptfs->pcdev, strip_copy_rop2))
361
0
                           (ptfs->pcdev,
362
0
                            source->sdata + (y - ptfs->y0) * source->sraster,
363
0
                            source->sourcex + (x - ptfs->x0),
364
0
                            source->sraster, source_id,
365
0
                            (source->use_scolors ? source->scolors : NULL),
366
0
                            &data_tile, NULL,
367
0
                            x, y, w, h,
368
0
                            imod(xoff - x, data_tile.rep_width),
369
0
                            imod(yoff - y, data_tile.rep_height),
370
0
                            lop,
371
0
                            source->planar_height);
372
0
    }
373
5.42M
    return code;
374
5.42M
}
375
376
/* Fill a rectangle with a colored Pattern. */
377
/* Note that we treat this as "texture" for RasterOp. */
378
static int
379
tile_pattern_clist(const tile_fill_state_t * ptfs,
380
                  int x, int y, int w, int h)
381
28.2k
{
382
28.2k
    gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
383
28.2k
    gx_device_clist *cdev = ptile->cdev;
384
28.2k
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev;
385
28.2k
    gx_device *dev = ptfs->orig_dev;
386
28.2k
    int code;
387
388
28.2k
    crdev->offset_map = NULL;
389
28.2k
    code = crdev->page_info.io_procs->rewind(crdev->page_info.bfile, false, NULL);
390
28.2k
    if (code < 0) return code;
391
28.2k
    code = crdev->page_info.io_procs->rewind(crdev->page_info.cfile, false, NULL);
392
28.2k
    if (code < 0) return code;
393
394
28.2k
    clist_render_init(cdev);
395
     /* Check for and get ICC profile table */
396
28.2k
    if (crdev->icc_table == NULL) {
397
28.2k
        code = clist_read_icctable(crdev);
398
28.2k
        if (code < 0)
399
0
            return code;
400
28.2k
    }
401
    /* Also allocate the icc cache for the clist reader */
402
28.2k
    if ( crdev->icc_cache_cl == NULL )
403
28.2k
        crdev->icc_cache_cl = gsicc_cache_new(crdev->memory->thread_safe_memory);
404
28.2k
    if_debug0m('L', dev->memory, "Pattern clist playback begin\n");
405
28.2k
    code = clist_playback_file_bands(playback_action_render,
406
28.2k
                crdev, &crdev->page_info, dev, 0, 0, ptfs->xoff - x, ptfs->yoff - y);
407
28.2k
    if_debug0m('L', dev->memory, "Pattern clist playback end\n");
408
    /* FIXME: it would be preferable to have this persist, but as
409
     * clist_render_init() sets it to NULL, we currently have to
410
     * cleanup before returning. Set to NULL for safety
411
     */
412
28.2k
    rc_decrement(crdev->icc_cache_cl, "tile_pattern_clist");
413
28.2k
    crdev->icc_cache_cl = NULL;
414
28.2k
    return code;
415
28.2k
}
416
417
int
418
gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
419
                             int w, int h, gx_device * dev,
420
                             gs_logical_operation_t lop,
421
                             const gx_rop_source_t * source)
422
7.67M
{
423
7.67M
    gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
424
7.67M
    const gx_rop_source_t *rop_source = source;
425
7.67M
    gx_rop_source_t no_source;
426
7.67M
    gx_strip_bitmap *bits;
427
7.67M
    tile_fill_state_t state;
428
7.67M
    int code;
429
430
7.67M
    if (ptile == 0)             /* null pattern */
431
7.02M
        return 0;
432
646k
    if (rop_source == NULL)
433
640k
        set_rop_no_source(rop_source, no_source, dev);
434
646k
    bits = &ptile->tbits;
435
436
646k
    code = tile_fill_init(&state, pdevc, dev, false);  /* This _may_ allocate state.cdev */
437
646k
    if (code < 0) {
438
0
        goto exit;
439
0
    }
440
646k
    if (ptile->is_simple && ptile->cdev == NULL) {
441
387k
        int px =
442
387k
            imod(-(int)fastfloor(ptile->step_matrix.tx - state.phase.x + 0.5),
443
387k
                 bits->rep_width);
444
387k
        int py =
445
387k
            imod(-(int)fastfloor(ptile->step_matrix.ty - state.phase.y + 0.5),
446
387k
                 bits->rep_height);
447
448
387k
        if (CLIPDEV_INSTALLED)
449
36.3k
            tile_clip_set_phase(state.cdev, px, py);
450
387k
        if (source == NULL && lop_no_S_is_T(lop))
451
380k
            code = (*dev_proc(state.pcdev, strip_tile_rectangle))
452
380k
                (state.pcdev, bits, x, y, w, h,
453
380k
                 gx_no_color_index, gx_no_color_index, px, py);
454
6.80k
        else
455
6.80k
            code = (*dev_proc(state.pcdev, strip_copy_rop2))
456
6.80k
                        (state.pcdev,
457
6.80k
                         rop_source->sdata, rop_source->sourcex,
458
6.80k
                         rop_source->sraster, rop_source->id,
459
6.80k
                         (rop_source->use_scolors ? rop_source->scolors : NULL),
460
6.80k
                         bits, NULL, x, y, w, h, px, py, lop,
461
6.80k
                         rop_source->planar_height);
462
387k
    } else {
463
259k
        state.lop = lop;
464
259k
        state.source = source;
465
259k
        state.orig_dev = dev;
466
259k
        if (ptile->cdev == NULL) {
467
241k
            code = tile_by_steps(&state, x, y, w, h, ptile,
468
241k
                                 &ptile->tbits, tile_colored_fill);
469
241k
        } else {
470
17.1k
            gx_device_clist *cdev = ptile->cdev;
471
17.1k
            gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev;
472
17.1k
            gx_strip_bitmap tbits;
473
474
17.1k
            crdev->yplane.depth = 0; /* Don't know what to set here. */
475
17.1k
            crdev->yplane.shift = 0;
476
17.1k
            crdev->yplane.index = -1;
477
17.1k
            crdev->pages = NULL;
478
17.1k
            crdev->num_pages = 1;
479
17.1k
            state.orig_dev = dev;
480
17.1k
            tbits = ptile->tbits;
481
17.1k
            tbits.size.x = crdev->width;
482
17.1k
            tbits.size.y = crdev->height;
483
17.1k
            code = tile_by_steps(&state, x, y, w, h, ptile,
484
17.1k
                                 &tbits, tile_pattern_clist);
485
17.1k
        }
486
259k
    }
487
646k
exit:
488
646k
    if (CLIPDEV_INSTALLED) {
489
270k
        tile_clip_free((gx_device_tile_clip *)state.cdev);
490
270k
        state.cdev = NULL;
491
270k
    }
492
646k
    return code;
493
646k
}
494
495
/* Fill a rectangle with an uncolored Pattern. */
496
/* Note that we treat this as "texture" for RasterOp. */
497
static int
498
tile_masked_fill(const tile_fill_state_t * ptfs,
499
                 int x, int y, int w, int h)
500
48.5k
{
501
48.5k
    if (ptfs->source == NULL)
502
48.5k
        return (*ptfs->fill_rectangle)
503
48.5k
            (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL);
504
0
    else {
505
0
        const gx_rop_source_t *source = ptfs->source;
506
0
        gx_rop_source_t step_source;
507
508
0
        step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster;
509
0
        step_source.sourcex = source->sourcex + (x - ptfs->x0);
510
0
        step_source.sraster = source->sraster;
511
0
        step_source.id = (w == ptfs->w0 && h == ptfs->h0 ?
512
0
                          source->id : gx_no_bitmap_id);
513
0
        step_source.scolors[0] = source->scolors[0];
514
0
        step_source.scolors[1] = source->scolors[1];
515
0
        step_source.planar_height = source->planar_height;
516
0
        step_source.use_scolors = source->use_scolors;
517
0
        return (*ptfs->fill_rectangle)
518
0
            (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source);
519
0
    }
520
48.5k
}
521
int
522
gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc,
523
                            int x, int y, int w, int h, gx_device * dev,
524
                            gs_logical_operation_t lop,
525
                            const gx_rop_source_t * source)
526
91.4k
{
527
91.4k
    gx_color_tile *ptile = pdevc->mask.m_tile;
528
91.4k
    tile_fill_state_t state;
529
91.4k
    int code;
530
531
    /*
532
     * This routine should never be called if there is no masking,
533
     * but we leave the checks below just in case.
534
     */
535
91.4k
    code = tile_fill_init(&state, pdevc, dev, true);
536
91.4k
    if (code < 0)
537
1
        goto exit;
538
91.4k
    if (state.pcdev == dev || ptile->is_simple)
539
83.6k
        code = (*gx_dc_type_data_pure.fill_rectangle)
540
83.6k
            (pdevc, x, y, w, h, state.pcdev, lop, source);
541
7.78k
    else {
542
7.78k
        state.lop = lop;
543
7.78k
        state.source = source;
544
7.78k
        state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle;
545
7.78k
        code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
546
7.78k
                             tile_masked_fill);
547
7.78k
    }
548
91.4k
exit:
549
91.4k
    if (CLIPDEV_INSTALLED) {
550
91.4k
        tile_clip_free((gx_device_tile_clip *)state.cdev);
551
91.4k
        state.cdev = NULL;
552
91.4k
    }
553
91.4k
    return code;
554
91.4k
}
555
556
int
557
gx_dc_devn_masked_fill_rect(const gx_device_color * pdevc,
558
                            int x, int y, int w, int h, gx_device * dev,
559
                            gs_logical_operation_t lop,
560
                            const gx_rop_source_t * source)
561
12
{
562
12
    gx_color_tile *ptile = pdevc->mask.m_tile;
563
12
    tile_fill_state_t state;
564
12
    int code;
565
566
    /*
567
     * This routine should never be called if there is no masking,
568
     * but we leave the checks below just in case.
569
     */
570
12
    code = tile_fill_init(&state, pdevc, dev, true);
571
12
    if (code < 0)
572
0
        goto exit;
573
12
    if (state.pcdev == dev || ptile->is_simple) {
574
0
        gx_device_color dcolor = *pdevc;
575
576
0
        if (ptile == NULL) {
577
0
        int k;
578
579
            /* Have to set the pdevc to a non mask type since the pattern was stored as non-masking */
580
0
            dcolor.type = gx_dc_type_devn;
581
0
            for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
582
0
                dcolor.colors.devn.values[k] = pdevc->colors.devn.values[k];
583
0
            }
584
0
        }
585
0
        code = (*gx_dc_type_data_devn.fill_rectangle)
586
0
            (&dcolor, x, y, w, h, state.pcdev, lop, source);
587
12
    } else {
588
12
        state.lop = lop;
589
12
        state.source = source;
590
12
        state.fill_rectangle = gx_dc_type_data_devn.fill_rectangle;
591
12
        code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
592
12
                             tile_masked_fill);
593
12
    }
594
12
exit:
595
12
    if (CLIPDEV_INSTALLED) {
596
12
        tile_clip_free((gx_device_tile_clip *)state.cdev);
597
12
        state.cdev = NULL;
598
12
    }
599
12
    return code;
600
12
}
601
602
int
603
gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc,
604
                              int x, int y, int w, int h, gx_device * dev,
605
                              gs_logical_operation_t lop,
606
                              const gx_rop_source_t * source)
607
32
{
608
32
    gx_color_tile *ptile = pdevc->mask.m_tile;
609
32
    tile_fill_state_t state;
610
32
    int code;
611
612
32
    code = tile_fill_init(&state, pdevc, dev, true);
613
32
    if (code < 0)
614
0
        goto exit;
615
32
    if (state.pcdev == dev || ptile->is_simple)
616
12
        code = (*gx_dc_type_data_ht_binary.fill_rectangle)
617
12
            (pdevc, x, y, w, h, state.pcdev, lop, source);
618
20
    else {
619
20
        state.lop = lop;
620
20
        state.source = source;
621
20
        state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle;
622
20
        code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
623
20
                             tile_masked_fill);
624
20
    }
625
32
exit:
626
32
    if (CLIPDEV_INSTALLED) {
627
32
        tile_clip_free((gx_device_tile_clip *)state.cdev);
628
32
        state.cdev = NULL;
629
32
    }
630
32
    return code;
631
32
}
632
633
int
634
gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc,
635
                               int x, int y, int w, int h, gx_device * dev,
636
                               gs_logical_operation_t lop,
637
                               const gx_rop_source_t * source)
638
1.16k
{
639
1.16k
    gx_color_tile *ptile = pdevc->mask.m_tile;
640
1.16k
    tile_fill_state_t state;
641
1.16k
    int code;
642
643
1.16k
    code = tile_fill_init(&state, pdevc, dev, true);
644
1.16k
    if (code < 0)
645
0
        goto exit;
646
1.16k
    if (state.pcdev == dev || ptile->is_simple)
647
12
        code = (*gx_dc_type_data_ht_colored.fill_rectangle)
648
12
            (pdevc, x, y, w, h, state.pcdev, lop, source);
649
1.15k
    else {
650
1.15k
        state.lop = lop;
651
1.15k
        state.source = source;
652
1.15k
        state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle;
653
1.15k
        code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
654
1.15k
                             tile_masked_fill);
655
1.15k
    }
656
1.16k
exit:
657
1.16k
    if (CLIPDEV_INSTALLED) {
658
1.16k
        tile_clip_free((gx_device_tile_clip *)state.cdev);
659
1.16k
        state.cdev = NULL;
660
1.16k
    }
661
1.16k
    return code;
662
1.16k
}
663
664
/*
665
 * This is somewhat a clone of the tile_by_steps function but one
666
 * that performs filling from and to pdf14dev (transparency) buffers.
667
 * At some point it may be desirable to do some optimization here.
668
 */
669
static int
670
tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0,
671
              gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile,
672
              int native16)
673
16.1k
{
674
16.1k
    int x1 = x0 + w0, y1 = y0 + h0;
675
16.1k
    int i0, i1, j0, j1, i, j;
676
16.1k
    gs_matrix step_matrix;      /* translated by phase */
677
16.1k
    gx_pattern_trans_t *ptrans_pat = ptile->ttrans;
678
#ifdef DEBUG
679
    const gs_memory_t *mem = ptile->ttrans->mem;
680
#endif
681
16.1k
    int code;
682
683
16.1k
    ptfs->x0 = x0, ptfs->w0 = w0;
684
16.1k
    ptfs->y0 = y0, ptfs->h0 = h0;
685
16.1k
    step_matrix = ptile->step_matrix;
686
16.1k
    step_matrix.tx -= ptfs->phase.x;
687
16.1k
    step_matrix.ty -= ptfs->phase.y;
688
16.1k
    {
689
16.1k
        gs_rect bbox;           /* bounding box in device space */
690
16.1k
        gs_rect ibbox;          /* bounding box in stepping space */
691
16.1k
        double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
692
16.1k
        double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
693
16.1k
        double u0, v0, u1, v1;
694
695
16.1k
        bbox.p.x = x0, bbox.p.y = y0;
696
16.1k
        bbox.q.x = x1, bbox.q.y = y1;
697
16.1k
        code = gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
698
16.1k
        if (code < 0)
699
0
            return code;
700
16.1k
        if_debug10m('T', mem,
701
16.1k
          "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
702
16.1k
                    x0, y0, w0, h0,
703
16.1k
                    ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
704
16.1k
                    step_matrix.tx, step_matrix.ty);
705
        /*
706
         * If the pattern is partly transparent and XStep/YStep is smaller
707
         * than the device space BBox, we need to ensure that we cover
708
         * each pixel of the rectangle being filled with *every* pattern
709
         * that overlaps it, not just *some* pattern copy.
710
         */
711
16.1k
        u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
712
16.1k
        v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
713
16.1k
        u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
714
16.1k
        v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
715
16.1k
        if (!ptile->is_simple)
716
16.1k
            u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
717
16.1k
        i0 = (int)fastfloor(u0);
718
16.1k
        j0 = (int)fastfloor(v0);
719
16.1k
        i1 = (int)ceil(u1);
720
16.1k
        j1 = (int)ceil(v1);
721
16.1k
    }
722
16.1k
    if_debug4m('T', mem, "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
723
3.84M
    for (i = i0; i < i1; i++)
724
16.2M
        for (j = j0; j < j1; j++) {
725
12.4M
            int x = (int)fastfloor(step_matrix.xx * i +
726
12.4M
                          step_matrix.yx * j + step_matrix.tx);
727
12.4M
            int y = (int)fastfloor(step_matrix.xy * i +
728
12.4M
                          step_matrix.yy * j + step_matrix.ty);
729
12.4M
            int w = ptrans_pat->width;
730
12.4M
            int h = ptrans_pat->height;
731
12.4M
            int xoff, yoff;
732
12.4M
            int px, py;
733
734
12.4M
            if_debug4m('T', mem, "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
735
12.4M
            if (x < x0)
736
69.8k
                xoff = x0 - x, x = x0, w -= xoff;
737
12.3M
            else
738
12.3M
                xoff = 0;
739
12.4M
            if (y < y0)
740
3.86M
                yoff = y0 - y, y = y0, h -= yoff;
741
8.55M
            else
742
8.55M
                yoff = 0;
743
12.4M
            if (x + w > x1)
744
12.3M
                w = x1 - x;
745
12.4M
            if (y + h > y1)
746
56.7k
                h = y1 - y;
747
12.4M
            if_debug6m('T', mem, "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
748
12.4M
                       x, y, w, h, xoff, yoff);
749
12.4M
            if (w > 0 && h > 0) {
750
751
9.50k
                px = imod(xoff - x, ptile->ttrans->width);
752
9.50k
                py = imod(yoff - y, ptile->ttrans->height);
753
754
                /* Set the offsets for colored pattern fills */
755
9.50k
                ptfs->xoff = xoff;
756
9.50k
                ptfs->yoff = yoff;
757
758
                /* We only go through blending during tiling, if there was overlap
759
                   as defined by the step matrix and the bounding box.
760
                   Ignore if the area is outside the fill_trans_buffer.rect (bug 700719) */
761
9.50k
                if (x > fill_trans_buffer->rect.q.x || x+w < 0 ||
762
9.50k
                    y > fill_trans_buffer->rect.q.y || y+h < 0)
763
0
                    continue; /* skip the fill (can breakpoint here) */
764
9.50k
                ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile,
765
9.50k
                    fill_trans_buffer, native16);
766
9.50k
            }
767
12.4M
        }
768
16.1k
    return 0;
769
16.1k
}
770
771
static void
772
be_rev_cpy(uint16_t *dst,const uint16_t *src,int n)
773
0
{
774
0
    for (; n != 0; n--) {
775
0
        uint16_t in = *src++;
776
0
        ((byte *)dst)[0] = in>>8;
777
0
        ((byte *)dst)[1] = in;
778
0
        dst++;
779
0
    }
780
0
}
781
782
/* This does the case of tiling with simple tiles.  Since it is not commented
783
 * anywhere note that simple means that the tile size is the same as the step
784
 * matrix size and the cross terms in the step matrix are 0.  Hence a simple
785
 * case of tile replication. This needs to be optimized.  */
786
/* Our source tile runs (conceptually) from (0,0) to
787
 * (ptile->ttrans->width, ptile->ttrans->height). In practise, only a limited
788
 * section of this (ptile->rect) may actually be used. */
789
void
790
tile_rect_trans_simple(int xmin, int ymin, int xmax, int ymax,
791
                       int px, int py, const gx_color_tile *ptile,
792
                       gx_pattern_trans_t *fill_trans_buffer,
793
                       int native16)
794
23.2k
{
795
23.2k
    int kk, jj, ii, h, w;
796
23.2k
    int buff_out_y_offset, buff_out_x_offset;
797
23.2k
    unsigned char *ptr_out, *ptr_in, *buff_out, *buff_in, *ptr_out_temp;
798
23.2k
    unsigned char *row_ptr;
799
23.2k
    int in_row_offset;
800
23.2k
    int dx, dy;
801
23.2k
    int left_rem_end, left_width, num_full_tiles, right_tile_width;
802
23.2k
    int left_copy_rem_end, left_copy_width, left_copy_offset, left_copy_start;
803
23.2k
    int mid_copy_width, right_copy_width;
804
23.2k
    int tile_width  = ptile->ttrans->width;
805
23.2k
    int tile_height = ptile->ttrans->height;
806
23.2k
    int src_planes = fill_trans_buffer->n_chan + (fill_trans_buffer->has_tags ? 1 : 0);
807
23.2k
    pdf14_buf *buf = fill_trans_buffer->buf;
808
23.2k
    bool deep = fill_trans_buffer->deep;
809
810
    /* Update the bbox in the topmost stack entry to reflect the fact that we
811
     * have drawn into it. FIXME: This makes the groups too large! */
812
23.2k
    if (buf->dirty.p.x > xmin)
813
9.42k
        buf->dirty.p.x = xmin;
814
23.2k
    if (buf->dirty.p.y > ymin)
815
9.04k
        buf->dirty.p.y = ymin;
816
23.2k
    if (buf->dirty.q.x < xmax)
817
9.42k
        buf->dirty.q.x = xmax;
818
23.2k
    if (buf->dirty.q.y < ymax)
819
15.2k
        buf->dirty.q.y = ymax;
820
23.2k
    buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y;
821
23.2k
    buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x;
822
823
23.2k
    buff_out = fill_trans_buffer->transbytes +
824
23.2k
        buff_out_y_offset * fill_trans_buffer->rowstride +
825
23.2k
        (buff_out_x_offset<<deep);
826
827
23.2k
    buff_in = ptile->ttrans->transbytes;
828
829
23.2k
    h = ymax - ymin;
830
23.2k
    w = xmax - xmin;
831
832
23.2k
    if (h <= 0 || w <= 0) return;
833
834
    /* Calc dx, dy within the entire (conceptual) input tile. */
835
15.2k
    dx = (xmin + px) % tile_width;
836
15.2k
    dy = (ymin + py) % tile_height;
837
838
    /* To speed this up, the inner loop on the width is implemented with
839
     * memcpys where we have a left remainder, full tiles and a right
840
     * remainder. Depending upon the rect that we are filling we may have
841
     * only one of these three portions, or two or all three.  We compute
842
     * the parts now outside the loops. */
843
844
    /* Left remainder part */
845
15.2k
    left_rem_end = min(dx+w,tile_width);
846
15.2k
    left_width = left_rem_end - dx;
847
15.2k
    left_copy_start = max(dx,ptile->ttrans->rect.p.x);
848
15.2k
    left_copy_rem_end = min(dx+w,ptile->ttrans->rect.q.x);
849
15.2k
    left_copy_width = left_copy_rem_end - left_copy_start;
850
15.2k
    if (left_copy_width < 0)
851
0
        left_copy_width = 0;
852
15.2k
    left_copy_offset = (left_copy_start-ptile->ttrans->rect.p.x)<<deep;
853
854
    /* Now the middle part */
855
15.2k
    num_full_tiles = (int)fastfloor((float) (w - left_width)/ (float) tile_width);
856
15.2k
    mid_copy_width = ptile->ttrans->rect.q.x - ptile->ttrans->rect.p.x;
857
858
    /* Now the right part */
859
15.2k
    right_tile_width = w - num_full_tiles*tile_width - left_width;
860
15.2k
    right_copy_width = right_tile_width - ptile->ttrans->rect.p.x;
861
15.2k
    if (right_copy_width > ptile->ttrans->rect.q.x)
862
0
        right_copy_width = ptile->ttrans->rect.q.x;
863
15.2k
    right_copy_width -= ptile->ttrans->rect.p.x;
864
15.2k
    if (right_copy_width < 0)
865
0
        right_copy_width = 0;
866
867
15.2k
    if (deep && native16) {
868
        /* fill_trans_buffer is in native endian. ptile is in big endian. */
869
        /* Convert as we copy. */
870
0
        for (kk = 0; kk < src_planes; kk++) {
871
872
0
            ptr_out = buff_out + kk * fill_trans_buffer->planestride;
873
0
            ptr_in  = buff_in  + kk * ptile->ttrans->planestride;
874
0
            if (fill_trans_buffer->has_shape && kk == fill_trans_buffer->n_chan)
875
0
                ptr_out += fill_trans_buffer->planestride; /* tag plane follows shape plane */
876
877
0
            for (jj = 0; jj < h; jj++, ptr_out += fill_trans_buffer->rowstride) {
878
879
0
                in_row_offset = ((jj + dy) % ptile->ttrans->height);
880
0
                if (in_row_offset >= ptile->ttrans->rect.q.y)
881
0
                    continue;
882
0
                in_row_offset -= ptile->ttrans->rect.p.y;
883
0
                if (in_row_offset < 0)
884
0
                    continue;
885
0
                row_ptr = ptr_in + in_row_offset * ptile->ttrans->rowstride;
886
887
                 /* This is the case when we have no blending. */
888
0
                ptr_out_temp = ptr_out;
889
890
                /* Left part */
891
0
                be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)(row_ptr + left_copy_offset), left_copy_width);
892
0
                ptr_out_temp += left_width<<deep;
893
894
                /* Now the full tiles */
895
896
0
                for ( ii = 0; ii < num_full_tiles; ii++){
897
0
                    be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)row_ptr, mid_copy_width);
898
0
                    ptr_out_temp += tile_width<<deep;
899
0
                }
900
901
                /* Now the remainder */
902
0
                be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)row_ptr, right_copy_width);
903
0
            }
904
0
        }
905
15.2k
    } else {
906
62.7k
        for (kk = 0; kk < src_planes; kk++) {
907
908
47.4k
            ptr_out = buff_out + kk * fill_trans_buffer->planestride;
909
47.4k
            ptr_in  = buff_in  + kk * ptile->ttrans->planestride;
910
47.4k
            if (fill_trans_buffer->has_shape && kk == fill_trans_buffer->n_chan)
911
0
                ptr_out += fill_trans_buffer->planestride; /* tag plane follows shape plane */
912
913
348k
            for (jj = 0; jj < h; jj++, ptr_out += fill_trans_buffer->rowstride) {
914
915
301k
                in_row_offset = ((jj + dy) % ptile->ttrans->height);
916
301k
                if (in_row_offset >= ptile->ttrans->rect.q.y)
917
0
                    continue;
918
301k
                in_row_offset -= ptile->ttrans->rect.p.y;
919
301k
                if (in_row_offset < 0)
920
0
                    continue;
921
301k
                row_ptr = ptr_in + in_row_offset * ptile->ttrans->rowstride;
922
923
                 /* This is the case when we have no blending. */
924
301k
                ptr_out_temp = ptr_out;
925
926
                /* Left part */
927
301k
                memcpy( ptr_out_temp, row_ptr + left_copy_offset, left_copy_width<<deep);
928
301k
                ptr_out_temp += left_width<<deep;
929
930
                /* Now the full tiles */
931
932
400k
                for ( ii = 0; ii < num_full_tiles; ii++){
933
99.2k
                    memcpy( ptr_out_temp, row_ptr, mid_copy_width<<deep);
934
99.2k
                    ptr_out_temp += tile_width<<deep;
935
99.2k
                }
936
937
                /* Now the remainder */
938
301k
                memcpy( ptr_out_temp, row_ptr, right_copy_width<<deep);
939
301k
            }
940
47.4k
        }
941
15.2k
    }
942
943
    /* If the group we are filling has a shape plane fill that now */
944
    /* Note:  Since this was a virgin group push we can just blast it with
945
     * 255 */
946
15.2k
    if (fill_trans_buffer->has_shape) {
947
0
        ptr_out = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride;
948
0
        for (jj = 0; jj < h; jj++,ptr_out += fill_trans_buffer->rowstride) {
949
0
            memset(ptr_out, 255, w<<deep);
950
0
        }
951
0
    }
952
15.2k
}
953
954
/* This does the case of tiling with non simple tiles.  In this case, the
955
 * tiles may overlap and so we really need to do blending within the existing
956
 * buffer.  This needs some serious optimization. */
957
static void
958
do_tile_rect_trans_blend(int xmin, int ymin, int xmax, int ymax,
959
                         int px, int py, const gx_color_tile *ptile,
960
                         gx_pattern_trans_t *fill_trans_buffer)
961
738
{
962
738
    int kk, jj, ii, h, w;
963
738
    int buff_out_y_offset, buff_out_x_offset;
964
738
    unsigned char *buff_out, *buff_in;
965
738
    unsigned char *buff_ptr, *row_ptr_in, *row_ptr_out;
966
738
    unsigned char *tile_ptr;
967
738
    int in_row_offset;
968
738
    int dx, dy;
969
738
    byte src[PDF14_MAX_PLANES];
970
738
    byte dst[PDF14_MAX_PLANES];
971
738
    int tile_width  = ptile->ttrans->width;
972
738
    int tile_height = ptile->ttrans->height;
973
738
    int num_chan    = ptile->ttrans->n_chan;  /* Includes alpha */
974
738
    int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0);
975
738
    pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14;
976
977
738
    if (fill_trans_buffer->has_tags == 0)
978
738
        tag_offset = 0;
979
980
738
    buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y;
981
738
    buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x;
982
983
738
    h = ymax - ymin;
984
738
    w = xmax - xmin;
985
986
738
    if (h <= 0 || w <= 0) return;
987
988
    /* Calc dx, dy within the entire (conceptual) input tile. */
989
738
    dx = (xmin + px) % tile_width;
990
738
    dy = (ymin + py) % tile_height;
991
992
738
    buff_out = fill_trans_buffer->transbytes +
993
738
        buff_out_y_offset * fill_trans_buffer->rowstride +
994
738
        buff_out_x_offset;
995
996
738
    buff_in = ptile->ttrans->transbytes;
997
998
11.3k
    for (jj = 0; jj < h; jj++){
999
1000
10.6k
        in_row_offset = (jj + dy) % ptile->ttrans->height;
1001
10.6k
        if (in_row_offset >= ptile->ttrans->rect.q.y)
1002
0
            continue;
1003
10.6k
        in_row_offset -= ptile->ttrans->rect.p.y;
1004
10.6k
        if (in_row_offset < 0)
1005
0
            continue;
1006
10.6k
        row_ptr_in = buff_in + in_row_offset * ptile->ttrans->rowstride;
1007
1008
10.6k
        row_ptr_out = buff_out + jj * fill_trans_buffer->rowstride;
1009
1010
11.4M
        for (ii = 0; ii < w; ii++) {
1011
11.3M
            int x_in_offset = (dx + ii) % ptile->ttrans->width;
1012
1013
11.3M
            if (x_in_offset >= ptile->ttrans->rect.q.x)
1014
0
                continue;
1015
11.3M
            x_in_offset -= ptile->ttrans->rect.p.x;
1016
11.3M
            if (x_in_offset < 0)
1017
0
                continue;
1018
11.3M
            tile_ptr = row_ptr_in + x_in_offset;
1019
11.3M
            buff_ptr = row_ptr_out + ii;
1020
1021
            /* We need to blend here.  The blending mode from the current
1022
               imager state is used.
1023
            */
1024
1025
            /* The color values. This needs to be optimized */
1026
48.0M
            for (kk = 0; kk < num_chan; kk++) {
1027
36.7M
                dst[kk] = *(buff_ptr + kk * fill_trans_buffer->planestride);
1028
36.7M
                src[kk] = *(tile_ptr + kk * ptile->ttrans->planestride);
1029
36.7M
            }
1030
1031
            /* Blend */
1032
11.3M
            art_pdf_composite_pixel_alpha_8(dst, src, ptile->ttrans->n_chan-1,
1033
11.3M
                                            ptile->blending_mode, ptile->ttrans->n_chan-1,
1034
11.3M
                                            ptile->ttrans->blending_procs, p14dev);
1035
1036
            /* Store the color values */
1037
48.0M
            for (kk = 0; kk < num_chan; kk++) {
1038
36.7M
                *(buff_ptr + kk * fill_trans_buffer->planestride) = dst[kk];
1039
36.7M
            }
1040
            /* Now handle the blending of the tag. NB: dst tag_offset follows shape */
1041
11.3M
            if (tag_offset > 0) {
1042
0
                int src_tag = *(tile_ptr + num_chan * ptile->ttrans->planestride);
1043
0
                int dst_tag = *(buff_ptr + tag_offset * fill_trans_buffer->planestride);
1044
1045
0
                dst_tag |= src_tag; /* simple blend combines tags */
1046
0
                *(buff_ptr + tag_offset * fill_trans_buffer->planestride) = dst_tag;
1047
0
            }
1048
11.3M
        }
1049
10.6k
    }
1050
1051
    /* If the group we are filling has a shape plane fill that now */
1052
    /* Note:  Since this was a virgin group push we can just blast it with
1053
     * 255 */
1054
738
    if (fill_trans_buffer->has_shape) {
1055
0
        buff_ptr = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride;
1056
1057
0
        for (jj = 0; jj < h; jj++) {
1058
0
            memset(buff_ptr, 255, w);
1059
0
            buff_ptr += fill_trans_buffer->rowstride;
1060
0
        }
1061
0
    }
1062
738
}
1063
1064
/* In this version, source data is big endian, dest is native endian */
1065
static void
1066
do_tile_rect_trans_blend_16(int xmin, int ymin, int xmax, int ymax,
1067
                            int px, int py, const gx_color_tile *ptile,
1068
                            gx_pattern_trans_t *fill_trans_buffer)
1069
0
{
1070
0
    int kk, jj, ii, h, w;
1071
0
    int buff_out_y_offset, buff_out_x_offset;
1072
0
    uint16_t *buff_out, *buff_in;
1073
0
    uint16_t *buff_ptr, *row_ptr_in, *row_ptr_out;
1074
0
    uint16_t *tile_ptr;
1075
0
    int in_row_offset;
1076
0
    int dx, dy;
1077
0
    uint16_t src[PDF14_MAX_PLANES];
1078
0
    uint16_t dst[PDF14_MAX_PLANES];
1079
0
    int tile_width  = ptile->ttrans->width;
1080
0
    int tile_height = ptile->ttrans->height;
1081
0
    int num_chan    = ptile->ttrans->n_chan;  /* Includes alpha */
1082
0
    int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0);
1083
0
    pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14;
1084
1085
0
    if (fill_trans_buffer->has_tags == 0)
1086
0
        tag_offset = 0;
1087
1088
0
    buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y;
1089
0
    buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x;
1090
1091
0
    h = ymax - ymin;
1092
0
    w = xmax - xmin;
1093
1094
0
    if (h <= 0 || w <= 0) return;
1095
1096
    /* Calc dx, dy within the entire (conceptual) input tile. */
1097
0
    dx = (xmin + px) % tile_width;
1098
0
    dy = (ymin + py) % tile_height;
1099
1100
0
    buff_out = (uint16_t *)(void *)(fill_trans_buffer->transbytes +
1101
0
                                    buff_out_y_offset * fill_trans_buffer->rowstride +
1102
0
                                    buff_out_x_offset*2);
1103
1104
0
    buff_in = (uint16_t *)(void *)ptile->ttrans->transbytes;
1105
1106
0
    for (jj = 0; jj < h; jj++){
1107
1108
0
        in_row_offset = (jj + dy) % ptile->ttrans->height;
1109
0
        if (in_row_offset >= ptile->ttrans->rect.q.y)
1110
0
            continue;
1111
0
        in_row_offset -= ptile->ttrans->rect.p.y;
1112
0
        if (in_row_offset < 0)
1113
0
            continue;
1114
0
        row_ptr_in = buff_in + in_row_offset * (ptile->ttrans->rowstride>>1);
1115
1116
0
        row_ptr_out = buff_out + jj * (fill_trans_buffer->rowstride>>1);
1117
1118
0
        for (ii = 0; ii < w; ii++) {
1119
0
            int x_in_offset = (dx + ii) % ptile->ttrans->width;
1120
1121
0
            if (x_in_offset >= ptile->ttrans->rect.q.x)
1122
0
                continue;
1123
0
            x_in_offset -= ptile->ttrans->rect.p.x;
1124
0
            if (x_in_offset < 0)
1125
0
                continue;
1126
0
            tile_ptr = row_ptr_in + x_in_offset;
1127
0
            buff_ptr = row_ptr_out + ii;
1128
1129
            /* We need to blend here.  The blending mode from the current
1130
               imager state is used.
1131
            */
1132
1133
            /* Data is stored in big endian, but must be processed in native */
1134
0
#define GET16_BE2NATIVE(v) \
1135
0
    ((((byte *)(v))[0]<<8) | (((byte *)(v))[1]))
1136
1137
            /* The color values. This needs to be optimized */
1138
0
            for (kk = 0; kk < num_chan; kk++) {
1139
0
                dst[kk] = *(buff_ptr + kk * (fill_trans_buffer->planestride>>1));
1140
0
                src[kk] = GET16_BE2NATIVE(tile_ptr + kk * (ptile->ttrans->planestride>>1));
1141
0
            }
1142
1143
            /* Blend */
1144
0
            art_pdf_composite_pixel_alpha_16(dst, src, ptile->ttrans->n_chan-1,
1145
0
                                             ptile->blending_mode, ptile->ttrans->n_chan-1,
1146
0
                                             ptile->ttrans->blending_procs, p14dev);
1147
1148
            /* Store the color values */
1149
0
            for (kk = 0; kk < num_chan; kk++) {
1150
0
                *(buff_ptr + kk * (fill_trans_buffer->planestride>>1)) = dst[kk];
1151
0
            }
1152
            /* Now handle the blending of the tag. NB: dst tag_offset follows shape */
1153
0
            if (tag_offset > 0) {
1154
0
                int src_tag = GET16_BE2NATIVE(tile_ptr + (num_chan * ptile->ttrans->planestride>>1));
1155
0
                int dst_tag = *(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1));
1156
1157
0
                dst_tag |= src_tag; /* simple blend combines tags */
1158
0
                *(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1)) = dst_tag;
1159
0
            }
1160
0
        }
1161
0
    }
1162
0
#undef GET16_BE2NATIVE
1163
1164
    /* If the group we are filling has a shape plane fill that now */
1165
    /* Note:  Since this was a virgin group push we can just blast it with
1166
     * 255 */
1167
0
    if (fill_trans_buffer->has_shape) {
1168
0
        buff_ptr = buff_out + fill_trans_buffer->n_chan * (fill_trans_buffer->planestride>>1);
1169
1170
0
        for (jj = 0; jj < h; jj++) {
1171
0
            memset(buff_ptr, 255, w*2);
1172
0
            buff_ptr += fill_trans_buffer->rowstride>>1;
1173
0
        }
1174
0
    }
1175
0
}
1176
1177
/* In this version, both source and dest data is big endian */
1178
static void
1179
do_tile_rect_trans_blend_16be(int xmin, int ymin, int xmax, int ymax,
1180
                              int px, int py, const gx_color_tile *ptile,
1181
                              gx_pattern_trans_t *fill_trans_buffer)
1182
0
{
1183
0
    int kk, jj, ii, h, w;
1184
0
    int buff_out_y_offset, buff_out_x_offset;
1185
0
    uint16_t *buff_out, *buff_in;
1186
0
    uint16_t *buff_ptr, *row_ptr_in, *row_ptr_out;
1187
0
    uint16_t *tile_ptr;
1188
0
    int in_row_offset;
1189
0
    int dx, dy;
1190
0
    uint16_t src[PDF14_MAX_PLANES];
1191
0
    uint16_t dst[PDF14_MAX_PLANES];
1192
0
    int tile_width  = ptile->ttrans->width;
1193
0
    int tile_height = ptile->ttrans->height;
1194
0
    int num_chan    = ptile->ttrans->n_chan;  /* Includes alpha */
1195
0
    int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0);
1196
0
    pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14;
1197
1198
0
    if (fill_trans_buffer->has_tags == 0)
1199
0
        tag_offset = 0;
1200
1201
0
    buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y;
1202
0
    buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x;
1203
1204
0
    h = ymax - ymin;
1205
0
    w = xmax - xmin;
1206
1207
0
    if (h <= 0 || w <= 0) return;
1208
1209
    /* Calc dx, dy within the entire (conceptual) input tile. */
1210
0
    dx = (xmin + px) % tile_width;
1211
0
    dy = (ymin + py) % tile_height;
1212
1213
0
    buff_out = (uint16_t *)(void *)(fill_trans_buffer->transbytes +
1214
0
                                    buff_out_y_offset * fill_trans_buffer->rowstride +
1215
0
                                    buff_out_x_offset*2);
1216
1217
0
    buff_in = (uint16_t *)(void *)ptile->ttrans->transbytes;
1218
1219
0
    for (jj = 0; jj < h; jj++){
1220
1221
0
        in_row_offset = (jj + dy) % ptile->ttrans->height;
1222
0
        if (in_row_offset >= ptile->ttrans->rect.q.y)
1223
0
            continue;
1224
0
        in_row_offset -= ptile->ttrans->rect.p.y;
1225
0
        if (in_row_offset < 0)
1226
0
            continue;
1227
0
        row_ptr_in = buff_in + in_row_offset * (ptile->ttrans->rowstride>>1);
1228
1229
0
        row_ptr_out = buff_out + jj * (fill_trans_buffer->rowstride>>1);
1230
1231
0
        for (ii = 0; ii < w; ii++) {
1232
0
            int x_in_offset = (dx + ii) % ptile->ttrans->width;
1233
1234
0
            if (x_in_offset >= ptile->ttrans->rect.q.x)
1235
0
                continue;
1236
0
            x_in_offset -= ptile->ttrans->rect.p.x;
1237
0
            if (x_in_offset < 0)
1238
0
                continue;
1239
0
            tile_ptr = row_ptr_in + x_in_offset;
1240
0
            buff_ptr = row_ptr_out + ii;
1241
1242
            /* We need to blend here.  The blending mode from the current
1243
               imager state is used.
1244
            */
1245
1246
            /* Data is stored in big endian, but must be processed in native */
1247
0
#define GET16_BE2NATIVE(v) \
1248
0
    ((((byte *)(v))[0]<<8) | (((byte *)(v))[1]))
1249
0
#define PUT16_NATIVE2BE(p,v) \
1250
0
    ((((byte *)(p))[0] = v>>8), (((byte *)(p))[1] = v))
1251
1252
            /* The color values. This needs to be optimized */
1253
0
            for (kk = 0; kk < num_chan; kk++) {
1254
0
                dst[kk] = GET16_BE2NATIVE(buff_ptr + kk * (fill_trans_buffer->planestride>>1));
1255
0
                src[kk] = GET16_BE2NATIVE(tile_ptr + kk * (ptile->ttrans->planestride>>1));
1256
0
            }
1257
1258
            /* Blend */
1259
0
            art_pdf_composite_pixel_alpha_16(dst, src, ptile->ttrans->n_chan-1,
1260
0
                                             ptile->blending_mode, ptile->ttrans->n_chan-1,
1261
0
                                             ptile->ttrans->blending_procs, p14dev);
1262
1263
            /* Store the color values */
1264
0
            for (kk = 0; kk < num_chan; kk++) {
1265
0
                PUT16_NATIVE2BE(buff_ptr + kk * (fill_trans_buffer->planestride>>1), dst[kk]);
1266
0
            }
1267
            /* Now handle the blending of the tag. NB: dst tag_offset follows shape */
1268
0
            if (tag_offset > 0) {
1269
0
                int src_tag = GET16_BE2NATIVE(tile_ptr + (num_chan * ptile->ttrans->planestride>>1));
1270
0
                int dst_tag = GET16_BE2NATIVE(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1));
1271
1272
0
                dst_tag |= src_tag; /* simple blend combines tags */
1273
0
                PUT16_NATIVE2BE(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1), dst_tag);
1274
0
            }
1275
0
        }
1276
0
    }
1277
1278
    /* If the group we are filling has a shape plane fill that now */
1279
    /* Note:  Since this was a virgin group push we can just blast it with
1280
     * 255 */
1281
0
    if (fill_trans_buffer->has_shape) {
1282
0
        buff_ptr = buff_out + fill_trans_buffer->n_chan * (fill_trans_buffer->planestride>>1);
1283
1284
0
        for (jj = 0; jj < h; jj++) {
1285
0
            memset(buff_ptr, 255, w*2);
1286
0
            buff_ptr += fill_trans_buffer->rowstride>>1;
1287
0
        }
1288
0
    }
1289
0
}
1290
1291
void
1292
tile_rect_trans_blend(int xmin, int ymin, int xmax, int ymax,
1293
                      int px, int py, const gx_color_tile *ptile,
1294
                      gx_pattern_trans_t *fill_trans_buffer,
1295
                      int native16)
1296
738
{
1297
738
    pdf14_buf *buf = fill_trans_buffer->buf;
1298
1299
    /* Update the bbox in the topmost stack entry to reflect the fact that we
1300
     * have drawn into it. FIXME: This makes the groups too large! */
1301
738
    if (buf->dirty.p.x > xmin)
1302
652
        buf->dirty.p.x = xmin;
1303
738
    if (buf->dirty.p.y > ymin)
1304
652
        buf->dirty.p.y = ymin;
1305
738
    if (buf->dirty.q.x < xmax)
1306
652
        buf->dirty.q.x = xmax;
1307
738
    if (buf->dirty.q.y < ymax)
1308
677
        buf->dirty.q.y = ymax;
1309
1310
738
    if (!ptile->ttrans->deep)
1311
738
        do_tile_rect_trans_blend(xmin, ymin, xmax, ymax,
1312
738
                                 px, py, ptile, fill_trans_buffer);
1313
0
    else if (native16)
1314
0
        do_tile_rect_trans_blend_16(xmin, ymin, xmax, ymax,
1315
0
                                    px, py, ptile, fill_trans_buffer);
1316
0
    else
1317
0
        do_tile_rect_trans_blend_16be(xmin, ymin, xmax, ymax,
1318
0
                                      px, py, ptile, fill_trans_buffer);
1319
738
}
1320
1321
/* This version does a rect fill with the transparency object */
1322
int
1323
gx_dc_pat_trans_fill_rectangle(const gx_device_color * pdevc, int x, int y,
1324
                               int w, int h, gx_device * dev,
1325
                               gs_logical_operation_t lop,
1326
                               const gx_rop_source_t * source)
1327
0
{
1328
0
    gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
1329
0
    int code;
1330
0
    gs_int_point phase;
1331
0
    const gx_rop_source_t *rop_source = source;
1332
0
    gx_rop_source_t no_source;
1333
1334
0
    if (ptile == 0)             /* null pattern */
1335
0
        return 0;
1336
0
    if (rop_source == NULL)
1337
0
        set_rop_no_source(rop_source, no_source, dev);
1338
1339
0
    phase.x = pdevc->phase.x;
1340
0
    phase.y = pdevc->phase.y;
1341
1342
#if 0
1343
    if_debug8m('v', ptile->ttrans->mem,
1344
            "[v]gx_dc_pat_trans_fill_rectangle, Fill: (%d, %d), %d x %d To Buffer: (%d, %d), %d x %d \n",
1345
            x, y, w, h,  ptile->ttrans->fill_trans_buffer->rect.p.x,
1346
            ptile->ttrans->fill_trans_buffer->rect.p.y,
1347
            ptile->ttrans->fill_trans_buffer->rect.q.x -
1348
            ptile->ttrans->fill_trans_buffer->rect.p.x,
1349
            ptile->ttrans->fill_trans_buffer->rect.q.y -
1350
            ptile->ttrans->fill_trans_buffer->rect.p.y);
1351
#endif
1352
0
    code = gx_trans_pattern_fill_rect(x, y, x+w, y+h, ptile,
1353
0
                                      ptile->ttrans->fill_trans_buffer, phase,
1354
0
                                      dev, pdevc, 0);
1355
0
    return code;
1356
0
}
1357
1358
/* This fills the transparency buffer rectangles with a pattern buffer
1359
   that includes transparency */
1360
int
1361
gx_trans_pattern_fill_rect(int xmin, int ymin, int xmax, int ymax,
1362
                           gx_color_tile *ptile,
1363
                           gx_pattern_trans_t *fill_trans_buffer,
1364
                           gs_int_point phase, gx_device *dev,
1365
                           const gx_device_color * pdevc,
1366
                           int native16)
1367
70.0k
{
1368
70.0k
    tile_fill_trans_state_t state_trans;
1369
70.0k
    tile_fill_state_t state_clist_trans;
1370
70.0k
    int code = 0;
1371
70.0k
    int w = xmax - xmin;
1372
70.0k
    int h = ymax - ymin;
1373
1374
70.0k
    if (ptile == NULL)             /* null pattern */
1375
0
        return 0;
1376
1377
70.0k
    fit_fill_xywh(dev, xmin, ymin, w, h);
1378
70.0k
    if (w < 0 || h < 0)
1379
0
        return 0;
1380
70.0k
    xmax = w + xmin;
1381
70.0k
    ymax = h + ymin;
1382
1383
    /* Initialize the fill state */
1384
70.0k
    state_trans.phase.x = phase.x;
1385
70.0k
    state_trans.phase.y = phase.y;
1386
1387
70.0k
    if (ptile->is_simple && ptile->cdev == NULL) {
1388
        /* A simple case.  Tile is not clist and simple. */
1389
14.4k
        int px =
1390
14.4k
            imod(-(int)fastfloor(ptile->step_matrix.tx - phase.x + 0.5),
1391
14.4k
                  ptile->ttrans->width);
1392
14.4k
        int py =
1393
14.4k
            imod(-(int)fastfloor(ptile->step_matrix.ty - phase.y + 0.5),
1394
14.4k
                 ptile->ttrans->height);
1395
1396
14.4k
        if (fill_trans_buffer == NULL)
1397
0
            return_error(gs_error_unknownerror);
1398
1399
14.4k
        tile_rect_trans_simple(xmin, ymin, xmax, ymax, px, py, ptile,
1400
14.4k
            fill_trans_buffer, native16);
1401
55.6k
    } else {
1402
55.6k
        if (ptile->cdev == NULL) {
1403
            /* No clist for the pattern, but a complex case
1404
               This portion transforms the bounding box by the step matrix
1405
               and does partial rect fills with tiles that fall into this
1406
               transformed bbox */
1407
16.1k
            if (fill_trans_buffer == NULL)
1408
0
                return_error(gs_error_unknownerror);
1409
1410
16.1k
            code = tile_by_steps_trans(&state_trans, xmin, ymin, xmax-xmin,
1411
16.1k
                                        ymax-ymin, fill_trans_buffer, ptile,
1412
16.1k
                                        native16);
1413
1414
39.4k
        } else {
1415
            /* clist for the trans tile.  This uses the pdf14 device as a target
1416
               and should blend directly into the buffer.  Note that the
1417
               pattern can not have a push pdf14 device or a pop pdf14 device
1418
               compositor action.  Those are removed during the compositor
1419
               clist writing operation where we check for the case of a pattern
1420
               with a transparency */
1421
39.4k
            gx_device_clist *cdev = ptile->cdev;
1422
39.4k
            gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev;
1423
39.4k
            gx_strip_bitmap tbits;
1424
1425
39.4k
            code = tile_fill_init(&state_clist_trans, pdevc, dev, false);
1426
39.4k
            if (code < 0)
1427
0
            {
1428
                /* Can't use CLIPDEV_INSTALLED macro because it assumes a tile_fill_state_t structure, called 'state' */
1429
0
                if (state_clist_trans.cdev != NULL) {
1430
0
                    tile_clip_free((gx_device_tile_clip *)state_clist_trans.cdev);
1431
0
                    state_clist_trans.cdev = NULL;
1432
0
                }
1433
0
                return code;
1434
0
            }
1435
1436
39.4k
            state_clist_trans.phase.x = phase.x;
1437
39.4k
            state_clist_trans.phase.y = phase.y;
1438
39.4k
            crdev->yplane.depth = 0;
1439
39.4k
            crdev->yplane.shift = 0;
1440
39.4k
            crdev->yplane.index = -1;
1441
39.4k
            crdev->pages = NULL;
1442
39.4k
            crdev->num_pages = 1;
1443
39.4k
            state_clist_trans.orig_dev = dev;
1444
39.4k
            state_clist_trans.pdevc = pdevc;
1445
39.4k
            tbits = ptile->tbits;
1446
39.4k
            tbits.size.x = crdev->width;
1447
39.4k
            tbits.size.y = crdev->height;
1448
39.4k
            if (code >= 0)
1449
39.4k
                code = tile_by_steps(&state_clist_trans, xmin, ymin, xmax-xmin,
1450
39.4k
                                     ymax-ymin, ptile, &tbits, tile_pattern_clist);
1451
1452
39.4k
            if (code >= 0 && (state_clist_trans.cdev != NULL)) {
1453
0
                tile_clip_free((gx_device_tile_clip *)state_clist_trans.cdev);
1454
0
                state_clist_trans.cdev = NULL;
1455
0
            }
1456
1457
39.4k
        }
1458
55.6k
    }
1459
70.0k
    return code;
1460
70.0k
}