Coverage Report

Created: 2025-06-10 06:56

/src/ghostpdl/base/gsline.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Line parameter operators for Ghostscript library */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gxfixed.h"    /* ditto */
23
#include "gxmatrix.h"   /* for gzstate */
24
#include "gzstate.h"
25
#include "gscoord.h"    /* for currentmatrix, setmatrix */
26
#include "gsline.h"   /* for prototypes */
27
#include "gzline.h"
28
29
/* ------ Device-independent parameters ------ */
30
31
1.01M
#define pgs_lp gs_currentlineparams_inline(pgs)
32
33
/* setlinewidth */
34
int
35
gs_setlinewidth(gs_gstate * pgs, double width)
36
222k
{
37
222k
    gx_set_line_width(pgs_lp, width);
38
222k
    return 0;
39
222k
}
40
41
/* currentlinewidth */
42
float
43
gs_currentlinewidth(const gs_gstate * pgs)
44
354
{
45
354
    return gx_current_line_width(pgs_lp);
46
354
}
47
48
/* setlinecap (sets all 3 caps) */
49
int
50
gs_setlinecap(gs_gstate * pgs, gs_line_cap cap)
51
48.4k
{
52
48.4k
    if ((uint) cap > gs_line_cap_max)
53
714
        return_error(gs_error_rangecheck);
54
47.7k
    pgs_lp->start_cap = cap;
55
47.7k
    pgs_lp->end_cap   = cap;
56
47.7k
    pgs_lp->dash_cap  = cap;
57
47.7k
    return 0;
58
48.4k
}
59
60
/* setlinestartcap */
61
int
62
gs_setlinestartcap(gs_gstate * pgs, gs_line_cap cap)
63
78.1k
{
64
78.1k
    if ((uint) cap > gs_line_cap_max)
65
0
        return_error(gs_error_rangecheck);
66
78.1k
    pgs_lp->start_cap = cap;
67
78.1k
    return 0;
68
78.1k
}
69
70
/* setlineendcap */
71
int
72
gs_setlineendcap(gs_gstate * pgs, gs_line_cap cap)
73
78.1k
{
74
78.1k
    if ((uint) cap > gs_line_cap_max)
75
0
        return_error(gs_error_rangecheck);
76
78.1k
    pgs_lp->end_cap = cap;
77
78.1k
    return 0;
78
78.1k
}
79
80
/* setlinedashcap */
81
int
82
gs_setlinedashcap(gs_gstate * pgs, gs_line_cap cap)
83
78.1k
{
84
78.1k
    if ((uint) cap > gs_line_cap_max)
85
0
        return_error(gs_error_rangecheck);
86
78.1k
    pgs_lp->dash_cap = cap;
87
78.1k
    return 0;
88
78.1k
}
89
90
/* currentlinecap */
91
gs_line_cap
92
gs_currentlinecap(const gs_gstate * pgs)
93
18
{
94
    /* This assumes that all caps are the same as start_cap - this will be
95
     * the case for postscript at least. */
96
18
    return pgs_lp->start_cap;
97
18
}
98
99
/* setlinejoin */
100
int
101
gs_setlinejoin(gs_gstate * pgs, gs_line_join join)
102
123k
{
103
123k
    if ((uint) join > gs_line_join_max)
104
558
        return_error(gs_error_rangecheck);
105
123k
    pgs_lp->join = join;
106
123k
    return 0;
107
123k
}
108
109
/* currentlinejoin */
110
gs_line_join
111
gs_currentlinejoin(const gs_gstate * pgs)
112
9
{
113
9
    return pgs_lp->join;
114
9
}
115
116
/* setmiterlimit */
117
int
118
gx_set_miter_limit(gx_line_params * plp, double limit)
119
83.2k
{
120
83.2k
    if (limit < 1.0)
121
2
        return_error(gs_error_rangecheck);
122
83.2k
    plp->miter_limit = limit;
123
    /*
124
     * Compute the miter check value.  The supplied miter limit is an
125
     * upper bound on 1/sin(phi/2); we convert this to a lower bound on
126
     * tan(phi).  Note that if phi > pi/2, this is negative.  We use the
127
     * half-angle and angle-sum formulas here to avoid the trig functions.
128
     * We also need a special check for phi/2 close to pi/4.
129
     * Some C compilers can't handle this as a conditional expression....
130
     */
131
83.2k
    {
132
83.2k
        double limit_squared = limit * limit;
133
134
83.2k
        if (limit_squared < 2.0001 && limit_squared > 1.9999)
135
0
            plp->miter_check = 1.0e6;
136
83.2k
        else
137
83.2k
            plp->miter_check =
138
83.2k
                sqrt(limit_squared - 1) * 2 / (limit_squared - 2);
139
83.2k
    }
140
83.2k
    return 0;
141
83.2k
}
142
int
143
gs_setmiterlimit(gs_gstate * pgs, double limit)
144
81.5k
{
145
81.5k
    return gx_set_miter_limit(pgs_lp, limit);
146
81.5k
}
147
148
/* currentmiterlimit */
149
float
150
gs_currentmiterlimit(const gs_gstate * pgs)
151
10
{
152
10
    return pgs_lp->miter_limit;
153
10
}
154
155
/* setdash */
156
int
157
gx_set_dash(gx_dash_params * dash, const float *pattern, uint length,
158
            double offset, gs_memory_t * mem)
159
163k
{
160
163k
    uint n = length;
161
163k
    const float *dfrom = pattern;
162
163k
    bool ink = true;
163
163k
    int index = 0;
164
163k
    float pattern_length = 0.0;
165
163k
    float dist_left;
166
163k
    float *ppat = dash->pattern;
167
168
    /* Check the dash pattern. */
169
234k
    while (n--) {
170
70.6k
        float elt = *dfrom++;
171
172
70.6k
        if (elt < 0)
173
0
            return_error(gs_error_rangecheck);
174
70.6k
        pattern_length += elt;
175
70.6k
    }
176
163k
    if (length == 0) {   /* empty pattern */
177
123k
        dist_left = 0.0;
178
123k
        if (mem && ppat) {
179
1.48k
            gs_free_object(mem, ppat, "gx_set_dash(old pattern)");
180
1.48k
            ppat = NULL;
181
1.48k
        }
182
123k
    } else {
183
40.5k
        uint size = length * sizeof(float);
184
185
40.5k
        if (pattern_length == 0)
186
0
            return_error(gs_error_rangecheck);
187
        /* Compute the initial index, ink_on, and distance left */
188
        /* in the pattern, according to the offset. */
189
81.0k
#define f_mod(a, b) ((a) - floor((a) / (b)) * (b))
190
40.5k
        if (length & 1) { /* Odd and even repetitions of the pattern */
191
            /* have opposite ink values! */
192
25.2k
            float length2 = pattern_length * 2;
193
194
25.2k
            dist_left = f_mod(offset, length2);
195
            /* Rounding errors can leave dist_left > length2 */
196
25.2k
            dist_left = f_mod(dist_left, length2);
197
25.2k
            if (dist_left >= pattern_length)
198
0
                dist_left -= pattern_length, ink = !ink;
199
25.2k
        } else {
200
15.2k
            dist_left = f_mod(offset, pattern_length);
201
            /* Rounding errors can leave dist_left > length */
202
15.2k
            dist_left = f_mod(dist_left, pattern_length);
203
15.2k
        }
204
40.5k
        if (dist_left > pattern_length)
205
0
            return_error(gs_error_rangecheck);
206
40.5k
        while ((dist_left -= pattern[index]) >= 0 &&
207
40.5k
               (dist_left > 0 || pattern[index] != 0)
208
40.5k
            )
209
14
            ink = !ink, index++;
210
40.5k
        if (mem != NULL) {
211
14.1k
            if (ppat == NULL)
212
13.7k
                ppat = (float *)gs_alloc_bytes(mem, size,
213
14.1k
                                               "gx_set_dash(pattern)");
214
464
            else if (length != dash->pattern_size)
215
2
                ppat = gs_resize_object(mem, ppat, size,
216
14.1k
                                        "gx_set_dash(pattern)");
217
14.1k
        }
218
40.5k
        if (ppat == NULL)
219
0
            return_error(gs_error_VMerror);
220
40.5k
        if (ppat != pattern)
221
15.2k
            memcpy(ppat, pattern, length * sizeof(float));
222
40.5k
    }
223
163k
    dash->pattern = ppat;
224
163k
    dash->pattern_size = length;
225
163k
    dash->offset = offset;
226
163k
    dash->pattern_length = pattern_length;
227
163k
    dash->init_ink_on = ink;
228
163k
    dash->init_index = index;
229
163k
    dash->init_dist_left = -dist_left;
230
163k
    return 0;
231
163k
}
232
int
233
gs_setdash(gs_gstate * pgs, const float *pattern, uint length, double offset)
234
117k
{
235
117k
    return gx_set_dash(&pgs_lp->dash, pattern, length, offset,
236
117k
                       pgs->memory);
237
117k
}
238
239
/* currentdash */
240
uint
241
gs_currentdash_length(const gs_gstate * pgs)
242
0
{
243
0
    return pgs_lp->dash.pattern_size;
244
0
}
245
const float *
246
gs_currentdash_pattern(const gs_gstate * pgs)
247
0
{
248
0
    return pgs_lp->dash.pattern;
249
0
}
250
float
251
gs_currentdash_offset(const gs_gstate * pgs)
252
63
{
253
63
    return pgs_lp->dash.offset;
254
63
}
255
256
/* Internal accessor for line parameters */
257
const gx_line_params *
258
gs_currentlineparams(const gs_gstate * pgs)
259
2.58k
{
260
2.58k
    return gs_currentlineparams_inline(pgs);
261
2.58k
}
262
263
/* ------ Device-dependent parameters ------ */
264
265
/* setflat */
266
int
267
gs_gstate_setflat(gs_gstate * pgs, double flat)
268
63.6k
{
269
63.6k
    if (flat <= 0.2)
270
25.9k
        flat = 0.2;
271
37.7k
    else if (flat > 100)
272
9
        flat = 100;
273
63.6k
    pgs->flatness = flat;
274
63.6k
    return 0;
275
63.6k
}
276
int
277
gs_setflat(gs_gstate * pgs, double flat)
278
34.0k
{
279
34.0k
    return gs_gstate_setflat(pgs, flat);
280
34.0k
}
281
282
/* currentflat */
283
float
284
gs_currentflat(const gs_gstate * pgs)
285
14
{
286
14
    return pgs->flatness;
287
14
}
288
289
/* setstrokeadjust */
290
int
291
gs_setstrokeadjust(gs_gstate * pgs, bool stroke_adjust)
292
32.4k
{
293
32.4k
    pgs->stroke_adjust = stroke_adjust;
294
32.4k
    return 0;
295
32.4k
}
296
297
/* currentstrokeadjust */
298
bool
299
gs_currentstrokeadjust(const gs_gstate * pgs)
300
0
{
301
0
    return pgs->stroke_adjust;
302
0
}
303
304
/* ------ Extensions ------ */
305
306
/* Device-independent */
307
308
/* setdashadapt */
309
void
310
gs_setdashadapt(gs_gstate * pgs, bool adapt)
311
78.1k
{
312
78.1k
    pgs_lp->dash.adapt = adapt;
313
78.1k
}
314
315
/* currentdashadapt */
316
bool
317
gs_gstate_currentdashadapt(const gs_gstate * pgs)
318
24.4k
{
319
24.4k
    return gs_currentlineparams_inline(pgs)->dash.adapt;
320
24.4k
}
321
bool
322
gs_currentdashadapt(const gs_gstate * pgs)
323
0
{
324
0
    return gs_gstate_currentdashadapt((const gs_gstate *)pgs);
325
0
}
326
327
/* setcurvejoin */
328
int
329
gs_setcurvejoin(gs_gstate * pgs, int join)
330
78.1k
{
331
78.1k
    if (join < -1 || join > gs_line_join_max)
332
0
        return_error(gs_error_rangecheck);
333
78.1k
    pgs_lp->curve_join = join;
334
78.1k
    return 0;
335
78.1k
}
336
337
/* currentcurvejoin */
338
int
339
gs_currentcurvejoin(const gs_gstate * pgs)
340
0
{
341
0
    return pgs_lp->curve_join;
342
0
}
343
344
/* Device-dependent */
345
346
/* setaccuratecurves */
347
void
348
gs_setaccuratecurves(gs_gstate * pgs, bool accurate)
349
78.1k
{
350
78.1k
    pgs->accurate_curves = accurate;
351
78.1k
}
352
353
/* currentaccuratecurves */
354
bool
355
gs_gstate_currentaccuratecurves(const gs_gstate * pgs)
356
0
{
357
0
    return pgs->accurate_curves;
358
0
}
359
bool
360
gs_currentaccuratecurves(const gs_gstate * pgs)
361
0
{
362
0
    return gs_gstate_currentaccuratecurves((const gs_gstate *)pgs);
363
0
}
364
365
/* setdotlength */
366
int
367
gx_set_dot_length(gx_line_params * plp, double length, bool absolute)
368
111k
{
369
111k
    if (length < 0)
370
0
        return_error(gs_error_rangecheck);
371
111k
    plp->dot_length = length;
372
111k
    plp->dot_length_absolute = absolute;
373
111k
    return 0;
374
111k
}
375
int
376
gs_setdotlength(gs_gstate * pgs, double length, bool absolute)
377
78.1k
{
378
78.1k
    return gx_set_dot_length(pgs_lp, length, absolute);
379
78.1k
}
380
381
/* currentdotlength */
382
float
383
gs_currentdotlength(const gs_gstate * pgs)
384
0
{
385
0
    return pgs_lp->dot_length;
386
0
}
387
bool
388
gs_currentdotlength_absolute(const gs_gstate * pgs)
389
0
{
390
0
    return pgs_lp->dot_length_absolute;
391
0
}
392
393
/* setdotorientation */
394
int
395
gs_setdotorientation(gs_gstate *pgs)
396
78.1k
{
397
78.1k
    if (is_xxyy(&pgs->ctm) || is_xyyx(&pgs->ctm))
398
78.1k
        return gs_currentmatrix(pgs, &pgs_lp->dot_orientation);
399
78.1k
    return_error(gs_error_rangecheck);
400
78.1k
}
401
402
/* dotorientation */
403
int
404
gs_dotorientation(gs_gstate *pgs)
405
0
{
406
0
    return gs_setmatrix(pgs, &pgs_lp->dot_orientation);
407
0
}