beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / splash / SplashClip.cc
blob85c6b11473da8b8d1ec80f286253b2416cdfdd1b
1 //========================================================================
2 //
3 // SplashClip.cc
4 //
5 //========================================================================
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
17 // To see a description of the changes please see the Changelog file that
18 // came with your tarball or type make ChangeLog if you are building from git
20 //========================================================================
22 #include <config.h>
24 #ifdef USE_GCC_PRAGMAS
25 #pragma implementation
26 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #include "goo/gmem.h"
31 #include "SplashErrorCodes.h"
32 #include "SplashPath.h"
33 #include "SplashXPath.h"
34 #include "SplashXPathScanner.h"
35 #include "SplashBitmap.h"
36 #include "SplashClip.h"
38 //------------------------------------------------------------------------
39 // SplashClip.flags
40 //------------------------------------------------------------------------
42 #define splashClipEO 0x01 // use even-odd rule
44 //------------------------------------------------------------------------
45 // SplashClip
46 //------------------------------------------------------------------------
48 SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
49 SplashCoord x1, SplashCoord y1,
50 GBool antialiasA) {
51 antialias = antialiasA;
52 if (x0 < x1) {
53 xMin = x0;
54 xMax = x1;
55 } else {
56 xMin = x1;
57 xMax = x0;
59 if (y0 < y1) {
60 yMin = y0;
61 yMax = y1;
62 } else {
63 yMin = y1;
64 yMax = y0;
66 xMinI = splashFloor(xMin);
67 yMinI = splashFloor(yMin);
68 xMaxI = splashCeil(xMax) - 1;
69 yMaxI = splashCeil(yMax) - 1;
70 paths = NULL;
71 flags = NULL;
72 scanners = NULL;
73 length = size = 0;
76 SplashClip::SplashClip(SplashClip *clip) {
77 int yMinAA, yMaxAA;
78 int i;
80 antialias = clip->antialias;
81 xMin = clip->xMin;
82 yMin = clip->yMin;
83 xMax = clip->xMax;
84 yMax = clip->yMax;
85 xMinI = clip->xMinI;
86 yMinI = clip->yMinI;
87 xMaxI = clip->xMaxI;
88 yMaxI = clip->yMaxI;
89 length = clip->length;
90 size = clip->size;
91 paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
92 flags = (Guchar *)gmallocn(size, sizeof(Guchar));
93 scanners = (SplashXPathScanner **)
94 gmallocn(size, sizeof(SplashXPathScanner *));
95 for (i = 0; i < length; ++i) {
96 paths[i] = clip->paths[i]->copy();
97 flags[i] = clip->flags[i];
98 if (antialias) {
99 yMinAA = yMinI * splashAASize;
100 yMaxAA = (yMaxI + 1) * splashAASize - 1;
101 } else {
102 yMinAA = yMinI;
103 yMaxAA = yMaxI;
105 scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO,
106 yMinAA, yMaxAA);
110 SplashClip::~SplashClip() {
111 int i;
113 for (i = 0; i < length; ++i) {
114 delete paths[i];
115 delete scanners[i];
117 gfree(paths);
118 gfree(flags);
119 gfree(scanners);
122 void SplashClip::grow(int nPaths) {
123 if (length + nPaths > size) {
124 if (size == 0) {
125 size = 32;
127 while (size < length + nPaths) {
128 size *= 2;
130 paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
131 flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
132 scanners = (SplashXPathScanner **)
133 greallocn(scanners, size, sizeof(SplashXPathScanner *));
137 void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
138 SplashCoord x1, SplashCoord y1) {
139 int i;
141 for (i = 0; i < length; ++i) {
142 delete paths[i];
143 delete scanners[i];
145 gfree(paths);
146 gfree(flags);
147 gfree(scanners);
148 paths = NULL;
149 flags = NULL;
150 scanners = NULL;
151 length = size = 0;
153 if (x0 < x1) {
154 xMin = x0;
155 xMax = x1;
156 } else {
157 xMin = x1;
158 xMax = x0;
160 if (y0 < y1) {
161 yMin = y0;
162 yMax = y1;
163 } else {
164 yMin = y1;
165 yMax = y0;
167 xMinI = splashFloor(xMin);
168 yMinI = splashFloor(yMin);
169 xMaxI = splashCeil(xMax) - 1;
170 yMaxI = splashCeil(yMax) - 1;
173 SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
174 SplashCoord x1, SplashCoord y1) {
175 if (x0 < x1) {
176 if (x0 > xMin) {
177 xMin = x0;
178 xMinI = splashFloor(xMin);
180 if (x1 < xMax) {
181 xMax = x1;
182 xMaxI = splashCeil(xMax) - 1;
184 } else {
185 if (x1 > xMin) {
186 xMin = x1;
187 xMinI = splashFloor(xMin);
189 if (x0 < xMax) {
190 xMax = x0;
191 xMaxI = splashCeil(xMax) - 1;
194 if (y0 < y1) {
195 if (y0 > yMin) {
196 yMin = y0;
197 yMinI = splashFloor(yMin);
199 if (y1 < yMax) {
200 yMax = y1;
201 yMaxI = splashCeil(yMax) - 1;
203 } else {
204 if (y1 > yMin) {
205 yMin = y1;
206 yMinI = splashFloor(yMin);
208 if (y0 < yMax) {
209 yMax = y0;
210 yMaxI = splashCeil(yMax) - 1;
213 return splashOk;
216 SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
217 SplashCoord flatness, GBool eo) {
218 SplashXPath *xPath;
219 int yMinAA, yMaxAA;
221 xPath = new SplashXPath(path, matrix, flatness, gTrue);
223 // check for an empty path
224 if (xPath->length == 0) {
225 xMax = xMin - 1;
226 yMax = yMin - 1;
227 xMaxI = splashCeil(xMax) - 1;
228 yMaxI = splashCeil(yMax) - 1;
229 delete xPath;
231 // check for a rectangle
232 } else if (xPath->length == 4 &&
233 ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
234 xPath->segs[0].x0 == xPath->segs[1].x0 &&
235 xPath->segs[0].x0 == xPath->segs[3].x1 &&
236 xPath->segs[2].x0 == xPath->segs[2].x1 &&
237 xPath->segs[2].x0 == xPath->segs[1].x1 &&
238 xPath->segs[2].x0 == xPath->segs[3].x0 &&
239 xPath->segs[1].y0 == xPath->segs[1].y1 &&
240 xPath->segs[1].y0 == xPath->segs[0].y1 &&
241 xPath->segs[1].y0 == xPath->segs[2].y0 &&
242 xPath->segs[3].y0 == xPath->segs[3].y1 &&
243 xPath->segs[3].y0 == xPath->segs[0].y0 &&
244 xPath->segs[3].y0 == xPath->segs[2].y1) ||
245 (xPath->segs[0].y0 == xPath->segs[0].y1 &&
246 xPath->segs[0].y0 == xPath->segs[1].y0 &&
247 xPath->segs[0].y0 == xPath->segs[3].y1 &&
248 xPath->segs[2].y0 == xPath->segs[2].y1 &&
249 xPath->segs[2].y0 == xPath->segs[1].y1 &&
250 xPath->segs[2].y0 == xPath->segs[3].y0 &&
251 xPath->segs[1].x0 == xPath->segs[1].x1 &&
252 xPath->segs[1].x0 == xPath->segs[0].x1 &&
253 xPath->segs[1].x0 == xPath->segs[2].x0 &&
254 xPath->segs[3].x0 == xPath->segs[3].x1 &&
255 xPath->segs[3].x0 == xPath->segs[0].x0 &&
256 xPath->segs[3].x0 == xPath->segs[2].x1))) {
257 clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
258 xPath->segs[2].x0, xPath->segs[2].y0);
259 delete xPath;
261 } else {
262 grow(1);
263 if (antialias) {
264 xPath->aaScale();
266 xPath->sort();
267 paths[length] = xPath;
268 flags[length] = eo ? splashClipEO : 0;
269 if (antialias) {
270 yMinAA = yMinI * splashAASize;
271 yMaxAA = (yMaxI + 1) * splashAASize - 1;
272 } else {
273 yMinAA = yMinI;
274 yMaxAA = yMaxI;
276 scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
277 ++length;
280 return splashOk;
283 SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
284 int rectXMax, int rectYMax) {
285 // This tests the rectangle:
286 // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
287 // y = [rectYMin, rectYMax + 1)
288 // against the clipping region:
289 // x = [xMin, xMax) (note: clipping coords are fp)
290 // y = [yMin, yMax)
291 if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax ||
292 (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
293 return splashClipAllOutside;
295 if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
296 (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
297 length == 0) {
298 return splashClipAllInside;
300 return splashClipPartial;
303 SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
304 int i;
306 // This tests the rectangle:
307 // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
308 // y = [spanY, spanY + 1)
309 // against the clipping region:
310 // x = [xMin, xMax) (note: clipping coords are fp)
311 // y = [yMin, yMax)
312 if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax ||
313 (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
314 return splashClipAllOutside;
316 if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
317 (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
318 return splashClipPartial;
320 if (antialias) {
321 for (i = 0; i < length; ++i) {
322 if (!scanners[i]->testSpan(spanXMin * splashAASize,
323 spanXMax * splashAASize + (splashAASize - 1),
324 spanY * splashAASize)) {
325 return splashClipPartial;
328 } else {
329 for (i = 0; i < length; ++i) {
330 if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
331 return splashClipPartial;
335 return splashClipAllInside;
338 void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) {
339 int xx0, xx1, xx, yy, i;
340 SplashColorPtr p;
342 // zero out pixels with x < xMin
343 xx0 = *x0 * splashAASize;
344 xx1 = splashFloor(xMin * splashAASize);
345 if (xx1 > aaBuf->getWidth()) {
346 xx1 = aaBuf->getWidth();
348 if (xx0 < xx1) {
349 xx0 &= ~7;
350 for (yy = 0; yy < splashAASize; ++yy) {
351 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
352 for (xx = xx0; xx + 7 < xx1; xx += 8) {
353 *p++ = 0;
355 if (xx < xx1 && !adjustVertLine) {
356 *p &= 0xff >> (xx1 & 7);
359 *x0 = splashFloor(xMin);
362 // zero out pixels with x > xMax
363 xx0 = splashFloor(xMax * splashAASize) + 1;
364 if (xx0 < 0) {
365 xx0 = 0;
367 xx1 = (*x1 + 1) * splashAASize;
368 if (xx0 < xx1 && !adjustVertLine) {
369 for (yy = 0; yy < splashAASize; ++yy) {
370 p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
371 xx = xx0;
372 if (xx & 7) {
373 *p &= 0xff00 >> (xx & 7);
374 xx = (xx & ~7) + 8;
375 ++p;
377 for (; xx < xx1; xx += 8) {
378 *p++ = 0;
381 *x1 = splashFloor(xMax);
384 // check the paths
385 for (i = 0; i < length; ++i) {
386 scanners[i]->clipAALine(aaBuf, x0, x1, y);
388 if (*x0 > *x1) {
389 *x0 = *x1;
391 if (*x0 < 0) {
392 *x0 = 0;
394 if ((*x0>>1) >= aaBuf->getRowSize()) {
395 xx0 = *x0;
396 *x0 = (aaBuf->getRowSize() - 1) << 1;
397 if (xx0 & 1) {
398 *x0 = *x0 + 1;
401 if (*x1 < *x0) {
402 *x1 = *x0;
404 if ((*x1>>1) >= aaBuf->getRowSize()) {
405 xx0 = *x1;
406 *x1 = (aaBuf->getRowSize() - 1) << 1;
407 if (xx0 & 1) {
408 *x1 = *x1 + 1;