Coverage Report

Created: 2025-04-22 06:20

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