Coverage Report

Created: 2026-02-14 07:09

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