Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/base/gxstroke.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 stroking procedures for Ghostscript library */
18
#include "math_.h"
19
#include <stdlib.h> /* abs() */
20
#include "gx.h"
21
#include "gpcheck.h"
22
#include "gserrors.h"
23
#include "gsdcolor.h"
24
#include "gsptype1.h"
25
#include "gxfixed.h"
26
#include "gxfarith.h"
27
#include "gxmatrix.h"
28
#include "gscoord.h"
29
#include "gsdevice.h"
30
#include "gxdevice.h"
31
#include "gxhttile.h"
32
#include "gxgstate.h"
33
#include "gzline.h"
34
#include "gzpath.h"
35
#include "gzcpath.h"
36
#include "gxpaint.h"
37
#include "gsstate.h"            /* for gs_currentcpsimode */
38
39
/* RJW: There appears to be a difference in the xps and postscript models
40
 * (at least in as far as Microsofts implementation of xps and Acrobats of
41
 * postscript). Acrobat (and ghostscript) are happy to join a line segment
42
 * around a corner, even when the next segment is a dash gap. Microsofts
43
 * implementation of XPS does not.
44
 *
45
 * A test file that shows this up is tests_private/comparefiles/298-05.ps
46
 *
47
 * Enabling the following define would emulate xps behaviour here.
48
 */
49
#undef AVOID_JOINING_TO_DASH_GAPS
50
51
/*
52
 * We don't really know whether it's a good idea to take fill adjustment
53
 * into account for stroking.  Disregarding it means that strokes
54
 * come out thinner than fills; observing it produces heavy-looking
55
 * strokes at low resolutions.  But in any case, we must disregard it
56
 * when stroking zero-width lines.
57
 */
58
#define USE_FILL_ADJUSTMENT
59
60
#ifdef USE_FILL_ADJUSTMENT
61
#  define STROKE_ADJUSTMENT(thin, pgs, xy)\
62
0
     (thin ? fixed_0 : (pgs)->fill_adjust.xy)
63
#else
64
#  define STROKE_ADJUSTMENT(thin, pgs, xy) fixed_0
65
#endif
66
67
/*
68
 * For some reason, we commented out the optimization for portrait,
69
 * landscape, and uniform (non-scaled) transformations.  We have no record
70
 * of why we did this, and we don't know what bugs re-enabling it may
71
 * introduce.
72
 */
73
#define OPTIMIZE_ORIENTATION
74
75
/*
76
 * Compute the amount by which to expand a stroked bounding box to account
77
 * for line width, caps and joins.  Return 0 if the result is exact, 1 if
78
 * it may be conservative, or gs_error_limitcheck if the result is too
79
 * large to fit in a gs_fixed_point.
80
 *
81
 * Because of square caps and miter and triangular joins, the maximum
82
 * expansion on each side (in user space) is
83
 *      K * line_width/2
84
 * where K is determined as follows:
85
 *      For round or butt caps, E = 1
86
 *      For square caps, E = sqrt(2)
87
 *        If the path is only a single line segment, K = E;
88
 *          if triangular joins, K = 2;
89
 *          if miter joins, K = max(miter_limit, E);
90
 *      otherwise, K = E.
91
 *
92
 * If the following conditions apply, K = E yields an exact result:
93
 *      - The CTM is of the form [X 0 0 Y] or [0 X Y 0].
94
 *      - Square or round caps are used, or all subpaths are closed.
95
 *      - All segments (including the implicit segment created by
96
 *        closepath) are vertical or horizontal lines.
97
 *
98
 * Note that these conditions are sufficient, but not necessary, to get an
99
 * exact result.  We choose this set of conditions because it is easy to
100
 * check and covers many common cases.  Clients that care always have the
101
 * option of using strokepath to get an exact result.
102
 */
103
static float join_expansion_factor(const gs_gstate *, gs_line_join);
104
int
105
gx_stroke_path_expansion(const gs_gstate * pgs, const gx_path * ppath,
106
                         gs_fixed_point * ppt)
107
0
{
108
0
    const subpath *psub;
109
0
    const segment *pseg;
110
0
    double cx = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yx);
111
0
    double cy = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yy);
112
0
    double expand = pgs->line_params.half_width;
113
0
    int result = 1;
114
115
0
    if (ppath == NULL) {
116
0
        ppt->x = ppt->y = 0;
117
0
        return 0;   /* no expansion */
118
0
    }
119
0
    psub = ppath->first_subpath;
120
    /* Adjust the expansion (E) for square caps, if needed */
121
0
    if (pgs->line_params.start_cap == gs_cap_square ||
122
0
        pgs->line_params.end_cap == gs_cap_square)
123
0
            expand *= 1.414213562;
124
125
    /* Check for whether an exact result can be computed easily. */
126
0
    if (is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
127
0
        is_fzero2(pgs->ctm.xx, pgs->ctm.yy)
128
0
        ) {
129
0
        bool must_be_closed =
130
0
            !(pgs->line_params.start_cap == gs_cap_square ||
131
0
              pgs->line_params.start_cap == gs_cap_round  ||
132
0
              pgs->line_params.end_cap   == gs_cap_square ||
133
0
              pgs->line_params.end_cap   == gs_cap_round  ||
134
0
              pgs->line_params.dash_cap  == gs_cap_square ||
135
0
              pgs->line_params.dash_cap  == gs_cap_round);
136
0
        gs_fixed_point prev;
137
138
0
        prev.x = prev.y = 0; /* Quiet gcc warning. */
139
0
        for (pseg = (const segment *)psub; pseg;
140
0
             prev = pseg->pt, pseg = pseg->next
141
0
             )
142
0
            switch (pseg->type) {
143
0
            case s_start:
144
0
                if (((const subpath *)pseg)->curve_count ||
145
0
                    (must_be_closed && !((const subpath *)pseg)->is_closed)
146
0
                    )
147
0
                    goto not_exact;
148
0
                break;
149
0
            case s_line:
150
0
            case s_dash:
151
0
            case s_line_close:
152
0
                if (!(pseg->pt.x == prev.x || pseg->pt.y == prev.y))
153
0
                    goto not_exact;
154
0
                break;
155
0
            case s_gap:
156
0
            default:            /* other/unknown segment type */
157
0
                goto not_exact;
158
0
            }
159
0
        result = 0;             /* exact result */
160
0
    }
161
0
not_exact:
162
0
    if (result) {
163
0
        if (!gx_path_has_curves(ppath) && gx_path_subpath_count(ppath) <= 1 &&
164
0
            (psub == 0 || (pseg = psub->next) == 0 ||
165
0
             (pseg = pseg->next) == 0 || pseg->type == s_line_close))
166
0
            DO_NOTHING;
167
0
        else {
168
0
            float factor = join_expansion_factor(pgs, pgs->line_params.join);
169
170
0
            if (pgs->line_params.curve_join >= 0)
171
0
                factor = max(factor, join_expansion_factor(pgs,
172
0
                                (gs_line_join)pgs->line_params.curve_join));
173
0
            expand *= factor;
174
0
        }
175
0
    }
176
177
    /* Short-cut gs_bbox_transform. */
178
0
    {
179
0
        float exx = expand * cx;
180
0
        float exy = expand * cy;
181
0
        int code = set_float2fixed_vars(ppt->x, exx);
182
183
0
        if (code < 0)
184
0
            return code;
185
0
        code = set_float2fixed_vars(ppt->y, exy);
186
0
        if (code < 0)
187
0
            return code;
188
0
    }
189
190
0
    return result;
191
0
}
192
static float
193
join_expansion_factor(const gs_gstate *pgs, gs_line_join join)
194
0
{
195
0
    switch (join) {
196
0
    case gs_join_miter: return pgs->line_params.miter_limit;
197
0
    case gs_join_triangle: return 2.0;
198
0
    default: return 1.0;
199
0
    }
200
0
}
201
202
/*
203
 * Structure for a partial line (passed to the drawing routine).
204
 * Two of these are required to do joins right.
205
 * Each endpoint includes the two ends of the cap as well,
206
 * and the deltas for square, round, and triangular cap computation.
207
 *
208
 * The two base values for computing the caps of a partial line are the
209
 * width and the end cap delta.  The width value is one-half the line
210
 * width (suitably transformed) at 90 degrees counter-clockwise
211
 * (in device space, but with "90 degrees" interpreted in *user*
212
 * coordinates) at the end (as opposed to the origin) of the line.
213
 * The cdelta value is one-half the transformed line width in the same
214
 * direction as the line.  From these, we compute two other values at each
215
 * end of the line: co and ce, which are the ends of the cap.
216
 * Note that the cdelta values at o are the negatives of the values at e,
217
 * as are the offsets from p to co and ce.
218
 *
219
 * Initially, only o.p, e.p, e.cdelta, width, and thin are set.
220
 * compute_caps fills in the rest.
221
 */
222
typedef gs_fixed_point *p_ptr;
223
typedef struct endpoint_s {
224
    gs_fixed_point p;           /* the end of the line */
225
    gs_fixed_point co, ce;      /* ends of the cap, p +/- width */
226
    gs_fixed_point cdelta;      /* +/- cap length */
227
} endpoint;
228
typedef endpoint *ep_ptr;
229
typedef const endpoint *const_ep_ptr;
230
typedef struct partial_line_s {
231
    endpoint o;                 /* starting coordinate */
232
    endpoint e;                 /* ending coordinate */
233
    gs_fixed_point width;       /* one-half line width, see above */
234
    gs_fixed_point vector;      /* The line segment direction */
235
    bool thin;                  /* true if minimum-width line */
236
} partial_line;
237
typedef partial_line *pl_ptr;
238
239
/* As we stroke a path, we run through the line segments that make it up.
240
 * We gather each line segment together with any degenerate line segments
241
 * that follow it (call this set "prev"), and then 'join them' to the next
242
 * line segment (and any degenerate line segments that follow it) (if there
243
 * is one) (call this "current").
244
 *
245
 * In order to get the joins right we need to keep flags about both
246
 * prev and current, and whether they originally came from arcs.
247
 */
248
typedef enum note_flags {
249
250
    /* If set, all the line segments that make up current come from arcs. */
251
    nf_all_from_arc       = 1,
252
253
    /* If set, at least one of the line segments that make up current, come
254
     * from arcs. */
255
    nf_some_from_arc      = 2,
256
257
    /* If set then this segment should have a dash cap on the start rather
258
     * than a start cap. */
259
    nf_dash_head          = 4,
260
261
    /* If set then this segment should have a dash cap on the end rather
262
     * than an end cap. */
263
    nf_dash_tail          = 8,
264
265
    /* If set, all the line segments that make up prev come from arcs. */
266
    nf_prev_all_from_arc  = 16,
267
268
    /* If set, at least one of the line segment that make up prev, come from
269
     * arcs. */
270
    nf_prev_some_from_arc = 32,
271
272
    /* If set then prev should have a dash cap on the start rather
273
     * than a start cap. */
274
    nf_prev_dash_head     = 64,
275
276
    /* If set then prev should have a dash cap on the end rather
277
     * than an end cap. */
278
    nf_prev_dash_tail     = 128
279
280
} note_flags;
281
282
/* Macro to combine the prev and current arc_flags. After applying this
283
 * macro, the bits in the result have the following meanings:
284
 *  nf_all_from_arc    set if all the components of current and prev
285
 *                     come from an Arc.
286
 *  nf_some_from_arc   set if any of the components of current and
287
 *                     prev come from an Arc.
288
 *  nf_dash_head       set if prev should have a dash cap rather than
289
 *                     a start cap.
290
 *  nf_dash_tail       set if prev should have a dash cap rather than
291
 *                     an end cap.
292
 */
293
#define COMBINE_FLAGS(F) \
294
0
    (((F>>4) | ((F) & nf_some_from_arc)) & \
295
0
     (((F) & nf_all_from_arc) ? ~0 : ~nf_all_from_arc))
296
297
/* Assign a point.  Some compilers would do this with very slow code */
298
/* if we simply implemented it as an assignment. */
299
#define ASSIGN_POINT(pp, p)\
300
0
  ((pp)->x = (p).x, (pp)->y = (p).y)
301
302
/* Other forward declarations */
303
static bool width_is_thin(pl_ptr);
304
static void adjust_stroke(gx_device *, pl_ptr, const gs_gstate *, bool, bool, note_flags);
305
static int line_join_points(const gx_line_params * pgs_lp,
306
                             pl_ptr plp, pl_ptr nplp,
307
                             gs_fixed_point * join_points,
308
                             const gs_matrix * pmat, gs_line_join join,
309
                             bool reflected);
310
static int line_join_points_fast_cw(const gx_line_params * pgs_lp,
311
                                    pl_ptr plp, pl_ptr nplp,
312
                                    gs_fixed_point * rjoin_points,
313
                                    const gs_matrix * pmat,
314
                                    gs_line_join join);
315
static int line_join_points_fast_ccw(const gx_line_params * pgs_lp,
316
                                     pl_ptr plp, pl_ptr nplp,
317
                                     gs_fixed_point * join_points,
318
                                     const gs_matrix * pmat,
319
                                     gs_line_join join);
320
static void compute_caps(pl_ptr);
321
static int add_points(gx_path *, const gs_fixed_point *,
322
                       int, bool);
323
static int add_pie_join(gx_path *, pl_ptr, pl_ptr, bool, bool);
324
static int add_pie_join_fast_cw(gx_path *, pl_ptr, pl_ptr, bool);
325
static int add_pie_join_fast_ccw(gx_path *, pl_ptr, pl_ptr, bool);
326
static int add_round_cap(gx_path *, const_ep_ptr);
327
static int add_pie_cap(gx_path *, const_ep_ptr);
328
static int cap_points(gs_line_cap, const_ep_ptr,
329
                       gs_fixed_point * /*[3] */ );
330
static int join_under_pie(gx_path *, pl_ptr, pl_ptr, bool);
331
332
/* Define the default implementation of the device stroke_path procedure. */
333
int
334
gx_default_stroke_path(gx_device * dev, const gs_gstate * pgs,
335
                       gx_path * ppath, const gx_stroke_params * params,
336
                       const gx_drawing_color * pdcolor,
337
                       const gx_clip_path * pcpath)
338
0
{
339
0
    return gx_stroke_path_only(ppath, (gx_path *) 0, dev, pgs, params,
340
0
                               pdcolor, pcpath);
341
0
}
342
343
/* Fill a partial stroked path.  Free variables: */
344
/* to_path, stroke_path_body, fill_params, always_thin, pgs, dev, pdevc, */
345
/* code, ppath, exit(label). */
346
#define FILL_STROKE_PATH(dev, thin, pcpath, final)\
347
0
  if(to_path==&stroke_path_body && !gx_path_is_void(&stroke_path_body) &&\
348
0
     (final || lop_is_idempotent(pgs->log_op))) {\
349
0
    fill_params.adjust.x = STROKE_ADJUSTMENT(thin, pgs, x);\
350
0
    fill_params.adjust.y = STROKE_ADJUSTMENT(thin, pgs, y);\
351
0
    if (to_path_reverse != NULL) {\
352
0
        code = gx_join_path_and_reverse(to_path, to_path_reverse);\
353
0
        if(code < 0) goto exit;\
354
0
    }\
355
0
    code = gx_fill_path_only(to_path, dev, pgs, &fill_params, pdevc, pcpath);\
356
0
    gx_path_free(&stroke_path_body, "fill_stroke_path");\
357
0
    if ( code < 0 ) goto exit;\
358
0
    gx_path_init_local(&stroke_path_body, ppath->memory);\
359
0
  }
360
361
/*
362
 * Define the internal procedures that stroke a partial_line
363
 * (the first pl_ptr argument).  If both partial_lines are non-null,
364
 * the procedure creates an appropriate join; otherwise, the procedure
365
 * creates an end cap.  If the first int is 0, the procedure also starts
366
 * with an appropriate cap.
367
 */
368
#define stroke_line_proc(proc)\
369
  int proc(gx_path *, gx_path *, bool ensure_closed, int, pl_ptr, pl_ptr,\
370
           const gx_device_color *, gx_device *, const gs_gstate *,\
371
           const gx_stroke_params *, const gs_fixed_rect *, int,\
372
           gs_line_join, bool, note_flags)
373
typedef stroke_line_proc((*stroke_line_proc_t));
374
375
static stroke_line_proc(stroke_add);
376
static stroke_line_proc(stroke_add_compat);
377
static stroke_line_proc(stroke_add_fast);
378
static stroke_line_proc(stroke_fill);
379
static int stroke_add_initial_cap_compat(gx_path * ppath, pl_ptr plp, bool adlust_longitude,
380
           const gx_device_color * pdevc, gx_device * dev,
381
           const gs_gstate * pgs);
382
383
/* Define the orientations we handle specially. */
384
typedef enum {
385
    orient_other = 0,
386
    orient_portrait,            /* [xx 0 0 yy tx ty] */
387
    orient_landscape            /* [0 xy yx 0 tx ty] */
388
} orientation;
389
390
/*
391
 * Internal function used to merge the 2 sides of a stroked path.
392
 * path contains the 'forward' side, rpath contains the 'reversed' side.
393
 * Reverse rpath, then append it to path.
394
 *
395
 * If path is closed, then rpath should be too. If path is open, then the
396
 * starting and ending points of both paths should be the same, so as to
397
 * guarantee a closed path.
398
 */
399
static int
400
gx_join_path_and_reverse(gx_path * path, gx_path * rpath)
401
0
{
402
0
    int code;
403
404
0
    if (gx_path_is_void(rpath))
405
0
        return 0;
406
0
     code = gx_path_append_reversed(rpath, path);
407
0
    if (code < 0)
408
0
        return code;
409
410
0
    gx_path_free(rpath, "gx_join_path_and_reverse");
411
0
    gx_path_init_local(rpath, path->memory);
412
413
0
    return gx_path_close_subpath(path);
414
0
}
415
416
/*
417
 * Stroke a path.  If to_path != 0, append the stroke outline to it;
418
 * if to_path == 0, draw the strokes on pdev.
419
 *
420
 * Note that gx_stroke_path_only with to_path != NULL may clip the path to
421
 * the clipping path, as for to_path == NULL.  This is almost never
422
 * what is wanted.
423
 */
424
static int
425
gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
426
               const gs_gstate * pgs, const gx_stroke_params * params,
427
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
428
0
{
429
0
    bool CPSI_mode = gs_currentcpsimode(pgs->memory);
430
0
    bool traditional = CPSI_mode | params->traditional;
431
0
    stroke_line_proc_t line_proc =
432
0
               ((to_path == 0 && !gx_dc_is_pattern1_color_clist_based(pdevc))
433
0
                      ? (lop_is_idempotent(pgs->log_op) ? stroke_fill : stroke_add) :
434
0
                        (traditional ? stroke_add_compat : stroke_add_fast));
435
0
    gs_fixed_rect ibox, cbox;
436
0
    gx_device_clip cdev;
437
0
    gx_device *dev = pdev;
438
0
    int code = 0;
439
0
    gx_fill_params fill_params;
440
0
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
441
0
    int dash_count = pgs_lp->dash.pattern_size;
442
0
    gx_path fpath, dpath;
443
0
    gx_path stroke_path_body;
444
0
    gx_path stroke_path_reverse;
445
0
    gx_path *to_path_reverse = NULL;
446
0
    const gx_path *spath;
447
0
    float xx = pgs->ctm.xx, xy = pgs->ctm.xy;
448
0
    float yx = pgs->ctm.yx, yy = pgs->ctm.yy;
449
    /*
450
     * We are dealing with a reflected coordinate system
451
     * if transform(1,0) is counter-clockwise from transform(0,1).
452
     * See the note in stroke_add for the algorithm.
453
     */
454
0
    int uniform;
455
0
    bool reflected;
456
0
    orientation orient =
457
0
        (
458
0
#ifdef OPTIMIZE_ORIENTATION
459
0
         is_fzero2(xy, yx) ?
460
0
         (uniform = (xx == yy ? 1 : xx == -yy ? -1 : 0),
461
0
          reflected = (uniform ? uniform < 0 : (xx < 0) != (yy < 0)),
462
0
          orient_portrait) :
463
0
         is_fzero2(xx, yy) ?
464
0
         (uniform = (xy == yx ? -1 : xy == -yx ? 1 : 0),
465
0
          reflected = (uniform ? uniform < 0 : (xy < 0) == (yx < 0)),
466
0
          orient_landscape) :
467
    /* We should optimize uniform rotated coordinate systems */
468
    /* here as well, but we don't. */
469
0
#endif
470
0
         (uniform = 0,
471
0
          reflected = xy * yx > xx * yy,
472
0
          orient_other));
473
0
    const segment_notes not_first = sn_not_first;
474
0
    gs_line_join curve_join =
475
0
        (pgs_lp->curve_join >= 0 ? (gs_line_join)pgs_lp->curve_join :
476
0
         pgs_lp->join == gs_join_none || pgs_lp->join == gs_join_round ?
477
0
            gs_join_bevel : pgs_lp->join);
478
0
    float line_width = pgs_lp->half_width;      /* (*half* the line width) */
479
0
    bool always_thin;
480
0
    double line_width_and_scale;
481
0
    double device_line_width_scale = 0; /* Quiet compiler. */
482
0
    double device_dot_length = pgs_lp->dot_length * fixed_1;
483
0
    const subpath *psub;
484
0
    gs_matrix initial_matrix;
485
0
    bool initial_matrix_reflected;
486
0
    note_flags flags;
487
488
0
    (*dev_proc(pdev, get_initial_matrix)) (pdev, &initial_matrix);
489
0
    initial_matrix_reflected = initial_matrix.xy * initial_matrix.yx >
490
0
                               initial_matrix.xx * initial_matrix.yy;
491
492
#ifdef DEBUG
493
    if (gs_debug_c('o')) {
494
        int i;
495
496
        dmlprintf4(ppath->memory, "[o]half_width=%f, start_cap=%d, end_cap=%d, dash_cap=%d,\n",
497
                   pgs_lp->half_width, (int)pgs_lp->start_cap,
498
                   (int)pgs_lp->end_cap, (int)pgs_lp->dash_cap);
499
        dmlprintf3(ppath->memory, "   join=%d, miter_limit=%f, miter_check=%f,\n",
500
                   (int)pgs_lp->join, pgs_lp->miter_limit,
501
                   pgs_lp->miter_check);
502
        dmlprintf1(ppath->memory, "   dash pattern=%d", dash_count);
503
        for (i = 0; i < dash_count; i++)
504
            dmprintf1(ppath->memory, ",%f", pgs_lp->dash.pattern[i]);
505
        dmputs(ppath->memory, ",\n");
506
        dmlprintf4(ppath->memory, "\toffset=%f, init(ink_on=%d, index=%d, dist_left=%f)\n",
507
                   pgs_lp->dash.offset, pgs_lp->dash.init_ink_on,
508
                   pgs_lp->dash.init_index, pgs_lp->dash.init_dist_left);
509
    }
510
#endif
511
512
0
    gx_path_bbox(ppath, &ibox);
513
    /* Expand the path bounding box by the scaled line width. */
514
0
    {
515
0
        gs_fixed_point expansion;
516
517
0
        if (gx_stroke_path_expansion(pgs, ppath, &expansion) < 0) {
518
            /* The expansion is so large it caused a limitcheck. */
519
0
            ibox.p.x = ibox.p.y = min_fixed;
520
0
            ibox.q.x = ibox.q.y = max_fixed;
521
0
        } else {
522
0
            expansion.x += pgs->fill_adjust.x;
523
0
            expansion.y += pgs->fill_adjust.y;
524
            /*
525
             * It's theoretically possible for the following computations to
526
             * overflow, so we need to check for this.
527
             */
528
0
            ibox.p.x = (ibox.p.x < min_fixed + expansion.x ? min_fixed :
529
0
                        ibox.p.x - expansion.x);
530
0
            ibox.p.y = (ibox.p.y < min_fixed + expansion.y ? min_fixed :
531
0
                        ibox.p.y - expansion.y);
532
0
            ibox.q.x = (ibox.q.x > max_fixed - expansion.x ? max_fixed :
533
0
                        ibox.q.x + expansion.x);
534
0
            ibox.q.y = (ibox.q.y > max_fixed - expansion.y ? max_fixed :
535
0
                        ibox.q.y + expansion.y);
536
0
        }
537
0
    }
538
    /* Check the expanded bounding box against the clipping regions. */
539
0
    if (pcpath)
540
0
        gx_cpath_inner_box(pcpath, &cbox);
541
0
    else if (pdevc)
542
0
        (*dev_proc(pdev, get_clipping_box)) (pdev, &cbox);
543
0
    else {
544
        /* This is strokepath, not stroke.  Don't clip. */
545
0
        cbox = ibox;
546
0
    }
547
0
    if (!rect_within(ibox, cbox)) {
548
        /* Intersect the path box and the clip bounding box. */
549
        /* If the intersection is empty, this call is a no-op. */
550
0
        gs_fixed_rect bbox;
551
552
0
        if (pcpath) {
553
0
            gx_cpath_outer_box(pcpath, &bbox);
554
0
            if_debug4m('f', ppath->memory, "   outer_box=(%g,%g),(%g,%g)\n",
555
0
                       fixed2float(bbox.p.x), fixed2float(bbox.p.y),
556
0
                       fixed2float(bbox.q.x), fixed2float(bbox.q.y));
557
0
            rect_intersect(ibox, bbox);
558
0
        } else
559
0
            rect_intersect(ibox, cbox);
560
0
        if (ibox.p.x >= ibox.q.x || ibox.p.y >= ibox.q.y) {
561
            /* Intersection of boxes is empty! */
562
0
            return 0;
563
0
        }
564
        /*
565
         * The path is neither entirely inside the inner clip box
566
         * nor entirely outside the outer clip box.
567
         * If we had to flatten the path, this is where we would
568
         * recompute its bbox and make the tests again,
569
         * but we don't bother right now.
570
         */
571
        /*
572
         * If there is a clipping path, set up a clipping device.
573
         * for stroke_fill because, because the latter uses low level methods
574
         * which don't accept a clipping path.
575
         * Note that in some cases stroke_fill appends the path to stroke_path_body
576
         * instead a real painting, and it is painted with FILL_STROKE_PATH.
577
         *
578
         * Contrary to that, FILL_STROKE_PATH paints a path with
579
         * the fill_path method, which handles a clipping path,
580
         * so we don't pass the clipper device to FILL_STROKE_PATH
581
         * to prevent an appearence of superposing clippers.
582
         */
583
0
        if (pcpath && line_proc == stroke_fill) {
584
0
            gx_make_clip_device_on_stack(&cdev, pcpath, pdev);
585
0
            cdev.max_fill_band = pdev->max_fill_band;
586
0
            dev = (gx_device *)&cdev;
587
0
        }
588
0
    }
589
0
    fill_params.rule = gx_rule_winding_number;
590
0
    fill_params.flatness = pgs->flatness;
591
0
    if (line_width < 0)
592
0
        line_width = -line_width;
593
0
    line_width_and_scale = line_width * (double)int2fixed(1);
594
0
    if (is_fzero(line_width))
595
0
        always_thin = true;
596
0
    else {
597
0
        float xa, ya;
598
599
0
        switch (orient) {
600
0
            case orient_portrait:
601
0
                xa = xx, ya = yy;
602
0
                goto sat;
603
0
            case orient_landscape:
604
0
                xa = xy, ya = yx;
605
0
              sat:
606
0
                if (xa < 0)
607
0
                    xa = -xa;
608
0
                if (ya < 0)
609
0
                    ya = -ya;
610
0
                always_thin = (max(xa, ya) * line_width < 0.5);
611
0
                if (!always_thin && uniform) {  /* Precompute a value we'll need later. */
612
0
                    device_line_width_scale = line_width_and_scale * xa;
613
0
                }
614
0
                break;
615
0
            default:
616
0
                {
617
                    /* The check is more complicated, but it's worth it. */
618
                    /* Compute radii of the transformed round brush. */
619
                    /* Let x = [a, sqrt(1-a^2)]'
620
                       radius^2 is an extremum of :
621
                       rr(a)=(CTM*x)^2 = (a*xx + sqrt(1 - a^2)*xy)^2 + (a*yx + sqrt(1 - a^2)*yy)^2
622
                       With solving D(rr(a),a)==0, got :
623
                       max_rr = (xx^2 + xy^2 + yx^2 + yy^2 + sqrt(((xy + yx)^2 + (xx - yy)^2)*((xy - yx)^2 + (xx + yy)^2)))/2.
624
                       r = sqrt(max_rr);
625
                       Well we could use eigenvalues of the quadratic form,
626
                       but it gives same result with a bigger calculus.
627
                     */
628
0
                    double max_rr = ((double)(xx*xx + xy*xy + yx*yx + yy*yy) +
629
0
                                     sqrt((double)((xy + yx)*(xy + yx) + (xx - yy)*(xx - yy)) *
630
0
                                                  ((xy - yx)*(xy - yx) + (xx + yy)*(xx + yy))
631
0
                                          )
632
0
                                     )/2;
633
634
0
                    always_thin = max_rr * line_width * line_width < 0.25;
635
0
                }
636
0
        }
637
0
    }
638
0
    if_debug7m('o', ppath->memory, "[o]ctm=(%g,%g,%g,%g,%g,%g) thin=%d\n",
639
0
              xx, xy, yx, yy, pgs->ctm.tx, pgs->ctm.ty, always_thin);
640
0
    if (device_dot_length != 0) {
641
        /*
642
         * Compute the dot length in device space.  We can't do this
643
         * quite right for non-uniform coordinate systems; too bad.
644
         */
645
0
        gs_matrix mat;
646
0
        const gs_matrix *pmat;
647
648
0
        if (pgs_lp->dot_length_absolute) {
649
0
            gs_deviceinitialmatrix(pdev, &mat);
650
0
            pmat = &mat;
651
0
        } else
652
0
            pmat = (const gs_matrix *)&pgs->ctm;
653
0
        device_dot_length *= fabs(pmat->xy) + fabs(pmat->yy);
654
0
    }
655
    /* Start by flattening the path.  We should do this on-the-fly.... */
656
0
    if (!gx_path_has_curves(ppath) && !gx_path_has_long_segments(ppath)) {
657
        /* don't need to flatten */
658
0
        if (!ppath->first_subpath)
659
0
            return 0;
660
0
        spath = ppath;
661
0
    } else {
662
0
        gx_path_init_local(&fpath, ppath->memory);
663
0
        if ((code = gx_path_add_flattened_for_stroke(ppath, &fpath,
664
0
                                                params->flatness, pgs)) < 0
665
0
            )
666
0
            return code;
667
0
        spath = &fpath;
668
0
    }
669
0
    if (dash_count) {
670
0
        float max_dash_len = 0;
671
0
        float expand_squared;
672
0
        int i;
673
0
        float adjust = (float)pgs->fill_adjust.x;
674
0
        if (adjust > (float)pgs->fill_adjust.y)
675
0
            adjust = (float)pgs->fill_adjust.y;
676
0
        for (i = 0; i < dash_count; i++) {
677
0
            if (max_dash_len < pgs_lp->dash.pattern[i])
678
0
                max_dash_len = pgs_lp->dash.pattern[i];
679
0
        }
680
0
        expand_squared = pgs->ctm.xx * pgs->ctm.yy - pgs->ctm.xy * pgs->ctm.yx;
681
0
        if (expand_squared < 0)
682
0
            expand_squared = -expand_squared;
683
0
        expand_squared *= max_dash_len * max_dash_len;
684
        /* Wide lines in curves can show dashes up, so fudge to allow for
685
         * this. */
686
0
        if (pgs->line_params.half_width > 1)
687
0
            adjust /= pgs->line_params.half_width;
688
0
        if (expand_squared*65536.0f >= (float)(adjust*adjust)) {
689
0
            gx_path_init_local(&dpath, ppath->memory);
690
0
            code = gx_path_add_dash_expansion(spath, &dpath, pgs);
691
0
            if (code < 0)
692
0
                goto exf;
693
0
            spath = &dpath;
694
0
        } else {
695
0
            dash_count = 0;
696
0
        }
697
0
    }
698
0
    if (to_path == 0) {
699
        /* We might try to defer this if it's expensive.... */
700
0
        to_path = &stroke_path_body;
701
0
        gx_path_init_local(&stroke_path_body, ppath->memory);
702
0
    }
703
0
    if (line_proc == stroke_add_fast) {
704
0
        to_path_reverse = &stroke_path_reverse;
705
0
        gx_path_init_local(&stroke_path_reverse, ppath->memory);
706
0
    }
707
0
    for (psub = spath->first_subpath; psub != 0;) {
708
0
        int index = 0;
709
0
        const segment *pseg = (const segment *)psub;
710
0
        fixed x = pseg->pt.x;
711
0
        fixed y = pseg->pt.y;
712
0
        bool is_closed = ((const subpath *)pseg)->is_closed;
713
0
        partial_line pl, pl_prev, pl_first;
714
0
        bool zero_length = true;
715
0
        int pseg_notes = pseg->notes;
716
717
0
        flags = nf_all_from_arc;
718
719
        /* Run through each segment in the current path, drawing each segment
720
         * delayed by 1 - that is, when we're looking at segment n, we draw
721
         * (or not) segment n-1. This delay allows us to always know whether
722
         * to join or cap the line. */
723
0
        while ((pseg = pseg->next) != 0 &&
724
0
               pseg->type != s_start
725
0
            ) {
726
            /* Compute the width parameters in device space. */
727
            /* We work with unscaled values, for speed. */
728
0
            fixed sx, udx, sy, udy;
729
0
            bool is_dash_segment;
730
731
0
            pseg_notes = pseg->notes;
732
733
0
         d2:is_dash_segment = false;
734
0
         d1:if (pseg->type == s_dash) {
735
0
                dash_segment *pd = (dash_segment *)pseg;
736
737
0
                sx = pd->pt.x;
738
0
                sy = pd->pt.y;
739
0
                udx = pd->tangent.x;
740
0
                udy = pd->tangent.y;
741
0
                is_dash_segment = true;
742
0
            } else if (pseg->type == s_gap) {
743
0
                sx = pseg->pt.x;
744
0
                sy = pseg->pt.y;
745
0
                udx = sx - x;
746
0
                udy = sy - y;
747
0
                is_dash_segment = true;
748
0
            } else {
749
0
                sx = pseg->pt.x;
750
0
                sy = pseg->pt.y;
751
0
                udx = sx - x;
752
0
                udy = sy - y;
753
0
            }
754
0
            zero_length &= ((udx | udy) == 0);
755
0
            pl.o.p.x = x, pl.o.p.y = y;
756
0
          d:flags = (((pseg_notes & sn_not_first) ?
757
0
                      ((flags & nf_all_from_arc) | nf_some_from_arc) : 0) |
758
0
                     ((pseg_notes & sn_dash_head) ? nf_dash_head : 0)    |
759
0
                     ((pseg_notes & sn_dash_tail) ? nf_dash_tail : 0)    |
760
0
                     (flags & ~nf_all_from_arc));
761
0
            pl.e.p.x = sx, pl.e.p.y = sy;
762
0
            if (!(udx | udy) || pseg->type == s_dash || pseg->type == s_gap) { /* degenerate or short */
763
                /*
764
                 * If this is the first segment of the subpath,
765
                 * check the entire subpath for degeneracy.
766
                 * Otherwise, ignore the degenerate segment.
767
                 */
768
0
                if (index != 0 && pseg->type != s_dash && pseg->type != s_gap)
769
0
                {
770
0
                    if (pseg->next == NULL || pseg->next->type == s_start)
771
0
                        continue;
772
0
                    pseg = pseg->next;
773
                    /* We're skipping a degenerate path segment; if it was
774
                     * labelled as being the first from a curve, then make
775
                     * sure the one we're skipping to is also labelled as
776
                     * being the first from a curve, otherwise we can get
777
                     * improper joins being used. See Bug 696466. */
778
0
                    pseg_notes = (((pseg_notes & sn_not_first) == 0) ?
779
0
                                  (pseg->notes & ~sn_not_first) :
780
0
                                  pseg->notes);
781
0
                    goto d2;
782
0
                }
783
                /* Check for a degenerate subpath. */
784
0
                while ((pseg = pseg->next) != 0 &&
785
0
                       pseg->type != s_start
786
0
                    ) {
787
0
                    if (is_dash_segment)
788
0
                        break;
789
0
                    if (pseg->type == s_dash || pseg->type == s_gap)
790
0
                        goto d1;
791
0
                    sx = pseg->pt.x, udx = sx - x;
792
0
                    sy = pseg->pt.y, udy = sy - y;
793
0
                    if (udx | udy) {
794
0
                        zero_length = false;
795
0
                        goto d;
796
0
                    }
797
0
                }
798
0
                if (pgs_lp->dot_length == 0 &&
799
0
                    pgs_lp->start_cap != gs_cap_round &&
800
0
                    pgs_lp->end_cap != gs_cap_round &&
801
0
                    !is_dash_segment) {
802
                    /* From PLRM, stroke operator :
803
                       If a subpath is degenerate (consists of a single-point closed path
804
                       or of two or more points at the same coordinates),
805
                       stroke paints it only if round line caps have been specified */
806
0
                    break;
807
0
                }
808
                /*
809
                 * If the subpath is a dash, take the orientation from the dash segment.
810
                 * Otherwise orient the dot according to the previous segment if
811
                 * any, or else the next segment if any, or else
812
                 * according to the specified dot orientation.
813
                 */
814
0
                {
815
                    /* When passing here, either pseg == NULL or it points to the
816
                       start of the next subpaph. So we can't use pseg
817
                       for determining the segment direction.
818
                       In same time, psub->last may help, so use it. */
819
0
                    const segment *end = psub->last;
820
821
0
                    if (is_dash_segment) {
822
                        /* Nothing. */
823
0
                    } else if (end != 0 && (end->pt.x != x || end->pt.y != y))
824
0
                        sx = end->pt.x, sy = end->pt.y, udx = sx - x, udy = sy - y;
825
0
                }
826
                /*
827
                 * Compute the properly oriented dot length, and then
828
                 * draw the dot like a very short line.
829
                 */
830
0
                if ((udx | udy) == 0) {
831
0
                    if (is_fzero(pgs_lp->dot_orientation.xy)) {
832
                        /* Portrait orientation, dot length = X */
833
0
                        udx = fixed_1;
834
0
                    } else {
835
                        /* Landscape orientation, dot length = Y */
836
0
                        udy = fixed_1;
837
0
                    }
838
0
                }
839
0
                if (sx == x && sy == y && (pseg == NULL || pseg->type == s_start)) {
840
0
                    double scale = device_dot_length /
841
0
                                hypot((double)udx, (double)udy);
842
0
                    fixed udx1, udy1;
843
                    /*
844
                     * If we're using butt caps, make sure the "line" is
845
                     * long enough to show up.
846
                     * Don't apply this with always_thin, becase
847
                     * draw thin line always rounds the length up.
848
                     */
849
0
                    if (!always_thin && (pgs_lp->start_cap == gs_cap_butt ||
850
0
                                         pgs_lp->end_cap   == gs_cap_butt ||
851
0
                                         pgs_lp->dash_cap  == gs_cap_butt)) {
852
0
                        fixed dmax = max(any_abs(udx), any_abs(udy));
853
854
0
                        if (dmax * scale < fixed_1)
855
0
                            scale = (float)fixed_1 / dmax;
856
0
                    }
857
0
                    udx1 = (fixed) (udx * scale);
858
0
                    udy1 = (fixed) (udy * scale);
859
0
                    sx = x + udx1;
860
0
                    sy = y + udy1;
861
0
                }
862
                /*
863
                 * Back up 1 segment to keep the bookkeeping straight.
864
                 */
865
0
                pseg = (pseg != 0 ? pseg->prev : psub->last);
866
0
                if (!is_dash_segment)
867
0
                    goto d;
868
0
                pl.e.p.x = sx;
869
0
                pl.e.p.y = sy;
870
0
            }
871
0
            pl.vector.x = udx;
872
0
            pl.vector.y = udy;
873
0
            if (always_thin) {
874
0
                pl.e.cdelta.x = pl.e.cdelta.y = 0;
875
0
                pl.width.x = pl.width.y = 0;
876
0
                pl.thin = true;
877
0
            } else {
878
0
                if (uniform != 0) {
879
                    /* We can save a lot of work in this case. */
880
                    /* We know orient != orient_other. */
881
0
                    double dpx = udx, dpy = udy;
882
0
                    double wl = device_line_width_scale /
883
0
                    hypot(dpx, dpy);
884
885
0
                    pl.e.cdelta.x = (fixed) (dpx * wl);
886
0
                    pl.e.cdelta.y = (fixed) (dpy * wl);
887
                    /* The width is the cap delta rotated by */
888
                    /* 90 degrees. */
889
0
                    if (initial_matrix_reflected)
890
0
                        pl.width.x = pl.e.cdelta.y, pl.width.y = -pl.e.cdelta.x;
891
0
                    else
892
0
                        pl.width.x = -pl.e.cdelta.y, pl.width.y = pl.e.cdelta.x;
893
0
                    pl.thin = false;    /* if not always_thin, */
894
                    /* then never thin. */
895
896
0
                } else {
897
0
                    gs_point dpt;       /* unscaled */
898
0
                    float wl;
899
900
0
                    code = gs_gstate_idtransform(pgs,
901
0
                                                 (float)udx, (float)udy,
902
0
                                                 &dpt);
903
0
                    if (code < 0) {
904
0
                        dpt.x = 0; dpt.y = 0;
905
                        /* Swallow the error */
906
0
                        code = 0;
907
0
                    } else {
908
0
                        wl = line_width_and_scale /
909
0
                            hypot(dpt.x, dpt.y);
910
                        /* Construct the width vector in */
911
                        /* user space, still unscaled. */
912
0
                        dpt.x *= wl;
913
0
                        dpt.y *= wl;
914
0
                    }
915
916
                    /*
917
                     * We now compute both perpendicular
918
                     * and (optionally) parallel half-widths,
919
                     * as deltas in device space.  We use
920
                     * a fixed-point, unscaled version of
921
                     * gs_dtransform.  The second computation
922
                     * folds in a 90-degree rotation (in user
923
                     * space, before transforming) in the
924
                     * direction that corresponds to counter-
925
                     * clockwise in device space.
926
                     */
927
0
                    pl.e.cdelta.x = (fixed) (dpt.x * xx);
928
0
                    pl.e.cdelta.y = (fixed) (dpt.y * yy);
929
0
                    if (orient != orient_portrait)
930
0
                        pl.e.cdelta.x += (fixed) (dpt.y * yx),
931
0
                            pl.e.cdelta.y += (fixed) (dpt.x * xy);
932
0
                    if (!reflected ^ initial_matrix_reflected)
933
0
                        dpt.x = -dpt.x, dpt.y = -dpt.y;
934
0
                    pl.width.x = (fixed) (dpt.y * xx),
935
0
                        pl.width.y = -(fixed) (dpt.x * yy);
936
0
                    if (orient != orient_portrait)
937
0
                        pl.width.x -= (fixed) (dpt.x * yx),
938
0
                            pl.width.y += (fixed) (dpt.y * xy);
939
0
                    pl.thin = width_is_thin(&pl);
940
0
                }
941
0
                if (!pl.thin) {
942
0
                    if (index)
943
0
                        dev->sgr.stroke_stored = false;
944
0
                    adjust_stroke(dev, &pl, pgs, false,
945
0
                            (pseg->prev == 0 || pseg->prev->type == s_start) &&
946
0
                            (pseg->next == 0 || pseg->next->type == s_start) &&
947
0
                            (zero_length || !is_closed),
948
0
                            COMBINE_FLAGS(flags));
949
0
                    compute_caps(&pl);
950
0
                }
951
0
            }
952
0
            if (index++) {
953
0
                gs_line_join join =
954
0
                    (pseg_notes & not_first ? curve_join : pgs_lp->join);
955
0
                int first;
956
0
                pl_ptr lptr;
957
0
                bool ensure_closed;
958
959
0
                if (join == gs_join_none) {
960
                    /* Fake the end of a subpath so we get */
961
                    /* caps instead of joins. */
962
0
                    first = 0;
963
0
                    lptr = 0;
964
0
                    index = 1;
965
0
                } else {
966
0
                    first = (is_closed ? 1 : index - 2);
967
0
                    lptr = &pl;
968
0
                }
969
#ifdef AVOID_JOINING_TO_DASH_GAPS
970
                if (is_dash_segment) /* Never join to a dash segment */
971
                    lptr = NULL;
972
#endif
973
0
                if (pseg->type == s_gap)
974
0
                {
975
0
                    lptr = NULL;
976
                    /* We are always drawing one line segment behind, so make
977
                     * sure we don't draw the next one. */
978
0
                    index = 0;
979
0
                }
980
981
0
                ensure_closed = ((to_path == &stroke_path_body &&
982
0
                                  lop_is_idempotent(pgs->log_op)) ||
983
0
                                 (lptr == NULL ? true : lptr->thin));
984
                /* Draw the PREVIOUS line segment, joining it to lptr (or
985
                 * capping if lptr == NULL. */
986
0
                code = (*line_proc) (to_path, to_path_reverse, ensure_closed,
987
0
                                     first, &pl_prev, lptr,
988
0
                                     pdevc, dev, pgs, params, &cbox,
989
0
                                     uniform, join, initial_matrix_reflected,
990
0
                                     COMBINE_FLAGS(flags));
991
0
                if (code < 0)
992
0
                    goto exit;
993
0
                FILL_STROKE_PATH(pdev, always_thin, pcpath, false);
994
0
            } else if (pseg->type == s_gap) {
995
                /* If this segment is a gap, then we don't want to draw it
996
                 * next time! */
997
0
                index = 0;
998
0
            } else
999
0
                pl_first = pl;
1000
0
            pl_prev = pl;
1001
0
            x = sx, y = sy;
1002
0
            flags = (flags<<4) | nf_all_from_arc;
1003
0
        }
1004
0
        if (index) {
1005
            /* If closed, join back to start, else cap. */
1006
0
            segment_notes notes = (pseg == 0 ?
1007
0
                                   (const segment *)spath->first_subpath :
1008
0
                                   pseg)->notes;
1009
0
            gs_line_join join = (notes & not_first ? curve_join :
1010
0
                                 pgs_lp->join);
1011
0
            gs_line_cap cap;
1012
            /* For some reason, the Borland compiler requires the cast */
1013
            /* in the following statement. */
1014
0
            pl_ptr lptr =
1015
0
                (!is_closed || join == gs_join_none || zero_length ?
1016
0
                 (pl_ptr) 0 : (pl_ptr) & pl_first);
1017
1018
#ifdef AVOID_JOINING_TO_DASH_GAPS
1019
            if (lptr && psub->type == s_dash)
1020
                lptr = NULL;
1021
#endif
1022
            /* If the subpath starts with a gap, then cap, don't join! */
1023
0
            if (lptr && psub->type == s_start && psub->next && psub->next->type == s_gap)
1024
0
                lptr = NULL;
1025
1026
0
            flags = (((notes & sn_not_first) ?
1027
0
                      ((flags & nf_all_from_arc) | nf_some_from_arc) : 0) |
1028
0
                     ((notes & sn_dash_head) ? nf_dash_head : 0) |
1029
0
                     ((notes & sn_dash_tail) ? nf_dash_tail : 0) |
1030
0
                     (flags & ~nf_all_from_arc));
1031
0
            code = (*line_proc) (to_path, to_path_reverse, true,
1032
0
                                 index - 1, &pl_prev, lptr, pdevc,
1033
0
                                 dev, pgs, params, &cbox, uniform, join,
1034
0
                                 initial_matrix_reflected,
1035
0
                                 COMBINE_FLAGS(flags));
1036
0
            if (code < 0)
1037
0
                goto exit;
1038
0
            FILL_STROKE_PATH(pdev, always_thin, pcpath, false);
1039
0
            cap = ((flags & nf_prev_dash_head) ?
1040
0
                   pgs_lp->start_cap : pgs_lp->dash_cap);
1041
0
            if (traditional && lptr == 0 && cap != gs_cap_butt) {
1042
                /* Create the initial cap at last. */
1043
0
                code = stroke_add_initial_cap_compat(to_path, &pl_first, index == 1, pdevc, dev, pgs);
1044
0
                if (code < 0)
1045
0
                    goto exit;
1046
0
                FILL_STROKE_PATH(pdev, always_thin, pcpath, false);
1047
0
            }
1048
0
        }
1049
0
        psub = (const subpath *)pseg;
1050
0
    }
1051
0
    if (to_path_reverse != NULL)
1052
0
        code = gx_join_path_and_reverse(to_path, to_path_reverse);
1053
0
    FILL_STROKE_PATH(pdev, always_thin, pcpath, true);
1054
0
  exit:
1055
0
    if (dev == (gx_device *)&cdev)
1056
0
        cdev.target->sgr = cdev.sgr;
1057
0
    if (to_path == &stroke_path_body)
1058
0
        gx_path_free(&stroke_path_body, "gx_stroke_path_only error");   /* (only needed if error) */
1059
0
    if (to_path_reverse == &stroke_path_reverse)
1060
0
        gx_path_free(&stroke_path_reverse, "gx_stroke_path_only error");
1061
0
  exf:
1062
0
    if (dash_count)
1063
0
        gx_path_free(&dpath, "gx_stroke_path exit(dash path)");
1064
0
    if (ppath->curve_count)
1065
0
        gx_path_free(&fpath, "gx_stroke_path exit(flattened path)");
1066
0
    return code;
1067
0
}
1068
1069
int
1070
gx_stroke_path_only(gx_path * ppath, gx_path * to_path, gx_device * pdev,
1071
               const gs_gstate * pgs, const gx_stroke_params * params,
1072
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
1073
0
{
1074
0
    return gx_stroke_path_only_aux(ppath, to_path, pdev, pgs, params, pdevc, pcpath);
1075
0
}
1076
1077
/* ------ Internal routines ------ */
1078
1079
/*
1080
 * Test whether a line is thin, i.e., whether the half-width, measured
1081
 * perpendicular to the line in device space, is less than 0.5 pixel.
1082
 * Unfortunately, the width values we computed are perpendicular to the
1083
 * line in *user* space, so we may have to do some extra work.
1084
 */
1085
static bool
1086
width_is_thin(pl_ptr plp)
1087
0
{
1088
0
    fixed dx, dy, wx = plp->width.x, wy = plp->width.y;
1089
1090
    /* If the line is horizontal or vertical, things are easy. */
1091
0
    if ((dy = plp->vector.y) == 0)
1092
0
        return any_abs(wy) < fixed_half;
1093
0
    if ((dx = plp->vector.x) == 0)
1094
0
        return any_abs(wx) < fixed_half;
1095
1096
    /* For the longest time, we used to have a test here that
1097
     * attempted to trivially accept diagonal lines as being
1098
     * thin based on the components of the perpendicular
1099
     * width vector in device space as both being less than 0.5.
1100
     * Bug 702196 showed some examples where this was clearly
1101
     * wrong.
1102
     *
1103
     * The cause for this bug was that the 0.5 figure was wrong.
1104
     * For the point to be less than 1/2 a pixel perpendicular
1105
     * distant from the line, we'd need x^2 + y^2 < .5^2.
1106
     * For a 45 degree line, that'd be 2(x^2) < 1/4 = x^2 < 1/8
1107
     * or x < sqr(1/8). 45 degree line is the "worst case", so
1108
     * if both horizontal and vertical widths are less than
1109
     * sqr(1/8), the line is thin. sqr(1/8) = 0.35355339059.
1110
     * So, we should be using sqr(1/8) rather than 0.5.
1111
     *
1112
     * Fixing this did indeed produce many many progressions,
1113
     * but left just the odd file still showing problems.
1114
     *
1115
     * Further investigations show that those cases were due to
1116
     * the use of "non-uniform" scaling matrices, for example
1117
     * (83 0 0 51 0 0). With such matrices, it's possible for
1118
     * nearly horizontal lines to be thin, but nearly vertical
1119
     * ones to be thick (or vice versa). Having the style of
1120
     * line "pop" between thick and thin in a single stroke
1121
     * looks very noticeable.
1122
     *
1123
     * We could change the trivial optimisation below to only
1124
     * apply in the 'uniform' case, but that would never actually
1125
     * trigger (as tested on the cluster), because all such
1126
     * cases are caught by the "always_thin" condition in the
1127
     * caller.
1128
     *
1129
     * Just removing the trivial test and leaving the 'complicated'
1130
     * test below us would leave us vulnerable to "popping",
1131
     * so we disable both. In practice this makes no difference
1132
     * to the number of tests showing diffs in the cluster.
1133
     */
1134
#if 0 /* DISABLED TEST, see above */
1135
    {
1136
        /* thin_threshold = fixed sqr(1/8) - see above. */
1137
        const fixed thin_threshold = float2fixed(0.35355339059f);
1138
        if (any_abs(wx) < thin_threshold && any_abs(wy) < thin_threshold)
1139
            return true;
1140
    }
1141
1142
    /*
1143
     * We have to do this the hard way, by actually computing the
1144
     * perpendicular distance.  The distance from the point (U,V)
1145
     * from a line from (0,0) to (C,D) is
1146
     *      abs(C*V - D*U) / sqrt(C^2 + D^2)
1147
     * In this case, (U,V) is plp->width, and (C,D) is (dx,dy).
1148
     */
1149
    {
1150
        double C = dx, D = dy;
1151
        double num = C * wy - D * wx;
1152
        double denom = hypot(C, D);
1153
1154
        /* both num and denom are scaled by fixed_scale^2, */
1155
        /* so we don't need to do any de-scaling for the test. */
1156
        return fabs(num) < denom * 0.5;
1157
    }
1158
#else
1159
0
    return false;
1160
0
#endif
1161
0
}
1162
1163
/* Adjust the endpoints and width of a stroke segment along a specified axis */
1164
static void
1165
adjust_stroke_transversal(pl_ptr plp, const gs_gstate * pgs, bool thin, bool horiz)
1166
0
{
1167
0
    fixed *pw;
1168
0
    fixed *pov;
1169
0
    fixed *pev;
1170
0
    fixed w, w2;
1171
0
    fixed adj2;
1172
1173
0
    if (horiz) {
1174
        /* More horizontal stroke */
1175
0
        pw = &plp->width.y, pov = &plp->o.p.y, pev = &plp->e.p.y;
1176
0
        adj2 = STROKE_ADJUSTMENT(thin, pgs, y) << 1;
1177
0
    } else {
1178
        /* More vertical stroke */
1179
0
        pw = &plp->width.x, pov = &plp->o.p.x, pev = &plp->e.p.x;
1180
0
        adj2 = STROKE_ADJUSTMENT(thin, pgs, x) << 1;
1181
0
    }
1182
    /* Round the larger component of the width up or down, */
1183
    /* whichever way produces a result closer to the correct width. */
1184
    /* Note that just rounding the larger component */
1185
    /* may not produce the correct result. */
1186
0
    w = *pw;
1187
0
    if (w > 0)
1188
0
        w2 = fixed_rounded(w << 1);     /* full line width */
1189
0
    else
1190
0
        w2 = -fixed_rounded(-w << 1);   /* full line width */
1191
0
    if (w2 == 0 && *pw != 0) {
1192
        /* Make sure thin lines don't disappear. */
1193
0
        w2 = (*pw < 0 ? -fixed_1 + adj2 : fixed_1 - adj2);
1194
0
        *pw = arith_rshift_1(w2);
1195
0
    }
1196
    /* Only adjust the endpoints if the line is horizontal or vertical. */
1197
0
    if (*pov == *pev) {
1198
        /* We're going to round the endpoint coordinates, so */
1199
        /* take the fill adjustment into account now. */
1200
0
        if (w >= 0)
1201
0
            w2 += adj2;
1202
0
        else
1203
0
            w2 = adj2 - w2;
1204
0
        if (w2 & fixed_1)       /* odd width, move to half-pixel */
1205
0
            *pov = *pev = fixed_floor(*pov) + fixed_half;
1206
0
        else                    /* even width, move to pixel */
1207
0
            *pov = *pev = fixed_rounded(*pov);
1208
1209
0
    }
1210
0
}
1211
1212
static void
1213
adjust_stroke_longitude(pl_ptr plp, const gs_gstate * pgs,
1214
                        bool thin, bool horiz,
1215
                        gs_line_cap start_cap, gs_line_cap end_cap)
1216
0
{
1217
1218
0
    fixed *pow = (horiz ? &plp->o.p.y : &plp->o.p.x);
1219
0
    fixed *pew = (horiz ? &plp->e.p.y : &plp->e.p.x);
1220
1221
    /* Only adjust the endpoints if the line is horizontal or vertical.
1222
       Debugged with pdfwrite->ppmraw 72dpi file2.pdf */
1223
0
    if (*pow == *pew) {
1224
0
        fixed *pov = (horiz ? &plp->o.p.x : &plp->o.p.y);
1225
0
        fixed *pev = (horiz ? &plp->e.p.x : &plp->e.p.y);
1226
0
        fixed length = any_abs(*pov - *pev);
1227
0
        fixed length_r, length_r_2;
1228
0
        fixed mv = (*pov + *pev) / 2, mv_r;
1229
0
        fixed adj2 = (horiz ? STROKE_ADJUSTMENT(thin, pgs, x)
1230
0
                            : STROKE_ADJUSTMENT(thin, pgs, y)) << 1;
1231
1232
        /* fixme :
1233
           The best value for adjust_longitude is whether
1234
           the dash is isolated and doesn't cover entire segment.
1235
           The current data structure can't pass this info.
1236
           Therefore we restrict adjust_stroke_longitude with 1 pixel length.
1237
        */
1238
0
        if (length > fixed_1) /* comparefiles/file2.pdf */
1239
0
            return;
1240
0
        if (start_cap == gs_cap_butt || end_cap == gs_cap_butt) {
1241
0
            length_r = fixed_rounded(length);
1242
0
            if (length_r < fixed_1)
1243
0
                length_r = fixed_1;
1244
0
            length_r_2 = length_r / 2;
1245
0
        } else {
1246
            /* Account width for proper placing cap centers. */
1247
0
            fixed width = any_abs(horiz ? plp->width.y : plp->width.x);
1248
1249
0
            length_r = fixed_rounded(length + width * 2 + adj2);
1250
0
            length_r_2 = fixed_rounded(length) / 2;
1251
0
        }
1252
0
        if (length_r & fixed_1)
1253
0
            mv_r = fixed_floor(mv) + fixed_half;
1254
0
        else
1255
0
            mv_r = fixed_floor(mv);
1256
0
        if (*pov < *pev) {
1257
0
            *pov = mv_r - length_r_2;
1258
0
            *pev = mv_r + length_r_2;
1259
0
        } else {
1260
0
            *pov = mv_r + length_r_2;
1261
0
            *pev = mv_r - length_r_2;
1262
0
        }
1263
0
    }
1264
0
}
1265
1266
/* Adjust the endpoints and width of a stroke segment */
1267
/* to achieve more uniform rendering. */
1268
/* Only o.p, e.p, e.cdelta, and width have been set. */
1269
static void
1270
adjust_stroke(gx_device *dev, pl_ptr plp, const gs_gstate * pgs,
1271
              bool thin, bool adjust_longitude, note_flags flags)
1272
0
{
1273
0
    bool horiz, adjust = true;
1274
0
    gs_line_cap start_cap = (flags & nf_dash_head ?
1275
0
                             pgs->line_params.dash_cap :
1276
0
                             pgs->line_params.start_cap);
1277
0
    gs_line_cap end_cap   = (flags & nf_dash_tail ?
1278
0
                             pgs->line_params.dash_cap :
1279
0
                             pgs->line_params.end_cap);
1280
1281
    /* If stroke_adjustment is disabled, or this isn't a horizontal or
1282
     * vertical line, then bale. */
1283
0
    if (!pgs->stroke_adjust || (plp->width.x != 0 && plp->width.y != 0)) {
1284
0
        dev->sgr.stroke_stored = false;
1285
0
        return;                 /* don't adjust */
1286
0
    }
1287
    /* Recognizing gradients, which some obsolete software
1288
       represent as a set of parallel strokes.
1289
       Such strokes must not be adjusted - bug 687974. */
1290
0
    if (dev->sgr.stroke_stored &&
1291
0
        (start_cap == gs_cap_butt || end_cap == gs_cap_butt) &&
1292
0
        dev->sgr.orig[3].x == plp->vector.x && dev->sgr.orig[3].y == plp->vector.y) {
1293
        /* Parallel. */
1294
0
        if ((int64_t)(plp->o.p.x - dev->sgr.orig[0].x) * plp->vector.x ==
1295
0
            (int64_t)(plp->o.p.y - dev->sgr.orig[0].y) * plp->vector.y &&
1296
0
            (int64_t)(plp->e.p.x - dev->sgr.orig[1].x) * plp->vector.x ==
1297
0
            (int64_t)(plp->e.p.y - dev->sgr.orig[1].y) * plp->vector.y) {
1298
            /* Transversal shift. */
1299
0
            if (any_abs(plp->o.p.x - dev->sgr.orig[0].x) <= any_abs(plp->width.x + dev->sgr.orig[2].x) &&
1300
0
                any_abs(plp->o.p.y - dev->sgr.orig[0].y) <= any_abs(plp->width.y + dev->sgr.orig[2].y) &&
1301
0
                any_abs(plp->e.p.x - dev->sgr.orig[1].x) <= any_abs(plp->width.x + dev->sgr.orig[2].x) &&
1302
0
                any_abs(plp->e.p.y - dev->sgr.orig[1].y) <= any_abs(plp->width.y + dev->sgr.orig[2].y)) {
1303
                /* The strokes were contacting or overlapping. */
1304
0
                if (any_abs(plp->o.p.x - dev->sgr.orig[0].x) >= any_abs(plp->width.x + dev->sgr.orig[2].x) / 2 &&
1305
0
                    any_abs(plp->o.p.y - dev->sgr.orig[0].y) >= any_abs(plp->width.y + dev->sgr.orig[2].y) / 2 &&
1306
0
                    any_abs(plp->e.p.x - dev->sgr.orig[1].x) >= any_abs(plp->width.x + dev->sgr.orig[2].x) / 2 &&
1307
0
                    any_abs(plp->e.p.y - dev->sgr.orig[1].y) >= any_abs(plp->width.y + dev->sgr.orig[2].y) / 2) {
1308
                    /* The strokes were not much overlapping. */
1309
0
                    if (!(any_abs(plp->o.p.x - dev->sgr.adjusted[0].x) <= any_abs(plp->width.x + dev->sgr.adjusted[2].x) &&
1310
0
                          any_abs(plp->o.p.y - dev->sgr.adjusted[0].y) <= any_abs(plp->width.y + dev->sgr.adjusted[2].y) &&
1311
0
                          any_abs(plp->e.p.x - dev->sgr.adjusted[1].x) <= any_abs(plp->width.x + dev->sgr.adjusted[2].x) &&
1312
0
                          any_abs(plp->e.p.y - dev->sgr.adjusted[1].y) <= any_abs(plp->width.y + dev->sgr.adjusted[2].y))) {
1313
                        /* they became not contacting.
1314
                           We should not have adjusted the last stroke. Since if we did,
1315
                           lets change the current one to restore the contact,
1316
                           so that we don't leave gaps when rasterising. See bug 687974.
1317
                         */
1318
0
                        fixed delta_w_x = (dev->sgr.adjusted[2].x - dev->sgr.orig[2].x);
1319
0
                        fixed delta_w_y = (dev->sgr.adjusted[2].y - dev->sgr.orig[2].y);
1320
0
                        fixed shift_o_x = (dev->sgr.adjusted[0].x - dev->sgr.orig[0].x);
1321
0
                        fixed shift_o_y = (dev->sgr.adjusted[0].y - dev->sgr.orig[0].y);
1322
0
                        fixed shift_e_x = (dev->sgr.adjusted[1].x - dev->sgr.orig[1].x); /* Must be same, but we prefer clarity. */
1323
0
                        fixed shift_e_y = (dev->sgr.adjusted[1].y - dev->sgr.orig[1].y);
1324
1325
0
                        if (plp->o.p.x < dev->sgr.orig[0].x ||
1326
0
                            (plp->o.p.x == dev->sgr.orig[0].x && plp->o.p.y < dev->sgr.orig[0].y)) {
1327
                            /* Left contact, adjust to keep the contact. */
1328
0
                            if_debug4m('O', dev->memory, "[O]don't adjust {{%f,%f},{%f,%f}}\n",
1329
0
                                       fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
1330
0
                                       fixed2float(plp->e.p.x), fixed2float(plp->e.p.y));
1331
0
                            plp->width.x += (shift_o_x - delta_w_x) / 2;
1332
0
                            plp->width.y += (shift_o_y - delta_w_y) / 2;
1333
0
                            plp->o.p.x += (shift_o_x - delta_w_x) / 2;
1334
0
                            plp->o.p.y += (shift_o_y - delta_w_y) / 2;
1335
0
                            plp->e.p.x += (shift_e_x - delta_w_x) / 2;
1336
0
                            plp->e.p.y += (shift_e_y - delta_w_y) / 2;
1337
0
                            adjust = false;
1338
0
                        } else {
1339
                            /* Right contact, adjust to keep the contact. */
1340
0
                            if_debug4m('O', dev->memory, "[O]don't adjust {{%f,%f},{%f,%f}}\n",
1341
0
                                       fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
1342
0
                                       fixed2float(plp->e.p.x), fixed2float(plp->e.p.y));
1343
0
                            plp->width.x -= (shift_o_x + delta_w_x) / 2;
1344
0
                            plp->width.y -= (shift_o_y + delta_w_y) / 2;
1345
0
                            plp->o.p.x += (shift_o_x + delta_w_x) / 2;
1346
0
                            plp->o.p.y += (shift_o_y + delta_w_y) / 2;
1347
0
                            plp->e.p.x += (shift_e_x + delta_w_x) / 2;
1348
0
                            plp->e.p.y += (shift_e_y + delta_w_y) / 2;
1349
0
                            adjust = false;
1350
0
                        }
1351
0
                    }
1352
0
                }
1353
0
            }
1354
0
        }
1355
0
    }
1356
0
    if ((start_cap == gs_cap_butt) || (end_cap == gs_cap_butt)) {
1357
0
        dev->sgr.stroke_stored = true;
1358
0
        dev->sgr.orig[0] = plp->o.p;
1359
0
        dev->sgr.orig[1] = plp->e.p;
1360
0
        dev->sgr.orig[2] = plp->width;
1361
0
        dev->sgr.orig[3] = plp->vector;
1362
0
    } else
1363
0
        dev->sgr.stroke_stored = false;
1364
0
    if (adjust) {
1365
0
        horiz = (any_abs(plp->width.x) <= any_abs(plp->width.y));
1366
0
        adjust_stroke_transversal(plp, pgs, thin, horiz);
1367
0
        if (adjust_longitude)
1368
0
            adjust_stroke_longitude(plp, pgs, thin, horiz, start_cap, end_cap);
1369
0
    }
1370
0
    if ((start_cap == gs_cap_butt) || (end_cap == gs_cap_butt)) {
1371
0
        dev->sgr.adjusted[0] = plp->o.p;
1372
0
        dev->sgr.adjusted[1] = plp->e.p;
1373
0
        dev->sgr.adjusted[2] = plp->width;
1374
0
        dev->sgr.adjusted[3] = plp->vector;
1375
0
    }
1376
0
}
1377
1378
/* Compute the intersection of two lines.  This is a messy algorithm */
1379
/* that somehow ought to be useful in more places than just here.... */
1380
/* If the lines are (nearly) parallel, return -1 without setting *pi; */
1381
/* otherwise, return 0 if the intersection is beyond *pp1 and *pp2 in */
1382
/* the direction determined by *pd1 and *pd2, and 1 otherwise. */
1383
static int
1384
line_intersect(
1385
                  p_ptr pp1,    /* point on 1st line */
1386
                  p_ptr pd1,    /* slope of 1st line (dx,dy) */
1387
                  p_ptr pp2,    /* point on 2nd line */
1388
                  p_ptr pd2,    /* slope of 2nd line */
1389
                  p_ptr pi)
1390
0
{                               /* return intersection here */
1391
    /* We don't have to do any scaling, the factors all work out right. */
1392
0
    double u1 = pd1->x, v1 = pd1->y;
1393
0
    double u2 = pd2->x, v2 = pd2->y;
1394
0
    double denom = u1 * v2 - u2 * v1;
1395
0
    double xdiff = pp2->x - pp1->x;
1396
0
    double ydiff = pp2->y - pp1->y;
1397
0
    double f1;
1398
0
    double max_result = any_abs(denom) * (double)max_fixed;
1399
1400
#if defined(DEBUG) && !defined(GS_THREADSAFE)
1401
    if (gs_debug_c('O')) {
1402
        dlprintf4("[o]Intersect %f,%f(%f/%f)",
1403
                  fixed2float(pp1->x), fixed2float(pp1->y),
1404
                  fixed2float(pd1->x), fixed2float(pd1->y));
1405
        dlprintf4(" & %f,%f(%f/%f),\n",
1406
                  fixed2float(pp2->x), fixed2float(pp2->y),
1407
                  fixed2float(pd2->x), fixed2float(pd2->y));
1408
        dlprintf3("\txdiff=%f ydiff=%f denom=%f ->\n",
1409
                  xdiff, ydiff, denom);
1410
    }
1411
#endif
1412
    /* Check for degenerate result. */
1413
0
    if (any_abs(xdiff) >= max_result || any_abs(ydiff) >= max_result) {
1414
        /* The lines are nearly parallel, */
1415
        /* or one of them has zero length.  Punt. */
1416
0
        if_debug0('O', "\tdegenerate!\n");
1417
0
        return -1;
1418
0
    }
1419
0
    f1 = (v2 * xdiff - u2 * ydiff) / denom;
1420
0
    pi->x = pp1->x + (fixed) (f1 * u1);
1421
0
    pi->y = pp1->y + (fixed) (f1 * v1);
1422
0
    if_debug2('O', "\t%f,%f\n",
1423
0
              fixed2float(pi->x), fixed2float(pi->y));
1424
0
    return (f1 >= 0 && (v1 * xdiff >= u1 * ydiff ? denom >= 0 : denom < 0) ? 0 : 1);
1425
0
}
1426
1427
/* Set up the width and delta parameters for a thin line. */
1428
/* We only approximate the width and height. */
1429
static void
1430
set_thin_widths(register pl_ptr plp)
1431
0
{
1432
0
    fixed dx = plp->e.p.x - plp->o.p.x, dy = plp->e.p.y - plp->o.p.y;
1433
1434
0
#define TRSIGN(v, c) ((v) >= 0 ? (c) : -(c))
1435
0
    if (any_abs(dx) > any_abs(dy)) {
1436
0
        plp->width.x = plp->e.cdelta.y = 0;
1437
0
        plp->width.y = plp->e.cdelta.x = TRSIGN(dx, fixed_half);
1438
0
    } else {
1439
0
        plp->width.y = plp->e.cdelta.x = 0;
1440
0
        plp->width.x = -(plp->e.cdelta.y = TRSIGN(dy, fixed_half));
1441
0
    }
1442
0
#undef TRSIGN
1443
0
}
1444
1445
/* Draw a line on the device. */
1446
/* Treat no join the same as a bevel join. */
1447
/* rpath should always be NULL, hence ensure_closed can be ignored */
1448
static int
1449
stroke_fill(gx_path * ppath, gx_path * rpath, bool ensure_closed, int first,
1450
            register pl_ptr plp, pl_ptr nplp, const gx_device_color * pdevc,
1451
            gx_device * dev, const gs_gstate * pgs,
1452
            const gx_stroke_params * params, const gs_fixed_rect * pbbox,
1453
            int uniform, gs_line_join join, bool reflected,
1454
            note_flags flags)
1455
0
{
1456
0
    const fixed lix = plp->o.p.x;
1457
0
    const fixed liy = plp->o.p.y;
1458
0
    const fixed litox = plp->e.p.x;
1459
0
    const fixed litoy = plp->e.p.y;
1460
1461
    /* assert(lop_is_idempotent(pgs->log_op)); */
1462
0
    if (plp->thin) {
1463
        /* Minimum-width line, don't have to be careful with caps/joins. */
1464
0
        return (*dev_proc(dev, draw_thin_line))(dev, lix, liy, litox, litoy,
1465
0
                                                pdevc, pgs->log_op,
1466
0
                                                pgs->fill_adjust.x,
1467
0
                                                pgs->fill_adjust.y);
1468
0
    }
1469
    /* Check for being able to fill directly. */
1470
0
    {
1471
0
        const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
1472
0
        gs_line_cap start_cap = (flags & nf_dash_head ?
1473
0
                                 pgs_lp->dash_cap : pgs_lp->start_cap);
1474
0
        gs_line_cap end_cap   = (flags & nf_dash_tail ?
1475
0
                                 pgs_lp->dash_cap : pgs_lp->end_cap);
1476
1477
0
        if (first != 0)
1478
0
            start_cap = gs_cap_butt;
1479
0
        if (nplp != 0)
1480
0
            end_cap = gs_cap_butt;
1481
0
        if (!plp->thin && (nplp == 0 || !nplp->thin)
1482
0
            && (start_cap == gs_cap_butt || start_cap == gs_cap_square)
1483
0
            && (end_cap   == gs_cap_butt || end_cap   == gs_cap_square)
1484
0
            && (join == gs_join_bevel || join == gs_join_miter ||
1485
0
                join == gs_join_none)
1486
0
            && (pgs->fill_adjust.x | pgs->fill_adjust.y) == 0
1487
0
            ) {
1488
0
            gs_fixed_point points[6];
1489
0
            int npoints, code;
1490
0
            fixed ax, ay, bx, by;
1491
1492
0
            npoints = cap_points(start_cap, &plp->o, points);
1493
0
            if (nplp == 0)
1494
0
                code = cap_points(end_cap, &plp->e, points + npoints);
1495
0
            else
1496
0
                code = line_join_points(pgs_lp, plp, nplp, points + npoints,
1497
0
                                        (uniform ? (gs_matrix *) 0 :
1498
0
                                         &ctm_only(pgs)), join, reflected);
1499
0
            if (code < 0)
1500
0
                goto general;
1501
            /* Make sure the parallelogram fill won't overflow. */
1502
0
#define SUB_OVERFLOWS(r, u, v)\
1503
0
  (((r = u - v) ^ u) < 0 && (u ^ v) < 0)
1504
0
            if (SUB_OVERFLOWS(ax, points[0].x, points[1].x) ||
1505
0
                SUB_OVERFLOWS(ay, points[0].y, points[1].y) ||
1506
0
                SUB_OVERFLOWS(bx, points[2].x, points[1].x) ||
1507
0
                SUB_OVERFLOWS(by, points[2].y, points[1].y)
1508
0
                )
1509
0
                goto general;
1510
0
#undef SUB_OVERFLOWS
1511
0
            if (nplp != 0) {
1512
0
                if (join == gs_join_miter) {
1513
                    /* Make sure we have a bevel and not a miter. */
1514
0
                    if (!(points[2].x == plp->e.co.x &&
1515
0
                          points[2].y == plp->e.co.y &&
1516
0
                          points[5].x == plp->e.ce.x &&
1517
0
                          points[5].y == plp->e.ce.y)
1518
0
                        )
1519
0
                        goto fill;
1520
0
                } {
1521
0
                    const gs_fixed_point *bevel = points + 2;
1522
1523
                    /* Identify which 3 points define the bevel triangle. */
1524
0
                    if (points[3].x == nplp->o.p.x &&
1525
0
                        points[3].y == nplp->o.p.y
1526
0
                        )
1527
0
                        ++bevel;
1528
                    /* Fill the bevel. */
1529
0
                    code = (*dev_proc(dev, fill_triangle)) (dev,
1530
0
                                                         bevel->x, bevel->y,
1531
0
                               bevel[1].x - bevel->x, bevel[1].y - bevel->y,
1532
0
                               bevel[2].x - bevel->x, bevel[2].y - bevel->y,
1533
0
                                                        pdevc, pgs->log_op);
1534
0
                    if (code < 0)
1535
0
                        return code;
1536
0
                }
1537
0
            }
1538
            /* Fill the body of the stroke. */
1539
0
            return (*dev_proc(dev, fill_parallelogram)) (dev,
1540
0
                                                   points[1].x, points[1].y,
1541
0
                                                         ax, ay, bx, by,
1542
0
                                                         pdevc, pgs->log_op);
1543
0
          fill:
1544
0
            code = add_points(ppath, points, npoints + code, true);
1545
0
            if (code < 0)
1546
0
                return code;
1547
0
            return gx_path_close_subpath(ppath);
1548
0
        }
1549
0
    }
1550
    /* General case: construct a path for the fill algorithm. */
1551
0
 general:
1552
0
    return stroke_add(ppath, rpath, ensure_closed, first, plp, nplp, pdevc,
1553
0
                      dev, pgs, params, pbbox, uniform, join, reflected,
1554
0
                      flags);
1555
0
}
1556
1557
/* Add a segment to the path.  This handles all the complex cases. */
1558
static int
1559
stroke_add(gx_path * ppath, gx_path * rpath, bool ensure_closed, int first,
1560
           pl_ptr plp, pl_ptr nplp, const gx_device_color * pdevc,
1561
           gx_device * dev, const gs_gstate * pgs,
1562
           const gx_stroke_params * params,
1563
           const gs_fixed_rect * ignore_pbbox, int uniform,
1564
           gs_line_join join, bool reflected, note_flags flags)
1565
0
{
1566
0
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
1567
0
    gs_fixed_point points[8];
1568
0
    int npoints;
1569
0
    int code;
1570
0
    bool moveto_first = true;
1571
0
    gs_line_cap start_cap = (flags & nf_dash_head ?
1572
0
                             pgs_lp->dash_cap : pgs_lp->start_cap);
1573
0
    gs_line_cap end_cap   = (flags & nf_dash_tail ?
1574
0
                             pgs_lp->dash_cap : pgs_lp->end_cap);
1575
1576
0
    if (plp->thin) {
1577
        /* We didn't set up the endpoint parameters before, */
1578
        /* because the line was thin.  Do it now. */
1579
0
        set_thin_widths(plp);
1580
0
        adjust_stroke(dev, plp, pgs, true, first == 0 && nplp == 0, flags);
1581
0
        compute_caps(plp);
1582
0
    }
1583
    /* Create an initial cap if desired. */
1584
0
    if (first == 0 && start_cap == gs_cap_round) {
1585
0
        if ((code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
1586
0
            (code = add_pie_cap(ppath, &plp->o)) < 0)
1587
0
            return code;
1588
0
        npoints = 0;
1589
0
        moveto_first = false;
1590
0
    } else {
1591
0
        if ((npoints = cap_points((first == 0 ? start_cap : gs_cap_butt),
1592
0
                                  &plp->o, points)) < 0)
1593
0
            return npoints;
1594
0
    }
1595
0
    if (nplp == 0) {
1596
        /* Add a final cap. */
1597
0
        if (end_cap == gs_cap_round) {
1598
0
            ASSIGN_POINT(&points[npoints], plp->e.co);
1599
0
            ++npoints;
1600
0
            if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
1601
0
                return code;
1602
0
            code = add_pie_cap(ppath, &plp->e);
1603
0
            goto done;
1604
0
        }
1605
0
        code = cap_points(end_cap, &plp->e, points + npoints);
1606
0
    } else if (nplp->thin) /* no join */
1607
0
        code = cap_points(gs_cap_butt, &plp->e, points + npoints);
1608
0
    else if (join == gs_join_round) {
1609
0
        ASSIGN_POINT(&points[npoints], plp->e.co);
1610
0
        ++npoints;
1611
0
        if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
1612
0
            return code;
1613
0
        code = add_pie_join(ppath, plp, nplp, reflected, true);
1614
0
        goto done;
1615
0
    } else if (flags & nf_all_from_arc) {
1616
        /* If all the segments in 'prev' and 'current' are from a curve
1617
         * then the join should actually be a round one, because it would
1618
         * have been round if we had flattened it enough. */
1619
0
        ASSIGN_POINT(&points[npoints], plp->e.co);
1620
0
        ++npoints;
1621
0
        if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
1622
0
            return code;
1623
0
        code = add_pie_join(ppath, plp, nplp, reflected, false);
1624
0
        goto done;
1625
0
    } else                      /* non-round join */
1626
0
       code = line_join_points(pgs_lp, plp, nplp, points + npoints,
1627
0
                                (uniform ? (gs_matrix *) 0 : &ctm_only(pgs)),
1628
0
                                join, reflected);
1629
0
    if (code < 0)
1630
0
        return code;
1631
0
    code = add_points(ppath, points, npoints + code, moveto_first);
1632
0
  done:
1633
0
    if (code < 0)
1634
0
        return code;
1635
0
    if ((flags & nf_some_from_arc) && (!plp->thin) &&
1636
0
        (nplp != NULL) && (!nplp->thin))
1637
0
        code = join_under_pie(ppath, plp, nplp, reflected);
1638
0
    return gx_path_close_subpath(ppath);
1639
0
}
1640
1641
/* When painting the 'underjoin' (the 'inside' of a join), we
1642
 * need to take special care if the curve is particularly wide as
1643
 * the leading edge of the underside of the first stroked segment
1644
 * may be beyond the leading edge of the underside of the second
1645
 * stroked segment. Similarly, the trailing edge of the second
1646
 * stroked segment may be behing the trailing edge of the first
1647
 * stroked segment. We detect those cases here.
1648
 *
1649
 * We detect the first case by projecting plp.width onto nplp.vector.
1650
 * If the projected vector is longer then nplp.vector, we have a
1651
 * problem.
1652
 *
1653
 * len_vector_squared = nplp.vector.x * nplp.vector.x + nplp.vector.y * nplp.nvector.y
1654
 * len_vector = sqr(len_vector_squared)
1655
 * len_projection_unnormalised = plp.width.x * nplp.vector.x + plp.width.y * nplp.vector.y
1656
 * len_projection = len_projection_unnormalised / len_vector
1657
 *
1658
 * len_projection > len_vector === len_projection_unnormalised > len_vector * len_vector
1659
 * === len_projection_unnormalised > len_vector_squared
1660
 */
1661
1662
#ifdef SLOWER_BUT_MORE_ACCURATE_STROKING
1663
static bool
1664
wide_underjoin(pl_ptr plp, pl_ptr nplp)
1665
{
1666
    double h_squared = (double)nplp->vector.x * nplp->vector.x + (double)nplp->vector.y * nplp->vector.y;
1667
    double dot = (double)plp->width.x * nplp->vector.x + (double)plp->width.y * nplp->vector.y;
1668
1669
    if (dot < 0)
1670
        dot = -dot;
1671
    if (dot > h_squared)
1672
        return 1;
1673
1674
    h_squared = (double)plp->vector.x * plp->vector.x + (double)plp->vector.y * plp->vector.y;
1675
    dot = (double)nplp->width.x * plp->vector.x + (double)nplp->width.y * plp->vector.y;
1676
    if (dot < 0)
1677
        dot = -dot;
1678
    if (dot > h_squared)
1679
        return 1;
1680
1681
    return 0;
1682
}
1683
#endif
1684
1685
static int
1686
check_miter(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
1687
            const gs_matrix * pmat, p_ptr outp, p_ptr np, p_ptr mpt,
1688
            bool ccw0)
1689
0
{
1690
    /*
1691
     * Check whether a miter join is appropriate.
1692
     * Let a, b be the angles of the two lines.
1693
     * We check tan(a-b) against the miter_check
1694
     * by using the following formula:
1695
     *      If tan(a)=u1/v1 and tan(b)=u2/v2, then
1696
     *      tan(a-b) = (u1*v2 - u2*v1) / (u1*u2 + v1*v2).
1697
     *
1698
     * We can do all the computations unscaled,
1699
     * because we're only concerned with ratios.
1700
     * However, if we have a non-uniform coordinate
1701
     * system (indicated by pmat != 0), we must do the
1702
     * computations in user space.
1703
     */
1704
0
    float check;
1705
0
    double u1, v1, u2, v2;
1706
0
    double num, denom;
1707
0
    int code;
1708
1709
    /*
1710
     * Don't bother with the miter check if the two
1711
     * points to be joined are very close together,
1712
     * namely, in the same square half-pixel.
1713
     */
1714
0
    if (fixed2long(outp->x << 1) == fixed2long(np->x << 1) &&
1715
0
        fixed2long(outp->y << 1) == fixed2long(np->y << 1))
1716
0
        return 1;
1717
1718
0
    check = pgs_lp->miter_check;
1719
0
    u1 = plp->vector.y, v1 = plp->vector.x;
1720
0
    u2 = -nplp->vector.y, v2 = -nplp->vector.x;
1721
1722
0
    if (pmat) {
1723
0
        gs_point pt;
1724
1725
0
        code = gs_distance_transform_inverse(v1, u1, pmat, &pt);
1726
0
        if (code < 0)
1727
0
        return code;
1728
0
        v1 = pt.x, u1 = pt.y;
1729
0
        code = gs_distance_transform_inverse(v2, u2, pmat, &pt);
1730
0
        if (code < 0)
1731
0
            return code;
1732
0
        v2 = pt.x, u2 = pt.y;
1733
        /*
1734
         * We need to recompute ccw according to the
1735
         * relative positions of the lines in user space.
1736
         * We repeat the computation described above,
1737
         * using the cdelta values instead of the widths.
1738
         * Because the definition of ccw above is inverted
1739
         * from the intuitive one (for historical reasons),
1740
         * we actually have to do the test backwards.
1741
         */
1742
0
        ccw0 = v1 * u2 < v2 * u1;
1743
#if defined(DEBUG) && !defined(GS_THREADSAFE)
1744
        {
1745
            double a1 = atan2(u1, v1), a2 = atan2(u2, v2), dif = a1 - a2;
1746
1747
            if (dif < 0)
1748
                dif += 2 * M_PI;
1749
            else if (dif >= 2 * M_PI)
1750
                dif -= 2 * M_PI;
1751
            if (dif != 0 && (dif < M_PI) != ccw0)
1752
                lprintf8("ccw wrong: tan(a1=%g)=%g/%g, tan(a2=%g)=%g,%g, dif=%g, ccw0=%d\n",
1753
                         a1, u1, v1, a2, u2, v2, dif, ccw0);
1754
        }
1755
#endif
1756
0
    }
1757
0
    num = u1 * v2 - u2 * v1;
1758
0
    denom = u1 * u2 + v1 * v2;
1759
    /*
1760
     * We will want either tan(a-b) or tan(b-a)
1761
     * depending on the orientations of the lines.
1762
     * Fortunately we know the relative orientations already.
1763
     */
1764
0
    if (!ccw0)          /* have plp - nplp, want vice versa */
1765
0
        num = -num;
1766
#if defined(DEBUG) && !defined(GS_THREADSAFE)
1767
    if (gs_debug_c('O')) {
1768
        dlprintf4("[o]Miter check: u1/v1=%f/%f, u2/v2=%f/%f,\n",
1769
                  u1, v1, u2, v2);
1770
        dlprintf3("        num=%f, denom=%f, check=%f\n",
1771
                  num, denom, check);
1772
    }
1773
#endif
1774
    /*
1775
     * If we define T = num / denom, then we want to use
1776
     * a miter join iff arctan(T) >= arctan(check).
1777
     * We know that both of these angles are in the 1st
1778
     * or 2nd quadrant, and since arctan is monotonic
1779
     * within each quadrant, we can do the comparisons
1780
     * on T and check directly, taking signs into account
1781
     * as follows:
1782
     *              sign(T) sign(check)     atan(T) >= atan(check)
1783
     *              ------- -----------     ----------------------
1784
     *              +       +               T >= check
1785
     *              -       +               true
1786
     *              +       -               false
1787
     *              -       -               T >= check
1788
     */
1789
0
    if (num == 0 && denom == 0)
1790
0
        return_error(gs_error_unregistered); /* Must not happen. */
1791
0
    if (denom < 0)
1792
0
        num = -num, denom = -denom;
1793
    /* Now denom >= 0, so sign(num) = sign(T). */
1794
0
    if (check > 0 ?
1795
0
        (num < 0 || num >= denom * check) :
1796
0
        (num < 0 && num >= denom * check)
1797
0
        ) {
1798
        /* OK to use a miter join. */
1799
0
        gs_fixed_point dirn1, dirn2;
1800
1801
0
        dirn1.x = plp->e.cdelta.x;
1802
0
        dirn1.y = plp->e.cdelta.y;
1803
        /* If this direction is small enough that we might have
1804
         * underflowed and the vector record is suitable for us
1805
         * to use to calculate a better one, then do so. */
1806
0
        if ((abs(dirn1.x) + abs(dirn1.y) < 16) &&
1807
0
            ((plp->vector.x != 0) || (plp->vector.y != 0)))
1808
0
        {
1809
0
            float scale = 65536.0;
1810
0
            if (abs(plp->vector.x) > abs(plp->vector.y))
1811
0
                scale /= abs(plp->vector.x);
1812
0
            else
1813
0
                scale /= abs(plp->vector.y);
1814
0
            dirn1.x = (fixed)(plp->vector.x*scale);
1815
0
            dirn1.y = (fixed)(plp->vector.y*scale);
1816
0
        }
1817
0
        dirn2.x = nplp->o.cdelta.x;
1818
0
        dirn2.y = nplp->o.cdelta.y;
1819
        /* If this direction is small enough that we might have
1820
         * underflowed and the vector record is suitable for us
1821
         * to use to calculate a better one, then do so. */
1822
0
        if ((abs(dirn2.x) + abs(dirn2.y) < 16) &&
1823
0
            ((nplp->vector.x != 0) || (nplp->vector.y != 0)))
1824
0
        {
1825
0
            float scale = 65536.0;
1826
0
            if (abs(nplp->vector.x) > abs(nplp->vector.y))
1827
0
                scale /= abs(nplp->vector.x);
1828
0
            else
1829
0
                scale /= abs(nplp->vector.y);
1830
0
            dirn2.x = (fixed)(-nplp->vector.x*scale);
1831
0
            dirn2.y = (fixed)(-nplp->vector.y*scale);
1832
0
        }
1833
0
        if_debug0('O', "        ... passes.\n");
1834
        /* Compute the intersection of the extended edge lines. */
1835
0
        if (line_intersect(outp, &dirn1, np, &dirn2, mpt) == 0)
1836
0
            return 0;
1837
0
    }
1838
0
    return 1;
1839
0
}
1840
1841
/* Add a segment to the path.
1842
 * This works by crafting 2 paths, one for each edge, that will later be
1843
 * merged together. */
1844
static int
1845
stroke_add_fast(gx_path * ppath, gx_path * rpath, bool ensure_closed, int first,
1846
                pl_ptr plp, pl_ptr nplp, const gx_device_color * pdevc,
1847
                gx_device * dev, const gs_gstate * pgs,
1848
                const gx_stroke_params * params,
1849
                const gs_fixed_rect * ignore_pbbox, int uniform,
1850
                gs_line_join join, bool reflected, note_flags flags)
1851
0
{
1852
0
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
1853
0
    gs_fixed_point points[8];
1854
0
    gs_fixed_point rpoints[8];
1855
0
    int npoints  = 0;
1856
0
    int nrpoints = 0;
1857
0
    int code;
1858
0
    bool moveto_first  = false;
1859
0
    bool rmoveto_first = false;
1860
0
    gs_line_cap start_cap, end_cap;
1861
0
    const gs_matrix *pmat = (uniform ? (const gs_matrix *)NULL : &ctm_only(pgs));
1862
0
    enum {
1863
0
        joinsense_cap = 0,
1864
0
        joinsense_cw = 1,
1865
0
        joinsense_ccw = 2,
1866
0
        joinsense_over = 4,
1867
0
        joinsense_under = 8,
1868
0
    } joinsense = joinsense_cap;
1869
1870
0
    if (plp->thin) {
1871
        /* We didn't set up the endpoint parameters before, */
1872
        /* because the line was thin.  Do it now. */
1873
0
        set_thin_widths(plp);
1874
0
        adjust_stroke(dev, plp, pgs, true, first == 0 && nplp == 0, flags);
1875
0
        compute_caps(plp);
1876
0
    }
1877
0
    start_cap = (flags & nf_dash_head ?
1878
0
                 pgs_lp->dash_cap : pgs_lp->start_cap);
1879
0
    end_cap   = (flags & nf_dash_tail ?
1880
0
                 pgs_lp->dash_cap : pgs_lp->end_cap);
1881
    /* If we're starting a new rpath here, we need to fake a new cap.
1882
     * Don't interfere if we would have been doing a cap anyway. */
1883
0
    if (gx_path_is_void(rpath) && (first != 0)) {
1884
0
        first = 0;
1885
0
        start_cap = gs_cap_butt;
1886
0
        end_cap   = gs_cap_butt;
1887
0
        moveto_first  = true;
1888
0
        rmoveto_first = true;
1889
0
    }
1890
0
    if (first == 0) {
1891
        /* Create an initial cap. */
1892
0
        if (start_cap == gs_cap_round) {
1893
0
            if ((code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
1894
0
                (code = add_pie_cap(ppath, &plp->o)) < 0)
1895
0
                return code;
1896
0
            moveto_first = false;
1897
0
        } else {
1898
0
            if ((npoints = cap_points(start_cap, &plp->o, points)) < 0)
1899
0
                return npoints;
1900
0
            moveto_first = true;
1901
0
        }
1902
0
        rmoveto_first = true;
1903
0
        ASSIGN_POINT(&rpoints[0], plp->o.co);
1904
0
        nrpoints = 1;
1905
0
    }
1906
    /* Add points to move us along the edges of this stroke */
1907
0
    ASSIGN_POINT(&points [npoints ], plp->e.co);
1908
0
    ASSIGN_POINT(&rpoints[nrpoints], plp->e.ce);
1909
0
    npoints++;
1910
0
    nrpoints++;
1911
1912
0
    if (nplp != NULL && !nplp->thin) {
1913
        /* We need to do a join. What sense is it it? */
1914
0
        double l, r;
1915
1916
0
        l = (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */;
1917
0
        r = (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
1918
1919
0
        if ((l == r) && (join == gs_join_round))
1920
0
             joinsense = joinsense_cap;
1921
0
        else if ((l > r) ^ reflected)
1922
0
             joinsense = joinsense_ccw | joinsense_over | joinsense_under;
1923
0
        else
1924
0
             joinsense = joinsense_cw | joinsense_over | joinsense_under;
1925
1926
0
        if (joinsense != joinsense_cap && join == gs_join_miter) {
1927
            /* We need to do a miter line join. Miters are 'special'
1928
             * in that we'd like to do them by adjusting the existing
1929
             * points, rather than adding new ones. */
1930
0
            gs_fixed_point mpt;
1931
0
            if (joinsense & joinsense_ccw) {
1932
                /* Underjoin (in reverse path):
1933
                 * A = plp->o.co, B = plp->e.ce, C = nplp->o.co, D = nplp->e.ce */
1934
0
                double xa =  plp->o.co.x, ya =  plp->o.co.y;
1935
0
                double xb =  plp->e.ce.x, yb =  plp->e.ce.y;
1936
0
                double xc = nplp->o.co.x, yc = nplp->o.co.y;
1937
0
                double xd = nplp->e.ce.x, yd = nplp->e.ce.y;
1938
0
                double xab = xa-xb, xac = xa-xc, xcd = xc-xd;
1939
0
                double yab = ya-yb, yac = ya-yc, ycd = yc-yd;
1940
0
                double t_num = xac * ycd - yac * xcd;
1941
0
                double t_den = xab * ycd - yab * xcd;
1942
0
                code = check_miter(pgs_lp, plp, nplp, pmat, &plp->e.co,
1943
0
                                   &nplp->o.ce, &mpt, true);
1944
0
                if (code < 0)
1945
0
                    return code;
1946
0
                if (code == 0) {
1947
0
                    points[npoints-1].x = mpt.x;
1948
0
                    points[npoints-1].y = mpt.y;
1949
0
                    if (ensure_closed) {
1950
0
                        points[npoints].x = nplp->o.ce.x;
1951
0
                        points[npoints].y = nplp->o.ce.y;
1952
0
                        npoints++;
1953
0
                    }
1954
0
                    joinsense &= ~joinsense_over;
1955
0
                } else
1956
0
                    join = gs_join_bevel;
1957
0
                if (t_den != 0 &&
1958
0
                    ((t_num >= 0 && t_num <= t_den) ||
1959
0
                     (t_num <= 0 && t_num >= t_den))) {
1960
0
                    double x = xa - xab * t_num / t_den;
1961
0
                    double y = ya - yab * t_num / t_den;
1962
0
                    rpoints[nrpoints-1].x = (fixed)x;
1963
0
                    rpoints[nrpoints-1].y = (fixed)y;
1964
0
                    joinsense &= ~joinsense_under;
1965
0
                }
1966
0
            } else {
1967
                /* Underjoin (in fwd path):
1968
                 * A = plp->o.ce, B = plp->e.co, C = nplp->o.ce, D = nplp->e.co */
1969
0
                double xa =  plp->o.ce.x, ya =  plp->o.ce.y;
1970
0
                double xb =  plp->e.co.x, yb =  plp->e.co.y;
1971
0
                double xc = nplp->o.ce.x, yc = nplp->o.ce.y;
1972
0
                double xd = nplp->e.co.x, yd = nplp->e.co.y;
1973
0
                double xab = xa-xb, xac = xa-xc, xcd = xc-xd;
1974
0
                double yab = ya-yb, yac = ya-yc, ycd = yc-yd;
1975
0
                double t_num = xac * ycd - yac * xcd;
1976
0
                double t_den = xab * ycd - yab * xcd;
1977
0
                code = check_miter(pgs_lp, plp, nplp, pmat, &plp->e.ce,
1978
0
                                   &nplp->o.co, &mpt, false);
1979
0
                if (code < 0)
1980
0
                    return code;
1981
0
                if (code == 0) {
1982
0
                    rpoints[nrpoints-1].x = mpt.x;
1983
0
                    rpoints[nrpoints-1].y = mpt.y;
1984
0
                    if (ensure_closed) {
1985
0
                        rpoints[nrpoints].x = nplp->o.co.x;
1986
0
                        rpoints[nrpoints].y = nplp->o.co.y;
1987
0
                        nrpoints++;
1988
0
                    }
1989
0
                    joinsense &= ~joinsense_over;
1990
0
                } else
1991
0
                    join = gs_join_bevel;
1992
0
                if (t_den != 0 &&
1993
0
                    ((t_num >= 0 && t_num <= t_den) ||
1994
0
                     (t_num <= 0 && t_num >= t_den)))   {
1995
0
                    double x = xa - xab * t_num / t_den;
1996
0
                    double y = ya - yab * t_num / t_den;
1997
0
                    points[npoints-1].x = (fixed)x;
1998
0
                    points[npoints-1].y = (fixed)y;
1999
0
                    joinsense &= ~joinsense_under;
2000
0
                }
2001
0
            }
2002
0
        }
2003
0
    }
2004
2005
0
    if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
2006
0
        return code;
2007
0
    if ((code = add_points(rpath, rpoints, nrpoints, rmoveto_first)) < 0)
2008
0
        return code;
2009
0
    npoints  = 0;
2010
0
    nrpoints = 0;
2011
2012
0
    if (nplp == 0) { /* Add a final cap. */
2013
0
        if (end_cap == gs_cap_round) {
2014
0
            code = add_pie_cap(ppath, &plp->e);
2015
0
        } else {
2016
0
            code = cap_points(end_cap, &plp->e, points);
2017
0
            npoints = code;
2018
0
        }
2019
0
    } else if (nplp->thin) { /* no join */
2020
0
        code = cap_points(gs_cap_butt, &plp->e, points);
2021
0
        npoints = code;
2022
0
    } else if (joinsense == joinsense_cap) {
2023
        /* Do a cap */
2024
0
        code = add_pie_cap(ppath, &plp->e);
2025
0
        if (code >= 0) {
2026
            /* If the next line is in the opposite direction as the current one
2027
             * we want to leave the point on the same side as it was
2028
             * originally. This is required for paths that come to a stop
2029
             * and then reverse themselves, but may produce more complexity
2030
             * than we'd really like at the ends of smooth beziers. */
2031
0
            if ((double)(plp->width.x) * nplp->width.x + (double)plp->width.y * nplp->width.y >= 0)
2032
0
                code = gx_path_add_line(ppath, plp->e.co.x, plp->e.co.y);
2033
0
        }
2034
0
    } else if (joinsense & joinsense_ccw) {
2035
        /* CCW rotation. Join in the forward path. "Underjoin" in the
2036
         * reverse path. */
2037
0
        if (joinsense & joinsense_over) {
2038
            /* RJW: Ideally we should include the "|| flags" clause in
2039
             * the following condition. This forces all joins between
2040
             * line segments generated from arcs to be round. This would
2041
             * solve some flatness issues, but makes some pathological
2042
             * cases incredibly slow. */
2043
0
            if (join == gs_join_round /* || (flags & nf_all_from_arc) */) {
2044
0
                code = add_pie_join_fast_ccw(ppath, plp, nplp, reflected);
2045
0
            } else { /* non-round join */
2046
0
                code = line_join_points_fast_ccw(pgs_lp, plp, nplp,
2047
0
                                                 points, pmat, join);
2048
0
                npoints = code;
2049
0
            }
2050
0
            if (code < 0)
2051
0
                return code;
2052
0
        }
2053
0
        if (joinsense & joinsense_under) {
2054
            /* The underjoin */
2055
0
#ifndef SLOWER_BUT_MORE_ACCURATE_STROKING
2056
0
            if ((flags & (nf_some_from_arc | nf_prev_some_from_arc)) == 0) {
2057
                /* RJW: This is an approximation. We ought to draw a line
2058
                 * back to nplp->o.p, and then independently fill any exposed
2059
                 * region under the curve with a round join. Sadly, that's
2060
                 * a) really hard to do, and b) makes certain pathological
2061
                 * filling cases MUCH slower due to the greater number of
2062
                 * "cross-segment" line segments this produces. Instead,
2063
                 * we just skip the line to the middle, and join across the
2064
                 * bottom instead. This is akin to what other graphics libs
2065
                 * do (such as fitz, libart, etc). It's not perfect but in
2066
                 * most cases it's close, and results in faster to fill
2067
                 * paths.
2068
                 */
2069
                /* RJW: This goes wrong for some paths, as the 'underjoin' wind
2070
                 * will be the wrong way. See bug 694971 */
2071
0
                code = gx_path_add_line(rpath, nplp->o.p.x, nplp->o.p.y);
2072
0
                if (code < 0)
2073
0
                    return code;
2074
0
            }
2075
#else
2076
            if (wide_underjoin(plp, nplp))
2077
            {
2078
                code = gx_path_add_line(rpath, nplp->o.p.x, nplp->o.p.y);
2079
                if (code < 0)
2080
                    return code;
2081
                if ((flags & (nf_some_from_arc | nf_prev_some_from_arc)) != 0) {
2082
                    code = gx_path_add_line(rpath, nplp->o.co.x, nplp->o.co.y);
2083
                    if (code < 0)
2084
                        return code;
2085
                    code = gx_path_add_line(rpath, plp->e.ce.x, plp->e.ce.y);
2086
                    if (code < 0)
2087
                        return code;
2088
                    code = gx_path_add_line(rpath, nplp->o.p.x, nplp->o.p.y);
2089
                    if (code < 0)
2090
                        return code;
2091
                }
2092
            }
2093
#endif
2094
0
            code = gx_path_add_line(rpath, nplp->o.co.x, nplp->o.co.y);
2095
0
        }
2096
0
    } else if (joinsense & joinsense) {
2097
        /* CW rotation. Join in the reverse path. "Underjoin" in the
2098
         * forward path. */
2099
0
        if (joinsense & joinsense_over) {
2100
            /* RJW: Ideally we should include the "|| flags" clause in
2101
             * the following condition. This forces all joins between
2102
             * line segments generated from arcs to be round. This would
2103
             * solve some flatness issues, but makes some pathological
2104
             * cases incredibly slow. */
2105
0
            if (join == gs_join_round /* || (flags & nf_all_from_arc) */) {
2106
0
                code = add_pie_join_fast_cw(rpath, plp, nplp, reflected);
2107
0
            } else { /* non-round join */
2108
0
                code = line_join_points_fast_cw(pgs_lp, plp, nplp,
2109
0
                                                rpoints, pmat, join);
2110
0
                nrpoints = code;
2111
0
            }
2112
0
            if (code < 0)
2113
0
                return code;
2114
0
        }
2115
0
        if (joinsense & joinsense_under) {
2116
            /* The underjoin */
2117
0
#ifndef SLOWER_BUT_MORE_ACCURATE_STROKING
2118
0
            if ((flags & (nf_some_from_arc | nf_prev_some_from_arc)) == 0 &&
2119
0
                join != gs_join_miter) {
2120
                /* RJW: This is an approximation. We ought to draw a line
2121
                 * back to nplp->o.p, and then independently fill any exposed
2122
                 * region under the curve with a round join. Sadly, that's
2123
                 * a) really hard to do, and b) makes certain pathological
2124
                 * filling cases MUCH slower due to the greater number of
2125
                 * "cross-segment" line segments this produces. Instead,
2126
                 * we just skip the line to the middle, and join across the
2127
                 * bottom instead. This is akin to what other graphics libs
2128
                 * do (such as fitz, libart, etc). It's not perfect but in
2129
                 * most cases it's close, and results in faster to fill
2130
                 * paths.
2131
                 */
2132
                /* RJW: This goes wrong for some paths, as the 'underjoin' wind
2133
                 * will be the wrong way. See bug 694971 */
2134
0
                code = gx_path_add_line(ppath, nplp->o.p.x, nplp->o.p.y);
2135
0
                if (code < 0)
2136
0
                    return code;
2137
0
            }
2138
#else
2139
            if (wide_underjoin(plp, nplp))
2140
            {
2141
                code = gx_path_add_line(ppath, nplp->o.p.x, nplp->o.p.y);
2142
                if (code < 0)
2143
                    return code;
2144
                if ((flags & (nf_some_from_arc | nf_prev_some_from_arc)) != 0) {
2145
                    code = gx_path_add_line(ppath, nplp->o.ce.x, nplp->o.ce.y);
2146
                    if (code < 0)
2147
                        return code;
2148
                    code = gx_path_add_line(ppath, plp->e.co.x, plp->e.co.y);
2149
                    if (code < 0)
2150
                        return code;
2151
                    code = gx_path_add_line(ppath, nplp->o.p.x, nplp->o.p.y);
2152
                    if (code < 0)
2153
                        return code;
2154
                }
2155
            }
2156
#endif
2157
0
            code = gx_path_add_line(ppath, nplp->o.ce.x, nplp->o.ce.y);
2158
0
        }
2159
0
    }
2160
0
    if (code < 0)
2161
0
        return code;
2162
0
    if (npoints > 0) {
2163
0
        code = add_points(ppath, points, npoints, false);
2164
0
        if (code < 0)
2165
0
            return code;
2166
0
    }
2167
0
    if (nrpoints > 0) {
2168
0
        code = add_points(rpath, rpoints, nrpoints, false);
2169
0
        if (code < 0)
2170
0
            return code;
2171
0
    }
2172
0
    if (ensure_closed)
2173
0
        return gx_join_path_and_reverse(ppath, rpath);
2174
0
    return 0;
2175
0
}
2176
2177
/* Add a CPSI-compatible segment to the path.  This handles all the complex
2178
 * cases.
2179
 *
2180
 * This method doesn't support start/end/dash caps, but it's only used from
2181
 * postscript, so it doesn't need to.
2182
 */
2183
static int
2184
stroke_add_compat(gx_path * ppath, gx_path *rpath, bool ensure_closed,
2185
                  int first, pl_ptr plp, pl_ptr nplp,
2186
                  const gx_device_color * pdevc, gx_device * dev,
2187
                  const gs_gstate * pgs,
2188
                  const gx_stroke_params * params,
2189
                  const gs_fixed_rect * ignore_pbbox, int uniform,
2190
                  gs_line_join join, bool reflected, note_flags flags)
2191
0
{
2192
    /* Actually it adds 2 contours : one for the segment itself,
2193
       and another one for line join or for the ending cap.
2194
       Note CPSI creates negative contours. */
2195
0
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
2196
0
    gs_fixed_point points[5];
2197
0
    int npoints;
2198
0
    bool const moveto_first = true; /* Keeping this code closer to "stroke_add". */
2199
0
    int code;
2200
2201
0
    if (plp->thin) {
2202
        /* We didn't set up the endpoint parameters before, */
2203
        /* because the line was thin.  Do it now. */
2204
0
        set_thin_widths(plp);
2205
0
        adjust_stroke(dev, plp, pgs, true, first == 0 && nplp == 0, flags);
2206
0
        compute_caps(plp);
2207
0
    }
2208
    /* The segment itself : */
2209
0
    ASSIGN_POINT(&points[0], plp->o.ce);
2210
0
    ASSIGN_POINT(&points[1], plp->e.co);
2211
0
    ASSIGN_POINT(&points[2], plp->e.ce);
2212
0
    ASSIGN_POINT(&points[3], plp->o.co);
2213
0
    code = add_points(ppath, points, 4, moveto_first);
2214
0
    if (code < 0)
2215
0
        return code;
2216
0
    code = gx_path_close_subpath(ppath);
2217
0
    if (code < 0)
2218
0
        return code;
2219
0
    npoints = 0;
2220
0
    if (nplp == 0) {
2221
        /* Add a final cap. */
2222
0
        if (pgs_lp->start_cap == gs_cap_butt)
2223
0
            return 0;
2224
0
        if (pgs_lp->start_cap == gs_cap_round) {
2225
0
            ASSIGN_POINT(&points[npoints], plp->e.co);
2226
0
            ++npoints;
2227
0
            if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
2228
0
                return code;
2229
0
            return add_round_cap(ppath, &plp->e);
2230
0
        }
2231
0
        ASSIGN_POINT(&points[0], plp->e.ce);
2232
0
        ++npoints;
2233
0
        ASSIGN_POINT(&points[npoints], plp->e.co);
2234
0
        ++npoints;
2235
0
        code = cap_points(pgs_lp->start_cap, &plp->e, points + npoints);
2236
0
        if (code < 0)
2237
0
            return code;
2238
0
        npoints += code;
2239
0
    } else if (join == gs_join_round) {
2240
0
        ASSIGN_POINT(&points[npoints], plp->e.co);
2241
0
        ++npoints;
2242
0
        if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
2243
0
            return code;
2244
0
        return add_round_cap(ppath, &plp->e);
2245
0
    } else if (nplp->thin) {    /* no join */
2246
0
        npoints = 0;
2247
0
    } else {                    /* non-round join */
2248
0
        bool ccw =
2249
0
            (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */ >
2250
0
            (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
2251
2252
0
        if (ccw ^ reflected) {
2253
0
            ASSIGN_POINT(&points[0], plp->e.co);
2254
0
            ++npoints;
2255
0
            code = line_join_points(pgs_lp, plp, nplp, points + npoints,
2256
0
                                    (uniform ? (gs_matrix *) 0 : &ctm_only(pgs)),
2257
0
                                    join, reflected);
2258
0
            if (code < 0)
2259
0
                return code;
2260
0
            code--; /* Drop the last point of the non-compatible mode. */
2261
0
            npoints += code;
2262
0
        } else {
2263
0
            code = line_join_points(pgs_lp, plp, nplp, points,
2264
0
                                    (uniform ? (gs_matrix *) 0 : &ctm_only(pgs)),
2265
0
                                    join, reflected);
2266
0
            if (code < 0)
2267
0
                return code;
2268
0
            ASSIGN_POINT(&points[0], plp->e.ce); /* Replace the starting point of the non-compatible mode. */
2269
0
            npoints = code;
2270
0
        }
2271
0
    }
2272
0
    code = add_points(ppath, points, npoints, moveto_first);
2273
0
    if (code < 0)
2274
0
        return code;
2275
0
    code = gx_path_close_subpath(ppath);
2276
0
    return code;
2277
0
}
2278
2279
/* Add a CPSI-compatible segment to the path.  This handles all the complex
2280
 * cases.
2281
 *
2282
 * This method doesn't support start/end/dash caps, but it's only used from
2283
 * postscript, so it doesn't need to.
2284
 */
2285
static int
2286
stroke_add_initial_cap_compat(gx_path * ppath, pl_ptr plp, bool adlust_longitude,
2287
           const gx_device_color * pdevc, gx_device * dev,
2288
           const gs_gstate * pgs)
2289
0
{
2290
0
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pgs);
2291
0
    gs_fixed_point points[5];
2292
0
    int npoints = 0;
2293
0
    int code;
2294
2295
0
    if (pgs_lp->start_cap == gs_cap_butt)
2296
0
        return 0;
2297
0
    if (plp->thin) {
2298
        /* We didn't set up the endpoint parameters before, */
2299
        /* because the line was thin.  Do it now. */
2300
0
        set_thin_widths(plp);
2301
0
        adjust_stroke(dev, plp, pgs, true, adlust_longitude, 0);
2302
0
        compute_caps(plp);
2303
0
    }
2304
    /* Create an initial cap if desired. */
2305
0
    if (pgs_lp->start_cap == gs_cap_round) {
2306
0
        if ((code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
2307
0
            (code = add_round_cap(ppath, &plp->o)) < 0
2308
0
            )
2309
0
            return code;
2310
0
        return 0;
2311
0
    } else {
2312
0
        ASSIGN_POINT(&points[0], plp->o.co);
2313
0
        ++npoints;
2314
0
        if ((code = cap_points(pgs_lp->start_cap, &plp->o, points + npoints)) < 0)
2315
0
            return npoints;
2316
0
        npoints += code;
2317
0
        ASSIGN_POINT(&points[npoints], plp->o.ce);
2318
0
        ++npoints;
2319
0
        code = add_points(ppath, points, npoints, true);
2320
0
        if (code < 0)
2321
0
            return code;
2322
0
        return gx_path_close_subpath(ppath);
2323
0
    }
2324
0
}
2325
2326
/* Add lines with a possible initial moveto. */
2327
static int
2328
add_points(gx_path * ppath, const gs_fixed_point * points, int npoints,
2329
           bool moveto_first)
2330
0
{
2331
0
    int code;
2332
2333
0
    if (moveto_first) {
2334
0
        code = gx_path_add_point(ppath, points[0].x, points[0].y);
2335
0
        if (code < 0)
2336
0
            return code;
2337
0
        return gx_path_add_lines(ppath, points + 1, npoints - 1);
2338
0
    } else {
2339
0
        return gx_path_add_lines(ppath, points, npoints);
2340
0
    }
2341
0
}
2342
2343
/* ---------------- Join computation ---------------- */
2344
2345
/* Compute the points for a bevel, miter, or triangle join. */
2346
/* Treat no join the same as a bevel join. */
2347
/* If pmat != 0, we must inverse-transform the distances for */
2348
/* the miter check. */
2349
static int
2350
line_join_points(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
2351
                 gs_fixed_point * join_points, const gs_matrix * pmat,
2352
                 gs_line_join join, bool reflected)
2353
0
{
2354
0
#define jp1 join_points[0]
2355
0
#define np1 join_points[1]
2356
0
#define np2 join_points[2]
2357
0
#define jp2 join_points[3]
2358
0
#define jpx join_points[4]
2359
    /*
2360
     * Set np to whichever of nplp->o.co or .ce is outside
2361
     * the current line.  We observe that the point (x2,y2)
2362
     * is counter-clockwise from (x1,y1), relative to the origin,
2363
     * iff
2364
     *  (arctan(y2/x2) - arctan(y1/x1)) mod 2*pi < pi,
2365
     * taking the signs of xi and yi into account to determine
2366
     * the quadrants of the results.  It turns out that
2367
     * even though arctan is monotonic only in the 4th/1st
2368
     * quadrants and the 2nd/3rd quadrants, case analysis on
2369
     * the signs of xi and yi demonstrates that this test
2370
     * is equivalent to the much less expensive test
2371
     *  x1 * y2 > x2 * y1
2372
     * in all cases.
2373
     *
2374
     * In the present instance, x1,y1 are plp->width,
2375
     * x2,y2 are nplp->width, and the origin is
2376
     * their common point (plp->e.p, nplp->o.p).
2377
     * ccw will be true iff nplp.o.co (nplp.o.p + width) is
2378
     * counter-clockwise from plp.e.ce (plp.e.p + width),
2379
     * in which case we want tan(a-b) rather than tan(b-a).
2380
     *
2381
     * We make the test using double arithmetic only because
2382
     * the !@#&^*% C language doesn't give us access to
2383
     * the double-width-result multiplication operation
2384
     * that almost all CPUs provide!
2385
     */
2386
0
    bool ccw =
2387
0
        (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */ >
2388
0
        (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
2389
0
    bool ccw0 = ccw;
2390
0
    p_ptr outp, np;
2391
0
    int   code;
2392
0
    gs_fixed_point mpt;
2393
2394
0
    ccw ^= reflected;
2395
2396
    /* Initialize for a bevel join. */
2397
0
    ASSIGN_POINT(&jp1, plp->e.co);
2398
0
    ASSIGN_POINT(&jp2, plp->e.ce);
2399
2400
    /*
2401
     * Because of stroke adjustment, it is possible that
2402
     * plp->e.p != nplp->o.p.  For that reason, we must use
2403
     * nplp->o.p as np1 or np2.
2404
     */
2405
0
    if (!ccw) {
2406
0
        outp = &jp2;
2407
0
        ASSIGN_POINT(&np2, nplp->o.co);
2408
0
        ASSIGN_POINT(&np1, nplp->o.p);
2409
0
        np = &np2;
2410
0
    } else {
2411
0
        outp = &jp1;
2412
0
        ASSIGN_POINT(&np1, nplp->o.ce);
2413
0
        ASSIGN_POINT(&np2, nplp->o.p);
2414
0
        np = &np1;
2415
0
    }
2416
0
    if_debug1('O', "[O]use %s\n", (ccw ? "co (ccw)" : "ce (cw)"));
2417
2418
    /* Handle triangular joins now. */
2419
0
    if (join == gs_join_triangle) {
2420
0
        fixed tpx = outp->x - nplp->o.p.x + np->x;
2421
0
        fixed tpy = outp->y - nplp->o.p.y + np->y;
2422
2423
0
        ASSIGN_POINT(&jpx, jp2);
2424
0
        if (!ccw) {
2425
            /* Insert tp between np2 and jp2. */
2426
0
            jp2.x = tpx, jp2.y = tpy;
2427
0
        } else {
2428
            /* Insert tp between jp1 and np1. */
2429
0
            ASSIGN_POINT(&jp2, np2);
2430
0
            ASSIGN_POINT(&np2, np1);
2431
0
            np1.x = tpx, np1.y = tpy;
2432
0
        }
2433
0
        return 5;
2434
0
    }
2435
0
    if (join == gs_join_miter &&
2436
0
        (code = check_miter(pgs_lp, plp, nplp, pmat, outp, np, &mpt, ccw0)) <= 0) {
2437
0
        if (code < 0)
2438
0
            return code;
2439
0
        ASSIGN_POINT(outp, mpt);
2440
0
    }
2441
0
    return 4;
2442
0
}
2443
2444
static int
2445
line_join_points_fast_cw(const gx_line_params * pgs_lp,
2446
                         pl_ptr plp, pl_ptr nplp,
2447
                         gs_fixed_point * rjoin_points,
2448
                         const gs_matrix * pmat,
2449
                         gs_line_join join)
2450
0
{
2451
    /* rjoin_points will be added to a path that is currently at plp->e.ce.
2452
     */
2453
2454
    /* Join will be between plp->e.ce and nplp->o.co */
2455
0
    if (join == gs_join_triangle)
2456
0
    {
2457
0
        gs_fixed_point tp;
2458
2459
0
        tp.x = plp->e.ce.x - nplp->o.p.x + nplp->o.co.x;
2460
0
        tp.y = plp->e.ce.y - nplp->o.p.y + nplp->o.co.y;
2461
0
        ASSIGN_POINT(&rjoin_points[0], tp);
2462
0
        ASSIGN_POINT(&rjoin_points[1], nplp->o.co);
2463
0
        return 2;
2464
0
    }
2465
2466
    /* Set up for a Bevel join */
2467
0
    ASSIGN_POINT(&rjoin_points[0], nplp->o.co);
2468
2469
0
    return 1;
2470
0
}
2471
2472
static int
2473
line_join_points_fast_ccw(const gx_line_params * pgs_lp,
2474
                          pl_ptr plp, pl_ptr nplp,
2475
                          gs_fixed_point * join_points,
2476
                          const gs_matrix * pmat,
2477
                          gs_line_join join)
2478
0
{
2479
    /* join_points will be added to a path that is currently at plp->e.co.
2480
     */
2481
    /* Join will be between plp->e.co and nplp->o.ce */
2482
0
    if (join == gs_join_triangle)
2483
0
    {
2484
0
        gs_fixed_point tp;
2485
2486
0
        tp.x = plp->e.co.x - nplp->o.p.x + nplp->o.ce.x;
2487
0
        tp.y = plp->e.co.y - nplp->o.p.y + nplp->o.ce.y;
2488
0
        ASSIGN_POINT(&join_points[0], tp);
2489
0
        ASSIGN_POINT(&join_points[1], nplp->o.ce);
2490
0
        return 2;
2491
0
    }
2492
2493
    /* Set up for a Bevel join */
2494
0
    ASSIGN_POINT(&join_points[0], nplp->o.ce);
2495
2496
0
    return 1;
2497
0
}
2498
/* ---------------- Cap computations ---------------- */
2499
2500
/* Compute the endpoints of the two caps of a segment. */
2501
/* Only o.p, e.p, width, and cdelta have been set. */
2502
static void
2503
compute_caps(pl_ptr plp)
2504
0
{
2505
0
    fixed wx2 = plp->width.x;
2506
0
    fixed wy2 = plp->width.y;
2507
2508
0
    plp->o.co.x = plp->o.p.x + wx2, plp->o.co.y = plp->o.p.y + wy2;
2509
0
    plp->o.cdelta.x = -plp->e.cdelta.x,
2510
0
        plp->o.cdelta.y = -plp->e.cdelta.y;
2511
0
    plp->o.ce.x = plp->o.p.x - wx2, plp->o.ce.y = plp->o.p.y - wy2;
2512
0
    plp->e.co.x = plp->e.p.x - wx2, plp->e.co.y = plp->e.p.y - wy2;
2513
0
    plp->e.ce.x = plp->e.p.x + wx2, plp->e.ce.y = plp->e.p.y + wy2;
2514
#if defined(DEBUG) && !defined(GS_THREADSAFE)
2515
    if (gs_debug_c('O')) {
2516
        dlprintf4("[o]Stroke o=(%f,%f) e=(%f,%f)\n",
2517
                  fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
2518
                  fixed2float(plp->e.p.x), fixed2float(plp->e.p.y));
2519
        dlprintf4("\twxy=(%f,%f) lxy=(%f,%f)\n",
2520
                  fixed2float(wx2), fixed2float(wy2),
2521
                  fixed2float(plp->e.cdelta.x),
2522
                  fixed2float(plp->e.cdelta.y));
2523
    }
2524
#endif
2525
0
}
2526
2527
#define px endp->p.x
2528
#define py endp->p.y
2529
#define xo endp->co.x
2530
#define yo endp->co.y
2531
#define xe endp->ce.x
2532
#define ye endp->ce.y
2533
#define cdx endp->cdelta.x
2534
#define cdy endp->cdelta.y
2535
2536
/* Add a round cap to a path. */
2537
/* Assume the current point is the cap origin (endp->co). */
2538
static int
2539
add_round_cap(gx_path * ppath, const_ep_ptr endp)
2540
0
{
2541
0
    int code;
2542
2543
    /*
2544
     * Per the Red Book, we draw a full circle, even though a semicircle
2545
     * is sufficient for the join.
2546
     */
2547
0
    if ((code = gx_path_add_partial_arc(ppath, px + cdx, py + cdy,
2548
0
                                        xo + cdx, yo + cdy,
2549
0
                                        quarter_arc_fraction)) < 0 ||
2550
0
        (code = gx_path_add_partial_arc(ppath, xe, ye, xe + cdx, ye + cdy,
2551
0
                                        quarter_arc_fraction)) < 0 ||
2552
0
        (code = gx_path_add_partial_arc(ppath, px - cdx, py - cdy,
2553
0
                                        xe - cdx, ye - cdy,
2554
0
                                        quarter_arc_fraction)) < 0 ||
2555
0
        (code = gx_path_add_partial_arc(ppath, xo, yo, xo - cdx, yo - cdy,
2556
0
                                        quarter_arc_fraction)) < 0 ||
2557
        /* The final point must be (xe,ye). */
2558
0
        (code = gx_path_add_line(ppath, xe, ye)) < 0
2559
0
        )
2560
0
        return code;
2561
0
    return 0;
2562
0
}
2563
2564
/* Add a semicircular cap to a path. */
2565
/* Assume the current point is the cap origin (endp->co). */
2566
static int
2567
add_pie_cap(gx_path * ppath, const_ep_ptr endp)
2568
0
{
2569
0
    int code;
2570
2571
0
    if ((code = gx_path_add_partial_arc(ppath, px + cdx, py + cdy,
2572
0
                                        xo + cdx, yo + cdy,
2573
0
                                        quarter_arc_fraction)) < 0 ||
2574
0
        (code = gx_path_add_partial_arc(ppath, xe, ye, xe + cdx, ye + cdy,
2575
0
                                        quarter_arc_fraction)) < 0 ||
2576
0
        (code = gx_path_add_line(ppath, xe, ye)) < 0)
2577
0
        return code;
2578
0
    return 0;
2579
0
}
2580
2581
static int
2582
do_pie_join(gx_path * ppath, gs_fixed_point *centre,
2583
            gs_fixed_point *current_orig, gs_fixed_point *current_tangent,
2584
            gs_fixed_point *final, gs_fixed_point *final_tangent, bool ccw,
2585
            gs_fixed_point *width)
2586
0
{
2587
0
    int code;
2588
0
    double rad_squared, dist_squared, F;
2589
0
    gs_fixed_point current, tangent, tangmeet;
2590
2591
0
    tangent.x = current_tangent->x;
2592
0
    tangent.y = current_tangent->y;
2593
0
    current.x = current_orig->x;
2594
0
    current.y = current_orig->y;
2595
2596
    /* Is the join more than 90 degrees? */
2597
0
    if ((double)tangent.x * (double)final_tangent->x +
2598
0
        (double)tangent.y * (double)final_tangent->y > 0) {
2599
        /* Yes, so do a quarter turn. */
2600
0
        code = gx_path_add_partial_arc(ppath,
2601
0
                                       centre->x + tangent.x,
2602
0
                                       centre->y + tangent.y,
2603
                                       /* Point where tangents meet */
2604
0
                                       current.x + tangent.x,
2605
0
                                       current.y + tangent.y,
2606
0
                                       quarter_arc_fraction);
2607
0
        if (code < 0)
2608
0
            return code;
2609
0
        current.x = centre->x + tangent.x;
2610
0
        current.y = centre->y + tangent.y;
2611
0
        if (ccw) {
2612
0
            int tmp = tangent.x;
2613
0
            tangent.x = -tangent.y;
2614
0
            tangent.y = tmp;
2615
0
        } else {
2616
0
            int tmp = tangent.x;
2617
0
            tangent.x = tangent.y;
2618
0
            tangent.y = -tmp;
2619
0
        }
2620
0
    }
2621
2622
    /* Now we are guaranteed that the remaining arc is 90 degrees or
2623
     * less. Find where the tangents meet for this final section. */
2624
0
    if (line_intersect(&current, &tangent,
2625
0
                       final, final_tangent, &tangmeet) != 0) {
2626
0
        return gx_path_add_line(ppath, final->x, final->y);
2627
0
    }
2628
0
    current.x -= tangmeet.x;
2629
0
    current.y -= tangmeet.y;
2630
0
    dist_squared = ((double)current.x) * current.x +
2631
0
                   ((double)current.y) * current.y;
2632
0
    rad_squared  = ((double)width->x) * width->x +
2633
0
                   ((double)width->y) * width->y;
2634
0
    dist_squared /= rad_squared;
2635
0
    F = (4.0/3.0)*(1/(1+sqrt(1+dist_squared)));
2636
0
    return gx_path_add_partial_arc(ppath, final->x, final->y,
2637
0
                                   tangmeet.x, tangmeet.y, F);
2638
0
}
2639
2640
/* Add a pie shaped join to a path. */
2641
/* Assume the current point is the cap origin (endp->co). */
2642
static int
2643
add_pie_join(gx_path * ppath, pl_ptr plp, pl_ptr nplp, bool reflected,
2644
             bool cap)
2645
0
{
2646
0
    int code;
2647
0
    gs_fixed_point *current, *final, *tangent, *final_tangent;
2648
0
    double l, r;
2649
0
    bool ccw;
2650
2651
0
    l = (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */;
2652
0
    r = (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
2653
2654
0
    if (l == r) {
2655
0
        if (cap)
2656
0
            return add_pie_cap(ppath, &plp->e);
2657
0
        else
2658
0
            return gx_path_add_line(ppath, plp->e.ce.x, plp->e.ce.y);
2659
0
    }
2660
2661
0
    ccw = (l > r);
2662
2663
0
    ccw ^= reflected;
2664
2665
    /* At this point, the current point is plp->e.co */
2666
0
    if (ccw) {
2667
0
        current       = & plp->e.co;
2668
0
        final         = &nplp->o.ce;
2669
0
        tangent       = & plp->e.cdelta;
2670
0
        final_tangent = &nplp->o.cdelta;
2671
        /* Check for no join required */
2672
0
        if (current->x == final->x && current->y == final->y) {
2673
0
            return gx_path_add_line(ppath, plp->e.ce.x, plp->e.ce.y);
2674
0
        }
2675
0
    } else {
2676
0
        current       = &nplp->o.co;
2677
0
        final         = & plp->e.ce;
2678
0
        tangent       = &nplp->o.cdelta;
2679
0
        final_tangent = & plp->e.cdelta;
2680
0
        code = gx_path_add_line(ppath, plp->e.p.x, plp->e.p.y);
2681
0
        if (code < 0)
2682
0
            return code;
2683
0
        code = gx_path_add_line(ppath, current->x, current->y);
2684
0
        if (code < 0)
2685
0
            return code;
2686
0
        if (current->x == final->x && current->y == final->y)
2687
0
            return 0;
2688
0
    }
2689
2690
0
    if ((code = do_pie_join(ppath, &plp->e.p, current, tangent,
2691
0
                            final, final_tangent, !reflected, &plp->width)) < 0)
2692
0
        return code;
2693
0
    if (ccw &&
2694
0
        ((code = gx_path_add_line(ppath, plp->e.p.x, plp->e.p.y)) < 0 ||
2695
0
         (code = gx_path_add_line(ppath, plp->e.ce.x, plp->e.ce.y)) < 0))
2696
0
        return code;
2697
2698
0
    return 0;
2699
0
}
2700
2701
/* Add a pie shaped join to a path. */
2702
static int
2703
add_pie_join_fast_cw(gx_path * rpath, pl_ptr plp, pl_ptr nplp, bool reflected)
2704
0
{
2705
    /* At this point, the current point is plp->e.ce */
2706
0
    if (plp->e.ce.x == nplp->o.co.x && plp->e.ce.y == nplp->o.co.y)
2707
0
        return 0;
2708
2709
0
    return do_pie_join(rpath, &plp->e.p, &plp->e.ce, &plp->e.cdelta,
2710
0
                       &nplp->o.co, &nplp->o.cdelta, reflected, &plp->width);
2711
0
}
2712
2713
static int
2714
add_pie_join_fast_ccw(gx_path * ppath, pl_ptr plp, pl_ptr nplp, bool reflected)
2715
0
{
2716
    /* At this point, the current point is plp->e.co */
2717
    /* Check for no join required */
2718
0
    if (plp->e.co.x == nplp->o.ce.x && plp->e.co.y == nplp->o.ce.y)
2719
0
        return 0;
2720
2721
0
    return do_pie_join(ppath, &plp->e.p, &plp->e.co, &plp->e.cdelta,
2722
0
                       &nplp->o.ce, &nplp->o.cdelta, !reflected, &plp->width);
2723
0
}
2724
2725
static int
2726
join_under_pie(gx_path * ppath, pl_ptr plp, pl_ptr nplp, bool reflected)
2727
0
{
2728
0
    int code;
2729
0
    gs_fixed_point dirn1, dirn2, tangmeet;
2730
0
    double l, r;
2731
0
    bool ccw;
2732
2733
0
    l = (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */;
2734
0
    r = (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
2735
2736
0
    if (l == r)
2737
0
        return 0;
2738
2739
0
    ccw = (l > r);
2740
2741
0
    ccw ^= reflected;
2742
2743
0
    if (ccw) {
2744
0
        dirn1.x = - plp->width.x;
2745
0
        dirn1.y = - plp->width.y;
2746
0
        dirn2.x = -nplp->width.x;
2747
0
        dirn2.y = -nplp->width.y;
2748
0
        if (line_intersect(& plp->o.co, &dirn1,
2749
0
                           &nplp->e.ce, &dirn2, &tangmeet) != 0)
2750
0
            return 0;
2751
0
        if ((code = gx_path_close_subpath(ppath)) < 0 ||
2752
0
            (code = gx_path_add_point(ppath, tangmeet.x, tangmeet.y)) < 0  ||
2753
0
            (code = gx_path_add_line(ppath,plp->o.co.x,plp->o.co.y)) < 0 ||
2754
0
            (code = do_pie_join(ppath, &plp->e.p, &plp->o.co, &plp->o.cdelta,
2755
0
                                &nplp->e.ce, &nplp->e.cdelta, !reflected,
2756
0
                                &plp->width)))
2757
0
            return code;
2758
0
    } else {
2759
0
        if (line_intersect(& plp->o.ce, & plp->width,
2760
0
                           &nplp->e.co, &nplp->width, &tangmeet) != 0)
2761
0
            return 0;
2762
0
        if ((code = gx_path_close_subpath(ppath)) < 0 ||
2763
0
            (code = gx_path_add_point(ppath, tangmeet.x, tangmeet.y)) < 0  ||
2764
0
            (code = gx_path_add_line(ppath,nplp->e.co.x,nplp->e.co.y)) < 0 ||
2765
0
            (code = do_pie_join(ppath, &plp->e.p,&nplp->e.co,&nplp->e.cdelta,
2766
0
                                &plp->o.ce, &plp->o.cdelta, !reflected,
2767
0
                                &plp->width)))
2768
0
            return code;
2769
0
    }
2770
0
    return 0;
2771
0
}
2772
2773
/* Compute the points for a non-round cap. */
2774
/* Return the number of points. */
2775
static int
2776
cap_points(gs_line_cap type, const_ep_ptr endp, gs_fixed_point *pts /*[3]*/)
2777
0
{
2778
0
#define PUT_POINT(i, px, py)\
2779
0
  pts[i].x = (px), pts[i].y = (py)
2780
0
    switch (type) {
2781
0
        case gs_cap_butt:
2782
0
            PUT_POINT(0, xo, yo);
2783
0
            PUT_POINT(1, xe, ye);
2784
0
            return 2;
2785
0
        case gs_cap_square:
2786
0
            PUT_POINT(0, xo + cdx, yo + cdy);
2787
0
            PUT_POINT(1, xe + cdx, ye + cdy);
2788
0
            return 2;
2789
0
        case gs_cap_triangle:   /* (not supported by PostScript) */
2790
0
            PUT_POINT(0, xo, yo);
2791
0
            PUT_POINT(1, px + cdx, py + cdy);
2792
0
            PUT_POINT(2, xe, ye);
2793
0
            return 3;
2794
0
        default:                /* can't happen */
2795
0
            return_error(gs_error_unregistered);
2796
0
    }
2797
0
#undef PUT_POINT
2798
0
}