Coverage Report

Created: 2025-11-16 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gsline.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 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
22.0M
#define pgs_lp gs_currentlineparams_inline(pgs)
32
33
/* setlinewidth */
34
int
35
gs_setlinewidth(gs_gstate * pgs, double width)
36
5.15M
{
37
5.15M
    gx_set_line_width(pgs_lp, width);
38
5.15M
    return 0;
39
5.15M
}
40
41
/* currentlinewidth */
42
float
43
gs_currentlinewidth(const gs_gstate * pgs)
44
1.12k
{
45
1.12k
    return gx_current_line_width(pgs_lp);
46
1.12k
}
47
48
/* setlinecap (sets all 3 caps) */
49
int
50
gs_setlinecap(gs_gstate * pgs, gs_line_cap cap)
51
1.50M
{
52
1.50M
    if ((uint) cap > gs_line_cap_max)
53
32.9k
        return_error(gs_error_rangecheck);
54
1.47M
    pgs_lp->start_cap = cap;
55
1.47M
    pgs_lp->end_cap   = cap;
56
1.47M
    pgs_lp->dash_cap  = cap;
57
1.47M
    return 0;
58
1.50M
}
59
60
/* setlinestartcap */
61
int
62
gs_setlinestartcap(gs_gstate * pgs, gs_line_cap cap)
63
1.51M
{
64
1.51M
    if ((uint) cap > gs_line_cap_max)
65
0
        return_error(gs_error_rangecheck);
66
1.51M
    pgs_lp->start_cap = cap;
67
1.51M
    return 0;
68
1.51M
}
69
70
/* setlineendcap */
71
int
72
gs_setlineendcap(gs_gstate * pgs, gs_line_cap cap)
73
1.51M
{
74
1.51M
    if ((uint) cap > gs_line_cap_max)
75
0
        return_error(gs_error_rangecheck);
76
1.51M
    pgs_lp->end_cap = cap;
77
1.51M
    return 0;
78
1.51M
}
79
80
/* setlinedashcap */
81
int
82
gs_setlinedashcap(gs_gstate * pgs, gs_line_cap cap)
83
1.51M
{
84
1.51M
    if ((uint) cap > gs_line_cap_max)
85
0
        return_error(gs_error_rangecheck);
86
1.51M
    pgs_lp->dash_cap = cap;
87
1.51M
    return 0;
88
1.51M
}
89
90
/* currentlinecap */
91
gs_line_cap
92
gs_currentlinecap(const gs_gstate * pgs)
93
276
{
94
    /* This assumes that all caps are the same as start_cap - this will be
95
     * the case for postscript at least. */
96
276
    return pgs_lp->start_cap;
97
276
}
98
99
/* setlinejoin */
100
int
101
gs_setlinejoin(gs_gstate * pgs, gs_line_join join)
102
2.80M
{
103
2.80M
    if ((uint) join > gs_line_join_max)
104
26.7k
        return_error(gs_error_rangecheck);
105
2.77M
    pgs_lp->join = join;
106
2.77M
    return 0;
107
2.80M
}
108
109
/* currentlinejoin */
110
gs_line_join
111
gs_currentlinejoin(const gs_gstate * pgs)
112
1.48k
{
113
1.48k
    return pgs_lp->join;
114
1.48k
}
115
116
/* setmiterlimit */
117
int
118
gx_set_miter_limit(gx_line_params * plp, double limit)
119
1.60M
{
120
1.60M
    if (limit < 1.0)
121
34
        return_error(gs_error_rangecheck);
122
1.60M
    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
1.60M
    {
132
1.60M
        double limit_squared = limit * limit;
133
134
1.60M
        if (limit_squared < 2.0001 && limit_squared > 1.9999)
135
0
            plp->miter_check = 1.0e6;
136
1.60M
        else
137
1.60M
            plp->miter_check =
138
1.60M
                sqrt(limit_squared - 1) * 2 / (limit_squared - 2);
139
1.60M
    }
140
1.60M
    return 0;
141
1.60M
}
142
int
143
gs_setmiterlimit(gs_gstate * pgs, double limit)
144
1.56M
{
145
1.56M
    return gx_set_miter_limit(pgs_lp, limit);
146
1.56M
}
147
148
/* currentmiterlimit */
149
float
150
gs_currentmiterlimit(const gs_gstate * pgs)
151
86
{
152
86
    return pgs_lp->miter_limit;
153
86
}
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
3.74M
{
160
3.74M
    uint n = length;
161
3.74M
    const float *dfrom = pattern;
162
3.74M
    bool ink = true;
163
3.74M
    int index = 0;
164
3.74M
    float pattern_length = 0.0;
165
3.74M
    float dist_left;
166
3.74M
    float *ppat = dash->pattern;
167
168
    /* Check the dash pattern. */
169
5.53M
    while (n--) {
170
1.78M
        float elt = *dfrom++;
171
172
1.78M
        if (elt < 0)
173
0
            return_error(gs_error_rangecheck);
174
1.78M
        pattern_length += elt;
175
1.78M
    }
176
3.74M
    if (length == 0) {   /* empty pattern */
177
2.83M
        dist_left = 0.0;
178
2.83M
        if (mem && ppat) {
179
42.0k
            gs_free_object(mem, ppat, "gx_set_dash(old pattern)");
180
42.0k
            ppat = NULL;
181
42.0k
        }
182
2.83M
    } else {
183
916k
        uint size = length * sizeof(float);
184
185
916k
        if (length != 0 && size / length != sizeof(float))
186
0
            return gs_note_error(gs_error_undefinedresult);
187
188
916k
        if (pattern_length == 0)
189
1.70k
            return_error(gs_error_rangecheck);
190
        /* Compute the initial index, ink_on, and distance left */
191
        /* in the pattern, according to the offset. */
192
1.82M
#define f_mod(a, b) ((a) - floor((a) / (b)) * (b))
193
914k
        if (length & 1) { /* Odd and even repetitions of the pattern */
194
            /* have opposite ink values! */
195
446k
            float length2 = pattern_length * 2;
196
197
446k
            dist_left = f_mod(offset, length2);
198
            /* Rounding errors can leave dist_left > length2 */
199
446k
            dist_left = f_mod(dist_left, length2);
200
446k
            if (dist_left >= pattern_length)
201
3
                dist_left -= pattern_length, ink = !ink;
202
467k
        } else {
203
467k
            dist_left = f_mod(offset, pattern_length);
204
            /* Rounding errors can leave dist_left > length */
205
467k
            dist_left = f_mod(dist_left, pattern_length);
206
467k
        }
207
914k
        if (dist_left > pattern_length)
208
0
            return_error(gs_error_rangecheck);
209
914k
        while ((dist_left -= pattern[index]) >= 0 &&
210
63.2k
               (dist_left > 0 || pattern[index] != 0)
211
914k
            )
212
243
            ink = !ink, index++;
213
914k
        if (mem != NULL) {
214
394k
            if (ppat == NULL)
215
376k
                ppat = (float *)gs_alloc_bytes(mem, size,
216
394k
                                               "gx_set_dash(pattern)");
217
17.7k
            else if (length != dash->pattern_size)
218
20
                ppat = gs_resize_object(mem, ppat, size,
219
394k
                                        "gx_set_dash(pattern)");
220
394k
        }
221
914k
        if (ppat == NULL)
222
0
            return_error(gs_error_VMerror);
223
914k
        if (ppat != pattern)
224
415k
            memcpy(ppat, pattern, length * sizeof(float));
225
914k
    }
226
3.74M
    dash->pattern = ppat;
227
3.74M
    dash->pattern_size = length;
228
3.74M
    dash->offset = offset;
229
3.74M
    dash->pattern_length = pattern_length;
230
3.74M
    dash->init_ink_on = ink;
231
3.74M
    dash->init_index = index;
232
3.74M
    dash->init_dist_left = -dist_left;
233
3.74M
    return 0;
234
3.74M
}
235
int
236
gs_setdash(gs_gstate * pgs, const float *pattern, uint length, double offset)
237
2.71M
{
238
2.71M
    return gx_set_dash(&pgs_lp->dash, pattern, length, offset,
239
2.71M
                       pgs->memory);
240
2.71M
}
241
242
/* currentdash */
243
uint
244
gs_currentdash_length(const gs_gstate * pgs)
245
0
{
246
0
    return pgs_lp->dash.pattern_size;
247
0
}
248
const float *
249
gs_currentdash_pattern(const gs_gstate * pgs)
250
0
{
251
0
    return pgs_lp->dash.pattern;
252
0
}
253
float
254
gs_currentdash_offset(const gs_gstate * pgs)
255
1.40k
{
256
1.40k
    return pgs_lp->dash.offset;
257
1.40k
}
258
259
/* Internal accessor for line parameters */
260
const gx_line_params *
261
gs_currentlineparams(const gs_gstate * pgs)
262
48.8k
{
263
48.8k
    return gs_currentlineparams_inline(pgs);
264
48.8k
}
265
266
/* ------ Device-dependent parameters ------ */
267
268
/* setflat */
269
int
270
gs_gstate_setflat(gs_gstate * pgs, double flat)
271
10.0M
{
272
10.0M
    if (flat <= 0.2)
273
9.25M
        flat = 0.2;
274
826k
    else if (flat > 100)
275
57
        flat = 100;
276
10.0M
    pgs->flatness = flat;
277
10.0M
    return 0;
278
10.0M
}
279
int
280
gs_setflat(gs_gstate * pgs, double flat)
281
729k
{
282
729k
    return gs_gstate_setflat(pgs, flat);
283
729k
}
284
285
/* currentflat */
286
float
287
gs_currentflat(const gs_gstate * pgs)
288
121
{
289
121
    return pgs->flatness;
290
121
}
291
292
/* setstrokeadjust */
293
int
294
gs_setstrokeadjust(gs_gstate * pgs, bool stroke_adjust)
295
735k
{
296
735k
    pgs->stroke_adjust = stroke_adjust;
297
735k
    return 0;
298
735k
}
299
300
/* currentstrokeadjust */
301
bool
302
gs_currentstrokeadjust(const gs_gstate * pgs)
303
12
{
304
12
    return pgs->stroke_adjust;
305
12
}
306
307
/* ------ Extensions ------ */
308
309
/* Device-independent */
310
311
/* setdashadapt */
312
void
313
gs_setdashadapt(gs_gstate * pgs, bool adapt)
314
1.51M
{
315
1.51M
    pgs_lp->dash.adapt = adapt;
316
1.51M
}
317
318
/* currentdashadapt */
319
bool
320
gs_gstate_currentdashadapt(const gs_gstate * pgs)
321
459k
{
322
459k
    return gs_currentlineparams_inline(pgs)->dash.adapt;
323
459k
}
324
bool
325
gs_currentdashadapt(const gs_gstate * pgs)
326
0
{
327
0
    return gs_gstate_currentdashadapt((const gs_gstate *)pgs);
328
0
}
329
330
/* setcurvejoin */
331
int
332
gs_setcurvejoin(gs_gstate * pgs, int join)
333
1.51M
{
334
1.51M
    if (join < -1 || join > gs_line_join_max)
335
0
        return_error(gs_error_rangecheck);
336
1.51M
    pgs_lp->curve_join = join;
337
1.51M
    return 0;
338
1.51M
}
339
340
/* currentcurvejoin */
341
int
342
gs_currentcurvejoin(const gs_gstate * pgs)
343
0
{
344
0
    return pgs_lp->curve_join;
345
0
}
346
347
/* Device-dependent */
348
349
/* setaccuratecurves */
350
void
351
gs_setaccuratecurves(gs_gstate * pgs, bool accurate)
352
1.51M
{
353
1.51M
    pgs->accurate_curves = accurate;
354
1.51M
}
355
356
/* currentaccuratecurves */
357
bool
358
gs_gstate_currentaccuratecurves(const gs_gstate * pgs)
359
0
{
360
0
    return pgs->accurate_curves;
361
0
}
362
bool
363
gs_currentaccuratecurves(const gs_gstate * pgs)
364
0
{
365
0
    return gs_gstate_currentaccuratecurves((const gs_gstate *)pgs);
366
0
}
367
368
/* setdotlength */
369
int
370
gx_set_dot_length(gx_line_params * plp, double length, bool absolute)
371
2.19M
{
372
2.19M
    if (length < 0)
373
0
        return_error(gs_error_rangecheck);
374
2.19M
    plp->dot_length = length;
375
2.19M
    plp->dot_length_absolute = absolute;
376
2.19M
    return 0;
377
2.19M
}
378
int
379
gs_setdotlength(gs_gstate * pgs, double length, bool absolute)
380
1.51M
{
381
1.51M
    return gx_set_dot_length(pgs_lp, length, absolute);
382
1.51M
}
383
384
/* currentdotlength */
385
float
386
gs_currentdotlength(const gs_gstate * pgs)
387
0
{
388
0
    return pgs_lp->dot_length;
389
0
}
390
bool
391
gs_currentdotlength_absolute(const gs_gstate * pgs)
392
0
{
393
0
    return pgs_lp->dot_length_absolute;
394
0
}
395
396
/* setdotorientation */
397
int
398
gs_setdotorientation(gs_gstate *pgs)
399
1.51M
{
400
1.51M
    if (is_xxyy(&pgs->ctm) || is_xyyx(&pgs->ctm))
401
1.51M
        return gs_currentmatrix(pgs, &pgs_lp->dot_orientation);
402
1.51M
    return_error(gs_error_rangecheck);
403
1.51M
}
404
405
/* dotorientation */
406
int
407
gs_dotorientation(gs_gstate *pgs)
408
0
{
409
0
    return gs_setmatrix(pgs, &pgs_lp->dot_orientation);
410
0
}