Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpdfd.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Path drawing procedures for pdfwrite driver */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gxdevice.h"
22
#include "gxfixed.h"
23
#include "gxgstate.h"
24
#include "gxpaint.h"
25
#include "gxcoord.h"
26
#include "gxdevmem.h"
27
#include "gxcolor2.h"
28
#include "gxhldevc.h"
29
#include "gsstate.h"
30
#include "gxstate.h"
31
#include "gserrors.h"
32
#include "gsptype2.h"
33
#include "gsshade.h"
34
#include "gzpath.h"
35
#include "gzcpath.h"
36
#include "gdevpdfx.h"
37
#include "gdevpdfg.h"
38
#include "gdevpdfo.h"
39
#include "gsutil.h"
40
#include "gdevpdtf.h"
41
#include "gdevpdts.h"
42
#include "gxdevsop.h"
43
44
/* ---------------- Drawing ---------------- */
45
46
/* Fill a rectangle. */
47
int
48
gdev_pdf_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
49
                        gx_color_index color)
50
87.2M
{
51
87.2M
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
52
87.2M
    int code;
53
54
87.2M
    if (pdev->Eps2Write) {
55
87.2M
        float x0, y0, x1, y1;
56
87.2M
        gs_rect *Box;
57
58
87.2M
        if (!pdev->accumulating_charproc) {
59
85.1M
            Box = &pdev->BBox;
60
85.1M
            x0 = x / (pdev->HWResolution[0] / 72.0);
61
85.1M
            y0 = y / (pdev->HWResolution[1] / 72.0);
62
85.1M
            x1 = x0 + (w / (pdev->HWResolution[0] / 72.0));
63
85.1M
            y1 = y0 + (h / (pdev->HWResolution[1] / 72.0));
64
85.1M
        }
65
2.08M
        else {
66
2.08M
            Box = &pdev->charproc_BBox;
67
2.08M
            x0 = (float)x / 100;
68
2.08M
            y0 = (float)y / 100;
69
2.08M
            x1 = x0 + (w / 100);
70
2.08M
            y1 = y0 + (h / 100);
71
2.08M
        }
72
73
87.2M
        if (Box->p.x > x0)
74
33.5k
            Box->p.x = x0;
75
87.2M
        if (Box->p.y > y0)
76
16.0k
            Box->p.y = y0;
77
87.2M
        if (Box->q.x < x1)
78
2.03M
            Box->q.x = x1;
79
87.2M
        if (Box->q.y < y1)
80
1.35M
            Box->q.y = y1;
81
87.2M
        if (pdev->AccumulatingBBox)
82
87.1M
            return 0;
83
87.2M
    }
84
135k
    code = pdf_open_page(pdev, PDF_IN_STREAM);
85
135k
    if (code < 0)
86
0
        return code;
87
    /* Make sure we aren't being clipped. */
88
135k
    code = pdf_put_clip_path(pdev, NULL);
89
135k
    if (code < 0)
90
0
        return code;
91
135k
    pdf_set_pure_color(pdev, color, &pdev->saved_fill_color,
92
135k
                       &pdev->fill_used_process_color,
93
135k
                       &psdf_set_fill_color_commands);
94
135k
    if (!pdev->HaveStrokeColor)
95
134k
        pdev->saved_stroke_color = pdev->saved_fill_color;
96
135k
    pprintd4(pdev->strm, "%d %d %d %d re f\n", x, y, w, h);
97
135k
    return 0;
98
135k
}
99
100
/* ---------------- Path drawing ---------------- */
101
102
/* ------ Vector device implementation ------ */
103
104
static int
105
pdf_setlinewidth(gx_device_vector * vdev, double width)
106
99.9k
{
107
    /* Acrobat Reader doesn't accept negative line widths. */
108
99.9k
    return psdf_setlinewidth(vdev, fabs(width));
109
99.9k
}
110
111
static bool
112
pdf_can_handle_hl_color(gx_device_vector * vdev, const gs_gstate * pgs,
113
                 const gx_drawing_color * pdc)
114
2.20M
{
115
2.20M
    return pgs != NULL;
116
2.20M
}
117
118
static int
119
pdf_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs,
120
                 const gx_drawing_color * pdc)
121
1.51M
{
122
1.51M
    gx_device_pdf *const pdev = (gx_device_pdf *)vdev;
123
1.51M
    bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pgs, pdc);
124
1.51M
    const gs_gstate *pgs_for_hl_color = (hl_color ? pgs : NULL);
125
126
1.51M
    if (!pdev->HaveStrokeColor) {
127
        /* opdfread.ps assumes same color for stroking and non-stroking operations. */
128
544k
        int code = pdf_set_drawing_color(pdev, pgs_for_hl_color, pdc, &pdev->saved_stroke_color,
129
544k
                                    &pdev->stroke_used_process_color,
130
544k
                                    &psdf_set_stroke_color_commands);
131
544k
        if (code < 0)
132
9.91k
            return code;
133
544k
    }
134
1.50M
    return pdf_set_drawing_color(pdev, pgs_for_hl_color, pdc, &pdev->saved_fill_color,
135
1.50M
                                 &pdev->fill_used_process_color,
136
1.50M
                                 &psdf_set_fill_color_commands);
137
1.51M
}
138
139
static int
140
pdf_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs,
141
                   const gx_drawing_color * pdc)
142
103k
{
143
103k
    gx_device_pdf *const pdev = (gx_device_pdf *)vdev;
144
103k
    bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pgs, pdc);
145
103k
    const gs_gstate *pgs_for_hl_color = (hl_color ? pgs : NULL);
146
147
103k
    if (!pdev->HaveStrokeColor) {
148
        /* opdfread.ps assumes same color for stroking and non-stroking operations. */
149
39.9k
        int code = pdf_set_drawing_color(pdev, pgs_for_hl_color, pdc, &pdev->saved_fill_color,
150
39.9k
                                 &pdev->fill_used_process_color,
151
39.9k
                                 &psdf_set_fill_color_commands);
152
39.9k
        if (code < 0)
153
117
            return code;
154
39.9k
    }
155
103k
    return pdf_set_drawing_color(pdev, pgs_for_hl_color, pdc, &pdev->saved_stroke_color,
156
103k
                                 &pdev->stroke_used_process_color,
157
103k
                                 &psdf_set_stroke_color_commands);
158
103k
}
159
160
static int
161
pdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
162
           gx_path_type_t type)
163
551k
{
164
551k
    gx_device_pdf *pdev = (gx_device_pdf *)vdev;
165
551k
    fixed xmax = int2fixed(32766), ymax = int2fixed(32766);
166
551k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
167
551k
    fixed xmin = (pdev->sbstack_depth > bottom ? -xmax : 0);
168
551k
    fixed ymin = (pdev->sbstack_depth > bottom ? -ymax : 0);
169
170
    /*
171
     * If we're doing a stroke operation, expand the checking box by the
172
     * stroke width.
173
     */
174
551k
    if (type & gx_path_type_stroke) {
175
156k
        double w = vdev->state.line_params.half_width;
176
156k
        double xw = w * (fabs(vdev->state.ctm.xx) + fabs(vdev->state.ctm.yx));
177
156k
        int d = float2fixed(xw) + fixed_1;
178
179
156k
        xmin -= d;
180
156k
        xmax += d;
181
156k
        ymin -= d;
182
156k
        ymax += d;
183
156k
    }
184
551k
    if (pdev->PDFA == 1) {
185
        /* Check values, and decide how to proceed based on PDFACompatibilitylevel */
186
0
        if (x0 < xmin || y0 < ymin || x1 - x0 > xmax || y1 - y0 >ymax) {
187
0
            switch(pdev->PDFACompatibilityPolicy) {
188
0
                case 0:
189
0
                    emprintf(pdev->memory,
190
0
                         "Required co-ordinate outside valid range for PDF/A-1, reverting to normal PDF output.\n");
191
0
                    pdev->AbortPDFAX = true;
192
0
                    pdev->PDFA = 0;
193
0
                    break;
194
0
                case 1:
195
0
                    emprintf(pdev->memory,
196
0
                         "Required co-ordinate outside valid range for PDF/A-1, clamping to valid range, output may be incorrect.\n");
197
                    /*
198
                     * Clamp coordinates to avoid tripping over Acrobat Reader's limit
199
                     * of 32K on user coordinate values, which was adopted by the PDF/A-1 spec.
200
                     */
201
0
                    if (x0 < xmin)
202
0
                        x0 = xmin;
203
204
0
                    if (y0 < ymin)
205
0
                        y0 = ymin;
206
207
                    /* We used to clamp x1 and y1 here, but actually, because this is a rectangle
208
                     * we don't need to do that, we need to clamp the *difference* between x0,x1
209
                     * and y0,y1 to keep it inside the Acrobat 4 or 5 limits.
210
                     */
211
0
                    if (x1 - x0 > xmax)
212
0
                        x1 = x0 + xmax;
213
0
                    if (y1 - y0 > ymax)
214
0
                        y1 = y0 + ymax;
215
0
                    break;
216
0
                default:
217
0
                case 2:
218
0
                    emprintf(pdev->memory,
219
0
                         "Required co-ordinate outside valid range for PDF/A-1, aborting.\n");
220
0
                    return_error(gs_error_limitcheck);
221
0
                    break;
222
0
            }
223
0
        }
224
0
    }
225
551k
    return psdf_dorect(vdev, x0, y0, x1, y1, type);
226
551k
}
227
228
static int
229
pdf_endpath(gx_device_vector * vdev, gx_path_type_t type)
230
1.44M
{
231
1.44M
    return 0;     /* always handled by caller */
232
1.44M
}
233
234
const gx_device_vector_procs pdf_vector_procs = {
235
        /* Page management */
236
    NULL,
237
        /* Imager state */
238
    pdf_setlinewidth,
239
    psdf_setlinecap,
240
    psdf_setlinejoin,
241
    psdf_setmiterlimit,
242
    psdf_setdash,
243
    psdf_setflat,
244
    psdf_setlogop,
245
        /* Other state */
246
    pdf_can_handle_hl_color,
247
    pdf_setfillcolor,
248
    pdf_setstrokecolor,
249
        /* Paths */
250
    psdf_dopath,
251
    pdf_dorect,
252
    psdf_beginpath,
253
    psdf_moveto,
254
    psdf_lineto,
255
    psdf_curveto,
256
    psdf_closepath,
257
    pdf_endpath
258
};
259
260
/* ------ Utilities ------ */
261
262
/* Store a copy of clipping path. */
263
int
264
pdf_remember_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
265
311k
{
266
311k
    int code = 0;
267
    /* Used for skipping redundant clip paths. SF bug #624168. */
268
311k
    if (pdev->clip_path != 0) {
269
0
        gx_path_free(pdev->clip_path, "pdf clip path");
270
0
    }
271
311k
    if (pcpath == 0) {
272
197k
        pdev->clip_path = 0;
273
197k
        return 0;
274
197k
    }
275
113k
    pdev->clip_path = gx_path_alloc(pdev->pdf_memory, "pdf clip path");
276
113k
    if (pdev->clip_path == 0)
277
0
        return_error(gs_error_VMerror);
278
279
113k
    code = gx_cpath_to_path((gx_clip_path *)pcpath, pdev->clip_path);
280
113k
    if (code < 0)
281
0
        return code;
282
283
    /* gx_cpath_to_path above ends up going through gx_path_assign_preserve
284
     * which specifically states that the segments of the paths (in this case pcpath
285
     * and pdev->clip_path) must have been allocated with the same allocator.
286
     * If that's not true (eg pdfi running inside GS) then we need to 'unshare'
287
     * the path. Otherwise we mauy end up with pcpath being freed and discarded
288
     * while the pdfwrite devcie still thinks it has a pointer to it.
289
     */
290
113k
    if (pcpath->path.memory != pdev->pdf_memory)
291
113k
        code = gx_path_unshare(pdev->clip_path);
292
293
113k
    return code;
294
113k
}
295
296
/* Check if same clipping path. */
297
static int
298
pdf_is_same_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
299
280k
{
300
    /* Used for skipping redundant clip paths. SF bug #624168. */
301
280k
    gs_cpath_enum cenum;
302
280k
    gs_path_enum penum;
303
280k
    gs_fixed_point vs0[3], vs1[3];
304
280k
    int code, pe_op;
305
306
280k
    if ((pdev->clip_path != 0) != (pcpath != 0))
307
166k
        return 0;
308
    /* Both clip paths are empty, so the same */
309
114k
    if (pdev->clip_path == 0)
310
0
        return 1;
311
114k
    code = gx_path_enum_init(&penum, pdev->clip_path);
312
114k
    if (code < 0)
313
0
        return code;
314
114k
    code = gx_cpath_enum_init(&cenum, (gx_clip_path *)pcpath);
315
114k
    if (code < 0)
316
0
        return code;
317
    /* This flags a warning in Coverity, uninitialised variable cenum.first_visit */
318
    /* This is because gx_cpath_enum_init doesn't initialise first_visit, but the */
319
    /* variable can be used in enum_next. However, this is not truly used this    */
320
    /* way. The enum_init sets the 'state' to 'scan', and the first thing that happens */
321
    /* in enum_next when state is 'scan' is to set first_visit. */
322
291k
    while ((code = gx_cpath_enum_next(&cenum, vs0)) > 0) {
323
272k
        pe_op = gx_path_enum_next(&penum, vs1);
324
272k
        if (pe_op < 0)
325
0
            return pe_op;
326
272k
        if (pe_op != code)
327
751
            return 0;
328
271k
        switch (pe_op) {
329
0
            case gs_pe_curveto:
330
0
                if (vs0[1].x != vs1[1].x || vs0[1].y != vs1[1].y ||
331
0
                    vs0[2].x != vs1[2].x || vs0[2].y != vs1[2].y)
332
0
                    return 0;
333
                /* fall through */
334
121k
            case gs_pe_moveto:
335
259k
            case gs_pe_lineto:
336
259k
            case gs_pe_gapto:
337
259k
                if (vs0[0].x != vs1[0].x || vs0[0].y != vs1[0].y)
338
95.4k
                    return 0;
339
271k
        }
340
271k
    }
341
18.4k
    if (code < 0)
342
0
        return code;
343
18.4k
    code = gx_path_enum_next(&penum, vs1);
344
18.4k
    if (code < 0)
345
0
        return code;
346
18.4k
    return (code == 0);
347
18.4k
}
348
349
int
350
pdf_check_soft_mask(gx_device_pdf * pdev, gs_gstate * pgs)
351
8.21M
{
352
8.21M
    int code = 0;
353
354
8.21M
    if (pgs && pdev->state.soft_mask_id != pgs->soft_mask_id) {
355
    /*
356
     * The contents must be open already, so the following will only exit
357
     * text or string context.
358
     */
359
402
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
360
402
    if (code < 0)
361
0
        return code;
362
402
    if (pdev->vgstack_depth > pdev->vgstack_bottom) {
363
205
        code = pdf_restore_viewer_state(pdev, pdev->strm);
364
205
        if (code < 0)
365
0
            return code;
366
205
    }
367
402
    }
368
8.21M
    return code;
369
8.21M
}
370
371
/* Test whether we will need to put the clipping path. */
372
bool
373
pdf_must_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
374
9.04M
{
375
9.04M
    if (pcpath == NULL) {
376
17.3k
        if (pdev->clip_path_id == pdev->no_clip_path_id)
377
14.9k
            return false;
378
9.02M
    } else {
379
9.02M
        if (pdev->clip_path_id == pcpath->id)
380
747k
            return false;
381
8.27M
        if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
382
8.27M
                                        int2fixed(pdev->width),
383
8.27M
                                        int2fixed(pdev->height)))
384
8.12M
            if (pdev->clip_path_id == pdev->no_clip_path_id)
385
8.11M
                return false;
386
166k
        if (pdf_is_same_clip_path(pdev, pcpath) > 0) {
387
18.1k
            pdev->clip_path_id = pcpath->id;
388
18.1k
            return false;
389
18.1k
        }
390
166k
    }
391
151k
    return true;
392
9.04M
}
393
394
static int pdf_write_path(gx_device_pdf * pdev, gs_path_enum *cenum, gdev_vector_dopath_state_t *state, gx_path *path, int is_clip_enum,
395
                               gx_path_type_t type, const gs_matrix *pmat)
396
1.35M
{
397
1.35M
    int pe_op;
398
1.35M
    gdev_vector_path_seg_record segments[5] = {0};
399
1.35M
    int i, seg_index = 0, is_rect = 1, buffering = 0, initial_m = 0, segs = 0, code, matrix_optimisable = 0;
400
1.35M
    gx_path_rectangular_type rtype = prt_none;
401
1.35M
    gs_fixed_rect rbox;
402
1.35M
    gx_device_vector *vdev = (gx_device_vector *)pdev;
403
1.35M
    gs_fixed_point line_start = {0,0};
404
1.35M
    gs_point p, q;
405
1.35M
    bool do_close = (type & (gx_path_type_clip | gx_path_type_stroke | gx_path_type_always_close)) != 0;
406
1.35M
    bool stored_moveto = false;
407
408
1.35M
    gdev_vector_dopath_init(state, (gx_device_vector *)pdev,
409
1.35M
                            type, pmat);
410
1.35M
    if (is_clip_enum)
411
48.3k
        code = gx_cpath_enum_init((gs_cpath_enum *)cenum, (gx_clip_path *)path);
412
1.30M
    else {
413
1.30M
        code = gx_path_enum_init(cenum, path);
414
1.30M
        rtype = gx_path_is_rectangular(path, &rbox);
415
1.30M
    }
416
1.35M
    if (code < 0)
417
0
        return code;
418
419
1.35M
    if((pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) &&
420
1.34M
        (state->scale_mat.xx == 1.0 && state->scale_mat.yy == 1.0 &&
421
1.34M
        is_xxyy(&state->scale_mat) && is_fzero2(state->scale_mat.tx, state->scale_mat.ty))) {
422
1.30M
         matrix_optimisable = 1;
423
1.30M
         buffering = 1;
424
1.30M
    }
425
    /*
426
     * if the path type is stroke, we only recognize closed
427
     * rectangles; otherwise, we recognize all rectangles.
428
     * Note that for stroking with a transformation, we can't use dorect,
429
     * which requires (untransformed) device coordinates.
430
     */
431
1.35M
    if (rtype != prt_none &&
432
468k
        (!(type & gx_path_type_stroke) || rtype == prt_closed) &&
433
468k
          matrix_optimisable == 1)
434
460k
    {
435
460k
        gs_point p, q;
436
437
460k
        gs_point_transform_inverse((double)rbox.p.x, (double)rbox.p.y,
438
460k
                                   &state->scale_mat, &p);
439
460k
        gs_point_transform_inverse((double)rbox.q.x, (double)rbox.q.y,
440
460k
                                   &state->scale_mat, &q);
441
460k
        code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
442
460k
                                       (fixed)q.x, (fixed)q.y, type);
443
460k
        if (code >= 0) {
444
460k
            if (code == 0)
445
460k
                return 1;
446
0
            return code;
447
460k
        }
448
        /* If the dorect proc failed, use a general path. */
449
460k
    }
450
451
    /* The following is an optimisation for space. If we see a closed subpath
452
     * which is a rectangle, emit it as a 're' instead of writing the individual
453
     * segments of the path. Note that 're' always applies the width before the
454
     * height when constructing the path, so we must take care to ensure that
455
     * we get the path direction correct. We do ths by detecting whether the path
456
     * moves first in the x or y directoin, if it moves in the y direction first,
457
     * we simply move one vertex round the rectangle, ie we start at point 2.
458
     */
459
9.12M
    do {
460
9.12M
        if (is_clip_enum)
461
396k
            segments[seg_index].op = pe_op = gx_cpath_enum_next((gs_cpath_enum *)cenum, segments[seg_index].vs);
462
8.73M
        else
463
8.73M
            segments[seg_index].op = pe_op = gx_path_enum_next(cenum, segments[seg_index].vs);
464
465
9.12M
        if (segs == 0 && pe_op > 0)
466
891k
            segs = 1;
467
468
9.12M
        if (type & gx_path_type_fill && pe_op == gs_pe_gapto) {
469
0
            pe_op = gs_pe_lineto;
470
0
            segments[seg_index].op = gs_pe_lineto;
471
0
        }
472
473
9.12M
        switch(pe_op) {
474
1.30M
            case gs_pe_moveto:
475
1.30M
            case gs_pe_gapto:
476
1.30M
                if (!buffering) {
477
219k
                    stored_moveto = true;
478
219k
                    line_start = segments[0].vs[0];
479
219k
                    seg_index = -1;
480
1.08M
                } else {
481
1.45M
                    for (i=0;i<seg_index;i++) {
482
370k
                        gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
483
370k
                    }
484
1.08M
                    line_start = segments[seg_index].vs[0];
485
1.08M
                    segments[0] = segments[seg_index];
486
1.08M
                    seg_index = 0;
487
1.08M
                    initial_m = 1;
488
1.08M
                }
489
1.30M
                break;
490
3.45M
            case gs_pe_lineto:
491
3.45M
                if (!buffering) {
492
1.73M
                    if (stored_moveto) {
493
131k
                        gdev_vector_dopath_segment(state, gs_pe_moveto, &line_start);
494
131k
                        stored_moveto = false;
495
131k
                    }
496
3.47M
                    for (i=0;i<=seg_index;i++)
497
1.73M
                        gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
498
1.73M
                    seg_index = -1;
499
1.73M
                } else {
500
1.71M
                    if (!initial_m) {
501
0
                        for (i=0;i<=seg_index;i++) {
502
0
                            gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
503
0
                        }
504
0
                        buffering = 0;
505
0
                        seg_index = -1;
506
0
                    }
507
1.71M
                    if (type & gx_path_type_optimize && seg_index > 0) {
508
1.71M
                        if (segments[seg_index - 1].op == gs_pe_lineto) {
509
777k
                            if (segments[seg_index].vs[0].x == segments[seg_index - 1].vs[0].x && segments[seg_index].vs[0].x == line_start.x) {
510
125k
                                if (segments[seg_index - 1].vs[0].y > line_start.y && segments[seg_index].vs[0].y >= segments[seg_index - 1].vs[0].y) {
511
48.1k
                                    segments[seg_index - 1].vs[0].y = segments[seg_index].vs[0].y;
512
48.1k
                                    seg_index--;
513
77.2k
                                } else {
514
77.2k
                                    if (segments[seg_index - 1].vs[0].y < line_start.y && segments[seg_index].vs[0].y <= segments[seg_index - 1].vs[0].y) {
515
48.8k
                                        segments[seg_index - 1].vs[0].y = segments[seg_index].vs[0].y;
516
48.8k
                                        seg_index--;
517
48.8k
                                    } else
518
28.3k
                                        line_start = segments[seg_index - 1].vs[0];
519
77.2k
                                }
520
652k
                            } else {
521
652k
                                if (segments[seg_index].vs[0].y == segments[seg_index - 1].vs[0].y && segments[seg_index].vs[0].y == line_start.y) {
522
7.28k
                                    if (segments[seg_index - 1].vs[0].x > line_start.x && segments[seg_index].vs[0].x > segments[seg_index - 1].vs[0].x) {
523
702
                                        segments[seg_index - 1].vs[0].x = segments[seg_index].vs[0].x;
524
702
                                        seg_index--;
525
6.58k
                                    } else {
526
6.58k
                                        if (segments[seg_index - 1].vs[0].x < line_start.x && segments[seg_index].vs[0].x < segments[seg_index - 1].vs[0].x) {
527
803
                                            segments[seg_index - 1].vs[0].x = segments[seg_index].vs[0].x;
528
803
                                            seg_index--;
529
803
                                        } else
530
5.77k
                                            line_start = segments[seg_index - 1].vs[0];
531
6.58k
                                    }
532
7.28k
                                } else
533
644k
                                    line_start = segments[seg_index - 1].vs[0];
534
652k
                            }
535
777k
                        }
536
1.71M
                    }
537
1.71M
                }
538
3.45M
                break;
539
3.19M
            case gs_pe_curveto:
540
3.19M
                if (stored_moveto) {
541
85.2k
                    gdev_vector_dopath_segment(state, gs_pe_moveto, &line_start);
542
85.2k
                    stored_moveto = false;
543
85.2k
                }
544
6.71M
                for (i=0;i<=seg_index;i++) {
545
3.52M
                    gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
546
3.52M
                }
547
3.19M
                line_start = segments[seg_index].vs[2];
548
3.19M
                seg_index = -1;
549
3.19M
                buffering = 0;
550
3.19M
                break;
551
384k
            case gs_pe_closepath:
552
384k
                if (!buffering || seg_index < 4) {
553
171k
                    if (stored_moveto && ((type & gx_path_type_stroke) && !(type & gx_path_type_fill)))
554
199
                        gdev_vector_dopath_segment(state, gs_pe_moveto, &line_start);
555
171k
                    stored_moveto = false;
556
171k
                    if (!do_close) {
557
128k
                        i = seg_index;
558
129k
                        while (i > 0 && segments[i - 1].op == gs_pe_moveto) {
559
1.48k
                            segments[i - 1] = segments[i];
560
1.48k
                            i--;
561
1.48k
                        }
562
128k
                        seg_index = i;
563
342k
                        for (i=0;i<seg_index;i++)
564
214k
                            gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
565
566
128k
                        seg_index = 0;
567
128k
                        if (is_clip_enum)
568
0
                            segments[seg_index].op = pe_op = gx_cpath_enum_next((gs_cpath_enum *)cenum, segments[seg_index].vs);
569
128k
                        else
570
128k
                            segments[seg_index].op = pe_op = gx_path_enum_next(cenum, segments[seg_index].vs);
571
572
128k
                        if (pe_op > 0) {
573
27.1k
                            gdev_vector_dopath_segment(state, gs_pe_closepath, segments[0].vs);
574
27.1k
                            if (pe_op == gs_pe_moveto) {
575
27.1k
                                if (matrix_optimisable)
576
27.1k
                                    buffering = 1;
577
0
                                else
578
0
                                    buffering = 0;
579
27.1k
                                seg_index = 0;
580
27.1k
                                initial_m = 1;
581
27.1k
                                line_start = segments[0].vs[0];
582
27.1k
                            } else {
583
0
                                gdev_vector_dopath_segment(state, segments[0].op, segments[0].vs);
584
0
                                buffering = 0;
585
0
                                seg_index = -1;
586
0
                            }
587
27.1k
                        }
588
128k
                    } else {
589
103k
                        for (i=0;i<=seg_index;i++)
590
60.1k
                            gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
591
43.8k
                        if (matrix_optimisable)
592
33.3k
                            buffering = 1;
593
10.5k
                        else
594
10.5k
                            buffering = 0;
595
43.8k
                        seg_index = -1;
596
43.8k
                    }
597
212k
                } else {
598
212k
                    is_rect = 1;
599
493k
                    for (i=1;i<seg_index;i++) {
600
401k
                        if (segments[i - 1].vs[0].x != segments[i].vs[0].x) {
601
252k
                            if (segments[i - 1].vs[0].y != segments[i].vs[0].y) {
602
107k
                                is_rect = 0;
603
107k
                                break;
604
144k
                            } else {
605
144k
                                if (segments[i].vs[0].x != segments[i + 1].vs[0].x || segments[i].vs[0].y == segments[i + 1].vs[0].x){
606
3.06k
                                    is_rect = 0;
607
3.06k
                                    break;
608
3.06k
                                }
609
144k
                            }
610
252k
                        } else {
611
149k
                            if (segments[i - 1].vs[0].y == segments[i].vs[0].y) {
612
3.26k
                                is_rect = 0;
613
3.26k
                                break;
614
146k
                            } else {
615
146k
                                if (segments[i].vs[0].y != segments[i + 1].vs[0].y || segments[i].vs[0].x == segments[i + 1].vs[0].x){
616
7.87k
                                    is_rect = 0;
617
7.87k
                                    break;
618
7.87k
                                }
619
146k
                            }
620
149k
                        }
621
401k
                    }
622
212k
                    if (segments[0].vs[0].x != segments[seg_index].vs[0].x || segments[0].vs[0].y != segments[seg_index].vs[0].y)
623
2.08k
                        is_rect = 0;
624
625
                    /* If we would have to alter the starting point, and we are dashing a stroke, then don't treat
626
                     * this as a rectangle. Changing the start vertex will alter the dash pattern.
627
                     */
628
212k
                    if (segments[0].vs[0].x == segments[1].vs[0].x && (type & gx_path_type_dashed_stroke))
629
0
                        is_rect = 0;
630
631
212k
                    if (is_rect == 1) {
632
90.4k
                        gs_fixed_point *pt = &segments[0].vs[0];
633
90.4k
                        fixed width, height;
634
635
90.4k
                        if (segments[0].vs[0].x == segments[1].vs[0].x) {
636
43.6k
                            pt = &segments[1].vs[0];
637
43.6k
                            width = segments[2].vs[0].x - segments[1].vs[0].x;
638
43.6k
                            height = segments[0].vs[0].y - segments[1].vs[0].y;
639
46.7k
                        } else {
640
46.7k
                            width = segments[1].vs[0].x - segments[0].vs[0].x;
641
46.7k
                            height = segments[2].vs[0].y - segments[1].vs[0].y;
642
46.7k
                        }
643
644
90.4k
                        gs_point_transform_inverse((double)pt->x, (double)pt->y,
645
90.4k
                                   &state->scale_mat, &p);
646
90.4k
                        gs_point_transform_inverse((double)width, (double)height,
647
90.4k
                                   &state->scale_mat, &q);
648
90.4k
                        code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
649
90.4k
                                       (fixed)p.x + (fixed)q.x, (fixed)p.y + (fixed)q.y, type);
650
90.4k
                        if (code < 0)
651
0
                            return code;
652
90.4k
                        seg_index = -1;
653
122k
                    } else {
654
735k
                        for (i=0;i<=seg_index;i++) {
655
612k
                            gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
656
612k
                        }
657
122k
                        buffering = 0;
658
122k
                        seg_index = -1;
659
122k
                    }
660
212k
                }
661
384k
                break;
662
793k
            default:
663
1.53M
                for (i=0;i<seg_index;i++)
664
741k
                    gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
665
793k
                if (stored_moveto && ((type & gx_path_type_stroke) && !(type & gx_path_type_fill)))
666
205
                    gdev_vector_dopath_segment(state, gs_pe_moveto, &line_start);
667
793k
                seg_index = -1;
668
793k
                buffering = 0;
669
793k
                break;
670
9.12M
        }
671
9.12M
        seg_index++;
672
9.12M
        if (seg_index > 4) {
673
240k
            for (i=0;i<seg_index;i++) {
674
200k
                gdev_vector_dopath_segment(state, segments[i].op, segments[i].vs);
675
200k
            }
676
40.0k
            seg_index = 0;
677
40.0k
            buffering = 0;
678
40.0k
        }
679
9.12M
    } while (pe_op > 0);
680
681
894k
    if (pe_op < 0)
682
0
        return pe_op;
683
684
894k
    code = vdev_proc(vdev, endpath)(vdev, type);
685
894k
    return (code < 0 ? code : segs);
686
894k
}
687
688
/* Put a single element of a clipping path list. */
689
static int
690
pdf_put_clip_path_list_elem(gx_device_pdf * pdev, gx_cpath_path_list *e,
691
        gs_path_enum *cenum, gdev_vector_dopath_state_t *state,
692
        gs_fixed_point vs[3])
693
5.27k
{
694
5.27k
    int segments = 0;
695
696
    /* This function was previously recursive and reversed the order of subpaths. This
697
     * could lead to a C exec stack overflow on sufficiently complex clipping paths
698
     * (such as those produced by pdfwrite as a fallback for certain kinds of images).
699
     * Writing the subpaths in the forward order avoids the problem, is probably
700
     * slightly faster and uses less memory. Bug #706523.
701
     */
702
16.9k
    while (e) {
703
11.6k
        segments = pdf_write_path(pdev, cenum, state, &e->path, 0, gx_path_type_clip | gx_path_type_optimize, NULL);
704
11.6k
        if (segments < 0)
705
0
            return segments;
706
11.6k
        if (segments)
707
11.6k
            pprints1(pdev->strm, "%s n\n", (e->rule <= 0 ? "W" : "W*"));
708
11.6k
        e = e->next;
709
11.6k
    }
710
5.27k
    return 0;
711
5.27k
}
712
713
/* Put a clipping path on the output file. */
714
int
715
pdf_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
716
2.63M
{
717
2.63M
    int code;
718
2.63M
    stream *s = pdev->strm;
719
2.63M
    gs_id new_id;
720
721
    /* Check for no update needed. */
722
2.63M
    if (pcpath == NULL) {
723
152k
        if (pdev->clip_path_id == pdev->no_clip_path_id)
724
152k
            return 0;
725
10
        new_id = pdev->no_clip_path_id;
726
2.47M
    } else {
727
2.47M
        if (pdev->clip_path_id == pcpath->id)
728
407k
            return 0;
729
2.07M
        new_id = pcpath->id;
730
2.07M
        if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
731
2.07M
                                        int2fixed(pdev->width),
732
2.07M
                                        int2fixed(pdev->height))
733
2.07M
            ) {
734
1.95M
            if (pdev->clip_path_id == pdev->no_clip_path_id)
735
1.95M
                return 0;
736
61
            new_id = pdev->no_clip_path_id;
737
61
        }
738
113k
        code = pdf_is_same_clip_path(pdev, pcpath);
739
113k
        if (code < 0)
740
0
            return code;
741
113k
        if (code) {
742
215
            pdev->clip_path_id = new_id;
743
215
            return 0;
744
215
        }
745
113k
    }
746
    /*
747
     * The contents must be open already, so the following will only exit
748
     * text or string context.
749
     */
750
113k
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
751
113k
    if (code < 0)
752
0
        return code;
753
    /* Use Q to unwind the old clipping path. */
754
113k
    if (pdev->vgstack_depth > pdev->vgstack_bottom) {
755
530
        code = pdf_restore_viewer_state(pdev, s);
756
530
        if (code < 0)
757
0
            return code;
758
530
    }
759
113k
    if (new_id != pdev->no_clip_path_id) {
760
113k
        gs_fixed_rect rect;
761
762
        /* Use q to allow the new clipping path to unwind.  */
763
113k
        code = pdf_save_viewer_state(pdev, s);
764
113k
        if (code < 0)
765
0
            return code;
766
        /* path_valid states that the clip path is a simple path. If the clip is an intersection of
767
         * two paths, then path_valid is false. The problem is that the rectangle list is the
768
         * scan-converted result of the clip, and ths is at the device resolution. Its possible
769
         * that the intersection of the clips, at device resolution, is rectangular but the
770
         * two paths are not, and that at a different resolution, nor is the intersection.
771
         * So we *only* want to write a rectangle, if the clip is rectangular, and its the
772
         * result of a simple rectangle. Otherwise we want to write the paths that create
773
         * the clip. However, see below about the path_list.
774
         */
775
113k
        if (pcpath->path_valid && cpath_is_rectangle(pcpath, &rect)) {
776
            /* Use unrounded coordinates. */
777
60.1k
            pprintg4(s, "%g %g %g %g re",
778
60.1k
                fixed2float(rect.p.x), fixed2float(rect.p.y),
779
60.1k
                fixed2float(rect.q.x) - fixed2float(rect.p.x),
780
60.1k
                fixed2float(rect.q.y) - fixed2float(rect.p.y));
781
60.1k
            pprints1(s, " %s n\n", (pcpath->rule <= 0 ? "W" : "W*"));
782
60.1k
        } else {
783
53.5k
            gdev_vector_dopath_state_t state;
784
53.5k
            gs_fixed_point vs[3];
785
786
            /* the first comment below is (now) incorrect. Previously in gx_clip_to_rectangle()
787
             * we would create a rectangular clip, without using a path to do so. This results
788
             * in a rectangular clip, where path_valid is false. However, we did *not* clear
789
             * the path_list! So if there had previously been a clip path set, by setting paths,
790
             * we did not clear it. This is not sensible, and caused massive confusion for this code
791
             * so it has been altered to clear path_list, indicating that there is a clip,
792
             * the path is not valid, and that it was not created using arbitrary paths.
793
             * In this case we just emit the rectangle as well (there should be only one).
794
             */
795
53.5k
            if (pcpath->path_list == NULL) {
796
                /*
797
                 * We think this should be never executed.
798
                 * This obsolete branch writes a clip path intersection
799
                 * as a set of rectangles computed by
800
                 * gx_cpath_intersect_path_slow.
801
                 * Those rectangles use coordinates rounded to pixels,
802
                 * therefore the precision may be unsatisfactory -
803
                 * see Bug 688407.
804
                 */
805
48.3k
                gs_cpath_enum cenum;
806
807
                /*
808
                 * We have to break 'const' here because the clip path
809
                 * enumeration logic uses some internal mark bits.
810
                 * This is very unfortunate, but until we can come up with
811
                 * a better algorithm, it's necessary.
812
                 */
813
48.3k
                code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)pcpath, 1, gx_path_type_clip | gx_path_type_optimize, NULL);
814
48.3k
                if (code < 0)
815
0
                    return code;
816
48.3k
                pprints1(s, "%s n\n", (pcpath->rule <= 0 ? "W" : "W*"));
817
48.3k
            } else {
818
5.27k
                gs_path_enum cenum;
819
820
5.27k
                code = pdf_put_clip_path_list_elem(pdev, pcpath->path_list, &cenum, &state, vs);
821
5.27k
                if (code < 0)
822
0
                    return code;
823
5.27k
            }
824
53.5k
        }
825
113k
    }
826
113k
    pdev->clip_path_id = new_id;
827
113k
    return pdf_remember_clip_path(pdev,
828
113k
            (pdev->clip_path_id == pdev->no_clip_path_id ? NULL : pcpath));
829
113k
}
830
831
/*
832
 * Compute the scaling to ensure that user coordinates for a path are within
833
 * PDF/A-1 valid range.  Return true if scaling was needed.  In this case, the
834
 * CTM will be multiplied by *pscale, and all coordinates will be divided by
835
 * *pscale.
836
 */
837
static bool
838
make_rect_scaling(const gx_device_pdf *pdev, const gs_fixed_rect *bbox,
839
                  double prescale, double *pscale)
840
1.30M
{
841
1.30M
    double bmin, bmax;
842
843
1.30M
    if (pdev->PDFA != 1) {
844
1.30M
        *pscale = 1;
845
1.30M
        return false;
846
1.30M
    }
847
848
0
    bmin = min(fixed2float(bbox->p.x) / pdev->scale.x, fixed2float(bbox->p.y) / pdev->scale.y) * prescale;
849
0
    bmax = max(fixed2float(bbox->q.x) / pdev->scale.x, fixed2float(bbox->q.y) / pdev->scale.y) * prescale;
850
0
    if (bmin <= int2fixed(-MAX_USER_COORD) ||
851
0
        bmax > int2fixed(MAX_USER_COORD)
852
0
        ) {
853
        /* Rescale the path. */
854
0
        *pscale = max(bmin / int2fixed(-MAX_USER_COORD),
855
0
                      bmax / int2fixed(MAX_USER_COORD));
856
0
        return true;
857
0
    } else {
858
0
        *pscale = 1;
859
0
        return false;
860
0
    }
861
0
}
862
863
/*
864
 * Prepare a fill with a color anc a clipping path.
865
 * Return 1 if there is nothing to paint.
866
 * Changes *box to the clipping box.
867
 */
868
static int
869
prepare_fill_with_clip(gx_device_pdf *pdev, const gs_gstate * pgs,
870
              gs_fixed_rect *box, bool have_path,
871
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
872
1.77M
{
873
1.77M
    bool new_clip;
874
1.77M
    int code;
875
876
    /*
877
     * Check for an empty clipping path.
878
     */
879
1.77M
    if (pcpath) {
880
1.76M
        gs_fixed_rect cbox;
881
882
1.76M
        gx_cpath_outer_box(pcpath, &cbox);
883
1.76M
        if (cbox.p.x >= cbox.q.x || cbox.p.y >= cbox.q.y)
884
14.6k
            return 1;    /* empty clipping path */
885
1.74M
        *box = cbox;
886
1.74M
    }
887
1.75M
    code = pdf_check_soft_mask(pdev, (gs_gstate *)pgs);
888
1.75M
    if (code < 0)
889
0
        return code;
890
891
1.75M
    new_clip = pdf_must_put_clip_path(pdev, pcpath);
892
1.75M
    if (have_path || pdev->context == PDF_IN_NONE || new_clip) {
893
1.52M
        if (new_clip)
894
40.0k
            code = pdf_unclip(pdev);
895
1.48M
        else
896
1.48M
            code = pdf_open_page(pdev, PDF_IN_STREAM);
897
1.52M
        if (code < 0)
898
0
            return code;
899
1.52M
    }
900
1.75M
    code = pdf_prepare_fill(pdev, pgs, false);
901
1.75M
    if (code < 0)
902
2.64k
        return code;
903
1.75M
    return pdf_put_clip_path(pdev, pcpath);
904
1.75M
}
905
906
/* -------------A local image converter device. -----------------------------*/
907
908
public_st_pdf_lcvd_t();
909
910
static int
911
lcvd_copy_color_shifted(gx_device * dev,
912
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
913
                      int x, int y, int w, int h)
914
0
{
915
0
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
916
0
    int code;
917
0
    int dw = cvd->mdev.width;
918
0
    int dh = cvd->mdev.height;
919
920
0
    cvd->mdev.width -= cvd->mdev.mapped_x;
921
0
    cvd->mdev.height -= cvd->mdev.mapped_y;
922
923
0
    code = cvd->std_copy_color((gx_device *)&cvd->mdev, base, sourcex, sraster, id,
924
0
        x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, w, h);
925
926
0
    cvd->mdev.width = dw;
927
0
    cvd->mdev.height = dh;
928
929
0
    return code;
930
0
}
931
932
static int
933
lcvd_copy_mono_shifted(gx_device * dev,
934
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
935
                      int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
936
6.94k
{
937
6.94k
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
938
6.94k
    int code;
939
6.94k
    int dw = cvd->mdev.width;
940
6.94k
    int dh = cvd->mdev.height;
941
942
6.94k
    cvd->mdev.width -= cvd->mdev.mapped_x;
943
6.94k
    cvd->mdev.height -= cvd->mdev.mapped_y;
944
945
6.94k
    code = cvd->std_copy_mono((gx_device *)&cvd->mdev, base, sourcex, sraster, id,
946
6.94k
                              x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, w, h,
947
6.94k
                              zero, one);
948
949
6.94k
    cvd->mdev.width = dw;
950
6.94k
    cvd->mdev.height = dh;
951
952
6.94k
    return code;
953
6.94k
}
954
955
static int
956
lcvd_fill_rectangle_shifted(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
957
20.2M
{
958
20.2M
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
959
20.2M
    int code;
960
20.2M
    int w = cvd->mdev.width;
961
20.2M
    int h = cvd->mdev.height;
962
963
20.2M
    if (cvd->pass == 2)
964
4.11M
        return 0;
965
966
16.0M
    cvd->mdev.width -= cvd->mdev.mapped_x;
967
16.0M
    cvd->mdev.height -= cvd->mdev.mapped_y;
968
969
16.0M
    code = cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
970
16.0M
        x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
971
972
16.0M
    cvd->mdev.width = w;
973
16.0M
    cvd->mdev.height = h;
974
975
16.0M
    return code;
976
20.2M
}
977
static int
978
lcvd_fill_rectangle_shifted2(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
979
1.41M
{
980
1.41M
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
981
1.41M
    int code = 0;
982
983
1.41M
    if (cvd->pass != 1)
984
352k
    {
985
352k
        if (cvd->mask) {
986
352k
            code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
987
352k
                x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, (gx_color_index)1);
988
352k
            if (code < 0)
989
0
                goto fail;
990
352k
        }
991
352k
    }
992
1.41M
    if (cvd->pass != 2)
993
1.09M
    {
994
1.09M
        int w = cvd->mdev.width;
995
1.09M
        int h = cvd->mdev.height;
996
1.09M
        cvd->mdev.width -= cvd->mdev.mapped_x;
997
1.09M
        cvd->mdev.height -= cvd->mdev.mapped_y;
998
999
1.09M
        code = cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
1000
1.09M
            x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
1001
1.09M
        cvd->mdev.width = w;
1002
1.09M
        cvd->mdev.height = h;
1003
1.09M
    }
1004
1005
1.41M
fail:
1006
1007
1.41M
    return code;
1008
1.41M
}
1009
static void
1010
lcvd_get_clipping_box_shifted_from_mdev(gx_device *dev, gs_fixed_rect *pbox)
1011
3.81k
{
1012
3.81k
    fixed ofs;
1013
3.81k
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
1014
3.81k
    int w = cvd->mdev.width;
1015
3.81k
    int h = cvd->mdev.height;
1016
1017
3.81k
    cvd->mdev.width -= cvd->mdev.mapped_x;
1018
3.81k
    cvd->mdev.height -= cvd->mdev.mapped_y;
1019
1020
3.81k
    cvd->std_get_clipping_box((gx_device *)&cvd->mdev, pbox);
1021
3.81k
    cvd->mdev.width = w;
1022
3.81k
    cvd->mdev.height = h;
1023
3.81k
    ofs = int2fixed(cvd->mdev.mapped_x);
1024
3.81k
    pbox->p.x += ofs;
1025
3.81k
    pbox->q.x += ofs;
1026
3.81k
    ofs = int2fixed(cvd->mdev.mapped_y);
1027
3.81k
    pbox->p.y += ofs;
1028
3.81k
    pbox->q.y += ofs;
1029
3.81k
}
1030
static int
1031
lcvd_dev_spec_op(gx_device *pdev1, int dev_spec_op,
1032
                void *data, int size)
1033
13.9M
{
1034
13.9M
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)pdev1;
1035
13.9M
    int code, w, h;
1036
1037
13.9M
    switch (dev_spec_op) {
1038
1.48M
        case gxdso_pattern_shading_area:
1039
1.48M
            return 1; /* Request shading area. */
1040
0
        case gxdso_pattern_can_accum:
1041
0
        case gxdso_pattern_start_accum:
1042
0
        case gxdso_pattern_finish_accum:
1043
0
        case gxdso_pattern_load:
1044
22
        case gxdso_pattern_is_cpath_accum:
1045
22
        case gxdso_pattern_shfill_doesnt_need_path:
1046
22
        case gxdso_pattern_handles_clip_path:
1047
22
        case gxdso_copy_color_is_fast:
1048
22
            return 0;
1049
13.9M
    }
1050
1051
12.4M
    w = cvd->mdev.width;
1052
12.4M
    h = cvd->mdev.height;
1053
12.4M
    cvd->mdev.width -= cvd->mdev.mapped_x;
1054
12.4M
    cvd->mdev.height -= cvd->mdev.mapped_y;
1055
1056
12.4M
    code = gx_default_dev_spec_op(pdev1, dev_spec_op, data, size);
1057
1058
12.4M
    cvd->mdev.width = w;
1059
12.4M
    cvd->mdev.height = h;
1060
1061
12.4M
    return code;
1062
13.9M
}
1063
static int
1064
lcvd_close_device_with_writing(gx_device *pdev)
1065
84
{
1066
    /* Assuming 'mdev' is being closed before 'mask' - see gx_image3_end_image. */
1067
84
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)pdev;
1068
84
    int code, code1;
1069
1070
84
    code = pdf_dump_converted_image(cvd->pdev, cvd, 0);
1071
84
    code1 = cvd->std_close_device((gx_device *)&cvd->mdev);
1072
84
    return code < 0 ? code : code1;
1073
84
}
1074
1075
static int
1076
write_image(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m, int for_pattern)
1077
1.47k
{
1078
1.47k
    gs_image_t image;
1079
1.47k
    pdf_image_writer writer;
1080
1.47k
    const int sourcex = 0;
1081
1.47k
    int code;
1082
1083
1.47k
    if (m != NULL)
1084
0
        pdf_put_matrix(pdev, NULL, m, " cm\n");
1085
1.47k
    code = pdf_copy_color_data(pdev, mdev->base, sourcex,
1086
1.47k
                mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
1087
1.47k
                &image, &writer, for_pattern);
1088
1.47k
    if (code == 1)
1089
1.47k
        code = 0; /* Empty image. */
1090
0
    else if (code == 0)
1091
0
        code = pdf_do_image(pdev, writer.pres, NULL, true);
1092
1.47k
    return code;
1093
1.47k
}
1094
static int
1095
write_mask(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m)
1096
0
{
1097
0
    const int sourcex = 0;
1098
0
    gs_id save_clip_id = pdev->clip_path_id;
1099
0
    bool save_skip_color = pdev->skip_colors;
1100
0
    int code;
1101
1102
0
    if (m != NULL)
1103
0
        pdf_put_matrix(pdev, NULL, m, " cm\n");
1104
0
    pdev->clip_path_id = pdev->no_clip_path_id;
1105
0
    pdev->skip_colors = true;
1106
0
    code = gdev_pdf_copy_mono((gx_device *)pdev, mdev->base, sourcex,
1107
0
                mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
1108
0
                gx_no_color_index, (gx_color_index)0);
1109
0
    pdev->clip_path_id = save_clip_id;
1110
0
    pdev->skip_colors = save_skip_color;
1111
0
    return code;
1112
0
}
1113
1114
static void
1115
max_subimage_width(int width, byte *base, int x0, int64_t count1, int *x1, int64_t *count)
1116
9.72k
{
1117
9.72k
    int64_t c = 0, c1 = count1 - 1;
1118
9.72k
    int x = x0;
1119
9.72k
    byte p = 1; /* The inverse of the previous bit. */
1120
9.72k
    byte r;     /* The inverse of the current  bit. */
1121
9.72k
    byte *q = base + (x / 8), m = 0x80 >> (x % 8);
1122
1123
7.95M
    for (; x < width; x++) {
1124
7.94M
        r = !(*q & m);
1125
7.94M
        if (p != r) {
1126
92.0k
            if (c >= c1) {
1127
20
                if (!r)
1128
12
                    goto ex; /* stop before the upgrade. */
1129
20
            }
1130
92.0k
            c++;
1131
92.0k
        }
1132
7.94M
        p = r;
1133
7.94M
        m >>= 1;
1134
7.94M
        if (!m) {
1135
991k
            m = 0x80;
1136
991k
            q++;
1137
991k
        }
1138
7.94M
    }
1139
9.70k
    if (p)
1140
6.95k
        c++; /* Account the last downgrade. */
1141
9.72k
ex:
1142
9.72k
    *count = c;
1143
9.72k
    *x1 = x;
1144
9.72k
}
1145
1146
static int
1147
cmpbits(const byte *base, const byte *base2, int w)
1148
116k
{
1149
116k
    int code;
1150
1151
116k
    code = memcmp(base, base2, w>>3);
1152
116k
    if (code)
1153
19.1k
        return code;
1154
97.4k
    base += w>>3;
1155
97.4k
    base2 += w>>3;
1156
97.4k
    w &= 7;
1157
97.4k
    if (w == 0)
1158
78.0k
        return 0;
1159
19.4k
    return ((*base ^ *base2) & (0xff00>>w));
1160
97.4k
}
1161
1162
static void
1163
compute_subimage(int width, int height, int raster, byte *base,
1164
                 int x0, int y0, int64_t MaxClipPathSize, int *x1, int *y1)
1165
151
{
1166
    /* Returns a semiopen range : [x0:x1)*[y0:y1). */
1167
151
    if (x0 != 0) {
1168
0
        int64_t count;
1169
1170
        /* A partial single scanline. */
1171
0
        max_subimage_width(width, base + y0 * raster, x0, MaxClipPathSize / 4, x1, &count);
1172
0
        *y1 = y0;
1173
151
    } else {
1174
151
        int xx, y = y0, yy;
1175
151
        int64_t count, count1 = MaxClipPathSize / 4;
1176
1177
9.85k
        for(; y < height && count1 > 0; ) {
1178
9.72k
            max_subimage_width(width, base + y * raster, 0, count1, &xx, &count);
1179
9.72k
            if (xx < width) {
1180
12
                if (y == y0) {
1181
                    /* Partial single scanline. */
1182
0
                    *y1 = y + 1;
1183
0
                    *x1 = xx;
1184
0
                    return;
1185
12
                } else {
1186
                    /* Full lines before this scanline. */
1187
12
                    break;
1188
12
                }
1189
12
            }
1190
9.70k
            count1 -= count;
1191
9.70k
            yy = y + 1;
1192
58.4k
            for (; yy < height; yy++)
1193
58.3k
                if (cmpbits(base + raster * y, base + raster * yy, width))
1194
9.57k
                    break;
1195
9.70k
            y = yy;
1196
1197
9.70k
        }
1198
151
        *y1 = y;
1199
151
        *x1 = width;
1200
151
    }
1201
151
}
1202
1203
static int
1204
image_line_to_clip(gx_device_pdf *pdev, byte *base, int x0, int x1, int y0, int y1, bool started)
1205
9.70k
{   /* returns the number of segments or error code. */
1206
9.70k
    int x = x0, xx;
1207
9.70k
    byte *q = base + (x / 8), m = 0x80 >> (x % 8);
1208
9.70k
    int64_t c = 0;
1209
1210
57.0k
    for (;;) {
1211
        /* Look for upgrade : */
1212
5.79M
        for (; x < x1; x++) {
1213
5.78M
            if (*q & m)
1214
47.3k
                break;
1215
5.73M
            m >>= 1;
1216
5.73M
            if (!m) {
1217
716k
                m = 0x80;
1218
716k
                q++;
1219
716k
            }
1220
5.73M
        }
1221
57.0k
        if (x == x1)
1222
9.70k
            return c;
1223
47.3k
        xx = x;
1224
        /* Look for downgrade : */
1225
2.24M
        for (; x < x1; x++) {
1226
2.24M
            if (!(*q & m))
1227
44.5k
                break;
1228
2.20M
            m >>= 1;
1229
2.20M
            if (!m) {
1230
273k
                m = 0x80;
1231
273k
                q++;
1232
273k
            }
1233
2.20M
        }
1234
        /* Found the interval [xx:x). */
1235
47.3k
        if (!started) {
1236
137
            stream_puts(pdev->strm, "n\n");
1237
137
            started = true;
1238
137
        }
1239
47.3k
        pprintld2(pdev->strm, "%ld %ld m ", xx, y0);
1240
47.3k
        pprintld2(pdev->strm, "%ld %ld l ", x, y0);
1241
47.3k
        pprintld2(pdev->strm, "%ld %ld l ", x, y1);
1242
47.3k
        pprintld2(pdev->strm, "%ld %ld l h\n", xx, y1);
1243
47.3k
        c += 4;
1244
47.3k
    }
1245
0
    return c;
1246
9.70k
}
1247
1248
static int
1249
mask_to_clip(gx_device_pdf *pdev, int width, int height,
1250
             int raster, byte *base, int x0, int y0, int x1, int y1)
1251
151
{
1252
151
    int y, yy, code = 0;
1253
151
    bool has_segments = false;
1254
1255
9.85k
    for (y = y0; y < y1 && code >= 0;) {
1256
9.70k
        yy = y + 1;
1257
9.70k
        if (x0 == 0) {
1258
58.4k
        for (; yy < y1; yy++)
1259
58.2k
            if (cmpbits(base + raster * y, base + raster * yy, width))
1260
9.55k
                break;
1261
9.70k
        }
1262
9.70k
        code = image_line_to_clip(pdev, base + raster * y, x0, x1, y, yy, has_segments);
1263
9.70k
        if (code > 0)
1264
9.46k
            has_segments = true;
1265
9.70k
        y = yy;
1266
9.70k
    }
1267
151
    if (has_segments)
1268
137
        stream_puts(pdev->strm, "W n\n");
1269
151
    return code < 0 ? code : has_segments ? 1 : 0;
1270
151
}
1271
1272
static int
1273
write_subimage(gx_device_pdf *pdev, gx_device_memory *mdev, int x, int y, int x1, int y1, int for_pattern)
1274
137
{
1275
137
    gs_image_t image;
1276
137
    pdf_image_writer writer;
1277
    /* expand in 1 pixel to provide a proper color interpolation */
1278
137
    int X = max(0, x - 1);
1279
137
    int Y = max(0, y - 1);
1280
137
    int X1 = min(mdev->width, x1 + 1);
1281
137
    int Y1 = min(mdev->height, y1 + 1);
1282
137
    int code;
1283
1284
137
    code = pdf_copy_color_data(pdev, mdev->base + mdev->raster * Y, X,
1285
137
                mdev->raster, gx_no_bitmap_id,
1286
137
                X, Y, X1 - X, Y1 - Y,
1287
137
                &image, &writer, for_pattern);
1288
137
    if (code < 0)
1289
0
        return code;
1290
137
    if (!writer.pres)
1291
137
        return 0; /* inline image. */
1292
0
    return pdf_do_image(pdev, writer.pres, NULL, true);
1293
137
}
1294
1295
static int
1296
write_image_with_clip(gx_device_pdf *pdev, pdf_lcvd_t *cvd, int for_pattern)
1297
131
{
1298
131
    int x = 0, y = 0;
1299
131
    int code, code1;
1300
1301
131
    if (cvd->write_matrix)
1302
106
        pdf_put_matrix(pdev, NULL, &cvd->m, " cm q\n");
1303
151
    for(;;) {
1304
151
        int x1, y1;
1305
1306
151
        compute_subimage(cvd->mask->width, cvd->mask->height,
1307
151
                         cvd->mask->raster, cvd->mask->base,
1308
151
                         x, y, max(pdev->MaxClipPathSize, 100), &x1, &y1);
1309
151
        code = mask_to_clip(pdev,
1310
151
                         cvd->mask->width, cvd->mask->height,
1311
151
                         cvd->mask->raster, cvd->mask->base,
1312
151
                         x, y, x1, y1);
1313
151
        if (code < 0)
1314
0
            return code;
1315
151
        if (code > 0) {
1316
137
            code1 = write_subimage(pdev, &cvd->mdev, x, y, x1, y1, for_pattern);
1317
137
            if (code1 < 0)
1318
0
                return code1;
1319
137
        }
1320
151
        if (x1 >= cvd->mdev.width && y1 >= cvd->mdev.height)
1321
131
            break;
1322
20
        if (code > 0)
1323
20
            stream_puts(pdev->strm, "Q q\n");
1324
20
        if (x1 == cvd->mask->width) {
1325
20
            x = 0;
1326
20
            y = y1;
1327
20
        } else {
1328
0
            x = x1;
1329
0
            y = y1;
1330
0
        }
1331
20
    }
1332
131
    if (cvd->write_matrix)
1333
106
        stream_puts(pdev->strm, "Q\n");
1334
131
    return 0;
1335
131
}
1336
1337
int
1338
pdf_dump_converted_image(gx_device_pdf *pdev, pdf_lcvd_t *cvd, int for_pattern)
1339
1.89k
{
1340
1.89k
    int code = 0;
1341
1342
1.89k
    if (cvd->pass == 1)
1343
0
        return 0;
1344
1345
1.89k
    cvd->mdev.width -= cvd->mdev.mapped_x;
1346
1.89k
    cvd->mdev.height -= cvd->mdev.mapped_y;
1347
1348
1.89k
    if (!cvd->path_is_empty || cvd->has_background) {
1349
1.47k
        if (!cvd->has_background)
1350
1.47k
            stream_puts(pdev->strm, "W n\n");
1351
1.47k
        code = write_image(pdev, &cvd->mdev, (cvd->write_matrix ? &cvd->m : NULL), for_pattern);
1352
1.47k
        cvd->path_is_empty = true;
1353
1.47k
    } else if (!cvd->mask_is_empty && pdev->PatternImagemask) {
1354
        /* Convert to imagemask with a pattern color. */
1355
        /* See also use_image_as_pattern in gdevpdfi.c . */
1356
0
        gs_gstate s;
1357
0
        gs_pattern1_instance_t inst;
1358
0
        gs_id id = gs_next_ids(cvd->mdev.memory, 1);
1359
0
        cos_value_t v;
1360
0
        const pdf_resource_t *pres;
1361
1362
0
        memset(&s, 0, sizeof(s));
1363
0
        s.ctm.xx = cvd->m.xx;
1364
0
        s.ctm.xy = cvd->m.xy;
1365
0
        s.ctm.yx = cvd->m.yx;
1366
0
        s.ctm.yy = cvd->m.yy;
1367
0
        s.ctm.tx = cvd->m.tx;
1368
0
        s.ctm.ty = cvd->m.ty;
1369
0
        memset(&inst, 0, sizeof(inst));
1370
0
        inst.saved = (gs_gstate *)&s; /* HACK : will use s.ctm only. */
1371
0
        inst.templat.PaintType = 1;
1372
0
        inst.templat.TilingType = 1;
1373
0
        inst.templat.BBox.p.x = inst.templat.BBox.p.y = 0;
1374
0
        inst.templat.BBox.q.x = cvd->mdev.width;
1375
0
        inst.templat.BBox.q.y = cvd->mdev.height;
1376
0
        inst.templat.XStep = (float)cvd->mdev.width;
1377
0
        inst.templat.YStep = (float)cvd->mdev.height;
1378
1379
0
        {
1380
0
            pattern_accum_param_s param;
1381
0
            param.pinst = (void *)&inst;
1382
0
            param.graphics_state = (void *)&s;
1383
0
            param.pinst_id = inst.id;
1384
1385
0
            code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
1386
0
                gxdso_pattern_start_accum, &param, sizeof(pattern_accum_param_s));
1387
0
        }
1388
1389
0
        if (code >= 0) {
1390
0
            stream_puts(pdev->strm, "W n\n");
1391
0
            code = write_image(pdev, &cvd->mdev, NULL, for_pattern);
1392
0
        }
1393
0
        pres = pdev->accumulating_substream_resource;
1394
0
        if (pres == NULL)
1395
0
            code = gs_note_error(gs_error_unregistered);
1396
0
        if (code >= 0) {
1397
0
            pattern_accum_param_s param;
1398
0
            param.pinst = (void *)&inst;
1399
0
            param.graphics_state = (void *)&s;
1400
0
            param.pinst_id = inst.id;
1401
1402
0
            code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
1403
0
                gxdso_pattern_finish_accum, &param, id);
1404
0
        }
1405
0
        if (code >= 0)
1406
0
            code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
1407
0
                gxdso_pattern_load, &id, sizeof(gs_id));
1408
0
        if (code >= 0)
1409
0
            code = pdf_cs_Pattern_colored(pdev, &v);
1410
0
        if (code >= 0) {
1411
0
            cos_value_write(&v, pdev);
1412
0
            pprinti64d1(pdev->strm, " cs /R%"PRId64" scn ", pdf_resource_id(pres));
1413
0
        }
1414
0
        if (code >= 0)
1415
0
            code = write_mask(pdev, cvd->mask, (cvd->write_matrix ? &cvd->m : NULL));
1416
0
        cvd->mask_is_empty = true;
1417
414
    } else if (!cvd->mask_is_empty && !pdev->PatternImagemask) {
1418
        /* Convert to image with a clipping path. */
1419
131
        stream_puts(pdev->strm, "q\n");
1420
131
        code = write_image_with_clip(pdev, cvd, for_pattern);
1421
131
        stream_puts(pdev->strm, "Q\n");
1422
283
    } else if (cvd->filled_trap){
1423
0
        stream_puts(pdev->strm, "q\n");
1424
0
        code = write_image_with_clip(pdev, cvd, for_pattern);
1425
0
        stream_puts(pdev->strm, "Q\n");
1426
0
    }
1427
1.89k
    cvd->filled_trap = false;
1428
1.89k
    cvd->mdev.width += cvd->mdev.mapped_x;
1429
1.89k
    cvd->mdev.height += cvd->mdev.mapped_y;
1430
1.89k
    if (code > 0)
1431
0
        code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
1432
0
                0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
1433
1434
1.89k
    return code;
1435
1.89k
}
1436
static int
1437
lcvd_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
1438
    const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
1439
    const gx_device_color * pdevc, gs_logical_operation_t lop)
1440
187k
{
1441
187k
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
1442
1443
187k
    if (cvd->mask != NULL)
1444
27.2k
        cvd->filled_trap = true;
1445
187k
    return gx_default_fill_trapezoid(dev, left, right, ybot, ytop, swap_axes, pdevc, lop);
1446
187k
}
1447
1448
static int
1449
lcvd_handle_fill_path_as_shading_coverage(gx_device *dev,
1450
    const gs_gstate *pgs, gx_path *ppath,
1451
    const gx_fill_params *params,
1452
    const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
1453
1.48M
{
1454
1.48M
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
1455
1.48M
    gx_device_pdf *pdev = (gx_device_pdf *)cvd->mdev.target;
1456
1.48M
    int code;
1457
1458
1.48M
    if (cvd->pass == 1)
1459
1.47M
        return 0;
1460
6.00k
    if (cvd->has_background)
1461
0
        return 0;
1462
6.00k
    if (gx_path_is_null(ppath)) {
1463
        /* use the mask. */
1464
3.05k
        if (!cvd->path_is_empty) {
1465
24
            code = pdf_dump_converted_image(pdev, cvd, 2);
1466
24
            if (code < 0)
1467
0
                return code;
1468
24
            stream_puts(pdev->strm, "Q q\n");
1469
24
            dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted2;
1470
24
        }
1471
3.05k
        if (cvd->mask && (!cvd->mask_is_clean || !cvd->path_is_empty)) {
1472
9
            code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
1473
9
                        0, 0, cvd->mask->width, cvd->mask->height, (gx_color_index)0);
1474
9
            if (code < 0)
1475
0
                return code;
1476
9
            cvd->mask_is_clean = true;
1477
9
        }
1478
3.05k
        cvd->path_is_empty = true;
1479
3.05k
        if (cvd->mask)
1480
3.05k
            cvd->mask_is_empty = false;
1481
3.05k
    } else {
1482
2.94k
        gs_matrix m;
1483
2.94k
        gs_path_enum cenum;
1484
2.94k
        gdev_vector_dopath_state_t state;
1485
1486
2.94k
        gs_make_translation(cvd->path_offset.x, cvd->path_offset.y, &m);
1487
        /* use the clipping. */
1488
2.94k
        if (!cvd->mask_is_empty) {
1489
23
            code = pdf_dump_converted_image(pdev, cvd, 2);
1490
23
            if (code < 0)
1491
0
                return code;
1492
23
            stream_puts(pdev->strm, "Q q\n");
1493
23
            dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted;
1494
23
            cvd->mask_is_empty = true;
1495
23
        }
1496
2.94k
        code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_fill | gx_path_type_optimize, &m);
1497
2.94k
        if (code < 0)
1498
0
            return code;
1499
2.94k
        stream_puts(pdev->strm, "h\n");
1500
2.94k
        cvd->path_is_empty = false;
1501
2.94k
    }
1502
6.00k
    return 0;
1503
6.00k
}
1504
1505
static int
1506
lcvd_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
1507
13.5k
{
1508
13.5k
    transform_pixel_region_data local_data;
1509
13.5k
    gx_dda_fixed_point local_pixels, local_rows;
1510
13.5k
    gs_int_rect local_clip;
1511
13.5k
    pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
1512
13.5k
    int ret;
1513
13.5k
    dev_t_proc_fill_rectangle((*fill_rectangle), gx_device);
1514
13.5k
    dev_t_proc_copy_color((*copy_color), gx_device);
1515
13.5k
    int w = cvd->mdev.width;
1516
13.5k
    int h = cvd->mdev.height;
1517
1518
13.5k
    cvd->mdev.width -= cvd->mdev.mapped_x;
1519
13.5k
    cvd->mdev.height -= cvd->mdev.mapped_y;
1520
1521
13.5k
    if (reason == transform_pixel_region_begin) {
1522
36
        local_data = *data;
1523
36
        local_pixels = *local_data.u.init.pixels;
1524
36
        local_rows = *local_data.u.init.rows;
1525
36
        local_clip = *local_data.u.init.clip;
1526
36
        local_data.u.init.pixels = &local_pixels;
1527
36
        local_data.u.init.rows = &local_rows;
1528
36
        local_data.u.init.clip = &local_clip;
1529
36
        local_pixels.x.state.Q -= int2fixed(cvd->mdev.mapped_x);
1530
36
        local_pixels.y.state.Q -= int2fixed(cvd->mdev.mapped_y);
1531
36
        local_rows.x.state.Q -= int2fixed(cvd->mdev.mapped_x);
1532
36
        local_rows.y.state.Q -= int2fixed(cvd->mdev.mapped_y);
1533
36
        local_clip.p.x -= cvd->mdev.mapped_x;
1534
36
        local_clip.p.y -= cvd->mdev.mapped_y;
1535
36
        local_clip.q.x -= cvd->mdev.mapped_x;
1536
36
        local_clip.q.y -= cvd->mdev.mapped_y;
1537
36
        ret = cvd->std_transform_pixel_region(dev, reason, &local_data);
1538
36
        data->state = local_data.state;
1539
36
        cvd->mdev.width = w;
1540
36
        cvd->mdev.height = h;
1541
36
        return ret;
1542
36
    }
1543
13.5k
    copy_color = dev_proc(&cvd->mdev, copy_color);
1544
13.5k
    fill_rectangle = dev_proc(&cvd->mdev, fill_rectangle);
1545
13.5k
    dev_proc(&cvd->mdev, copy_color) = cvd->std_copy_color;
1546
13.5k
    dev_proc(&cvd->mdev, fill_rectangle) = cvd->std_fill_rectangle;
1547
13.5k
    ret = cvd->std_transform_pixel_region(dev, reason, data);
1548
13.5k
    dev_proc(&cvd->mdev, copy_color) = copy_color;
1549
13.5k
    dev_proc(&cvd->mdev, fill_rectangle) = fill_rectangle;
1550
13.5k
    cvd->mdev.width = w;
1551
13.5k
    cvd->mdev.height = h;
1552
13.5k
    return ret;
1553
13.5k
}
1554
1555
int
1556
pdf_setup_masked_image_converter(gx_device_pdf *pdev, gs_memory_t *mem, const gs_matrix *m, pdf_lcvd_t **pcvd,
1557
                                 bool need_mask, int x, int y, int w, int h, bool write_on_close)
1558
2.07k
{
1559
2.07k
    int code;
1560
2.07k
    gx_device_memory *mask = 0;
1561
2.07k
    pdf_lcvd_t *cvd = *pcvd;
1562
1563
2.07k
    if (cvd == NULL) {
1564
106
        cvd = gs_alloc_struct(mem, pdf_lcvd_t, &st_pdf_lcvd_t, "pdf_setup_masked_image_converter");
1565
106
        if (cvd == NULL)
1566
0
            return_error(gs_error_VMerror);
1567
106
        *pcvd = cvd;
1568
106
    }
1569
2.07k
    cvd->pdev = pdev;
1570
2.07k
    gs_make_mem_device(&cvd->mdev, gdev_mem_device_for_bits(pdev->color_info.depth),
1571
2.07k
                mem, 0, (gx_device *)pdev);
1572
    /* x and y are always non-negative here. */
1573
2.07k
    if (x < 0 || y < 0)
1574
0
        return_error(gs_error_Fatal);
1575
2.07k
    cvd->mdev.width  = w; /* The size we want to allocate for */
1576
2.07k
    cvd->mdev.height = h;
1577
2.07k
    cvd->mdev.mapped_x = x;
1578
2.07k
    cvd->mdev.mapped_y = y;
1579
2.07k
    cvd->mdev.bitmap_memory = mem;
1580
2.07k
    cvd->mdev.color_info = pdev->color_info;
1581
2.07k
    cvd->path_is_empty = true;
1582
2.07k
    cvd->mask_is_empty = true;
1583
2.07k
    cvd->mask_is_clean = false;
1584
2.07k
    cvd->filled_trap = false;
1585
2.07k
    cvd->has_background = false;
1586
2.07k
    cvd->pass = 0;
1587
2.07k
    cvd->mask = 0;
1588
2.07k
    cvd->write_matrix = true;
1589
2.07k
    code = (*dev_proc(&cvd->mdev, open_device))((gx_device *)&cvd->mdev);
1590
2.07k
    if (code < 0)
1591
0
        return code; /* FIXME: free cvd? */
1592
2.07k
    code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
1593
2.07k
                0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
1594
2.07k
    if (code < 0)
1595
0
        return code; /* FIXME: free cvd? */
1596
2.07k
    if (need_mask) {
1597
200
        mask = gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory, "pdf_setup_masked_image_converter");
1598
200
        if (mask == NULL)
1599
0
            return_error(gs_error_VMerror); /* FIXME: free cvd? */
1600
200
        cvd->mask = mask;
1601
200
        gs_make_mem_mono_device(mask, mem, (gx_device *)pdev);
1602
200
        mask->width = cvd->mdev.width;
1603
200
        mask->height = cvd->mdev.height;
1604
200
        mask->raster = gx_device_raster((gx_device *)mask, 1);
1605
200
        mask->bitmap_memory = mem;
1606
200
        code = (*dev_proc(mask, open_device))((gx_device *)mask);
1607
200
        if (code < 0)
1608
0
            return code; /* FIXME: free cvd? */
1609
200
        if (write_on_close) {
1610
84
            code = (*dev_proc(mask, fill_rectangle))((gx_device *)mask,
1611
84
                        0, 0, mask->width, mask->height, (gx_color_index)0);
1612
84
            if (code < 0)
1613
0
                return code; /* FIXME: free cvd? */
1614
84
        }
1615
200
    }
1616
2.07k
    cvd->std_copy_color = dev_proc(&cvd->mdev, copy_color);
1617
2.07k
    cvd->std_copy_mono = dev_proc(&cvd->mdev, copy_mono);
1618
2.07k
    cvd->std_fill_rectangle = dev_proc(&cvd->mdev, fill_rectangle);
1619
2.07k
    cvd->std_close_device = dev_proc(&cvd->mdev, close_device);
1620
2.07k
    cvd->std_get_clipping_box = dev_proc(&cvd->mdev, get_clipping_box);
1621
2.07k
    cvd->std_transform_pixel_region = dev_proc(&cvd->mdev, transform_pixel_region);
1622
2.07k
    if (!write_on_close) {
1623
        /* Type 3 images will write to the mask directly. */
1624
1.99k
        dev_proc(&cvd->mdev, fill_rectangle) = (need_mask ? lcvd_fill_rectangle_shifted2
1625
1.99k
                                                          : lcvd_fill_rectangle_shifted);
1626
1.99k
    } else {
1627
84
        dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted;
1628
84
    }
1629
2.07k
    dev_proc(&cvd->mdev, get_clipping_box) = lcvd_get_clipping_box_shifted_from_mdev;
1630
2.07k
    dev_proc(&cvd->mdev, copy_color) = lcvd_copy_color_shifted;
1631
2.07k
    dev_proc(&cvd->mdev, copy_mono) = lcvd_copy_mono_shifted;
1632
2.07k
    dev_proc(&cvd->mdev, dev_spec_op) = lcvd_dev_spec_op;
1633
2.07k
    dev_proc(&cvd->mdev, fill_path) = lcvd_handle_fill_path_as_shading_coverage;
1634
2.07k
    dev_proc(&cvd->mdev, transform_pixel_region) = lcvd_transform_pixel_region;
1635
2.07k
    dev_proc(&cvd->mdev, fill_trapezoid) = lcvd_fill_trapezoid;
1636
2.07k
    cvd->m = *m;
1637
2.07k
    if (write_on_close) {
1638
84
        cvd->mdev.is_open = true;
1639
84
        if (mask)
1640
84
            mask->is_open = true;
1641
84
        dev_proc(&cvd->mdev, close_device) = lcvd_close_device_with_writing;
1642
84
    }
1643
2.07k
    cvd->mdev.width  = w + x; /* The size we appear to the world as */
1644
2.07k
    cvd->mdev.height = h + y;
1645
2.07k
    return 0;
1646
2.07k
}
1647
1648
void
1649
pdf_remove_masked_image_converter(gx_device_pdf *pdev, pdf_lcvd_t *cvd, bool need_mask)
1650
1.96k
{
1651
1.96k
    cvd->mdev.width  -= cvd->mdev.mapped_x;
1652
1.96k
    cvd->mdev.height -= cvd->mdev.mapped_y;
1653
1.96k
    (*dev_proc(&cvd->mdev, close_device))((gx_device *)&cvd->mdev);
1654
1.96k
    if (cvd->mask) {
1655
94
        (*dev_proc(cvd->mask, close_device))((gx_device *)cvd->mask);
1656
94
        gs_free_object(cvd->mask->memory, cvd->mask, "pdf_remove_masked_image_converter");
1657
94
    }
1658
1.96k
}
1659
1660
/* ------ Driver procedures ------ */
1661
1662
/* Fill a path. */
1663
int
1664
gdev_pdf_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
1665
                   const gx_fill_params * params,
1666
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1667
4.02M
{
1668
4.02M
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
1669
4.02M
    int code;
1670
    /*
1671
     * HACK: we fill an empty path in order to set the clipping path
1672
     * and the color for writing text.  If it weren't for this, we
1673
     * could detect and skip empty paths before putting out the clip
1674
     * path or the color.  We also clip with an empty path in order
1675
     * to advance currentpoint for show operations without actually
1676
     * drawing anything.
1677
     */
1678
4.02M
    bool have_path;
1679
4.02M
    gs_fixed_rect box = {{0, 0}, {0, 0}}, box1;
1680
4.02M
    gs_rect box2;
1681
1682
4.02M
    if (pdev->Eps2Write) {
1683
2.48M
        gx_path_bbox(ppath, &box1);
1684
2.48M
        if (box1.p.x != 0 || box1.p.y != 0 || box1.q.x != 0 || box1.q.y != 0){
1685
2.44M
            if (pcpath != 0)
1686
2.44M
                rect_intersect(box1, pcpath->outer_box);
1687
            /* convert fixed point co-ordinates to floating point and account for resolution */
1688
2.44M
            box2.p.x = fixed2int(box1.p.x) / (pdev->HWResolution[0] / 72.0);
1689
2.44M
            box2.p.y = fixed2int(box1.p.y) / (pdev->HWResolution[1] / 72.0);
1690
2.44M
            box2.q.x = fixed2int(box1.q.x) / (pdev->HWResolution[0] / 72.0);
1691
2.44M
            box2.q.y = fixed2int(box1.q.y) / (pdev->HWResolution[1] / 72.0);
1692
            /* Finally compare the new BBox of the path with the existing EPS BBox */
1693
2.44M
            if (box2.p.x < pdev->BBox.p.x)
1694
3.91k
                pdev->BBox.p.x = box2.p.x;
1695
2.44M
            if (box2.p.y < pdev->BBox.p.y)
1696
8.44k
                pdev->BBox.p.y = box2.p.y;
1697
2.44M
            if (box2.q.x > pdev->BBox.q.x)
1698
6.37k
                pdev->BBox.q.x = box2.q.x;
1699
2.44M
            if (box2.q.y > pdev->BBox.q.y)
1700
4.82k
                pdev->BBox.q.y = box2.q.y;
1701
2.44M
        }
1702
2.48M
        if (pdev->AccumulatingBBox)
1703
2.22M
            return 0;
1704
2.48M
    }
1705
1.79M
    have_path = !gx_path_is_void(ppath);
1706
1.79M
    if (!have_path && !pdev->vg_initial_set) {
1707
        /* See lib/gs_pdfwr.ps about "initial graphic state". */
1708
42.9k
        pdf_prepare_initial_viewer_state(pdev, pgs);
1709
42.9k
        pdf_reset_graphics(pdev);
1710
42.9k
        return 0;
1711
42.9k
    }
1712
1.75M
    if (have_path) {
1713
1.50M
        code = gx_path_bbox(ppath, &box);
1714
1.50M
        if (code < 0)
1715
0
            return code;
1716
1.50M
    }
1717
1.75M
    box1 = box;
1718
1719
1.75M
    code = prepare_fill_with_clip(pdev, pgs, &box, have_path, pdcolor, pcpath);
1720
1.75M
    if (code == gs_error_rangecheck) {
1721
        /* Fallback to the default implermentation for handling
1722
           a transparency with CompatibilityLevel<=1.3 . */
1723
2.64k
        return gx_default_fill_path((gx_device *)pdev, pgs, ppath, params, pdcolor, pcpath);
1724
2.64k
    }
1725
1.75M
    if (code < 0)
1726
0
        return code;
1727
1.75M
    if (code == 1)
1728
14.6k
        return 0; /* Nothing to paint. */
1729
1.73M
    if (!have_path)
1730
246k
        return 0;
1731
1.49M
    code = pdf_setfillcolor((gx_device_vector *)pdev, pgs, pdcolor);
1732
1.49M
    if (code == gs_error_rangecheck) {
1733
552k
        const bool convert_to_image = ((pdev->CompatibilityLevel <= 1.2 ||
1734
543k
                pdev->params.ColorConversionStrategy != ccs_LeaveColorUnchanged) &&
1735
9.91k
                gx_dc_is_pattern2_color(pdcolor));
1736
1737
552k
        if (!convert_to_image) {
1738
            /* Fallback to the default implermentation for handling
1739
            a shading with CompatibilityLevel<=1.2 . */
1740
550k
            return gx_default_fill_path(dev, pgs, ppath, params, pdcolor, pcpath);
1741
550k
        } else {
1742
            /* Convert a shading into a bitmap
1743
               with CompatibilityLevel<=1.2 . */
1744
2.51k
            pdf_lcvd_t cvd, *pcvd = &cvd;
1745
2.51k
            int sx, sy;
1746
2.51k
            gs_fixed_rect bbox, bbox1;
1747
2.51k
            bool need_mask = gx_dc_pattern2_can_overlap(pdcolor);
1748
2.51k
            gs_matrix m, save_ctm = ctm_only(pgs), ms, msi, mm;
1749
2.51k
            gs_int_point rect_size;
1750
            /* double scalex = 1.9, scaley = 1.4; debug purpose only. */
1751
2.51k
            double scale, scalex, scaley;
1752
2.51k
            int log2_scale_x = 0, log2_scale_y = 0;
1753
2.51k
            gx_drawing_color dc = *pdcolor;
1754
2.51k
            gs_pattern2_instance_t pi = *(gs_pattern2_instance_t *)dc.ccolor.pattern;
1755
2.51k
            gs_gstate *pgs2 = gs_gstate_copy(pi.saved, gs_gstate_memory(pi.saved));
1756
1757
2.51k
            if (pgs2 == NULL)
1758
0
                return_error(gs_error_VMerror);
1759
2.51k
            dc.ccolor.pattern = (gs_pattern_instance_t *)&pi;
1760
2.51k
            pi.saved = pgs2;
1761
2.51k
            code = gx_path_bbox(ppath, &bbox);
1762
2.51k
            if (code < 0)
1763
0
                goto image_exit;
1764
2.51k
            rect_intersect(bbox, box);
1765
2.51k
            code = gx_dc_pattern2_get_bbox(pdcolor, &bbox1);
1766
2.51k
            if (code < 0)
1767
0
                goto image_exit;
1768
2.51k
            if (code)
1769
2.51k
                rect_intersect(bbox, bbox1);
1770
2.51k
            if (bbox.p.x >= bbox.q.x || bbox.p.y >= bbox.q.y) {
1771
545
                code = 0;
1772
545
                goto image_exit;
1773
545
            }
1774
1.96k
            sx = fixed2int(bbox.p.x);
1775
1.96k
            sy = fixed2int(bbox.p.y);
1776
1.96k
            gs_make_identity(&m);
1777
1.96k
            rect_size.x = fixed2int(bbox.q.x + fixed_half) - sx;
1778
1.96k
            rect_size.y = fixed2int(bbox.q.y + fixed_half) - sy;
1779
1.96k
            if (rect_size.x == 0 || rect_size.y == 0)
1780
0
                goto image_exit;
1781
1.96k
            m.tx = (float)sx;
1782
1.96k
            m.ty = (float)sy;
1783
1.96k
            cvd.path_offset.x = sx;
1784
1.96k
            cvd.path_offset.y = sy;
1785
1.96k
            scale = (double)rect_size.x * rect_size.y * pdev->color_info.num_components /
1786
1.96k
                    pdev->MaxShadingBitmapSize;
1787
1.96k
            if (scale > 1) {
1788
                /* This section (together with the call to 'path_scale' below)
1789
                   sets up a downscaling when converting the shading into bitmap.
1790
                   We used floating point numbers to debug it, but in production
1791
                   we prefer to deal only with integers being powers of 2
1792
                   in order to avoid possible distorsions when scaling paths.
1793
                */
1794
288
                log2_scale_x = log2_scale_y = ilog2((int)ceil(sqrt(scale)));
1795
288
                if ((double)(1 << log2_scale_x) * (1 << log2_scale_y) < scale)
1796
274
                    log2_scale_y++;
1797
288
                if ((double)(1 << log2_scale_x) * (1 << log2_scale_y) < scale)
1798
175
                    log2_scale_x++;
1799
288
                scalex = (double)(1 << log2_scale_x);
1800
288
                scaley = (double)(1 << log2_scale_y);
1801
288
                rect_size.x = (int)floor(rect_size.x / scalex + 0.5);
1802
288
                rect_size.y = (int)floor(rect_size.y / scaley + 0.5);
1803
288
                gs_make_scaling(1.0 / scalex, 1.0 / scaley, &ms);
1804
288
                gs_make_scaling(scalex, scaley, &msi);
1805
288
                gs_matrix_multiply(&msi, &m, &m);
1806
288
                gs_matrix_multiply(&ctm_only(pgs), &ms, &mm);
1807
288
                gs_setmatrix((gs_gstate *)pgs, &mm);
1808
288
                gs_matrix_multiply(&ctm_only(pgs2), &ms, &mm);
1809
288
                gs_setmatrix((gs_gstate *)pgs2, &mm);
1810
288
                sx = fixed2int(bbox.p.x / (int)scalex);
1811
288
                sy = fixed2int(bbox.p.y / (int)scaley);
1812
288
                cvd.path_offset.x = sx; /* m.tx / scalex */
1813
288
                cvd.path_offset.y = sy;
1814
288
            }
1815
1.96k
            if (sx < 0 || sy < 0)
1816
0
                return 0;
1817
1818
1.96k
            code = pdf_setup_masked_image_converter(pdev, pdev->memory, &m, &pcvd, need_mask, sx, sy,
1819
1.96k
                            rect_size.x, rect_size.y, false);
1820
1.96k
            if (code >= 0) {
1821
1.96k
                gs_path_enum cenum;
1822
1.96k
                gdev_vector_dopath_state_t state;
1823
1824
1.96k
                pcvd->has_background = gx_dc_pattern2_has_background(pdcolor);
1825
1.96k
                stream_puts(pdev->strm, "q\n");
1826
1.96k
                code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_clip | gx_path_type_optimize, NULL);
1827
1.96k
                if (code >= 0) {
1828
1.96k
                    stream_puts(pdev->strm, (params->rule < 0 ? "W n\n" : "W* n\n"));
1829
1.96k
                    pdf_put_matrix(pdev, NULL, &cvd.m, " cm q\n");
1830
1.96k
                    cvd.write_matrix = false;
1831
1.96k
                    if (!pcvd->has_background) {
1832
1.96k
                        pcvd->pass = 1;
1833
1.96k
                        code = gs_shading_do_fill_rectangle(pi.templat.Shading,
1834
1.96k
                             NULL, (gx_device *)&cvd.mdev, pgs2, !pi.shfill);
1835
1.96k
                        pcvd->pass = 2;
1836
1.96k
                        pcvd->mask_is_empty = true;
1837
1.96k
                        pcvd->path_is_empty = true;
1838
1.96k
                        pcvd->filled_trap = 0;
1839
1.96k
                    }
1840
1.96k
                    if (code >= 0) {
1841
1.73k
                        code = gs_shading_do_fill_rectangle(pi.templat.Shading,
1842
1.73k
                             NULL, (gx_device *)&cvd.mdev, pgs2, !pi.shfill);
1843
1.73k
                    }
1844
1.96k
                    if (code >= 0)
1845
1.73k
                        code = pdf_dump_converted_image(pdev, &cvd, 2);
1846
1.96k
                }
1847
1.96k
                stream_puts(pdev->strm, "Q Q\n");
1848
1.96k
                pdf_remove_masked_image_converter(pdev, &cvd, need_mask);
1849
1.96k
            }
1850
1.96k
            gs_setmatrix((gs_gstate *)pgs, &save_ctm);
1851
2.51k
image_exit:
1852
2.51k
            gs_gstate_free(pgs2);
1853
2.51k
            return code;
1854
1.96k
        }
1855
552k
    }
1856
939k
    if (code < 0)
1857
0
        return code;
1858
939k
    {
1859
939k
        stream *s = pdev->strm;
1860
939k
        double scale;
1861
939k
        gs_matrix smat, *psmat = NULL;
1862
939k
        gs_path_enum cenum;
1863
939k
        gdev_vector_dopath_state_t state;
1864
1865
939k
        if (pcpath) {
1866
939k
            rect_intersect(box1, box);
1867
939k
            if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
1868
241k
                return 0;   /* outside the clipping path */
1869
939k
        }
1870
697k
        if (params->flatness != pdev->state.flatness) {
1871
3.64k
            pprintg1(s, "%g i\n", params->flatness);
1872
3.64k
            pdev->state.flatness = params->flatness;
1873
3.64k
        }
1874
697k
        if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
1875
0
            gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale,
1876
0
                            &smat);
1877
0
            pdf_put_matrix(pdev, "q ", &smat, "cm\n");
1878
0
            psmat = &smat;
1879
0
        }
1880
697k
        code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_fill | gx_path_type_optimize, NULL);
1881
697k
        if (code < 0)
1882
0
            return code;
1883
1884
697k
        stream_puts(s, (params->rule < 0 ? "f\n" : "f*\n"));
1885
697k
        if (psmat != NULL)
1886
0
            stream_puts(pdev->strm, "Q\n");
1887
697k
    }
1888
0
    return 0;
1889
697k
}
1890
1891
/* Stroke a path. */
1892
int
1893
gdev_pdf_stroke_path(gx_device * dev, const gs_gstate * pgs,
1894
                     gx_path * ppath, const gx_stroke_params * params,
1895
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1896
754k
{
1897
754k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
1898
754k
    stream *s;
1899
754k
    int code;
1900
754k
    double scale, path_scale;
1901
754k
    bool set_ctm;
1902
754k
    gs_matrix mat;
1903
754k
    double prescale = 1;
1904
754k
    gs_fixed_rect bbox;
1905
754k
    gs_path_enum cenum;
1906
754k
    gdev_vector_dopath_state_t state;
1907
1908
754k
    if (gx_path_is_void(ppath))
1909
128k
        return 0;    /* won't mark the page */
1910
625k
    code = pdf_check_soft_mask(pdev, (gs_gstate *)pgs);
1911
625k
    if (code < 0)
1912
0
        return code;
1913
625k
   if (pdf_must_put_clip_path(pdev, pcpath))
1914
66.4k
        code = pdf_unclip(pdev);
1915
559k
    else if ((pdev->last_charpath_op & TEXT_DO_FALSE_CHARPATH) && ppath->current_subpath &&
1916
0
        (ppath->last_charpath_segment == ppath->current_subpath->last) && !pdev->ForOPDFRead) {
1917
0
        bool hl_color = pdf_can_handle_hl_color((gx_device_vector *)pdev, pgs, pdcolor);
1918
0
        const gs_gstate *pgs_for_hl_color = (hl_color ? pgs : NULL);
1919
1920
0
        if (pdf_modify_text_render_mode(pdev->text->text_state, 1)) {
1921
            /* Set the colour for the stroke */
1922
0
            code = pdf_reset_color(pdev, pgs_for_hl_color, pdcolor, &pdev->saved_stroke_color,
1923
0
                        &pdev->stroke_used_process_color, &psdf_set_stroke_color_commands);
1924
0
            if (code == 0) {
1925
0
                s = pdev->strm;
1926
                /* Text is emitted scaled so that the CTM is an identity matrix, the line width
1927
                 * needs to be scaled to match otherwise we will get the default, or the current
1928
                 * width scaled by the CTM before the text, either of which would be wrong.
1929
                 */
1930
0
                scale = 72 / pdev->HWResolution[0];
1931
0
                scale *= fabs(pgs->ctm.xx);
1932
0
                pprintg1(s, "%g w\n", (pgs->line_params.half_width * 2) * (float)scale);
1933
                /* Some trickery here. We have altered the colour, text render mode and linewidth,
1934
                 * we don't want those to persist. By switching to a stream context we will flush the
1935
                 * pending text. This has the beneficial side effect of executing a grestore. So
1936
                 * everything works out neatly.
1937
                 */
1938
0
                code = pdf_open_page(pdev, PDF_IN_STREAM);
1939
0
                return(code);
1940
0
            }
1941
0
        }
1942
        /* Can only get here if any of the above steps fail, in which case we proceed to
1943
         * emit the charpath as a normal path, and stroke it.
1944
         */
1945
0
        code = pdf_open_page(pdev, PDF_IN_STREAM);
1946
0
    } else
1947
559k
        code = pdf_open_page(pdev, PDF_IN_STREAM);
1948
625k
    if (code < 0)
1949
0
        return code;
1950
625k
    code = pdf_prepare_stroke(pdev, pgs, false);
1951
625k
    if (code == gs_error_rangecheck) {
1952
        /* Fallback to the default implermentation for handling
1953
           a transparency with CompatibilityLevel<=1.3 . */
1954
933
        return gx_default_stroke_path((gx_device *)dev, pgs, ppath, params, pdcolor, pcpath);
1955
933
    }
1956
624k
    if (code < 0)
1957
0
        return code;
1958
624k
    code = pdf_put_clip_path(pdev, pcpath);
1959
624k
    if (code < 0)
1960
0
        return code;
1961
    /*
1962
     * If the CTM is not uniform, stroke width depends on angle.
1963
     * We'd like to avoid resetting the CTM, so we check for uniform
1964
     * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
1965
     * the CTM at the time of the stroke operation, not the CTM at
1966
     * the time the path was constructed, that is used for transforming
1967
     * the points of the path; so if we have to reset the CTM, we must
1968
     * do it before constructing the path, and inverse-transform all
1969
     * the coordinates.
1970
     */
1971
624k
    set_ctm = (bool)gdev_vector_stroke_scaling((gx_device_vector *)pdev,
1972
624k
                                               pgs, &scale, &mat);
1973
624k
    if (set_ctm && ((pgs->ctm.xx == 0 && pgs->ctm.xy == 0) ||
1974
62.7k
                    (pgs->ctm.yx == 0 && pgs->ctm.yy == 0))) {
1975
        /* Acrobat Reader 5 and Adobe Reader 6 issues
1976
           the "Wrong operand type" error with matrices, which have 3 zero coefs.
1977
           Besides that, we found that Acrobat Reader 4, Acrobat Reader 5
1978
           and Adobe Reader 6 all store the current path in user space
1979
           and apply CTM in the time of stroking - See the bug 687901.
1980
           Therefore a precise conversion of Postscript to PDF isn't possible in this case.
1981
           Adobe viewers render a line with a constant width instead.
1982
           At last, with set_ctm == true we need the inverse matrix in
1983
           gdev_vector_dopath. Therefore we exclude projection matrices
1984
           (see bug 688363). */
1985
1.52k
        set_ctm = false;
1986
1.52k
        scale = fabs(pgs->ctm.xx + pgs->ctm.xy + pgs->ctm.yx + pgs->ctm.yy) /* Using the non-zero coeff. */
1987
1.52k
                / sqrt(2); /* Empirically from Adobe. */
1988
1.52k
    }
1989
624k
    if (set_ctm && pdev->PDFA == 1) {
1990
        /*
1991
         * We want a scaling factor that will bring the largest reasonable
1992
         * user coordinate within bounds.  We choose a factor based on the
1993
         * minor axis of the transformation.  Thanks to Raph Levien for
1994
         * the following formula.
1995
         */
1996
0
        double a = mat.xx, b = mat.xy, c = mat.yx, d = mat.yy;
1997
0
        double u = fabs(a * d - b * c);
1998
0
        double v = a * a + b * b + c * c + d * d;
1999
0
        double minor = (sqrt(v + 2 * u) - sqrt(v - 2 * u)) * 0.5;
2000
2001
0
        prescale = (minor == 0 || minor > 1 ? 1 : 1 / minor);
2002
0
    }
2003
624k
    gx_path_bbox(ppath, &bbox);
2004
624k
    {
2005
        /* Check whether a painting appears inside the clipping box.
2006
           Doing so after writing the clipping path due to /SP pdfmark
2007
           uses a special hack with painting outside the clipping box
2008
           for synchronizing the clipping path (see lib/gs_pdfwr.ps).
2009
           That hack appeared because there is no way to pass
2010
           the gs_gstate through gdev_pdf_put_params,
2011
           which pdfmark is implemented with.
2012
        */
2013
624k
        gs_fixed_rect clip_box, stroke_bbox = bbox;
2014
624k
        gs_point d0, d1;
2015
624k
        gs_fixed_point p0, p1;
2016
624k
        fixed bbox_expansion_x, bbox_expansion_y;
2017
2018
624k
        gs_distance_transform(pgs->line_params.half_width, 0, &ctm_only(pgs), &d0);
2019
624k
        gs_distance_transform(0, pgs->line_params.half_width, &ctm_only(pgs), &d1);
2020
624k
        p0.x = float2fixed(any_abs(d0.x));
2021
624k
        p0.y = float2fixed(any_abs(d0.y));
2022
624k
        p1.x = float2fixed(any_abs(d1.x));
2023
624k
        p1.y = float2fixed(any_abs(d1.y));
2024
624k
        bbox_expansion_x = max(p0.x, p1.x) + fixed_1 * 2;
2025
624k
        bbox_expansion_y = max(p0.y, p1.y) + fixed_1 * 2;
2026
624k
        stroke_bbox.p.x -= bbox_expansion_x;
2027
624k
        stroke_bbox.p.y -= bbox_expansion_y;
2028
624k
        stroke_bbox.q.x += bbox_expansion_x;
2029
624k
        stroke_bbox.q.y += bbox_expansion_y;
2030
624k
        gx_cpath_outer_box(pcpath, &clip_box);
2031
624k
        rect_intersect(stroke_bbox, clip_box);
2032
624k
        if (stroke_bbox.q.x < stroke_bbox.p.x || stroke_bbox.q.y < stroke_bbox.p.y)
2033
35.9k
            return 0;
2034
624k
    }
2035
589k
    if (make_rect_scaling(pdev, &bbox, prescale, &path_scale)) {
2036
0
        scale /= path_scale;
2037
0
        if (set_ctm)
2038
0
            gs_matrix_scale(&mat, path_scale, path_scale, &mat);
2039
0
        else {
2040
0
            gs_make_scaling(path_scale, path_scale, &mat);
2041
0
            set_ctm = true;
2042
0
        }
2043
0
    }
2044
589k
    code = gdev_vector_prepare_stroke((gx_device_vector *)pdev, pgs, params,
2045
589k
                                      pdcolor, scale);
2046
589k
    if (code < 0)
2047
171
        return gx_default_stroke_path(dev, pgs, ppath, params, pdcolor,
2048
171
                                      pcpath);
2049
588k
    if (!pdev->HaveStrokeColor)
2050
249k
        pdev->saved_fill_color = pdev->saved_stroke_color;
2051
588k
    if (set_ctm)
2052
49.0k
        pdf_put_matrix(pdev, "q ", &mat, "cm\n");
2053
588k
    if (pgs->line_params.dash.offset != 0 || pgs->line_params.dash.pattern_size != 0)
2054
5.80k
        code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_stroke | gx_path_type_optimize | gx_path_type_dashed_stroke, (set_ctm ? &mat : (const gs_matrix *)0));
2055
583k
    else
2056
583k
        code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_stroke | gx_path_type_optimize, (set_ctm ? &mat : (const gs_matrix *)0));
2057
588k
    if (code < 0)
2058
0
        return code;
2059
588k
    s = pdev->strm;
2060
588k
    stream_puts(s, "S");
2061
588k
    stream_puts(s, (set_ctm ? " Q\n" : "\n"));
2062
588k
    if (pdev->Eps2Write) {
2063
132k
        pdev->AccumulatingBBox++;
2064
132k
        code = gx_default_stroke_path(dev, pgs, ppath, params, pdcolor,
2065
132k
                                      pcpath);
2066
132k
        pdev->AccumulatingBBox--;
2067
132k
        if (code < 0)
2068
1
            return code;
2069
132k
    }
2070
588k
    return 0;
2071
588k
}
2072
2073
int
2074
gdev_pdf_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
2075
                          const gx_fill_params *fill_params, const gx_drawing_color *pdcolor_fill,
2076
                          const gx_stroke_params *stroke_params, const gx_drawing_color *pdcolor_stroke,
2077
    const gx_clip_path *pcpath)
2078
15.5k
{
2079
15.5k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
2080
15.5k
    int code;
2081
15.5k
    bool new_clip;
2082
15.5k
    bool have_path;
2083
2084
15.5k
    have_path = !gx_path_is_void(ppath);
2085
15.5k
    if (!have_path) {
2086
11.8k
        if (!pdev->vg_initial_set) {
2087
            /* See lib/gs_pdfwr.ps about "initial graphic state". */
2088
0
            pdf_prepare_initial_viewer_state(pdev, pgs);
2089
0
            pdf_reset_graphics(pdev);
2090
0
            return 0;
2091
0
        }
2092
11.8k
    }
2093
2094
    /* PostScript doesn't have a fill+stroke primitive, so break it into two operations
2095
     * PDF 1.2 only has a single overprint setting, we can't be certainto match that
2096
     * Because our inpu tcould be from a higher level. So be sure and break it into
2097
     * 2 operations.
2098
     */
2099
15.5k
    if (pdev->ForOPDFRead || pdev->CompatibilityLevel < 1.3) {
2100
10.5k
        code = gdev_pdf_fill_path(dev, pgs, ppath, fill_params, pdcolor_fill, pcpath);
2101
10.5k
        if (code < 0)
2102
0
            return code;
2103
10.5k
        gs_swapcolors_quick(pgs);
2104
10.5k
        code = gdev_pdf_stroke_path(dev, pgs, ppath, stroke_params, pdcolor_stroke, pcpath);
2105
10.5k
        gs_swapcolors_quick(pgs);
2106
10.5k
        return code;
2107
10.5k
    } else {
2108
5.01k
        bool set_ctm;
2109
5.01k
        gs_matrix mat;
2110
5.01k
        double scale, path_scale;
2111
5.01k
        double prescale = 1;
2112
5.01k
        gs_fixed_rect bbox;
2113
5.01k
        gs_path_enum cenum;
2114
5.01k
        gdev_vector_dopath_state_t state;
2115
5.01k
        stream *s = pdev->strm;
2116
        /*
2117
         * Check for an empty clipping path.
2118
         */
2119
5.01k
        if (pcpath) {
2120
5.01k
            gs_fixed_rect cbox;
2121
2122
5.01k
            gx_cpath_outer_box(pcpath, &cbox);
2123
5.01k
            if (cbox.p.x >= cbox.q.x || cbox.p.y >= cbox.q.y)
2124
151
                return 1;   /* empty clipping path */
2125
5.01k
        }
2126
4.85k
        code = pdf_check_soft_mask(pdev, (gs_gstate *)pgs);
2127
4.85k
        if (code < 0)
2128
0
            return code;
2129
2130
4.85k
        new_clip = pdf_must_put_clip_path(pdev, pcpath);
2131
4.85k
        if (have_path || pdev->context == PDF_IN_NONE || new_clip) {
2132
1.26k
            if (new_clip)
2133
580
                code = pdf_unclip(pdev);
2134
687
            else
2135
687
                code = pdf_open_page(pdev, PDF_IN_STREAM);
2136
1.26k
            if (code < 0)
2137
0
                return code;
2138
1.26k
        }
2139
4.85k
        code = pdf_prepare_fill_stroke(pdev, pgs, false);
2140
4.85k
        if (code < 0)
2141
0
            return code;
2142
2143
4.85k
        code = pdf_put_clip_path(pdev, pcpath);
2144
4.85k
        if (code < 0)
2145
0
            return code;
2146
        /*
2147
         * If the CTM is not uniform, stroke width depends on angle.
2148
         * We'd like to avoid resetting the CTM, so we check for uniform
2149
         * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
2150
         * the CTM at the time of the stroke operation, not the CTM at
2151
         * the time the path was constructed, that is used for transforming
2152
         * the points of the path; so if we have to reset the CTM, we must
2153
         * do it before constructing the path, and inverse-transform all
2154
         * the coordinates.
2155
         */
2156
4.85k
        set_ctm = (bool)gdev_vector_stroke_scaling((gx_device_vector *)pdev,
2157
4.85k
                                                   pgs, &scale, &mat);
2158
4.85k
        if (set_ctm && ((pgs->ctm.xx == 0 && pgs->ctm.xy == 0) ||
2159
752
                        (pgs->ctm.yx == 0 && pgs->ctm.yy == 0))) {
2160
            /* Acrobat Reader 5 and Adobe Reader 6 issues
2161
               the "Wrong operand type" error with matrices, which have 3 zero coefs.
2162
               Besides that, we found that Acrobat Reader 4, Acrobat Reader 5
2163
               and Adobe Reader 6 all store the current path in user space
2164
               and apply CTM in the time of stroking - See the bug 687901.
2165
               Therefore a precise conversion of Postscript to PDF isn't possible in this case.
2166
               Adobe viewers render a line with a constant width instead.
2167
               At last, with set_ctm == true we need the inverse matrix in
2168
               gdev_vector_dopath. Therefore we exclude projection matrices
2169
               (see bug 688363). */
2170
24
            set_ctm = false;
2171
24
            scale = fabs(pgs->ctm.xx + pgs->ctm.xy + pgs->ctm.yx + pgs->ctm.yy) /* Using the non-zero coeff. */
2172
24
                    / sqrt(2); /* Empirically from Adobe. */
2173
24
        }
2174
4.85k
        if (pdev->PDFA == 1 && set_ctm) {
2175
            /*
2176
             * We want a scaling factor that will bring the largest reasonable
2177
             * user coordinate within bounds.  We choose a factor based on the
2178
             * minor axis of the transformation.  Thanks to Raph Levien for
2179
             * the following formula.
2180
             */
2181
0
            double a = mat.xx, b = mat.xy, c = mat.yx, d = mat.yy;
2182
0
            double u = fabs(a * d - b * c);
2183
0
            double v = a * a + b * b + c * c + d * d;
2184
0
            double minor = (sqrt(v + 2 * u) - sqrt(v - 2 * u)) * 0.5;
2185
2186
0
            prescale = (minor == 0 || minor > 1 ? 1 : 1 / minor);
2187
0
        }
2188
4.85k
        gx_path_bbox(ppath, &bbox);
2189
4.85k
        {
2190
            /* Check whether a painting appears inside the clipping box.
2191
               Doing so after writing the clipping path due to /SP pdfmark
2192
               uses a special hack with painting outside the clipping box
2193
               for synchronizing the clipping path (see lib/gs_pdfwr.ps).
2194
               That hack appeared because there is no way to pass
2195
               the gs_gstate through gdev_pdf_put_params,
2196
               which pdfmark is implemented with.
2197
            */
2198
4.85k
            gs_fixed_rect clip_box, stroke_bbox = bbox;
2199
4.85k
            gs_point d0, d1;
2200
4.85k
            gs_fixed_point p0, p1;
2201
4.85k
            fixed bbox_expansion_x, bbox_expansion_y;
2202
2203
4.85k
            gs_distance_transform(pgs->line_params.half_width, 0, &ctm_only(pgs), &d0);
2204
4.85k
            gs_distance_transform(0, pgs->line_params.half_width, &ctm_only(pgs), &d1);
2205
4.85k
            p0.x = float2fixed(any_abs(d0.x));
2206
4.85k
            p0.y = float2fixed(any_abs(d0.y));
2207
4.85k
            p1.x = float2fixed(any_abs(d1.x));
2208
4.85k
            p1.y = float2fixed(any_abs(d1.y));
2209
4.85k
            bbox_expansion_x = max(p0.x, p1.x) + fixed_1 * 2;
2210
4.85k
            bbox_expansion_y = max(p0.y, p1.y) + fixed_1 * 2;
2211
4.85k
            stroke_bbox.p.x -= bbox_expansion_x;
2212
4.85k
            stroke_bbox.p.y -= bbox_expansion_y;
2213
4.85k
            stroke_bbox.q.x += bbox_expansion_x;
2214
4.85k
            stroke_bbox.q.y += bbox_expansion_y;
2215
4.85k
            gx_cpath_outer_box(pcpath, &clip_box);
2216
4.85k
            rect_intersect(stroke_bbox, clip_box);
2217
4.85k
            if (stroke_bbox.q.x < stroke_bbox.p.x || stroke_bbox.q.y < stroke_bbox.p.y)
2218
774
                return 0;
2219
4.85k
        }
2220
4.08k
        if (make_rect_scaling(pdev, &bbox, prescale, &path_scale)) {
2221
0
            scale /= path_scale;
2222
0
            if (set_ctm)
2223
0
                gs_matrix_scale(&mat, path_scale, path_scale, &mat);
2224
0
            else {
2225
0
                gs_make_scaling(path_scale, path_scale, &mat);
2226
0
                set_ctm = true;
2227
0
            }
2228
0
        }
2229
2230
4.08k
        code = pdf_setfillcolor((gx_device_vector *)pdev, pgs, pdcolor_fill);
2231
4.08k
        if (code == gs_error_rangecheck) {
2232
            /* rangecheck means we revert to the equivalent to the default implementation */
2233
124
            code = gdev_pdf_fill_path(dev, pgs, ppath, fill_params, pdcolor_fill, pcpath);
2234
124
            if (code < 0)
2235
0
                return code;
2236
            /* Swap colors to make sure the pgs colorspace is correct for stroke */
2237
124
            gs_swapcolors_quick(pgs);
2238
124
            code = gdev_pdf_stroke_path(dev, pgs, ppath, stroke_params, pdcolor_stroke, pcpath);
2239
124
            gs_swapcolors_quick(pgs);
2240
124
            return code;
2241
124
        }
2242
2243
        /* Swap colors to make sure the pgs colorspace is correct for stroke */
2244
3.96k
        gs_swapcolors_quick(pgs);
2245
3.96k
        code = gdev_vector_prepare_stroke((gx_device_vector *)pdev, pgs, stroke_params,
2246
3.96k
                                          pdcolor_stroke, scale);
2247
3.96k
        gs_swapcolors_quick(pgs);
2248
3.96k
        if (code < 0) {
2249
0
            code = gdev_pdf_fill_path(dev, pgs, ppath, fill_params, pdcolor_fill, pcpath);
2250
0
            if (code < 0)
2251
0
                return code;
2252
0
            return gdev_pdf_stroke_path(dev, pgs, ppath, stroke_params, pdcolor_stroke, pcpath);
2253
0
        }
2254
3.96k
        if (!pdev->HaveStrokeColor)
2255
0
            pdev->saved_fill_color = pdev->saved_stroke_color;
2256
3.96k
        if (set_ctm)
2257
597
            pdf_put_matrix(pdev, "q ", &mat, "cm\n");
2258
3.96k
        if (pgs->line_params.dash.offset != 0 || pgs->line_params.dash.pattern_size != 0)
2259
7
            code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_stroke | gx_path_type_optimize | gx_path_type_dashed_stroke, (set_ctm ? &mat : (const gs_matrix *)0));
2260
3.95k
        else
2261
3.95k
            code = pdf_write_path(pdev, (gs_path_enum *)&cenum, &state, (gx_path *)ppath, 0, gx_path_type_stroke | gx_path_type_optimize, (set_ctm ? &mat : (const gs_matrix *)0));
2262
3.96k
        if (code < 0)
2263
0
            return code;
2264
3.96k
        s = pdev->strm;
2265
3.96k
        stream_puts(s, (fill_params->rule < 0 ? "B\n" : "B*\n"));
2266
3.96k
        stream_puts(s, (set_ctm ? "Q\n" : "\n"));
2267
3.96k
    }
2268
3.96k
    return 0;
2269
15.5k
}
2270
2271
/*
2272
   The fill_rectangle_hl_color device method.
2273
   See gxdevcli.h about return codes.
2274
 */
2275
int
2276
gdev_pdf_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
2277
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
2278
    const gx_clip_path *pcpath)
2279
17.7k
{
2280
17.7k
    int code;
2281
17.7k
    gs_fixed_rect box1 = *rect, box = box1;
2282
17.7k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
2283
17.7k
    double scale;
2284
17.7k
    gs_matrix smat, *psmat = NULL;
2285
17.7k
    const bool convert_to_image = (pdev->CompatibilityLevel <= 1.2 &&
2286
11.4k
            gx_dc_is_pattern2_color(pdcolor));
2287
2288
17.7k
    if (rect->p.x == rect->q.x)
2289
919
        return 0;
2290
16.8k
    if (!convert_to_image) {
2291
16.8k
        code = prepare_fill_with_clip(pdev, pgs, &box, true, pdcolor, pcpath);
2292
16.8k
        if (code < 0)
2293
0
            return code;
2294
16.8k
        if (code == 1)
2295
0
            return 0; /* Nothing to paint. */
2296
16.8k
        code = pdf_setfillcolor((gx_device_vector *)pdev, pgs, pdcolor);
2297
16.8k
        if (code < 0)
2298
0
            return code;
2299
16.8k
        if (pcpath)
2300
16.8k
            rect_intersect(box1, box);
2301
16.8k
        if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
2302
0
            return 0;   /* outside the clipping path */
2303
16.8k
        if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
2304
0
            gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale, &smat);
2305
0
            pdf_put_matrix(pdev, "q ", &smat, "cm\n");
2306
0
            psmat = &smat;
2307
0
        }
2308
16.8k
        pprintg4(pdev->strm, "%g %g %g %g re f\n",
2309
16.8k
                fixed2float(box1.p.x) / scale, fixed2float(box1.p.y) / scale,
2310
16.8k
                (fixed2float(box1.q.x) - fixed2float(box1.p.x)) / scale, (fixed2float(box1.q.y) - fixed2float(box1.p.y)) / scale);
2311
16.8k
        if (psmat != NULL)
2312
0
            stream_puts(pdev->strm, "Q\n");
2313
16.8k
        if (pdev->Eps2Write) {
2314
7.28k
            gs_rect *Box;
2315
2316
7.28k
            if (!pdev->accumulating_charproc)
2317
7.28k
                Box = &pdev->BBox;
2318
0
            else
2319
0
                Box = &pdev->charproc_BBox;
2320
2321
7.28k
            if (fixed2float(box1.p.x) / (pdev->HWResolution[0] / 72.0) < Box->p.x)
2322
660
                Box->p.x = fixed2float(box1.p.x) / (pdev->HWResolution[0] / 72.0);
2323
7.28k
            if (fixed2float(box1.p.y) / (pdev->HWResolution[1] / 72.0) < Box->p.y)
2324
655
                Box->p.y = fixed2float(box1.p.y) / (pdev->HWResolution[1] / 72.0);
2325
7.28k
            if (fixed2float(box1.q.x) / (pdev->HWResolution[0] / 72.0) > Box->q.x)
2326
919
                Box->q.x = fixed2float(box1.q.x) / (pdev->HWResolution[0] / 72.0);
2327
7.28k
            if (fixed2float(box1.q.y) / (pdev->HWResolution[1] / 72.0) > Box->q.y)
2328
818
                Box->q.y = fixed2float(box1.q.y) / (pdev->HWResolution[1] / 72.0);
2329
7.28k
        }
2330
16.8k
        return 0;
2331
16.8k
    } else {
2332
0
        gx_fill_params params;
2333
0
        gx_path path;
2334
2335
0
        params.rule = 1; /* Not important because the path is a rectange. */
2336
0
        params.adjust.x = params.adjust.y = 0;
2337
0
        params.flatness = pgs->flatness;
2338
0
        gx_path_init_local(&path, pgs->memory);
2339
0
        code = gx_path_add_rectangle(&path, rect->p.x, rect->p.y, rect->q.x, rect->q.y);
2340
0
        if (code < 0)
2341
0
            return code;
2342
0
        code = gdev_pdf_fill_path(dev, pgs, &path, &params, pdcolor, pcpath);
2343
0
        if (code < 0)
2344
0
            return code;
2345
0
        gx_path_free(&path, "gdev_pdf_fill_rectangle_hl_color");
2346
0
        return code;
2347
2348
0
    }
2349
16.8k
}
2350
2351
int
2352
gdev_pdf_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc)
2353
307k
{
2354
307k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
2355
307k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
2356
2357
307k
    if (gx_dc_pure_color(pdevc) == pdev->white && !is_in_page(pdev) && pdev->sbstack_depth <= bottom) {
2358
        /* PDF doesn't need to erase the page if its plain white */
2359
297k
        return 0;
2360
297k
    }
2361
10.1k
    else
2362
10.1k
        return gx_default_fillpage(dev, pgs, pdevc);
2363
307k
}