Coverage Report

Created: 2025-06-10 07:15

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