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#define splashClipEO 0x01 // use even-odd rule
41
42//------------------------------------------------------------------------
43// SplashClip
44//------------------------------------------------------------------------
45
46SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, bool antialiasA)
47{
48 antialias = antialiasA;
49 if (x0 < x1) {
50 xMin = x0;
51 xMax = x1;
52 } else {
53 xMin = x1;
54 xMax = x0;
55 }
56 if (y0 < y1) {
57 yMin = y0;
58 yMax = y1;
59 } else {
60 yMin = y1;
61 yMax = y0;
62 }
63 xMinI = splashFloor(x: xMin);
64 yMinI = splashFloor(x: yMin);
65 xMaxI = splashCeil(x: xMax) - 1;
66 yMaxI = splashCeil(x: yMax) - 1;
67 flags = nullptr;
68 length = size = 0;
69}
70
71SplashClip::SplashClip(const SplashClip *clip)
72{
73 int i;
74
75 antialias = clip->antialias;
76 xMin = clip->xMin;
77 yMin = clip->yMin;
78 xMax = clip->xMax;
79 yMax = clip->yMax;
80 xMinI = clip->xMinI;
81 yMinI = clip->yMinI;
82 xMaxI = clip->xMaxI;
83 yMaxI = clip->yMaxI;
84 length = clip->length;
85 size = clip->size;
86 flags = (unsigned char *)gmallocn(count: size, size: sizeof(unsigned char));
87 scanners = clip->scanners;
88 for (i = 0; i < length; ++i) {
89 flags[i] = clip->flags[i];
90 }
91}
92
93SplashClip::~SplashClip()
94{
95 gfree(p: flags);
96}
97
98void SplashClip::grow(int nPaths)
99{
100 if (length + nPaths > size) {
101 if (size == 0) {
102 size = 32;
103 }
104 while (size < length + nPaths) {
105 size *= 2;
106 }
107 flags = (unsigned char *)greallocn(p: flags, count: size, size: sizeof(unsigned char));
108 }
109}
110
111void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
112{
113 gfree(p: flags);
114 flags = nullptr;
115 scanners = {};
116 length = size = 0;
117
118 if (x0 < x1) {
119 xMin = x0;
120 xMax = x1;
121 } else {
122 xMin = x1;
123 xMax = x0;
124 }
125 if (y0 < y1) {
126 yMin = y0;
127 yMax = y1;
128 } else {
129 yMin = y1;
130 yMax = y0;
131 }
132 xMinI = splashFloor(x: xMin);
133 yMinI = splashFloor(x: yMin);
134 xMaxI = splashCeil(x: xMax) - 1;
135 yMaxI = splashCeil(x: yMax) - 1;
136}
137
138SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
139{
140 if (x0 < x1) {
141 if (x0 > xMin) {
142 xMin = x0;
143 xMinI = splashFloor(x: xMin);
144 }
145 if (x1 < xMax) {
146 xMax = x1;
147 xMaxI = splashCeil(x: xMax) - 1;
148 }
149 } else {
150 if (x1 > xMin) {
151 xMin = x1;
152 xMinI = splashFloor(x: xMin);
153 }
154 if (x0 < xMax) {
155 xMax = x0;
156 xMaxI = splashCeil(x: xMax) - 1;
157 }
158 }
159 if (y0 < y1) {
160 if (y0 > yMin) {
161 yMin = y0;
162 yMinI = splashFloor(x: yMin);
163 }
164 if (y1 < yMax) {
165 yMax = y1;
166 yMaxI = splashCeil(x: yMax) - 1;
167 }
168 } else {
169 if (y1 > yMin) {
170 yMin = y1;
171 yMinI = splashFloor(x: yMin);
172 }
173 if (y0 < yMax) {
174 yMax = y0;
175 yMaxI = splashCeil(x: yMax) - 1;
176 }
177 }
178 return splashOk;
179}
180
181SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, bool eo)
182{
183 int yMinAA, yMaxAA;
184
185 SplashXPath xPath(path, matrix, flatness, true);
186
187 // check for an empty path
188 if (xPath.length == 0) {
189 xMax = xMin - 1;
190 yMax = yMin - 1;
191 xMaxI = splashCeil(x: xMax) - 1;
192 yMaxI = splashCeil(x: yMax) - 1;
193
194 // check for a rectangle
195 } else if (xPath.length == 4
196 && ((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 && 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 && xPath.segs[3].y0 == xPath.segs[0].y0 && xPath.segs[3].y0 == xPath.segs[2].y1)
199 || (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 && 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 && xPath.segs[3].x0 == xPath.segs[0].x0 && xPath.segs[3].x0 == xPath.segs[2].x1))) {
202 clipToRect(x0: xPath.segs[0].x0, y0: xPath.segs[0].y0, x1: xPath.segs[2].x0, y1: xPath.segs[2].y0);
203
204 } else {
205 grow(nPaths: 1);
206 if (antialias) {
207 xPath.aaScale();
208 }
209 xPath.sort();
210 flags[length] = eo ? splashClipEO : 0;
211 if (antialias) {
212 yMinAA = yMinI * splashAASize;
213 yMaxAA = (yMaxI + 1) * splashAASize - 1;
214 } else {
215 yMinAA = yMinI;
216 yMaxAA = yMaxI;
217 }
218 scanners.emplace_back(args: std::make_shared<SplashXPathScanner>(args&: xPath, args&: eo, args&: yMinAA, args&: yMaxAA));
219 ++length;
220 }
221
222 return splashOk;
223}
224
225SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax)
226{
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 if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax || (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
234 return splashClipAllOutside;
235 }
236 if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && length == 0) {
237 return splashClipAllInside;
238 }
239 return splashClipPartial;
240}
241
242SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY)
243{
244 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 if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax || (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
253 return splashClipAllOutside;
254 }
255 if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
256 return splashClipPartial;
257 }
258 if (antialias) {
259 for (i = 0; i < length; ++i) {
260 if (!scanners[i]->testSpan(x0: spanXMin * splashAASize, x1: spanXMax * splashAASize + (splashAASize - 1), y: spanY * splashAASize)) {
261 return splashClipPartial;
262 }
263 }
264 } else {
265 for (i = 0; i < length; ++i) {
266 if (!scanners[i]->testSpan(x0: spanXMin, x1: spanXMax, y: spanY)) {
267 return splashClipPartial;
268 }
269 }
270 }
271 return splashClipAllInside;
272}
273
274void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, bool adjustVertLine)
275{
276 int xx0, xx1, xx, yy, i;
277 SplashColorPtr p;
278
279 // zero out pixels with x < xMin
280 xx0 = *x0 * splashAASize;
281 xx1 = splashFloor(x: xMin * splashAASize);
282 if (xx1 > aaBuf->getWidth()) {
283 xx1 = aaBuf->getWidth();
284 }
285 if (xx0 < xx1) {
286 xx0 &= ~7;
287 for (yy = 0; yy < splashAASize; ++yy) {
288 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
289 for (xx = xx0; xx + 7 < xx1; xx += 8) {
290 *p++ = 0;
291 }
292 if (xx < xx1 && !adjustVertLine) {
293 *p &= 0xff >> (xx1 & 7);
294 }
295 }
296 *x0 = splashFloor(x: xMin);
297 }
298
299 // zero out pixels with x > xMax
300 xx0 = splashFloor(x: xMax * splashAASize) + 1;
301 if (xx0 < 0) {
302 xx0 = 0;
303 }
304 xx1 = (*x1 + 1) * splashAASize;
305 if (xx0 < xx1 && !adjustVertLine) {
306 for (yy = 0; yy < splashAASize; ++yy) {
307 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
308 xx = xx0;
309 if (xx & 7) {
310 *p &= 0xff00 >> (xx & 7);
311 xx = (xx & ~7) + 8;
312 ++p;
313 }
314 for (; xx < xx1; xx += 8) {
315 *p++ = 0;
316 }
317 }
318 *x1 = splashFloor(x: xMax);
319 }
320
321 // check the paths
322 for (i = 0; i < length; ++i) {
323 scanners[i]->clipAALine(aaBuf, x0, x1, y);
324 }
325 if (*x0 > *x1) {
326 *x0 = *x1;
327 }
328 if (*x0 < 0) {
329 *x0 = 0;
330 }
331 if ((*x0 >> 1) >= aaBuf->getRowSize()) {
332 xx0 = *x0;
333 *x0 = (aaBuf->getRowSize() - 1) << 1;
334 if (xx0 & 1) {
335 *x0 = *x0 + 1;
336 }
337 }
338 if (*x1 < *x0) {
339 *x1 = *x0;
340 }
341 if ((*x1 >> 1) >= aaBuf->getRowSize()) {
342 xx0 = *x1;
343 *x1 = (aaBuf->getRowSize() - 1) << 1;
344 if (xx0 & 1) {
345 *x1 = *x1 + 1;
346 }
347 }
348}
349
350bool SplashClip::testClipPaths(int x, int y)
351{
352 if (antialias) {
353 x *= splashAASize;
354 y *= splashAASize;
355 }
356
357 for (int i = 0; i < length; ++i) {
358 if (!scanners[i]->test(x, y)) {
359 return false;
360 }
361 }
362
363 return true;
364}
365

source code of poppler/splash/SplashClip.cc