Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/splash/SplashPath.cc
Line
Count
Source
1
//========================================================================
2
//
3
// SplashPath.cc
4
//
5
//========================================================================
6
7
//========================================================================
8
//
9
// Modified under the Poppler project - http://poppler.freedesktop.org
10
//
11
// All changes made under the Poppler project to this file are licensed
12
// under GPL version 2 or later
13
//
14
// Copyright (C) 2018 Stefan BrĂ¼ns <stefan.bruens@rwth-aachen.de>
15
// Copyright (C) 2018-2021, 2025, 2026 Albert Astals Cid <aacid@kde.org>
16
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
17
//
18
// To see a description of the changes please see the Changelog file that
19
// came with your tarball or type make ChangeLog if you are building from git
20
//
21
//========================================================================
22
23
#include <config.h>
24
25
#include "goo/gmem.h"
26
#include "goo/GooLikely.h"
27
#include "SplashPath.h"
28
29
//------------------------------------------------------------------------
30
// SplashPath
31
//------------------------------------------------------------------------
32
33
// A path can be in three possible states:
34
//
35
// 1. no current point -- zero or more finished subpaths
36
//    [curSubpath == length]
37
//
38
// 2. one point in subpath
39
//    [curSubpath == length - 1]
40
//
41
// 3. open subpath with two or more points
42
//    [curSubpath < length - 1]
43
44
SplashPath::SplashPath()
45
0
{
46
0
    pts = nullptr;
47
0
    flags = nullptr;
48
0
    length = size = 0;
49
0
    curSubpath = 0;
50
0
    hints = nullptr;
51
0
    hintsLength = hintsSize = 0;
52
0
}
53
54
SplashPath::SplashPath(SplashPath &&path) noexcept
55
0
{
56
0
    length = path.length;
57
0
    size = path.size;
58
0
    pts = path.pts;
59
0
    flags = path.flags;
60
0
    curSubpath = path.curSubpath;
61
62
0
    hints = path.hints;
63
0
    hintsLength = hintsSize = path.hintsLength;
64
65
0
    path.pts = nullptr;
66
0
    path.flags = nullptr;
67
0
    path.length = path.size = 0;
68
0
    path.hints = nullptr;
69
0
    path.hintsLength = path.hintsSize = 0;
70
0
}
71
72
SplashPath::~SplashPath()
73
0
{
74
0
    gfree(pts);
75
0
    gfree(flags);
76
0
    gfree(hints);
77
0
}
78
79
void SplashPath::reserve(int nPts)
80
0
{
81
0
    grow(nPts - size);
82
0
}
83
84
// Add space for <nPts> more points.
85
void SplashPath::grow(int nPts)
86
0
{
87
0
    if (length + nPts > size) {
88
0
        if (size == 0) {
89
0
            size = 32;
90
0
        }
91
0
        while (size < length + nPts) {
92
0
            size *= 2;
93
0
        }
94
0
        pts = static_cast<SplashPathPoint *>(greallocn_checkoverflow(pts, size, sizeof(SplashPathPoint)));
95
0
        flags = static_cast<unsigned char *>(greallocn_checkoverflow(flags, size, sizeof(unsigned char)));
96
0
        if (unlikely(!pts || !flags)) {
97
0
            length = size = curSubpath = 0;
98
0
        }
99
0
    }
100
0
}
101
102
void SplashPath::append(SplashPath *path)
103
0
{
104
0
    int i;
105
106
0
    grow(path->length);
107
0
    if (unlikely(size == 0)) {
108
0
        return;
109
0
    }
110
111
0
    curSubpath = length + path->curSubpath;
112
0
    for (i = 0; i < path->length; ++i) {
113
0
        pts[length] = path->pts[i];
114
0
        flags[length] = path->flags[i];
115
0
        ++length;
116
0
    }
117
0
}
118
119
SplashError SplashPath::moveTo(double x, double y)
120
0
{
121
0
    if (onePointSubpath()) {
122
0
        return SplashError::BogusPath;
123
0
    }
124
0
    grow(1);
125
0
    if (unlikely(size == 0)) {
126
0
        return SplashError::BogusPath;
127
0
    }
128
0
    pts[length].x = x;
129
0
    pts[length].y = y;
130
0
    flags[length] = splashPathFirst | splashPathLast;
131
0
    curSubpath = length++;
132
0
    return SplashError::NoError;
133
0
}
134
135
SplashError SplashPath::lineTo(double x, double y)
136
0
{
137
0
    if (noCurrentPoint()) {
138
0
        return SplashError::NoCurPt;
139
0
    }
140
0
    flags[length - 1] &= ~splashPathLast;
141
0
    grow(1);
142
0
    if (unlikely(size == 0)) {
143
0
        return SplashError::BogusPath;
144
0
    }
145
0
    pts[length].x = x;
146
0
    pts[length].y = y;
147
0
    flags[length] = splashPathLast;
148
0
    ++length;
149
0
    return SplashError::NoError;
150
0
}
151
152
SplashError SplashPath::curveTo(double x1, double y1, double x2, double y2, double x3, double y3)
153
0
{
154
0
    if (noCurrentPoint()) {
155
0
        return SplashError::NoCurPt;
156
0
    }
157
0
    flags[length - 1] &= ~splashPathLast;
158
0
    grow(3);
159
0
    if (unlikely(size == 0)) {
160
0
        return SplashError::BogusPath;
161
0
    }
162
0
    pts[length].x = x1;
163
0
    pts[length].y = y1;
164
0
    flags[length] = splashPathCurve;
165
0
    ++length;
166
0
    pts[length].x = x2;
167
0
    pts[length].y = y2;
168
0
    flags[length] = splashPathCurve;
169
0
    ++length;
170
0
    pts[length].x = x3;
171
0
    pts[length].y = y3;
172
0
    flags[length] = splashPathLast;
173
0
    ++length;
174
0
    return SplashError::NoError;
175
0
}
176
177
SplashError SplashPath::close(bool force)
178
0
{
179
0
    if (noCurrentPoint()) {
180
0
        return SplashError::NoCurPt;
181
0
    }
182
0
    if (force || curSubpath == length - 1 || pts[length - 1].x != pts[curSubpath].x || pts[length - 1].y != pts[curSubpath].y) {
183
0
        const auto lineToStatus = lineTo(pts[curSubpath].x, pts[curSubpath].y);
184
0
        if (lineToStatus != SplashError::NoError) {
185
0
            return lineToStatus;
186
0
        }
187
0
    }
188
0
    flags[curSubpath] |= splashPathClosed;
189
0
    flags[length - 1] |= splashPathClosed;
190
0
    curSubpath = length;
191
0
    return SplashError::NoError;
192
0
}
193
194
void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt)
195
0
{
196
0
    if (hintsLength == hintsSize) {
197
0
        hintsSize = hintsLength ? 2 * hintsLength : 8;
198
0
        hints = static_cast<SplashPathHint *>(greallocn_checkoverflow(hints, hintsSize, sizeof(SplashPathHint)));
199
0
    }
200
0
    if (unlikely(!hints)) {
201
0
        return;
202
0
    }
203
0
    hints[hintsLength].ctrl0 = ctrl0;
204
0
    hints[hintsLength].ctrl1 = ctrl1;
205
0
    hints[hintsLength].firstPt = firstPt;
206
0
    hints[hintsLength].lastPt = lastPt;
207
0
    ++hintsLength;
208
0
}
209
210
void SplashPath::offset(double dx, double dy)
211
0
{
212
0
    int i;
213
214
0
    for (i = 0; i < length; ++i) {
215
0
        pts[i].x += dx;
216
0
        pts[i].y += dy;
217
0
    }
218
0
}
219
220
bool SplashPath::getCurPt(double *x, double *y)
221
0
{
222
0
    if (noCurrentPoint()) {
223
0
        return false;
224
0
    }
225
0
    *x = pts[length - 1].x;
226
0
    *y = pts[length - 1].y;
227
0
    return true;
228
0
}