Coverage Report

Created: 2025-06-10 06:59

/src/ghostpdl/base/gxclrect.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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
/* Rectangle-oriented command writing for command list */
18
#include "gx.h"
19
#include "gserrors.h"
20
#include "gsutil.h"   /* for gs_next_ids */
21
#include "gxdevice.h"
22
#include "gxdevmem.h"   /* must precede gxcldev.h */
23
#include "gxcldev.h"
24
#include "gxclpath.h"
25
#include "gxdevsop.h"
26
27
/* ---------------- Writing utilities ---------------- */
28
29
#define cmd_set_rect(rect)\
30
13.9M
  ((rect).x = x, (rect).y = y,\
31
13.9M
   (rect).width = width, (rect).height = height)
32
33
/* Write a rectangle. */
34
static int
35
cmd_size_rect(register const gx_cmd_rect * prect)
36
530k
{
37
530k
    return
38
530k
        cmd_sizew(prect->x) + cmd_sizew(prect->y) +
39
530k
        cmd_sizew(prect->width) + cmd_sizew(prect->height);
40
530k
}
41
static inline byte *
42
cmd_put_rect(const gx_cmd_rect * prect, byte * dp)
43
193k
{
44
193k
    cmd_putw(prect->x, &dp);
45
193k
    cmd_putw(prect->y, &dp);
46
193k
    cmd_putw(prect->width, &dp);
47
193k
    cmd_putw(prect->height, &dp);
48
193k
    return dp;
49
193k
}
50
51
int
52
cmd_write_rect_hl_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
53
                      int op, int x, int y, int width, int height,
54
                      bool extended_command)
55
0
{
56
0
    byte *dp;
57
0
    int code;
58
0
    int rcsize;
59
60
0
    cmd_set_rect(pcls->rect);
61
0
    if (extended_command) {
62
0
        rcsize = 2 + cmd_size_rect(&pcls->rect);
63
0
        code = set_cmd_put_extended_op(&dp, cldev, pcls, op, rcsize);
64
0
        dp += 2;
65
0
    } else {
66
0
        rcsize = 1 + cmd_size_rect(&pcls->rect);
67
0
        code = set_cmd_put_op(&dp, cldev, pcls, op, rcsize);
68
0
        dp += 1;
69
0
    }
70
0
    if (code < 0)
71
0
        return code;
72
0
    if_debug5m('L', cldev->memory, "[L]  rect hl r%d:%d,%d,%d,%d\n",
73
0
               rcsize - 1, pcls->rect.x, pcls->rect.y,
74
0
               pcls->rect.width, pcls->rect.height);
75
0
    cmd_put_rect(&pcls->rect, dp);
76
0
    return 0;
77
0
}
78
79
int
80
cmd_write_rect_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
81
                   int op, int x, int y, int width, int height)
82
11.3M
{
83
11.3M
    int dx = x - pcls->rect.x;
84
11.3M
    int dy = y - pcls->rect.y;
85
11.3M
    int dwidth = width - pcls->rect.width;
86
11.3M
    int dheight = height - pcls->rect.height;
87
11.3M
    byte *dp;
88
11.3M
    int code;
89
90
11.3M
#define check_range_xy(rmin, rmax)\
91
12.8M
  ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
92
12.8M
   (unsigned)(dy - rmin) <= (rmax - rmin))
93
11.3M
#define check_range_w(rmin, rmax)\
94
24.4M
  ((unsigned)(dwidth - rmin) <= (rmax - rmin))
95
11.3M
#define check_ranges(rmin, rmax)\
96
11.3M
  (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
97
1.04M
   (unsigned)(dheight - rmin) <= (rmax - rmin))
98
11.3M
    cmd_set_rect(pcls->rect);
99
11.3M
    if (dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
100
11.3M
        check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
101
11.3M
        ) {
102
10.2M
        byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
103
104
10.2M
        if (dx == width - dwidth && dy == 0) {
105
7.34M
            code = set_cmd_put_op(&dp, cldev, pcls, op_tiny + 8, 1);
106
7.34M
            if (code < 0)
107
0
                return code;
108
7.34M
        } else {
109
2.94M
            code = set_cmd_put_op(&dp, cldev, pcls, op_tiny, 2);
110
2.94M
            if (code < 0)
111
0
                return code;
112
2.94M
            dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
113
2.94M
        }
114
10.2M
    }
115
2.38M
#define rmin cmd_min_short
116
1.04M
#define rmax cmd_max_short
117
1.04M
    else if (check_ranges(rmin, rmax)) {
118
759k
        int dh = dheight - cmd_min_dxy_tiny;
119
120
759k
        if ((unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
121
759k
            dh != 0 && dy == 0
122
759k
            ) {
123
325k
            op += dh;
124
325k
            code = set_cmd_put_op(&dp, cldev, pcls, op + 0x10, 3);
125
325k
            if (code < 0)
126
0
                return code;
127
325k
            if_debug3m('L', cldev->memory, "    rs2:%d,%d,0,%d\n",
128
325k
                       dx, dwidth, dheight);
129
434k
        } else {
130
434k
            code = set_cmd_put_op(&dp, cldev, pcls, op + 0x10, 5);
131
434k
            if (code < 0)
132
0
                return code;
133
434k
            if_debug4m('L', cldev->memory, "    rs4:%d,%d,%d,%d\n",
134
434k
                       dx, dwidth, dy, dheight);
135
434k
            dp[3] = dy - rmin;
136
434k
            dp[4] = dheight - rmin;
137
434k
        }
138
759k
        dp[1] = dx - rmin;
139
759k
        dp[2] = dwidth - rmin;
140
759k
    }
141
289k
#undef rmin
142
289k
#undef rmax
143
289k
    else if (dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
144
289k
             (dy + dheight) != -4
145
289k
        ) {
146
95.9k
        int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
147
148
95.9k
        code = set_cmd_put_op(&dp, cldev, pcls,
149
95.9k
                              op + ((dy + 2) << 2) + dheight + 2, rcsize);
150
95.9k
        if (code < 0)
151
0
            return code;
152
95.9k
        ++dp;
153
95.9k
        cmd_put2w(x, width, &dp);
154
193k
    } else {
155
193k
        int rcsize = 1 + cmd_size_rect(&pcls->rect);
156
157
193k
        code = set_cmd_put_op(&dp, cldev, pcls, op, rcsize);
158
193k
        if (code < 0)
159
0
            return code;
160
193k
        if_debug5m('L', cldev->memory, "[L]  r%d:%d,%d,%d,%d\n",
161
193k
                   rcsize - 1, dx, dwidth, dy, dheight);
162
193k
        cmd_put_rect(&pcls->rect, dp + 1);
163
193k
    }
164
11.3M
    return 0;
165
11.3M
}
166
167
/* Put out a fill or tile rectangle command for fillpage. */
168
int
169
cmd_write_page_rect_cmd(gx_device_clist_writer * cldev, int op)
170
66.9k
{
171
    /* Since cmd_write_rect_cmd always writes 0x0 rectangle as a tiny one,
172
       here we write a "big" rectangle with the size 0x0.
173
       The clist reader must handle this case especially.
174
     */
175
66.9k
    int rcsize = 1 + 4 * cmd_sizew(0);
176
66.9k
    byte *dp;
177
66.9k
    int x = 0, y = 0, width = 0, height = 0; /* For cmd_set_rect */
178
66.9k
    gx_clist_state *pcls1;
179
66.9k
    int code;
180
181
66.9k
    if_debug0m('L', cldev->memory, "[L]fillpage beg\n");
182
66.9k
    code = set_cmd_put_all_op(&dp, cldev, op, rcsize);
183
66.9k
    if (code < 0)
184
0
        return code;
185
2.57M
    for (pcls1 = cldev->states; pcls1 < cldev->states + cldev->nbands; pcls1++)
186
2.51M
        cmd_set_rect(pcls1->rect);
187
66.9k
    ++dp;
188
66.9k
    cmd_putw(0, &dp);
189
66.9k
    cmd_putw(0, &dp);
190
66.9k
    cmd_putw(0, &dp);
191
66.9k
    cmd_putw(0, &dp);
192
66.9k
    if_debug0m('L', cldev->memory, "[L]fillpage end\n");
193
66.9k
    return 0;
194
66.9k
}
195
196
static inline byte *
197
cmd_put_frac31_color(gx_device_clist_writer * cldev, const frac31 *c, byte *dp)
198
7.65M
{
199
7.65M
    uchar num_components = cldev->clist_color_info.num_components;
200
7.65M
    uchar j;
201
202
15.3M
    for (j = 0; j < num_components; j++)
203
7.65M
        dp = cmd_put_frac31(c[j], dp);
204
7.65M
    return dp;
205
7.65M
}
206
207
static inline int
208
cmd_size_frac31_color(gx_device_clist_writer * cldev, const frac31 *c)
209
7.65M
{
210
7.65M
    uchar j;
211
7.65M
    int s = 0;
212
7.65M
    uchar num_components = cldev->clist_color_info.num_components;
213
214
15.3M
    for (j = 0; j < num_components; j++)
215
7.65M
        s += cmd_size_frac31(c[j]);
216
7.65M
    return s;
217
7.65M
}
218
219
static int
220
cmd_write_trapezoid_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
221
                    int op,  const gs_fixed_edge *left, const gs_fixed_edge *right,
222
                    fixed ybot, fixed ytop, int options,
223
                    const gs_fill_attributes *fa,
224
                    const frac31 *c0, const frac31 *c1,
225
                    const frac31 *c2, const frac31 *c3)
226
2.73M
{
227
2.73M
    byte *dp;
228
2.73M
    int rcsize;
229
2.73M
    int code;
230
2.73M
    int colors_mask = 0;
231
232
2.73M
    rcsize = 1 + cmd_sizew(left->start.x) + cmd_sizew(left->start.y)
233
2.73M
               + cmd_sizew(left->end.x) + cmd_sizew(left->end.y)
234
2.73M
               + cmd_sizew(right->start.x) + cmd_sizew(right->start.y)
235
2.73M
               + cmd_sizew(right->end.x) + cmd_sizew(right->end.y)
236
2.73M
               + cmd_sizew(options);
237
238
2.73M
    if (!(options & 4))
239
465k
        rcsize += cmd_sizew(ybot) + cmd_sizew(ytop);
240
2.73M
    if (options & 2) {
241
2.69M
        rcsize += cmd_sizew(fa->clip->p.x) + cmd_sizew(fa->clip->p.y)
242
2.69M
                + cmd_sizew(fa->clip->q.x) + cmd_sizew(fa->clip->q.y);
243
2.69M
        if (c0 != NULL) {
244
2.69M
            colors_mask += 1;
245
2.69M
            rcsize += cmd_size_frac31_color(cldev, c0);
246
2.69M
        }
247
2.69M
        if (c1 != NULL) {
248
2.69M
            colors_mask += 2;
249
2.69M
            rcsize += cmd_size_frac31_color(cldev, c1);
250
2.69M
        }
251
2.69M
        if (c2 != NULL) {
252
2.27M
            colors_mask += 4;
253
2.27M
            rcsize += cmd_size_frac31_color(cldev, c2);
254
2.27M
        }
255
2.69M
        if (c3 != NULL) {
256
0
            colors_mask += 8;
257
0
            rcsize += cmd_size_frac31_color(cldev, c3);
258
0
        }
259
2.69M
        rcsize += cmd_sizew(colors_mask);
260
2.69M
    }
261
2.73M
    code = set_cmd_put_op(&dp, cldev, pcls, op, rcsize);
262
2.73M
    if (code < 0)
263
0
        return code;
264
2.73M
    dp++;
265
2.73M
    cmd_putw(left->start.x, &dp);
266
2.73M
    cmd_putw(left->start.y, &dp);
267
2.73M
    cmd_putw(left->end.x, &dp);
268
2.73M
    cmd_putw(left->end.y, &dp);
269
2.73M
    cmd_putw(right->start.x, &dp);
270
2.73M
    cmd_putw(right->start.y, &dp);
271
2.73M
    cmd_putw(right->end.x, &dp);
272
2.73M
    cmd_putw(right->end.y, &dp);
273
2.73M
    cmd_putw(options, &dp);
274
2.73M
    if (!(options & 4)) {
275
465k
        cmd_putw(ybot, &dp);
276
465k
        cmd_putw(ytop, &dp);
277
465k
    }
278
2.73M
    if_debug6m('L', cldev->memory, "    t%d:%ld,%ld,%ld,%ld   %ld\n",
279
2.73M
               rcsize - 1, (long int)left->start.x, (long int)left->start.y,
280
2.73M
               (long int)left->end.x, (long int)left->end.y, (long int)ybot);
281
2.73M
    if_debug6m('L', cldev->memory, "    t%ld,%ld,%ld,%ld   %ld   o=%d\n",
282
2.73M
               (long int)right->start.x, (long int)right->start.y,
283
2.73M
               (long int)right->end.x, (long int)right->end.y, (long int)ytop,
284
2.73M
               options);
285
2.73M
    if (options & 2) {
286
2.69M
        cmd_putw(fa->clip->p.x, &dp);
287
2.69M
        cmd_putw(fa->clip->p.y, &dp);
288
2.69M
        cmd_putw(fa->clip->q.x, &dp);
289
2.69M
        cmd_putw(fa->clip->q.y, &dp);
290
2.69M
        cmd_putw(colors_mask, &dp);
291
2.69M
        if (c0 != NULL)
292
2.69M
            dp = cmd_put_frac31_color(cldev, c0, dp);
293
2.69M
        if (c1 != NULL)
294
2.69M
            dp = cmd_put_frac31_color(cldev, c1, dp);
295
2.69M
        if (c2 != NULL)
296
2.27M
            dp = cmd_put_frac31_color(cldev, c2, dp);
297
2.69M
        if (c3 != NULL)
298
0
            cmd_put_frac31_color(cldev, c3, dp);
299
2.69M
    }
300
2.73M
    return 0;
301
2.73M
}
302
303
/* ---------------- Driver procedures ---------------- */
304
305
int
306
clist_fillpage(gx_device * dev, gs_gstate *pgs, gx_drawing_color *pdcolor)
307
66.9k
{
308
66.9k
    gx_device_clist * const cldev = (gx_device_clist *)dev;
309
66.9k
    gx_device_clist_writer * const cdev = &(cldev->writer);
310
66.9k
    gx_clist_state * pcls;
311
66.9k
    int code;
312
313
    /* flush previous contents */
314
66.9k
    if ((code = clist_close_writer_and_init_reader(cldev) < 0))
315
66.9k
        return code;;
316
66.9k
    if ((code = clist_finish_page(dev, true)) < 0)
317
66.9k
        return code;;
318
319
66.9k
    pcls = cdev->states; /* Use any. */
320
321
66.9k
    code = cmd_put_drawing_color(cdev, pcls, pdcolor, NULL, devn_not_tile_fill);
322
66.9k
    if (code >= 0)
323
66.9k
        code = cmd_write_page_rect_cmd(cdev, cmd_op_fill_rect);
324
66.9k
    return code;
325
66.9k
}
326
327
int
328
clist_fill_rectangle(gx_device * dev, int rx, int ry, int rwidth, int rheight,
329
                     gx_color_index color)
330
12.1M
{
331
12.1M
    gx_device_clist_writer * const cdev =
332
12.1M
        &((gx_device_clist *)dev)->writer;
333
12.1M
    int code;
334
12.1M
    cmd_rects_enum_t re;
335
12.1M
    gx_color_usage_bits color_usage;
336
337
12.1M
    crop_fill(cdev, rx, ry, rwidth, rheight);
338
12.1M
    if (rwidth <= 0 || rheight <= 0)
339
1.10M
        return 0;
340
11.0M
    if (cdev->permanent_error < 0)
341
0
      return (cdev->permanent_error);
342
    /* If needed, update the trans_bbox */
343
11.0M
    if (cdev->pdf14_needed) {
344
10.5M
        gs_int_rect bbox;
345
346
10.5M
        bbox.p.x = rx;
347
10.5M
        bbox.q.x = rx + rwidth - 1;
348
10.5M
        bbox.p.y = ry;
349
10.5M
        bbox.q.y = ry + rheight - 1;
350
351
10.5M
        clist_update_trans_bbox(cdev, &bbox);
352
10.5M
    }
353
11.0M
    RECT_ENUM_INIT(re, ry, rheight);
354
11.0M
    color_usage = gx_color_index2usage(dev, color);
355
11.0M
    do {
356
11.0M
        RECT_STEP_INIT(re);
357
11.0M
        re.pcls->color_usage.or |= color_usage;
358
11.0M
        code = cmd_disable_lop(cdev, re.pcls);
359
11.0M
        if (code >= 0 && color != re.pcls->colors[1]) {
360
8.51M
            code = cmd_put_color(cdev, re.pcls, &clist_select_color1,
361
8.51M
                                 color, &re.pcls->colors[1]);
362
8.51M
        }
363
11.0M
        if (code >= 0) {
364
11.0M
            code = cmd_write_rect_cmd(cdev, re.pcls, cmd_op_fill_rect, rx, re.y,
365
11.0M
                                      rwidth, re.height);
366
11.0M
        }
367
11.0M
        if (code < 0)
368
0
            return code;
369
11.0M
        re.y += re.height;
370
11.0M
    } while (re.y < re.yend);
371
11.0M
    return 0;
372
11.0M
}
373
374
/* This is used in fills from devn color types */
375
int
376
clist_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
377
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
378
    const gx_clip_path *pcpath)
379
0
{
380
0
    gx_device_clist_writer * const cdev =
381
0
        &((gx_device_clist *)dev)->writer;
382
0
    int code;
383
0
    int rx, ry, rwidth, rheight;
384
0
    cmd_rects_enum_t re;
385
0
    gx_color_usage_bits color_usage = cmd_drawing_color_usage(cdev, pdcolor);
386
387
0
    rx = fixed2int(rect->p.x);
388
0
    ry = fixed2int(rect->p.y);
389
0
    rwidth = fixed2int(rect->q.x) - rx;
390
0
    rheight = fixed2int(rect->q.y) - ry;
391
392
0
    crop_fill(cdev, rx, ry, rwidth, rheight);
393
0
    if (rwidth <= 0 || rheight <= 0)
394
0
        return 0;
395
0
    if (cdev->permanent_error < 0)
396
0
      return (cdev->permanent_error);
397
    /* If needed, update the trans_bbox */
398
0
    if (cdev->pdf14_needed) {
399
0
        gs_int_rect bbox;
400
401
0
        bbox.p.x = rx;
402
0
        bbox.q.x = rx + rwidth - 1;
403
0
        bbox.p.y = ry;
404
0
        bbox.q.y = ry + rheight - 1;
405
406
0
        clist_update_trans_bbox(cdev, &bbox);
407
0
    }
408
0
    RECT_ENUM_INIT(re, ry, rheight);
409
0
    do {
410
0
        RECT_STEP_INIT(re);
411
0
        re.pcls->color_usage.or |= color_usage;
412
0
        code = cmd_disable_lop(cdev, re.pcls);
413
0
        code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re,
414
0
                                     devn_not_tile_fill);
415
0
        if (code >= 0) {
416
0
            code = cmd_write_rect_hl_cmd(cdev, re.pcls, cmd_op_fill_rect_hl,
417
0
                                         rx, re.y, rwidth, re.height, false);
418
0
        }
419
0
        if (code < 0)
420
0
            return code;
421
0
        re.y += re.height;
422
0
    } while (re.y < re.yend);
423
0
    return 0;
424
0
}
425
426
static inline int
427
clist_write_fill_trapezoid(gx_device * dev,
428
    const gs_fixed_edge *left, const gs_fixed_edge *right,
429
    fixed ybot, fixed ytop, int options,
430
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop,
431
    const gs_fill_attributes *fa,
432
    const frac31 *c0, const frac31 *c1,
433
    const frac31 *c2, const frac31 *c3)
434
2.59M
{
435
2.59M
    gx_device_clist_writer * const cdev =
436
2.59M
        &((gx_device_clist *)dev)->writer;
437
2.59M
    int code;
438
2.59M
    cmd_rects_enum_t re;
439
2.59M
    int ry, rheight, rx, rxe;
440
2.59M
    bool swap_axes = (options & 1);
441
442
2.59M
    if (options & 4) {
443
2.17M
        if (swap_axes) {
444
0
            rx =  fixed2int(max(min(min(left->start.y, left->end.y), right->start.y), fa->clip->p.y));
445
0
            rxe =  fixed2int_ceiling(min(max(max(left->start.y, left->end.y), right->start.y), fa->clip->q.y));
446
0
            ry = fixed2int(max(min(min(left->start.x, left->end.x), right->start.x), fa->clip->p.x));
447
0
            rheight = fixed2int_ceiling(min(max(max(left->start.x, left->end.x), right->start.x), fa->clip->q.x)) - ry;
448
2.17M
        } else {
449
2.17M
            rx = fixed2int(max(min(min(left->start.x, left->end.x), right->start.x), fa->clip->p.x));
450
2.17M
            rxe = fixed2int_ceiling(min(max(max(left->start.x, left->end.x), right->start.x), fa->clip->q.x));
451
2.17M
            ry = fixed2int(max(min(min(left->start.y, left->end.y), right->start.y), fa->clip->p.y));
452
2.17M
            rheight = fixed2int_ceiling(min(max(max(left->start.y, left->end.y), right->start.y), fa->clip->q.y)) - ry;
453
2.17M
        }
454
2.17M
    } else {
455
        /* fixme: this may give a significant overestimation,
456
           so the command will be written to many bands.
457
           Would like to know a better range by X
458
           with computing intersections of sides with ybot, ytop. */
459
422k
        if (swap_axes) {
460
162k
            rx = fixed2int(ybot);
461
162k
            rxe = fixed2int_ceiling(ytop);
462
162k
            ry = fixed2int(min(left->start.x, left->end.x));
463
162k
            rheight = fixed2int_ceiling(max(right->start.x, right->end.x)) - ry;
464
260k
        } else {
465
260k
            rx = fixed2int(min(left->start.x, left->end.x));
466
260k
            rxe = fixed2int_ceiling(max(right->start.x, right->end.x));
467
260k
            ry = fixed2int(ybot);
468
260k
            rheight = fixed2int_ceiling(ytop) - ry;
469
260k
        }
470
422k
    }
471
2.59M
    crop_fill_y(cdev, ry, rheight);
472
2.59M
    if (rheight <= 0)
473
65.5k
        return 0;
474
2.53M
    if (cdev->permanent_error < 0)
475
0
        return (cdev->permanent_error);
476
    /* If needed, update the trans_bbox */
477
2.53M
    if (cdev->pdf14_needed) {
478
2
        gs_int_rect bbox;
479
480
2
        bbox.p.x = rx;
481
2
        bbox.q.x = rxe;
482
2
        bbox.p.y = ry;
483
2
        bbox.q.y = ry + rheight;
484
485
2
        clist_update_trans_bbox(cdev, &bbox);
486
2
    }
487
2.53M
    RECT_ENUM_INIT(re, ry, rheight);
488
2.73M
    do {
489
2.73M
        RECT_STEP_INIT(re);
490
2.73M
        if (pdcolor != NULL) {
491
47.8k
            code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re,
492
47.8k
                                         devn_not_tile_fill);
493
47.8k
            if (code == gs_error_unregistered)
494
0
                return code;
495
47.8k
            if (code < 0) {
496
                /* Something went wrong, use the default implementation. */
497
8
                return gx_default_fill_trapezoid(dev, left, right, ybot, ytop, swap_axes, pdcolor, lop);
498
8
            }
499
47.8k
            code = cmd_update_lop(cdev, re.pcls, lop);
500
2.69M
        } else {
501
            /* Even with pdcolor NULL, we may still have colors packed in
502
               c0, c1, c2 or c3 */
503
2.69M
            re.pcls->color_usage.or |= gx_color_usage_all(cdev);
504
2.69M
            code = 0;
505
2.69M
        }
506
2.73M
        if (code >= 0) {
507
            /* Don't want to shorten the trapezoid by the band boundary,
508
               keeping in mind a further optimization with writing same data to all bands. */
509
2.73M
            code = cmd_write_trapezoid_cmd(cdev, re.pcls, cmd_opv_fill_trapezoid, left, right,
510
2.73M
                                      ybot, ytop, options, fa, c0, c1, c2, c3);
511
2.73M
        }
512
2.73M
        if (code < 0)
513
0
            return code;
514
2.73M
        re.y += re.height;
515
2.73M
    } while (re.y < re.yend);
516
2.53M
    return 0;
517
2.53M
}
518
519
int
520
clist_fill_trapezoid(gx_device * dev,
521
    const gs_fixed_edge *left, const gs_fixed_edge *right,
522
    fixed ybot, fixed ytop, bool swap_axes,
523
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
524
48.0k
{
525
48.0k
    return clist_write_fill_trapezoid(dev, left, right,
526
48.0k
        ybot, ytop, swap_axes, pdcolor, lop, NULL, NULL, NULL, NULL, NULL);
527
48.0k
}
528
529
int
530
clist_fill_linear_color_trapezoid(gx_device * dev, const gs_fill_attributes *fa,
531
        const gs_fixed_point *p0, const gs_fixed_point *p1,
532
        const gs_fixed_point *p2, const gs_fixed_point *p3,
533
        const frac31 *c0, const frac31 *c1,
534
        const frac31 *c2, const frac31 *c3)
535
374k
{
536
374k
    gs_fixed_edge left, right;
537
374k
    int code;
538
539
374k
    left.start = *p0;
540
374k
    left.end = *p1;
541
374k
    right.start = *p2;
542
374k
    right.end = *p3;
543
374k
    code = clist_write_fill_trapezoid(dev, &left, &right,
544
374k
        fa->ystart, fa->yend, fa->swap_axes | 2, NULL, fa->lop, fa, c0, c1, c2, c3);
545
374k
    if (code < 0)
546
0
        return code;
547
    /* NOTE : The return value 0 for the fill_linear_color_trapezoid method means
548
       that the device requests a further decomposition of the trapezoid.
549
       Currently we have no interface for checking whether the target device
550
       can handle a trapezoid without an attempt to fill it.
551
       Therefore the clist writer device must always return 1,
552
       and the clist reader must perform a further decomposition
553
       if the target device requests it.
554
     */
555
374k
    return 1;
556
374k
}
557
558
int
559
clist_fill_linear_color_triangle(gx_device * dev, const gs_fill_attributes *fa,
560
        const gs_fixed_point *p0, const gs_fixed_point *p1,
561
        const gs_fixed_point *p2,
562
        const frac31 *c0, const frac31 *c1, const frac31 *c2)
563
2.17M
{
564
2.17M
    gs_fixed_edge left, right;
565
2.17M
    int code;
566
567
2.17M
    left.start = *p0;
568
2.17M
    left.end = *p1;
569
2.17M
    right.start = *p2;
570
2.17M
    right.end.x = right.end.y = 0; /* unused. */
571
572
2.17M
    code = clist_write_fill_trapezoid(dev, &left, &right,
573
2.17M
        0, 0, fa->swap_axes | 2 | 4, NULL, fa->lop, fa, c0, c1, c2, NULL);
574
2.17M
    if (code < 0)
575
0
        return code;
576
    /* NOTE : The return value 0 for the fill_linear_color_triangle method means
577
       that the device requests a further decomposition of the trapezoid.
578
       Currently we have no interface for checking whether the target device
579
       can handle a trapezoid without an attempt to fill it.
580
       Therefore the clist writer device must always return 1,
581
       and the clist reader must perform a further decomposition
582
       if the target device requests it.
583
     */
584
2.17M
    return 1;
585
2.17M
}
586
587
extern dev_proc_open_device(pattern_clist_open_device);
588
extern dev_proc_dev_spec_op(pattern_accum_dev_spec_op);
589
590
int
591
clist_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
592
22.3M
{
593
22.3M
    gx_device_clist_common * const cdev = &((gx_device_clist *)pdev)->common;
594
595
22.3M
    if (dev_spec_op == gxdso_pattern_handles_clip_path)
596
121
        return 1;
597
22.3M
    if (dev_spec_op == gxdso_pattern_shfill_doesnt_need_path)
598
75
        return 1;
599
22.3M
    if (dev_spec_op == gxdso_copy_alpha_disabled) {
600
0
        gx_device_clist_writer * const cdev = &((gx_device_clist *)pdev)->writer;
601
0
        return (cdev->disable_mask & clist_disable_copy_alpha) != 0;
602
0
    }
603
22.3M
    if (dev_spec_op == gxdso_supports_devn
604
22.3M
     || dev_spec_op == gxdso_skip_icc_component_validation) {
605
10.6M
        cmm_dev_profile_t *dev_profile;
606
10.6M
        int code;
607
10.6M
        code = dev_proc(cdev, get_profile)((gx_device*) cdev, &dev_profile);
608
10.6M
        if (code == 0) {
609
10.6M
            return dev_profile->supports_devn;
610
10.6M
        } else {
611
0
            return 0;
612
0
        }
613
10.6M
    }
614
11.7M
    if (dev_spec_op == gxdso_restrict_bbox) {
615
0
        gx_device_clist_writer *cwdev = &((gx_device_clist *)pdev)->writer;
616
0
        gs_int_rect *ibox = (gs_int_rect *)data;
617
0
        if (ibox->p.y < cwdev->cropping_min)
618
0
            ibox->p.y = cwdev->cropping_min;
619
0
        if (ibox->q.y > cwdev->cropping_max)
620
0
            ibox->q.y = cwdev->cropping_max;
621
0
        return 0;
622
0
    }
623
11.7M
    if (dev_spec_op == gxdso_is_clist_device)
624
872
        return 1;
625
11.7M
    if (dev_spec_op == gxdso_overprint_active) {
626
2.49M
        gx_device_clist_writer* cwdev = &((gx_device_clist*)pdev)->writer;
627
2.49M
        return cwdev->op_fill_active || cwdev->op_stroke_active;
628
2.49M
    }
629
    /* This is a horrible hack. Accumulator devices have their procs
630
     * overriden by clist ones in gdev_prn_open. */
631
9.26M
    if (strncmp(pdev->dname, "pdf14-accum-", 12) == 0) {
632
0
        return pdf14_accum_dev_spec_op(pdev, dev_spec_op, data, size);
633
0
    }
634
    /* forward to the appropriate super class */
635
9.26M
    if (cdev->orig_spec_op)
636
9.26M
        return cdev->orig_spec_op(pdev, dev_spec_op, data, size);
637
21
    if (dev_proc(cdev, open_device) == pattern_clist_open_device)
638
21
        return pattern_accum_dev_spec_op(pdev, dev_spec_op, data, size);
639
0
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
640
21
}
641
642
/* Based heavily off of clist_strip_tile_rectangle */
643
int
644
clist_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tile,
645
                           int rx, int ry, int rwidth, int rheight,
646
                           const gx_drawing_color *pdcolor0,
647
                           const gx_drawing_color *pdcolor1, int px, int py)
648
0
{
649
0
    gx_device_clist_writer * const cdev =
650
0
        &((gx_device_clist *)dev)->writer;
651
0
    int depth = 1;
652
0
    int code;
653
0
    cmd_rects_enum_t re;
654
0
    gx_color_usage_bits color_usage = cmd_drawing_color_usage(cdev, pdcolor0);
655
656
0
    crop_fill(cdev, rx, ry, rwidth, rheight);
657
0
    if (rwidth <= 0 || rheight <= 0)
658
0
        return 0;
659
0
    if (cdev->permanent_error < 0)
660
0
      return (cdev->permanent_error);
661
    /* If needed, update the trans_bbox */
662
0
    if (cdev->pdf14_needed) {
663
0
        gs_int_rect bbox;
664
665
0
        bbox.p.x = rx;
666
0
        bbox.q.x = rx + rwidth - 1;
667
0
        bbox.p.y = ry;
668
0
        bbox.q.y = ry + rheight - 1;
669
670
0
        clist_update_trans_bbox(cdev, &bbox);
671
0
    }
672
0
    color_usage |= cmd_drawing_color_usage(cdev, pdcolor1);
673
0
    RECT_ENUM_INIT(re, ry, rheight);
674
0
    do {
675
0
        ulong offset_temp;
676
677
0
        RECT_STEP_INIT(re);
678
0
        re.pcls->color_usage.or |= color_usage;
679
0
        code = cmd_disable_lop(cdev, re.pcls);
680
0
        if (code < 0)
681
0
            return code;
682
        /* Change the tile if needed */
683
0
        if (!cls_has_tile_id(cdev, re.pcls, tile->id, offset_temp)) {
684
0
            if (tile->id != gx_no_bitmap_id) {
685
0
                code = clist_change_tile(cdev, re.pcls, tile, depth);
686
0
                if (code < 0)
687
0
                {
688
0
                    if (code == gs_error_limitcheck)
689
0
                    {
690
0
                        code = gx_default_strip_tile_rect_devn(dev, tile,
691
0
                                                               rx, re.y, rwidth, re.height,
692
0
                                                               pdcolor0, pdcolor1,
693
0
                                                               px, py);
694
0
                        if (code <= 0)
695
0
                            goto loop;
696
0
                    }
697
0
                    return code;
698
0
                }
699
0
            } else {
700
0
                return_error(gs_error_unregistered);
701
0
            }
702
0
        }
703
0
        code = 0;
704
        /* Write out the devn colors */
705
0
        code = cmd_put_drawing_color(cdev, re.pcls, pdcolor0, &re,
706
0
                                     devn_tile0);
707
0
        code = cmd_put_drawing_color(cdev, re.pcls, pdcolor1, &re,
708
0
                                     devn_tile1);
709
        /* Set the tile phase */
710
0
        if (px != re.pcls->tile_phase.x || py != re.pcls->tile_phase.y) {
711
0
            if (code >= 0)
712
0
                code = cmd_set_tile_phase(cdev, re.pcls, px, py);
713
0
        }
714
        /* Write out the actually command to fill with the devn colors */
715
0
        if (code >= 0) {
716
0
            code = cmd_write_rect_hl_cmd(cdev, re.pcls,
717
0
                                         cmd_opv_ext_tile_rect_hl, rx, re.y,
718
0
                                         rwidth, re.height, true);
719
0
        }
720
0
        if (code < 0)
721
0
            return code;
722
0
loop:
723
0
        re.y += re.height;
724
0
    } while (re.y < re.yend);
725
0
    return 0;
726
0
}
727
728
int
729
clist_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tile,
730
                           int rx, int ry, int rwidth, int rheight,
731
               gx_color_index color0, gx_color_index color1, int px, int py)
732
1.01k
{
733
1.01k
    gx_device_clist_writer * const cdev =
734
1.01k
        &((gx_device_clist *)dev)->writer;
735
1.01k
    int depth =
736
1.01k
        (color1 == gx_no_color_index && color0 == gx_no_color_index ?
737
1.01k
         cdev->clist_color_info.depth : 1);
738
1.01k
    gx_color_usage_bits color_usage =
739
1.01k
        (color1 == gx_no_color_index && color0 == gx_no_color_index ?
740
         /* We can't know what colors will be used: assume the worst. */
741
0
         gx_color_usage_all(dev) :
742
1.01k
         (color0 == gx_no_color_index ? 0 : gx_color_index2usage(dev, color0)) |
743
1.01k
         (color1 == gx_no_color_index ? 0 : gx_color_index2usage(dev, color1)));
744
1.01k
    int code;
745
1.01k
    cmd_rects_enum_t re;
746
747
1.01k
    crop_fill(cdev, rx, ry, rwidth, rheight);
748
1.01k
    if (rwidth <= 0 || rheight <= 0)
749
0
        return 0;
750
1.01k
    if (cdev->permanent_error < 0)
751
0
        return (cdev->permanent_error);
752
    /* If needed, update the trans_bbox */
753
1.01k
    if (cdev->pdf14_needed) {
754
167
        gs_int_rect bbox;
755
756
167
        bbox.p.x = rx;
757
167
        bbox.q.x = rx + rwidth - 1;
758
167
        bbox.p.y = ry;
759
167
        bbox.q.y = ry + rheight - 1;
760
761
167
        clist_update_trans_bbox(cdev, &bbox);
762
167
    }
763
1.01k
    RECT_ENUM_INIT(re, ry, rheight);
764
1.05k
    do {
765
1.05k
        ulong offset_temp;
766
767
1.05k
        RECT_STEP_INIT(re);
768
1.05k
        re.pcls->color_usage.or |= color_usage;
769
1.05k
        code = cmd_disable_lop(cdev, re.pcls);
770
1.05k
        if (code < 0)
771
0
            return code;
772
1.05k
        if (!cls_has_tile_id(cdev, re.pcls, tile->id, offset_temp)) {
773
9
            if (tile->id != gx_no_bitmap_id) {
774
9
                code = clist_change_tile(cdev, re.pcls, tile, depth);
775
9
            } else
776
0
                code = -1; /* Force the default implementation. Should never happen. */
777
9
            if (code < 0) {
778
                /* ok if gx_default... does retries internally: */
779
                /* it's self-sufficient */
780
0
                code = gx_default_strip_tile_rectangle(dev, tile,
781
0
                                                       rx, re.y, rwidth, re.height,
782
0
                                                       color0, color1,
783
0
                                                       px, py);
784
0
                if (code < 0)
785
0
                    return code;
786
0
                goto endr;
787
0
            }
788
9
        }
789
1.05k
        code = 0;
790
1.05k
        if (color0 != re.pcls->tile_colors[0] || color1 != re.pcls->tile_colors[1])
791
8
            code = cmd_set_tile_colors(cdev, re.pcls, color0, color1);
792
1.05k
        if (px != re.pcls->tile_phase.x || py != re.pcls->tile_phase.y) {
793
743
            if (code >= 0)
794
743
                code = cmd_set_tile_phase(cdev, re.pcls, px, py);
795
743
        }
796
1.05k
        if (code >= 0)
797
1.05k
            code = cmd_write_rect_cmd(cdev, re.pcls, cmd_op_tile_rect, rx, re.y,
798
1.05k
                                      rwidth, re.height);
799
1.05k
        if (code < 0)
800
0
            return code;
801
1.05k
endr:;
802
1.05k
        re.y += re.height;
803
1.05k
    } while (re.y < re.yend);
804
1.01k
    return 0;
805
1.01k
}
806
807
int
808
clist_copy_mono(gx_device * dev,
809
                const byte * data, int data_x, int raster, gx_bitmap_id id,
810
                int rx, int ry, int rwidth, int rheight,
811
                gx_color_index color0, gx_color_index color1)
812
301k
{
813
301k
    gx_device_clist_writer * const cdev =
814
301k
        &((gx_device_clist *)dev)->writer;
815
301k
    int y0;
816
301k
    gx_bitmap_id orig_id = id;
817
301k
    gx_color_usage_bits color_usage =
818
301k
        (color0 == gx_no_color_index ? 0 : gx_color_index2usage(dev, color0)) |
819
301k
        (color1 == gx_no_color_index ? 0 : gx_color_index2usage(dev, color1));
820
301k
    cmd_rects_enum_t re;
821
822
301k
    fit_copy(dev, data, data_x, raster, id, rx, ry, rwidth, rheight);
823
301k
    y0 = ry;
824
301k
    if (cdev->permanent_error < 0)
825
0
      return (cdev->permanent_error);
826
    /* If needed, update the trans_bbox */
827
301k
    if (cdev->pdf14_needed) {
828
440
        gs_int_rect bbox;
829
830
440
        bbox.p.x = rx;
831
440
        bbox.q.x = rx + rwidth - 1;
832
440
        bbox.p.y = ry;
833
440
        bbox.q.y = ry + rheight - 1;
834
835
440
        clist_update_trans_bbox(cdev, &bbox);
836
440
    }
837
301k
    RECT_ENUM_INIT(re, ry, rheight);
838
305k
    do {
839
305k
        int dx = data_x & 7;
840
305k
        int w1 = dx + rwidth;
841
305k
        const byte *row = data + (re.y - y0) * raster + (data_x >> 3);
842
305k
        int code;
843
844
305k
        RECT_STEP_INIT(re);
845
305k
        re.pcls->color_usage.or |= color_usage;
846
305k
        code = cmd_disable_lop(cdev, re.pcls);
847
305k
        if (code >= 0)
848
305k
            code = cmd_disable_clip(cdev, re.pcls);
849
305k
        if (color0 != re.pcls->colors[0] && code >= 0)
850
1.27k
            code = cmd_set_color0(cdev, re.pcls, color0);
851
305k
        if (color1 != re.pcls->colors[1] && code >= 0)
852
2.29k
            code = cmd_set_color1(cdev, re.pcls, color1);
853
305k
        if (code < 0)
854
0
            return code;
855
        /* Don't bother to check for a possible cache hit: */
856
        /* tile_rectangle and fill_mask handle those cases. */
857
306k
copy:{
858
306k
        gx_cmd_rect rect;
859
306k
        int rsize;
860
306k
        byte op = (byte) cmd_op_copy_mono_planes;
861
306k
        byte *dp;
862
306k
        uint csize;
863
306k
        uint compress;
864
306k
        int code;
865
866
306k
        rect.x = rx, rect.y = re.y;
867
306k
        rect.width = w1, rect.height = re.height;
868
306k
        rsize = (dx ? 3 : 1) + cmd_size_rect(&rect) + cmd_sizew(0); /* planar_height 0 */
869
306k
        code = cmd_put_bits(cdev, re.pcls, row, w1, re.height, raster,
870
306k
                            rsize, (orig_id == gx_no_bitmap_id ?
871
306k
                                    1 << cmd_compress_rle :
872
306k
                                    cmd_mask_compress_any),
873
306k
                            &dp, &csize);
874
306k
        if (code < 0 && !(code == gs_error_limitcheck))
875
0
            return code;
876
306k
        compress = (uint)code;
877
306k
        if (code < 0) {
878
            /* The bitmap was too large; split up the transfer. */
879
830
            if (re.height > 1) {
880
                /*
881
                 * Split the transfer by reducing the height.
882
                 * See the comment above FOR_RECTS in gxcldev.h.
883
                 */
884
830
                re.height >>= 1;
885
830
                goto copy;
886
830
            } else {
887
                /* Split a single (very long) row. */
888
0
                int w2 = w1 >> 1;
889
890
0
                code = clist_copy_mono(dev, row, dx,
891
0
                                       raster, gx_no_bitmap_id, rx, re.y,
892
0
                                       w2, 1, color0, color1);
893
0
                if (code >= 0)
894
0
                    code = clist_copy_mono(dev, row, dx + w2,
895
0
                                           raster, gx_no_bitmap_id,
896
0
                                           rx + w2, re.y,
897
0
                                           w1 - w2, 1, color0, color1);
898
0
                if (code < 0)
899
0
                    return code;
900
0
                continue;
901
0
            }
902
830
        }
903
305k
        op += compress;
904
305k
        if (dx) {
905
3.35k
            if_debug0m('L', dev->memory,
906
3.35k
                       "[L] fake end_run: really set_misc_data_x[2]\n");
907
3.35k
            *dp++ = cmd_count_op(cmd_opv_set_misc, 2, dev->memory);
908
3.35k
            *dp++ = cmd_set_misc_data_x + dx;
909
3.35k
        }
910
#ifdef DEBUG
911
        if (gs_debug_c('L')) {
912
            const char *const *sub = cmd_sub_op_names[op >> 4];
913
914
            if (sub)
915
                dmlprintf1(dev->memory, "[L] fake end_run: really %s\n", sub[op & 0xf]);
916
            else
917
                dmlprintf2(dev->memory, "[L] fake end_run: really %s %d\n", cmd_op_names[op >> 4], op & 0xf);
918
        }
919
#endif
920
305k
        *dp++ = cmd_count_op(op, csize, dev->memory);
921
        /* Store the plane_height */
922
305k
        cmd_putw(0, &dp);
923
305k
        cmd_put2w(rx, re.y, &dp);
924
305k
        cmd_put2w(w1, re.height, &dp);
925
305k
        re.pcls->rect = rect;
926
305k
        }
927
305k
    } while ((re.y += re.height) < re.yend);
928
301k
    return 0;
929
301k
}
930
931
/* The code duplication between this and clist_copy_mono needs to be removed */
932
int
933
clist_copy_planes(gx_device * dev,
934
                  const byte * data, int data_x, int raster, gx_bitmap_id id,
935
                  int rx, int ry, int rwidth, int rheight, int plane_height)
936
0
{
937
0
    gx_device_clist_writer * const cdev =
938
0
        &((gx_device_clist *)dev)->writer;
939
0
    int y0;
940
0
    gx_bitmap_id orig_id = id;
941
0
    cmd_rects_enum_t re;
942
0
    int bpc = dev->color_info.depth / dev->color_info.num_components;
943
0
    int pix_in_byte = bpc <= 8 ? 8/bpc : 1;
944
0
    int byte_in_pix = bpc >= 8 ? bpc/8 : 1;
945
946
0
    if (rwidth <= 0 || rheight <= 0)
947
0
        return 0;
948
949
0
    fit_copy(dev, data, data_x, raster, id, rx, ry, rwidth, rheight);
950
951
0
    y0 = ry;
952
0
    if (cdev->permanent_error < 0)
953
0
      return (cdev->permanent_error);
954
955
#ifdef DEBUG
956
    if (plane_height == 0) {
957
        dprintf("clist_copy_planes called with plane_height == 0.\n");
958
    }
959
#endif
960
961
    /* If needed, update the trans_bbox */
962
0
    if (cdev->pdf14_needed) {
963
0
        gs_int_rect bbox;
964
965
0
        bbox.p.x = rx;
966
0
        bbox.q.x = rx + rwidth - 1;
967
0
        bbox.p.y = ry;
968
0
        bbox.q.y = ry + rheight - 1;
969
970
0
        clist_update_trans_bbox(cdev, &bbox);
971
0
    }
972
973
0
    RECT_ENUM_INIT(re, ry, rheight);
974
0
    do {
975
0
        int code;
976
0
        gx_cmd_rect rect;
977
0
        int rsize;
978
0
        byte *dp, *dp2;
979
0
        uint csize;
980
0
        byte op = (byte) cmd_op_copy_mono_planes;
981
0
        int dx = data_x % pix_in_byte;
982
0
        int w1 = dx + rwidth;
983
0
        const byte *row = data + (re.y - y0) * raster + (data_x * byte_in_pix / pix_in_byte);
984
0
        int bytes_row = ((w1*bpc+7)/8 + 7) & ~7;
985
0
        int maxheight = data_bits_size / bytes_row / cdev->color_info.num_components;
986
0
        int plane;
987
988
0
        RECT_STEP_INIT(re);
989
0
        code = cmd_disable_lop(cdev, re.pcls);
990
0
        if (code >= 0)
991
0
            code = cmd_disable_clip(cdev, re.pcls);
992
0
        if (code < 0)
993
0
            return code;
994
        /* Don't bother to check for a possible cache hit: */
995
        /* tile_rectangle and fill_mask handle those cases. */
996
997
        /* We require that in the copy_planes case all the planes fit into
998
         * the data_bits area (for the copy_planes call by the clist reader) */
999
0
        if (re.height > maxheight)
1000
0
            re.height = maxheight;
1001
1002
0
        if (re.height == 0) {
1003
            /* Not even a single row fits. Revert to a single row and split it in two recursively */
1004
0
            int w2 = w1 >> 1;
1005
1006
0
            re.height = 1;
1007
0
            code = clist_copy_planes(dev, row, dx, raster,
1008
0
                                     gx_no_bitmap_id, rx, re.y,
1009
0
                                     w2, 1, plane_height);
1010
0
            if (code >= 0)
1011
0
                code = clist_copy_planes(dev, row, dx + w2,
1012
0
                                         raster, gx_no_bitmap_id,
1013
0
                                         rx + w2, re.y,
1014
0
                                         w1 - w2, 1, plane_height);
1015
0
            if (code < 0)
1016
0
                return code;
1017
0
            continue;
1018
0
        }
1019
1020
        /* 0x100 fudge is arbitrary, but the BufferSpace is large w.r.t. cbuf size so it doesn't matter */
1021
0
        if ((cdev->cend - cdev->cnext) < 0x100 + ((long)cdev->color_info.num_components * re.height * bytes_row))
1022
0
            cmd_write_buffer(cdev, cmd_opv_end_run); /* Insure that all planes fit in the bufferspace */
1023
1024
0
        rect.x = rx, rect.y = re.y;
1025
0
        rect.width = w1, rect.height = re.height;
1026
0
        rsize = (dx ? 3 : 1) + cmd_size_rect(&rect) + cmd_sizew(plane_height);
1027
        /* Copy the 0th plane - this is the one the op goes in. */
1028
0
        code = cmd_put_bits(cdev, re.pcls, row, w1*bpc, re.height, raster,
1029
0
                            rsize, (bpc == 1 ? (orig_id == gx_no_bitmap_id ?
1030
0
                                                1 << cmd_compress_rle :
1031
0
                                                cmd_mask_compress_any) : 0),
1032
0
                            &dp, &csize);
1033
0
        if (code < 0)
1034
0
            continue;
1035
        /* Write the command header out now, in case the following
1036
         * cmd_put_bits fill the buffer up. */
1037
0
        dp2 = dp;
1038
0
        if (dx) {
1039
0
            if_debug0m('L', cdev->memory,
1040
0
                       "[L] fake end_run: really set_misc_data_x[2]\n");
1041
0
            *dp2++ = cmd_count_op(cmd_opv_set_misc, 2, cdev->memory);
1042
0
            *dp2++ = cmd_set_misc_data_x + dx;
1043
0
        }
1044
#ifdef DEBUG
1045
        if (gs_debug_c('L')) {
1046
            const char *const *sub = cmd_sub_op_names[(op+code) >> 4];
1047
1048
            if (sub)
1049
                dmlprintf1(cdev->memory, "[L] fake end_run: really %s\n", sub[(op+code) & 0xf]);
1050
            else
1051
                dmlprintf2(cdev->memory, "[L] fake end_run: really %s %d\n", cmd_op_names[(op+code) >> 4], (op+code) & 0xf);
1052
        }
1053
#endif
1054
0
        *dp2++ = cmd_count_op(op + code, csize, cdev->memory);
1055
0
        cmd_putw(plane_height, &dp2);
1056
0
        cmd_put2w(rx, re.y, &dp2);
1057
0
        cmd_put2w(w1, re.height, &dp2);
1058
0
        for (plane = 1; plane < cdev->color_info.num_components && (code >= 0); plane++)
1059
0
        {
1060
0
            byte *dummy_dp;
1061
0
            uint csize2;
1062
            /* Copy subsequent planes - 1 byte header used to send the
1063
             * compression type. */
1064
0
            code = cmd_put_bits(cdev, re.pcls,
1065
0
                                row + plane_height * raster * plane,
1066
0
                                w1*bpc, re.height, raster, 1,
1067
0
                                (bpc == 1 ?
1068
0
                                 (orig_id == gx_no_bitmap_id ?
1069
0
                                  1 << cmd_compress_rle :
1070
0
                                  cmd_mask_compress_any) : 0),
1071
0
                                &dummy_dp, &csize2);
1072
0
            if (code >= 0)
1073
0
                *dummy_dp = code;
1074
1075
0
            csize += csize2;
1076
0
        }
1077
0
        if (code < 0 && !(code == gs_error_limitcheck))
1078
0
            return code;
1079
1080
0
        re.pcls->rect = rect;
1081
0
    } while ((re.y += re.height) < re.yend);
1082
0
    return 0;
1083
0
}
1084
1085
int
1086
clist_copy_color(gx_device * dev,
1087
                 const byte * data, int data_x, int raster, gx_bitmap_id id,
1088
                 int rx, int ry, int rwidth, int rheight)
1089
30.5k
{
1090
30.5k
    gx_device_clist_writer * const cdev =
1091
30.5k
        &((gx_device_clist *)dev)->writer;
1092
30.5k
    int depth = cdev->clist_color_info.depth; /* Could be different than target
1093
                                                 if 1.4 device */
1094
30.5k
    int y0;
1095
30.5k
    int data_x_bit;
1096
    /* We can't know what colors will be used: assume the worst. */
1097
30.5k
    gx_color_usage_bits all = gx_color_usage_all(cdev);
1098
30.5k
    cmd_rects_enum_t re;
1099
1100
30.5k
    fit_copy(dev, data, data_x, raster, id, rx, ry, rwidth, rheight);
1101
30.5k
    y0 = ry;
1102
30.5k
    data_x_bit = data_x * depth;
1103
30.5k
    if (cdev->permanent_error < 0)
1104
0
      return (cdev->permanent_error);
1105
    /* If needed, update the trans_bbox */
1106
30.5k
    if (cdev->pdf14_needed) {
1107
0
        gs_int_rect bbox;
1108
1109
0
        bbox.p.x = rx;
1110
0
        bbox.q.x = rx + rwidth - 1;
1111
0
        bbox.p.y = ry;
1112
0
        bbox.q.y = ry + rheight - 1;
1113
1114
0
        clist_update_trans_bbox(cdev, &bbox);
1115
0
    }
1116
30.5k
    RECT_ENUM_INIT(re, ry, rheight);
1117
30.5k
    do {
1118
30.5k
        int dx = (data_x_bit & 7) / depth;
1119
30.5k
        int w1 = dx + rwidth;
1120
30.5k
        const byte *row = data + (re.y - y0) * raster + (data_x_bit >> 3);
1121
30.5k
        int code;
1122
1123
30.5k
        RECT_STEP_INIT(re);
1124
30.5k
        re.pcls->color_usage.or |= all;
1125
1126
30.5k
        code = cmd_disable_lop(cdev, re.pcls);
1127
30.5k
        if (code >= 0)
1128
30.5k
            code = cmd_disable_clip(cdev, re.pcls);
1129
30.5k
        if (code < 0)
1130
0
            return code;
1131
30.5k
        if (re.pcls->color_is_alpha) {
1132
0
            byte *dp;
1133
1134
0
            code =
1135
0
                set_cmd_put_op(&dp, cdev, re.pcls, cmd_opv_set_copy_color, 1);
1136
0
            if (code < 0)
1137
0
                return code;
1138
0
            re.pcls->color_is_alpha = 0;
1139
0
        }
1140
30.5k
copy:{
1141
30.5k
            gx_cmd_rect rect;
1142
30.5k
            int rsize;
1143
30.5k
            byte op = (byte) cmd_op_copy_color_alpha;
1144
30.5k
            byte *dp;
1145
30.5k
            uint csize;
1146
30.5k
            uint compress;
1147
1148
30.5k
            rect.x = rx, rect.y = re.y;
1149
30.5k
            rect.width = w1, rect.height = re.height;
1150
30.5k
            rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
1151
30.5k
            code = cmd_put_bits(cdev, re.pcls, row, w1 * depth,
1152
30.5k
                                re.height, raster, rsize,
1153
30.5k
                                1 << cmd_compress_rle, &dp, &csize);
1154
30.5k
            if (code < 0 && !(code == gs_error_limitcheck))
1155
0
                return code;
1156
30.5k
            compress = (uint)code;
1157
30.5k
            if (code < 0) {
1158
                /* The bitmap was too large; split up the transfer. */
1159
0
                if (re.height > 1) {
1160
                    /* Split the transfer by reducing the height.
1161
                     * See the comment above FOR_RECTS in gxcldev.h.
1162
                     */
1163
0
                    re.height >>= 1;
1164
0
                    goto copy;
1165
0
                } else {
1166
                    /* Split a single (very long) row. */
1167
0
                    int w2 = w1 >> 1;
1168
1169
0
                    code = clist_copy_color(dev, row, dx,
1170
0
                                            raster, gx_no_bitmap_id,
1171
0
                                            rx, re.y, w2, 1);
1172
0
                    if (code >= 0)
1173
0
                        code = clist_copy_color(dev, row, dx + w2,
1174
0
                                                raster, gx_no_bitmap_id,
1175
0
                                                rx + w2, re.y, w1 - w2, 1);
1176
0
                    if (code < 0)
1177
0
                        return code;
1178
0
                    continue;
1179
0
                }
1180
0
            }
1181
30.5k
            op += compress;
1182
30.5k
            if (dx) {
1183
0
                if_debug0m('L', dev->memory,
1184
0
                           "[L] fake end_run: really set_misc_data_x[2]\n");
1185
0
                *dp++ = cmd_count_op(cmd_opv_set_misc, 2, dev->memory);
1186
0
                *dp++ = cmd_set_misc_data_x + dx;
1187
0
            }
1188
#ifdef DEBUG
1189
            if (gs_debug_c('L')) {
1190
                const char *const *sub = cmd_sub_op_names[op >> 4];
1191
1192
                if (sub)
1193
                    dmlprintf1(dev->memory, "[L] fake end_run: really %s\n", sub[op & 0xf]);
1194
                else
1195
                    dmlprintf2(dev->memory, "[L] fake end_run: really %s %d\n", cmd_op_names[op >> 4], op & 0xf);
1196
            }
1197
#endif
1198
30.5k
            *dp++ = cmd_count_op(op, csize, dev->memory);
1199
30.5k
            cmd_put2w(rx, re.y, &dp);
1200
30.5k
            cmd_put2w(w1, re.height, &dp);
1201
30.5k
            re.pcls->rect = rect;
1202
30.5k
        }
1203
30.5k
    } while ((re.y += re.height) < re.yend);
1204
30.5k
    return 0;
1205
30.5k
}
1206
1207
/* Patterned after clist_copy_alpha and sharing a command with
1208
   cmd_op_copy_color_alpha.  This was done due to avoid difficult
1209
   to follow code in the read back logic in gxclrast.c.  Due to the
1210
   recursive nature of this call, it would be a bit painful to do much
1211
   sharing between clist_copy_alpha_hl_color and clist_copy_alpha */
1212
int
1213
clist_copy_alpha_hl_color(gx_device * dev, const byte * data, int data_x,
1214
           int raster, gx_bitmap_id id, int rx, int ry, int rwidth, int rheight,
1215
                 const gx_drawing_color *pdcolor, int depth)
1216
0
{
1217
0
    gx_device_clist_writer * const cdev =
1218
0
        &((gx_device_clist *)dev)->writer;
1219
1220
0
    int log2_depth = ilog2(depth);
1221
0
    int y0;
1222
0
    int data_x_bit;
1223
0
    cmd_rects_enum_t re;
1224
0
    gx_color_usage_bits all = gx_color_usage_all(cdev);
1225
1226
    /* If the target can't perform copy_alpha, exit now */
1227
0
    if (depth > 1 && (cdev->disable_mask & clist_disable_copy_alpha) != 0)
1228
0
        return_error(gs_error_unknownerror);
1229
1230
0
    fit_copy(dev, data, data_x, raster, id, rx, ry, rwidth, rheight);
1231
0
    y0 = ry;
1232
0
    data_x_bit = data_x << log2_depth;
1233
0
    if (cdev->permanent_error < 0)
1234
0
      return (cdev->permanent_error);
1235
    /* If needed, update the trans_bbox */
1236
0
    if (cdev->pdf14_needed) {
1237
0
        gs_int_rect bbox;
1238
1239
0
        bbox.p.x = rx;
1240
0
        bbox.q.x = rx + rwidth - 1;
1241
0
        bbox.p.y = ry;
1242
0
        bbox.q.y = ry + rheight - 1;
1243
1244
0
        clist_update_trans_bbox(cdev, &bbox);
1245
0
    }
1246
0
    RECT_ENUM_INIT(re, ry, rheight);
1247
0
    do {
1248
0
        int dx = (data_x_bit & 7) >> log2_depth;
1249
0
        int w1 = dx + rwidth;
1250
0
        const byte *row = data + (re.y - y0) * raster + (data_x_bit >> 3);
1251
0
        int code;
1252
1253
0
        RECT_STEP_INIT(re);
1254
0
        re.pcls->color_usage.or = all;
1255
0
        code = cmd_disable_lop(cdev, re.pcls);
1256
0
        if (code >= 0)
1257
0
            code = cmd_disable_clip(cdev, re.pcls);
1258
0
        if (code < 0)
1259
0
            return code;
1260
0
        if (!re.pcls->color_is_alpha) {
1261
0
            byte *dp;
1262
1263
0
            code = set_cmd_put_op(&dp, cdev, re.pcls, cmd_opv_set_copy_alpha, 1);
1264
0
            if (code < 0)
1265
0
                return code;
1266
0
            re.pcls->color_is_alpha = 1;
1267
0
        }
1268
        /* Set extended command for overload of copy_color_alpha with devn type */
1269
0
        if (!re.pcls->color_is_devn) {
1270
0
            byte *dp;
1271
1272
0
            code = set_cmd_put_extended_op(&dp, cdev, re.pcls, cmd_opv_ext_set_color_is_devn, 2);
1273
0
            dp += 2;
1274
0
            if (code < 0)
1275
0
                  return code;
1276
0
            re.pcls->color_is_alpha = 1;
1277
0
        }
1278
        /* Set the color */
1279
0
        code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re, devn_not_tile_fill);
1280
0
copy:{
1281
0
            gx_cmd_rect rect;
1282
0
            int rsize;
1283
0
            byte op = (byte) cmd_op_copy_color_alpha;
1284
0
            byte *dp;
1285
0
            uint csize;
1286
0
            uint compress;
1287
1288
0
            rect.x = rx, rect.y = re.y;
1289
0
            rect.width = w1, rect.height = re.height;
1290
0
            rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
1291
0
            code = cmd_put_bits(cdev, re.pcls, row, w1 << log2_depth,
1292
0
                                re.height, raster, rsize,
1293
0
                                1 << cmd_compress_rle, &dp, &csize);
1294
0
            if (code < 0 && !(code == gs_error_limitcheck))
1295
0
                return code;
1296
0
            compress = (uint)code;
1297
0
            if (code < 0) {
1298
                /* The bitmap was too large; split up the transfer. */
1299
0
                if (re.height > 1) {
1300
                    /* Split the transfer by reducing the height.
1301
                     * See the comment above FOR_RECTS in gxcldev.h.
1302
                     */
1303
0
                    re.height >>= 1;
1304
0
                    goto copy;
1305
0
                } else {
1306
                    /* Split a single (very long) row. */
1307
0
                    int w2 = w1 >> 1;
1308
1309
0
                    code = clist_copy_alpha_hl_color(dev, row, dx,
1310
0
                                            raster, gx_no_bitmap_id, rx, re.y,
1311
0
                                            w2, 1, pdcolor, depth);
1312
0
                    if (code >= 0)
1313
0
                            code = clist_copy_alpha_hl_color(dev, row, dx + w2,
1314
0
                                                    raster, gx_no_bitmap_id,
1315
0
                                                    rx + w2, re.y, w1 - w2, 1,
1316
0
                                                    pdcolor, depth);
1317
0
                    if (code < 0)
1318
0
                        return code;
1319
0
                    continue;
1320
0
                }
1321
0
            }
1322
0
            op += compress;
1323
0
            if (dx) {
1324
0
                if_debug0m('L', dev->memory,
1325
0
                           "[L] fake end_run: really set_misc_data_x[2]\n");
1326
0
                *dp++ = cmd_count_op(cmd_opv_set_misc, 2, dev->memory);
1327
0
                *dp++ = cmd_set_misc_data_x + dx;
1328
0
            }
1329
#ifdef DEBUG
1330
            if (gs_debug_c('L')) {
1331
                const char *const *sub = cmd_sub_op_names[op >> 4];
1332
1333
                if (sub)
1334
                    dmlprintf1(dev->memory, "[L] fake end_run: really %s\n", sub[op & 0xf]);
1335
                else
1336
                    dmlprintf2(dev->memory, "[L] fake end_run: really %s %d\n", cmd_op_names[op >> 4], op & 0xf);
1337
            }
1338
#endif
1339
0
            *dp++ = cmd_count_op(op, csize, dev->memory);
1340
0
            *dp++ = depth;
1341
0
            cmd_put2w(rx, re.y, &dp);
1342
0
            cmd_put2w(w1, re.height, &dp);
1343
0
            re.pcls->rect = rect;
1344
0
        }
1345
0
    } while ((re.y += re.height) < re.yend);
1346
0
    return 0;
1347
0
}
1348
1349
int
1350
clist_copy_alpha(gx_device * dev, const byte * data, int data_x,
1351
           int raster, gx_bitmap_id id, int rx, int ry, int rwidth, int rheight,
1352
                 gx_color_index color, int depth)
1353
0
{
1354
0
    gx_device_clist_writer * const cdev =
1355
0
        &((gx_device_clist *)dev)->writer;
1356
    /* I don't like copying the entire body of clist_copy_color */
1357
    /* just to change 2 arguments and 1 opcode, */
1358
    /* but I don't see any alternative that doesn't require */
1359
    /* another level of procedure call even in the common case. */
1360
0
    int log2_depth = ilog2(depth);
1361
0
    int y0;
1362
0
    int data_x_bit;
1363
0
    cmd_rects_enum_t re;
1364
0
    gx_color_usage_bits color_usage = gx_color_index2usage(dev, color);
1365
1366
    /* If the target can't perform copy_alpha, exit now */
1367
0
    if (depth > 1 && (cdev->disable_mask & clist_disable_copy_alpha) != 0)
1368
0
        return_error(gs_error_unknownerror);
1369
1370
0
    fit_copy(dev, data, data_x, raster, id, rx, ry, rwidth, rheight);
1371
0
    y0 = ry;
1372
0
    data_x_bit = data_x << log2_depth;
1373
0
    if (cdev->permanent_error < 0)
1374
0
      return (cdev->permanent_error);
1375
    /* If needed, update the trans_bbox */
1376
0
    if (cdev->pdf14_needed) {
1377
0
        gs_int_rect bbox;
1378
1379
0
        bbox.p.x = rx;
1380
0
        bbox.q.x = rx + rwidth - 1;
1381
0
        bbox.p.y = ry;
1382
0
        bbox.q.y = ry + rheight - 1;
1383
1384
0
        clist_update_trans_bbox(cdev, &bbox);
1385
0
    }
1386
0
    RECT_ENUM_INIT(re, ry, rheight);
1387
0
    do {
1388
0
        int dx = (data_x_bit & 7) >> log2_depth;
1389
0
        int w1 = dx + rwidth;
1390
0
        const byte *row = data + (re.y - y0) * raster + (data_x_bit >> 3);
1391
0
        int code;
1392
1393
0
        RECT_STEP_INIT(re);
1394
0
        re.pcls->color_usage.or |= color_usage;
1395
0
        code = cmd_disable_lop(cdev, re.pcls);
1396
0
        if (code >= 0)
1397
0
            code = cmd_disable_clip(cdev, re.pcls);
1398
0
        if (code < 0)
1399
0
            return code;
1400
0
        if (!re.pcls->color_is_alpha) {
1401
0
            byte *dp;
1402
1403
0
            code = set_cmd_put_op(&dp, cdev, re.pcls, cmd_opv_set_copy_alpha, 1);
1404
0
            if (code < 0)
1405
0
                return code;
1406
0
            re.pcls->color_is_alpha = 1;
1407
0
        }
1408
0
        if (re.pcls->color_is_devn) {
1409
0
            byte *dp;
1410
1411
0
            code = set_cmd_put_extended_op(&dp, cdev, re.pcls, cmd_opv_ext_unset_color_is_devn, 1);
1412
0
            if (code < 0)
1413
0
                return code;
1414
0
            dp++;
1415
0
            re.pcls->color_is_alpha = 1;
1416
0
        }
1417
0
        if (color != re.pcls->colors[1]) {
1418
0
            code = cmd_set_color1(cdev, re.pcls, color);
1419
0
            if (code < 0)
1420
0
                return code;
1421
0
        }
1422
0
copy:{
1423
0
            gx_cmd_rect rect;
1424
0
            int rsize;
1425
0
            byte op = (byte) cmd_op_copy_color_alpha;
1426
0
            byte *dp;
1427
0
            uint csize;
1428
0
            uint compress;
1429
1430
0
            rect.x = rx, rect.y = re.y;
1431
0
            rect.width = w1, rect.height = re.height;
1432
0
            rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
1433
0
            code = cmd_put_bits(cdev, re.pcls, row, w1 << log2_depth,
1434
0
                                re.height, raster, rsize,
1435
0
                                1 << cmd_compress_rle, &dp, &csize);
1436
0
            if (code < 0 && !(code == gs_error_limitcheck))
1437
0
                return code;
1438
0
            compress = (uint)code;
1439
0
            if (code < 0) {
1440
                /* The bitmap was too large; split up the transfer. */
1441
0
                if (re.height > 1) {
1442
                    /* Split the transfer by reducing the height.
1443
                     * See the comment above FOR_RECTS in gxcldev.h.
1444
                     */
1445
0
                    re.height >>= 1;
1446
0
                    goto copy;
1447
0
                } else {
1448
                    /* Split a single (very long) row. */
1449
0
                    int w2 = w1 >> 1;
1450
1451
0
                    code = clist_copy_alpha(dev, row, dx,
1452
0
                                            raster, gx_no_bitmap_id, rx, re.y,
1453
0
                                            w2, 1, color, depth);
1454
0
                    if (code >= 0)
1455
0
                        code = clist_copy_alpha(dev, row, dx + w2,
1456
0
                                                raster, gx_no_bitmap_id,
1457
0
                                                rx + w2, re.y, w1 - w2, 1,
1458
0
                                                color, depth);
1459
0
                    if (code < 0)
1460
0
                        return code;
1461
0
                    continue;
1462
0
                }
1463
0
            }
1464
0
            op += compress;
1465
0
            if (dx) {
1466
0
                if_debug0m('L', dev->memory,
1467
0
                           "[L] fake end_run: really set_misc_data_x[2]\n");
1468
0
                *dp++ = cmd_count_op(cmd_opv_set_misc, 2, dev->memory);
1469
0
                *dp++ = cmd_set_misc_data_x + dx;
1470
0
            }
1471
#ifdef DEBUG
1472
            if (gs_debug_c('L')) {
1473
                const char *const *sub = cmd_sub_op_names[op >> 4];
1474
1475
                if (sub)
1476
                    dmlprintf1(dev->memory, "[L] fake end_run: really %s\n", sub[op & 0xf]);
1477
                else
1478
                    dmlprintf2(dev->memory, "[L] fake end_run: really %s %d\n", cmd_op_names[op >> 4], op & 0xf);
1479
            }
1480
#endif
1481
0
            *dp++ = cmd_count_op(op, csize, dev->memory);
1482
0
            *dp++ = depth;
1483
0
            cmd_put2w(rx, re.y, &dp);
1484
0
            cmd_put2w(w1, re.height, &dp);
1485
0
            re.pcls->rect = rect;
1486
0
        }
1487
0
    } while ((re.y += re.height) < re.yend);
1488
0
    return 0;
1489
0
}
1490
1491
int
1492
clist_strip_copy_rop2(gx_device * dev,
1493
             const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
1494
                     const gx_color_index * scolors,
1495
           const gx_strip_bitmap * textures, const gx_color_index * tcolors,
1496
                     int rx, int ry, int rwidth, int rheight,
1497
                     int phase_x, int phase_y, gs_logical_operation_t lop,
1498
                     uint planar_height)
1499
0
{
1500
0
    gx_device_clist_writer * const cdev =
1501
0
        &((gx_device_clist *)dev)->writer;
1502
0
    gs_rop3_t rop = lop_rop(lop);
1503
0
    gx_strip_bitmap tile_with_id;
1504
0
    const gx_strip_bitmap *tiles = textures;
1505
0
    int y0;
1506
    /* Compute the set of possible colors that this operation can generate. */
1507
0
    gx_color_usage_bits all = gx_color_usage_all(cdev);
1508
0
    bool subtractive = dev->color_info.num_components >= 4; /****** HACK ******/
1509
0
    gx_color_usage_bits S =
1510
0
        (scolors ? gx_color_index2usage(dev, scolors[0] | scolors[1]) : sdata ? all : 0);
1511
0
    gx_color_usage_bits T =
1512
0
        (tcolors ? gx_color_index2usage(dev, tcolors[0] | tcolors[1]) : textures ? all : 0);
1513
0
    gs_rop3_t color_rop =
1514
0
        (subtractive ? byte_reverse_bits[rop ^ 0xff] : rop);
1515
0
    bool slow_rop;
1516
0
    cmd_rects_enum_t re;
1517
1518
0
    if (scolors != 0 && scolors[0] != scolors[1]) {
1519
0
        crop_fill(cdev, rx, ry, rwidth, rheight);
1520
0
    } else {
1521
0
        crop_copy(cdev, sdata, sourcex, sraster, id, rx, ry, rwidth, rheight);
1522
0
    }
1523
0
    if (rwidth <= 0 || rheight <= 0)
1524
0
        return 0;
1525
1526
    /* If needed, update the trans_bbox */
1527
0
    if (cdev->pdf14_needed) {
1528
0
        gs_int_rect bbox;
1529
1530
0
        bbox.p.x = rx;
1531
0
        bbox.q.x = rx + rwidth - 1;
1532
0
        bbox.p.y = ry;
1533
0
        bbox.q.y = ry + rheight - 1;
1534
1535
0
        clist_update_trans_bbox(cdev, &bbox);
1536
0
    }
1537
    /*
1538
     * On CMYK devices, RasterOps must be executed with complete pixels
1539
     * if the operation involves the destination.
1540
     * This is because the black plane interacts with the other planes
1541
     * in the conversion between RGB and CMYK.  Check for this now.
1542
     */
1543
0
    {
1544
0
        gs_rop3_t rop_used = rop;
1545
1546
0
        if (scolors && (scolors[0] == scolors[1]))
1547
0
            rop_used = (scolors[0] == gx_device_black(dev) ?
1548
0
                        rop3_know_S_0(rop_used) :
1549
0
                        scolors[0] == gx_device_white(dev) ?
1550
0
                        rop3_know_S_1(rop_used) : rop_used);
1551
0
        if (tcolors && (tcolors[0] == tcolors[1]))
1552
0
            rop_used = (tcolors[0] == gx_device_black(dev) ?
1553
0
                        rop3_know_T_0(rop_used) :
1554
0
                        tcolors[0] == gx_device_white(dev) ?
1555
0
                        rop3_know_T_1(rop_used) : rop_used);
1556
0
        slow_rop = !(rop == rop3_0 || rop == rop3_1 ||
1557
0
                     rop == rop3_S || rop == rop3_T);
1558
0
    }
1559
0
    y0 = ry;
1560
0
    if (cdev->permanent_error < 0)
1561
0
      return (cdev->permanent_error);
1562
    /* If needed, update the trans_bbox */
1563
0
    if (cdev->pdf14_needed) {
1564
0
        gs_int_rect bbox;
1565
1566
0
        bbox.p.x = rx;
1567
0
        bbox.q.x = rx + rwidth - 1;
1568
0
        bbox.p.y = ry;
1569
0
        bbox.q.y = ry + rheight - 1;
1570
1571
0
        clist_update_trans_bbox(cdev, &bbox);
1572
0
    }
1573
0
    RECT_ENUM_INIT(re, ry, rheight);
1574
0
    do {
1575
0
        const byte *row = sdata + (re.y - y0) * sraster;
1576
0
        int code;
1577
1578
0
        RECT_STEP_INIT(re);
1579
        /* rops are defined to work on rop_operands, which are typically 32
1580
         * bits (unsigned long). We need to use gx_color_usage_bits, which
1581
         * are usually 64 bits. So, the following funky bit of code; although
1582
         * this is an if rather than a #if (as sizeof cannot be evaluated at
1583
         * preprocess time), it should resolve properly at compile time. */
1584
0
        if (sizeof(rop_operand) >= sizeof(gx_color_usage_bits)) {
1585
0
            gx_color_usage_bits D = re.pcls->color_usage.or;
1586
0
            re.pcls->color_usage.or =
1587
0
                    ((rop_proc_table[color_rop])((rop_operand)D, (rop_operand)S, (rop_operand)T) & all) | D;
1588
0
        } else if (2*sizeof(rop_operand) >= sizeof(gx_color_usage_bits)) {
1589
0
            rop_operand D;
1590
0
            D = (rop_operand)re.pcls->color_usage.or;
1591
0
            re.pcls->color_usage.or |=
1592
0
                    ((rop_proc_table[color_rop])(D, (rop_operand)S, (rop_operand)T) & all);
1593
0
#define DOWN(x) ((rop_operand)(((x)>>(4*sizeof(rop_operand)))>>(4*sizeof(rop_operand))))
1594
0
#define UP(x)   ((((gx_color_usage_bits)(x))<<(4*sizeof(rop_operand)))<<(4*sizeof(rop_operand)))
1595
0
            D = DOWN(re.pcls->color_usage.or);
1596
0
            re.pcls->color_usage.or |=
1597
0
                    UP((rop_proc_table[color_rop])(D, DOWN(S), DOWN(T))) & all;
1598
0
#undef DOWN
1599
0
#undef UP
1600
0
        }
1601
0
        re.pcls->color_usage.slow_rop |= slow_rop;
1602
0
        if (rop3_uses_T(rop)) {
1603
0
            if (tcolors == 0 || tcolors[0] != tcolors[1]) {
1604
0
                ulong offset_temp;
1605
1606
0
                if (!cls_has_tile_id(cdev, re.pcls, tiles->id, offset_temp)) {
1607
                    /* Change tile.  If there is no id, generate one. */
1608
0
                    if (tiles->id == gx_no_bitmap_id) {
1609
0
                        tile_with_id = *tiles;
1610
0
                        tile_with_id.id = gs_next_ids(dev->memory, 1);
1611
0
                        tiles = &tile_with_id;
1612
0
                    }
1613
0
                    code = clist_change_bits(cdev, re.pcls, tiles,
1614
0
                                            (tcolors != 0 ? 1 :
1615
0
                                                 cdev->clist_color_info.depth));
1616
0
                    if (code < 0 && !(code == gs_error_limitcheck))
1617
0
                        return code;
1618
0
                    if (code < 0) {
1619
                        /*
1620
                         * The error is a limitcheck: we have a tile that
1621
                         * is too big to fit in the command reading buffer.
1622
                         * For now, just divide up the transfer into scan
1623
                         * lines.  (If a single scan line won't fit, punt.)
1624
                         * Eventually, we'll need a way to transfer the tile
1625
                         * in pieces.
1626
                         */
1627
0
                        uint rep_height = tiles->rep_height;
1628
0
                        gs_id ids;
1629
0
                        gx_strip_bitmap line_tile;
1630
0
                        int data_shift = 0, phase_shift = 0, raster;
1631
0
                        int new_phase = phase_x;
1632
0
                        int tile_space_phase;
1633
0
                        int iy;
1634
1635
0
                        if (rep_height == 1 ||
1636
                            /****** CAN'T HANDLE SHIFT YET ******/
1637
0
                            tiles->rep_shift != 0
1638
0
                            )
1639
0
                            return code;
1640
                        /*
1641
                         * Allocate enough fake IDs, since the inner call on
1642
                         * clist_strip_copy_rop will need them anyway.
1643
                         */
1644
0
                        ids = gs_next_ids(dev->memory, min(re.height, rep_height));
1645
0
                        line_tile = *tiles;
1646
0
                        line_tile.size.y = 1;
1647
0
                        line_tile.rep_height = 1;
1648
0
                        raster = line_tile.raster;
1649
0
                        if (line_tile.num_planes > 0)
1650
0
                            line_tile.raster *= tiles->size.y;
1651
                        /* The rasterizer assumes tile phase relatively to the rectangle origin,
1652
                           (see x_offset in gdevmr8n.c), so compute "the tile phase in the tile space"
1653
                           with same expression : */
1654
0
                        tile_space_phase = (rx + phase_x) % tiles->rep_width;
1655
0
                        if (tile_space_phase + rwidth <= tiles->rep_width) {
1656
                            /* Narrow the tile to prevent buffer overflow - bug 689588.
1657
                               Note currently we don't narrow "wrapped" tiles (because bug 689588 doesn't need) :
1658
                               when tile_space_phase < rep_width && tile_space_phase + rwidth > rep_width,
1659
                               each line to be converted into 2 ones.
1660
                            */
1661
0
                            int depth = cdev->clist_color_info.depth;
1662
1663
0
                            if (line_tile.num_planes > 0)
1664
0
                                depth /= line_tile.num_planes;
1665
#         if 0
1666
                            /* Align bitmap data : */
1667
                            data_shift = ((tile_space_phase * depth) >> (log2_align_bitmap_mod + 3)) << log2_align_bitmap_mod;
1668
#         else
1669
0
                            data_shift = tile_space_phase * depth / 8; /* No bitmap data alignment because we'll only write it to clist.  */
1670
0
#         endif
1671
0
                            phase_shift = data_shift * 8 / depth;
1672
0
                            line_tile.rep_width = rwidth + (tile_space_phase - phase_shift);
1673
                            /* Normally line_tile.raster must account trailing row alignment bytes and
1674
                               to be computed as bitmap_raster(line_tile.rep_width * depth);
1675
                               but we can't apply it here because the trailing alignment bytes may be absent
1676
                               due to data_shift. We believe it is not harmful because we just write the data to clist,
1677
                               and because the bitmap height is 1.
1678
                               The clist reader must provide the trailing bytes if the rasterizer needs them.
1679
                             */
1680
0
                            if (line_tile.num_planes <= 1)
1681
0
                                line_tile.raster = (line_tile.rep_width * depth + 7) / 8;
1682
0
                            line_tile.size.x = line_tile.rep_width;
1683
0
                            line_tile.shift = 0;
1684
0
                            new_phase = (tile_space_phase - phase_shift - rx % line_tile.rep_width);
1685
                            /* Provide a positive phase for clist reader : */
1686
0
                            new_phase = (new_phase + line_tile.rep_width) % line_tile.rep_width;
1687
0
                        }
1688
0
                        for (iy = 0; iy < re.height; ++iy) {
1689
0
                            line_tile.data = tiles->data + raster *
1690
0
                                ((re.y + iy + phase_y) % rep_height) + data_shift;
1691
0
                            line_tile.id = ids + (iy % rep_height);
1692
0
                            code = clist_strip_copy_rop2(dev,
1693
0
                                    (sdata == 0 ? 0 : row + iy * sraster),
1694
0
                                    sourcex, sraster,
1695
0
                                    gx_no_bitmap_id, scolors,
1696
0
                                    &line_tile, tcolors,
1697
0
                                    rx, re.y + iy, rwidth, 1,
1698
0
                                    new_phase, 0, lop, planar_height);
1699
0
                            if (code < 0)
1700
0
                                return code;
1701
0
                        }
1702
0
                        continue;
1703
0
                    }
1704
0
                }
1705
0
                if (((phase_x != re.pcls->tile_phase.x) && (tiles->rep_width > 1)) ||
1706
0
                    ((phase_y != re.pcls->tile_phase.y) && (tiles->rep_height > 1))) {
1707
0
                    code = cmd_set_tile_phase(cdev, re.pcls, phase_x,
1708
0
                                              phase_y);
1709
0
                    if (code < 0)
1710
0
                        return code;
1711
0
                }
1712
0
            }
1713
            /* Set the tile colors. */
1714
0
            code =
1715
0
                (tcolors != 0 ?
1716
0
                 cmd_set_tile_colors(cdev, re.pcls, tcolors[0], tcolors[1]) :
1717
0
                 cmd_set_tile_colors(cdev, re.pcls, gx_no_color_index,
1718
0
                                     gx_no_color_index));
1719
0
            if (code < 0)
1720
0
                return code;
1721
0
        }
1722
0
        code = 0;
1723
0
        if (lop != re.pcls->lop)
1724
0
            code = cmd_set_lop(cdev, re.pcls, lop);
1725
0
        if (code >= 0)
1726
0
            code = cmd_enable_lop(cdev, re.pcls);
1727
0
        if (code < 0)
1728
0
            return code;
1729
        /* Set lop_enabled to -1 so that fill_rectangle / copy_* */
1730
        /* won't attempt to set it to 0. */
1731
0
        re.pcls->lop_enabled = -1;
1732
0
        if (scolors != NULL) {
1733
0
            if (scolors[0] == scolors[1])
1734
0
                code = clist_fill_rectangle(dev, rx, re.y, rwidth, re.height,
1735
0
                                            scolors[1]);
1736
0
            else
1737
0
                code = clist_copy_mono(dev, row, sourcex, sraster, id,
1738
0
                                       rx, re.y, rwidth, re.height,
1739
0
                                       scolors[0], scolors[1]);
1740
0
        } else if (planar_height) {
1741
0
            code = clist_copy_planes(dev, row, sourcex, sraster, id,
1742
0
                                     rx, re.y, rwidth, re.height,
1743
0
                                     planar_height);
1744
0
        } else {
1745
0
            code = clist_copy_color(dev, row, sourcex, sraster, id,
1746
0
                                    rx, re.y, rwidth, re.height);
1747
0
        }
1748
0
        re.pcls->lop_enabled = 1;
1749
0
        if (code < 0)
1750
0
            return code;
1751
0
    } while ((re.y += re.height) < re.yend);
1752
0
    return 0;
1753
0
}