Coverage Report

Created: 2022-10-31 07:00

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