Coverage Report

Created: 2025-02-15 06:18

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