Coverage Report

Created: 2025-07-12 07:23

/src/poppler/splash/SplashClip.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// SplashClip.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) 2010, 2021 Albert Astals Cid <aacid@kde.org>
15
// Copyright (C) 2013, 2021 Thomas Freitag <Thomas.Freitag@alfa.de>
16
// Copyright (C) 2019 Stefan BrĂ¼ns <stefan.bruens@rwth-aachen.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 <cstdlib>
26
#include <cstring>
27
#include "goo/gmem.h"
28
#include "SplashErrorCodes.h"
29
#include "SplashMath.h"
30
#include "SplashPath.h"
31
#include "SplashXPath.h"
32
#include "SplashXPathScanner.h"
33
#include "SplashBitmap.h"
34
#include "SplashClip.h"
35
36
//------------------------------------------------------------------------
37
// SplashClip.flags
38
//------------------------------------------------------------------------
39
40
7.46k
#define splashClipEO 0x01 // use even-odd rule
41
42
//------------------------------------------------------------------------
43
// SplashClip
44
//------------------------------------------------------------------------
45
46
SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, bool antialiasA)
47
385k
{
48
385k
    antialias = antialiasA;
49
385k
    if (x0 < x1) {
50
385k
        xMin = x0;
51
385k
        xMax = x1;
52
385k
    } else {
53
0
        xMin = x1;
54
0
        xMax = x0;
55
0
    }
56
385k
    if (y0 < y1) {
57
385k
        yMin = y0;
58
385k
        yMax = y1;
59
385k
    } else {
60
0
        yMin = y1;
61
0
        yMax = y0;
62
0
    }
63
385k
    xMinI = splashFloor(xMin);
64
385k
    yMinI = splashFloor(yMin);
65
385k
    xMaxI = splashCeil(xMax) - 1;
66
385k
    yMaxI = splashCeil(yMax) - 1;
67
385k
    flags = nullptr;
68
385k
    length = size = 0;
69
385k
}
70
71
SplashClip::SplashClip(const SplashClip *clip)
72
3.85M
{
73
3.85M
    int i;
74
75
3.85M
    antialias = clip->antialias;
76
3.85M
    xMin = clip->xMin;
77
3.85M
    yMin = clip->yMin;
78
3.85M
    xMax = clip->xMax;
79
3.85M
    yMax = clip->yMax;
80
3.85M
    xMinI = clip->xMinI;
81
3.85M
    yMinI = clip->yMinI;
82
3.85M
    xMaxI = clip->xMaxI;
83
3.85M
    yMaxI = clip->yMaxI;
84
3.85M
    length = clip->length;
85
3.85M
    size = clip->size;
86
3.85M
    flags = (unsigned char *)gmallocn(size, sizeof(unsigned char));
87
3.85M
    scanners = clip->scanners;
88
10.2M
    for (i = 0; i < length; ++i) {
89
6.43M
        flags[i] = clip->flags[i];
90
6.43M
    }
91
3.85M
}
92
93
SplashClip::~SplashClip()
94
4.24M
{
95
4.24M
    gfree(flags);
96
4.24M
}
97
98
void SplashClip::grow(int nPaths)
99
356k
{
100
356k
    if (length + nPaths > size) {
101
229k
        if (size == 0) {
102
228k
            size = 32;
103
228k
        }
104
229k
        while (size < length + nPaths) {
105
168
            size *= 2;
106
168
        }
107
229k
        flags = (unsigned char *)greallocn(flags, size, sizeof(unsigned char));
108
229k
    }
109
356k
}
110
111
void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
112
0
{
113
0
    gfree(flags);
114
0
    flags = nullptr;
115
0
    scanners = {};
116
0
    length = size = 0;
117
118
0
    if (x0 < x1) {
119
0
        xMin = x0;
120
0
        xMax = x1;
121
0
    } else {
122
0
        xMin = x1;
123
0
        xMax = x0;
124
0
    }
125
0
    if (y0 < y1) {
126
0
        yMin = y0;
127
0
        yMax = y1;
128
0
    } else {
129
0
        yMin = y1;
130
0
        yMax = y0;
131
0
    }
132
0
    xMinI = splashFloor(xMin);
133
0
    yMinI = splashFloor(yMin);
134
0
    xMaxI = splashCeil(xMax) - 1;
135
0
    yMaxI = splashCeil(yMax) - 1;
136
0
}
137
138
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
139
816k
{
140
816k
    if (x0 < x1) {
141
796k
        if (x0 > xMin) {
142
416k
            xMin = x0;
143
416k
            xMinI = splashFloor(xMin);
144
416k
        }
145
796k
        if (x1 < xMax) {
146
397k
            xMax = x1;
147
397k
            xMaxI = splashCeil(xMax) - 1;
148
397k
        }
149
796k
    } else {
150
20.8k
        if (x1 > xMin) {
151
11.1k
            xMin = x1;
152
11.1k
            xMinI = splashFloor(xMin);
153
11.1k
        }
154
20.8k
        if (x0 < xMax) {
155
10.1k
            xMax = x0;
156
10.1k
            xMaxI = splashCeil(xMax) - 1;
157
10.1k
        }
158
20.8k
    }
159
816k
    if (y0 < y1) {
160
103k
        if (y0 > yMin) {
161
65.5k
            yMin = y0;
162
65.5k
            yMinI = splashFloor(yMin);
163
65.5k
        }
164
103k
        if (y1 < yMax) {
165
57.0k
            yMax = y1;
166
57.0k
            yMaxI = splashCeil(yMax) - 1;
167
57.0k
        }
168
713k
    } else {
169
713k
        if (y1 > yMin) {
170
314k
            yMin = y1;
171
314k
            yMinI = splashFloor(yMin);
172
314k
        }
173
713k
        if (y0 < yMax) {
174
330k
            yMax = y0;
175
330k
            yMaxI = splashCeil(yMax) - 1;
176
330k
        }
177
713k
    }
178
816k
    return splashOk;
179
816k
}
180
181
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, bool eo)
182
1.17M
{
183
1.17M
    int yMinAA, yMaxAA;
184
185
1.17M
    SplashXPath xPath(path, matrix, flatness, true);
186
187
    // check for an empty path
188
1.17M
    if (xPath.length == 0) {
189
1.78k
        xMax = xMin - 1;
190
1.78k
        yMax = yMin - 1;
191
1.78k
        xMaxI = splashCeil(xMax) - 1;
192
1.78k
        yMaxI = splashCeil(yMax) - 1;
193
194
        // check for a rectangle
195
1.17M
    } else if (xPath.length == 4
196
1.17M
               && ((xPath.segs[0].x0 == xPath.segs[0].x1 && xPath.segs[0].x0 == xPath.segs[1].x0 && xPath.segs[0].x0 == xPath.segs[3].x1 && xPath.segs[2].x0 == xPath.segs[2].x1 && xPath.segs[2].x0 == xPath.segs[1].x1
197
946k
                    && xPath.segs[2].x0 == xPath.segs[3].x0 && xPath.segs[1].y0 == xPath.segs[1].y1 && xPath.segs[1].y0 == xPath.segs[0].y1 && xPath.segs[1].y0 == xPath.segs[2].y0 && xPath.segs[3].y0 == xPath.segs[3].y1
198
946k
                    && xPath.segs[3].y0 == xPath.segs[0].y0 && xPath.segs[3].y0 == xPath.segs[2].y1)
199
946k
                   || (xPath.segs[0].y0 == xPath.segs[0].y1 && xPath.segs[0].y0 == xPath.segs[1].y0 && xPath.segs[0].y0 == xPath.segs[3].y1 && xPath.segs[2].y0 == xPath.segs[2].y1 && xPath.segs[2].y0 == xPath.segs[1].y1
200
929k
                       && xPath.segs[2].y0 == xPath.segs[3].y0 && xPath.segs[1].x0 == xPath.segs[1].x1 && xPath.segs[1].x0 == xPath.segs[0].x1 && xPath.segs[1].x0 == xPath.segs[2].x0 && xPath.segs[3].x0 == xPath.segs[3].x1
201
929k
                       && xPath.segs[3].x0 == xPath.segs[0].x0 && xPath.segs[3].x0 == xPath.segs[2].x1))) {
202
816k
        clipToRect(xPath.segs[0].x0, xPath.segs[0].y0, xPath.segs[2].x0, xPath.segs[2].y0);
203
204
816k
    } else {
205
356k
        grow(1);
206
356k
        if (antialias) {
207
156
            xPath.aaScale();
208
156
        }
209
356k
        xPath.sort();
210
356k
        flags[length] = eo ? splashClipEO : 0;
211
356k
        if (antialias) {
212
156
            yMinAA = yMinI * splashAASize;
213
156
            yMaxAA = (yMaxI + 1) * splashAASize - 1;
214
356k
        } else {
215
356k
            yMinAA = yMinI;
216
356k
            yMaxAA = yMaxI;
217
356k
        }
218
356k
        scanners.emplace_back(std::make_shared<SplashXPathScanner>(xPath, eo, yMinAA, yMaxAA));
219
356k
        ++length;
220
356k
    }
221
222
1.17M
    return splashOk;
223
1.17M
}
224
225
SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax)
226
150M
{
227
    // This tests the rectangle:
228
    //     x = [rectXMin, rectXMax + 1)    (note: rect coords are ints)
229
    //     y = [rectYMin, rectYMax + 1)
230
    // against the clipping region:
231
    //     x = [xMin, xMax)                (note: clipping coords are fp)
232
    //     y = [yMin, yMax)
233
150M
    if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax || (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
234
90.7M
        return splashClipAllOutside;
235
90.7M
    }
236
60.1M
    if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && length == 0) {
237
42.8M
        return splashClipAllInside;
238
42.8M
    }
239
17.2M
    return splashClipPartial;
240
60.1M
}
241
242
SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY)
243
100M
{
244
100M
    int i;
245
246
    // This tests the rectangle:
247
    //     x = [spanXMin, spanXMax + 1)    (note: span coords are ints)
248
    //     y = [spanY, spanY + 1)
249
    // against the clipping region:
250
    //     x = [xMin, xMax)                (note: clipping coords are fp)
251
    //     y = [yMin, yMax)
252
100M
    if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax || (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
253
25.0M
        return splashClipAllOutside;
254
25.0M
    }
255
75.5M
    if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
256
6.35M
        return splashClipPartial;
257
6.35M
    }
258
69.1M
    if (antialias) {
259
0
        for (i = 0; i < length; ++i) {
260
0
            if (!scanners[i]->testSpan(spanXMin * splashAASize, spanXMax * splashAASize + (splashAASize - 1), spanY * splashAASize)) {
261
0
                return splashClipPartial;
262
0
            }
263
0
        }
264
69.1M
    } else {
265
93.3M
        for (i = 0; i < length; ++i) {
266
48.4M
            if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
267
24.3M
                return splashClipPartial;
268
24.3M
            }
269
48.4M
        }
270
69.1M
    }
271
44.8M
    return splashClipAllInside;
272
69.1M
}
273
274
void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, bool adjustVertLine)
275
43.3k
{
276
43.3k
    int xx0, xx1, xx, yy, i;
277
43.3k
    SplashColorPtr p;
278
279
    // zero out pixels with x < xMin
280
43.3k
    xx0 = *x0 * splashAASize;
281
43.3k
    xx1 = splashFloor(xMin * splashAASize);
282
43.3k
    if (xx1 > aaBuf->getWidth()) {
283
0
        xx1 = aaBuf->getWidth();
284
0
    }
285
43.3k
    if (xx0 < xx1) {
286
1.50k
        xx0 &= ~7;
287
7.54k
        for (yy = 0; yy < splashAASize; ++yy) {
288
6.03k
            p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
289
23.0k
            for (xx = xx0; xx + 7 < xx1; xx += 8) {
290
17.0k
                *p++ = 0;
291
17.0k
            }
292
6.03k
            if (xx < xx1 && !adjustVertLine) {
293
1.24k
                *p &= 0xff >> (xx1 & 7);
294
1.24k
            }
295
6.03k
        }
296
1.50k
        *x0 = splashFloor(xMin);
297
1.50k
    }
298
299
    // zero out pixels with x > xMax
300
43.3k
    xx0 = splashFloor(xMax * splashAASize) + 1;
301
43.3k
    if (xx0 < 0) {
302
0
        xx0 = 0;
303
0
    }
304
43.3k
    xx1 = (*x1 + 1) * splashAASize;
305
43.3k
    if (xx0 < xx1 && !adjustVertLine) {
306
84.0k
        for (yy = 0; yy < splashAASize; ++yy) {
307
67.2k
            p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
308
67.2k
            xx = xx0;
309
67.2k
            if (xx & 7) {
310
67.2k
                *p &= 0xff00 >> (xx & 7);
311
67.2k
                xx = (xx & ~7) + 8;
312
67.2k
                ++p;
313
67.2k
            }
314
189k
            for (; xx < xx1; xx += 8) {
315
122k
                *p++ = 0;
316
122k
            }
317
67.2k
        }
318
16.8k
        *x1 = splashFloor(xMax);
319
16.8k
    }
320
321
    // check the paths
322
61.1k
    for (i = 0; i < length; ++i) {
323
17.8k
        scanners[i]->clipAALine(aaBuf, x0, x1, y);
324
17.8k
    }
325
43.3k
    if (*x0 > *x1) {
326
2.13k
        *x0 = *x1;
327
2.13k
    }
328
43.3k
    if (*x0 < 0) {
329
0
        *x0 = 0;
330
0
    }
331
43.3k
    if ((*x0 >> 1) >= aaBuf->getRowSize()) {
332
0
        xx0 = *x0;
333
0
        *x0 = (aaBuf->getRowSize() - 1) << 1;
334
0
        if (xx0 & 1) {
335
0
            *x0 = *x0 + 1;
336
0
        }
337
0
    }
338
43.3k
    if (*x1 < *x0) {
339
0
        *x1 = *x0;
340
0
    }
341
43.3k
    if ((*x1 >> 1) >= aaBuf->getRowSize()) {
342
0
        xx0 = *x1;
343
0
        *x1 = (aaBuf->getRowSize() - 1) << 1;
344
0
        if (xx0 & 1) {
345
0
            *x1 = *x1 + 1;
346
0
        }
347
0
    }
348
43.3k
}
349
350
bool SplashClip::testClipPaths(int x, int y)
351
2.93G
{
352
2.93G
    if (antialias) {
353
25.3k
        x *= splashAASize;
354
25.3k
        y *= splashAASize;
355
25.3k
    }
356
357
3.02G
    for (int i = 0; i < length; ++i) {
358
536M
        if (!scanners[i]->test(x, y)) {
359
442M
            return false;
360
442M
        }
361
536M
    }
362
363
2.49G
    return true;
364
2.93G
}