1 //========================================================================
3 // SplashXPathScanner.cc
5 //========================================================================
7 //========================================================================
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) 2008, 2010, 2014 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
16 // Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
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
21 //========================================================================
25 #ifdef USE_GCC_PRAGMAS
26 #pragma implementation
33 #include "SplashMath.h"
34 #include "SplashXPath.h"
35 #include "SplashBitmap.h"
36 #include "SplashXPathScanner.h"
38 //------------------------------------------------------------------------
40 struct SplashIntersect
{
42 int x0
, x1
; // intersection of segment with [y, y+1)
43 int count
; // EO/NZWN counter increment
46 struct cmpIntersectFunctor
{
47 bool operator()(const SplashIntersect
&i0
, const SplashIntersect
&i1
) {
48 return (i0
.y
!= i1
.y
) ? (i0
.y
< i1
.y
) : (i0
.x0
< i1
.x0
);
52 //------------------------------------------------------------------------
54 //------------------------------------------------------------------------
56 SplashXPathScanner::SplashXPathScanner(SplashXPath
*xPathA
, GBool eoA
,
57 int clipYMin
, int clipYMax
) {
59 SplashCoord xMinFP
, yMinFP
, xMaxFP
, yMaxFP
;
67 if (xPath
->length
== 0) {
71 seg
= &xPath
->segs
[0];
72 if (seg
->x0
<= seg
->x1
) {
79 if (seg
->flags
& splashXPathFlip
) {
86 for (i
= 1; i
< xPath
->length
; ++i
) {
87 seg
= &xPath
->segs
[i
];
88 if (seg
->x0
< xMinFP
) {
90 } else if (seg
->x0
> xMaxFP
) {
93 if (seg
->x1
< xMinFP
) {
95 } else if (seg
->x1
> xMaxFP
) {
98 if (seg
->flags
& splashXPathFlip
) {
99 if (seg
->y0
> yMaxFP
) {
103 if (seg
->y1
> yMaxFP
) {
108 xMin
= splashFloor(xMinFP
);
109 xMax
= splashFloor(xMaxFP
);
110 yMin
= splashFloor(yMinFP
);
111 yMax
= splashFloor(yMaxFP
);
112 if (clipYMin
> yMin
) {
116 if (clipYMax
< yMax
) {
124 computeIntersections();
128 SplashXPathScanner::~SplashXPathScanner() {
133 void SplashXPathScanner::getBBoxAA(int *xMinA
, int *yMinA
,
134 int *xMaxA
, int *yMaxA
) {
135 *xMinA
= xMin
/ splashAASize
;
136 *yMinA
= yMin
/ splashAASize
;
137 *xMaxA
= xMax
/ splashAASize
;
138 *yMaxA
= yMax
/ splashAASize
;
141 void SplashXPathScanner::getSpanBounds(int y
, int *spanXMin
, int *spanXMax
) {
142 int interBegin
, interEnd
, xx
, i
;
144 if (y
< yMin
|| y
> yMax
) {
145 interBegin
= interEnd
= 0;
147 interBegin
= inter
[y
- yMin
];
148 interEnd
= inter
[y
- yMin
+ 1];
150 if (interBegin
< interEnd
) {
151 *spanXMin
= allInter
[interBegin
].x0
;
152 xx
= allInter
[interBegin
].x1
;
153 for (i
= interBegin
+ 1; i
< interEnd
; ++i
) {
154 if (allInter
[i
].x1
> xx
) {
160 *spanXMin
= xMax
+ 1;
165 GBool
SplashXPathScanner::test(int x
, int y
) {
166 int interBegin
, interEnd
, count
, i
;
168 if (y
< yMin
|| y
> yMax
) {
171 interBegin
= inter
[y
- yMin
];
172 interEnd
= inter
[y
- yMin
+ 1];
174 for (i
= interBegin
; i
< interEnd
&& allInter
[i
].x0
<= x
; ++i
) {
175 if (x
<= allInter
[i
].x1
) {
178 count
+= allInter
[i
].count
;
180 return eo
? (count
& 1) : (count
!= 0);
183 GBool
SplashXPathScanner::testSpan(int x0
, int x1
, int y
) {
184 int interBegin
, interEnd
, count
, xx1
, i
;
186 if (y
< yMin
|| y
> yMax
) {
189 interBegin
= inter
[y
- yMin
];
190 interEnd
= inter
[y
- yMin
+ 1];
192 for (i
= interBegin
; i
< interEnd
&& allInter
[i
].x1
< x0
; ++i
) {
193 count
+= allInter
[i
].count
;
196 // invariant: the subspan [x0,xx1] is inside the path
202 if (allInter
[i
].x0
> xx1
+ 1 &&
203 !(eo
? (count
& 1) : (count
!= 0))) {
206 if (allInter
[i
].x1
> xx1
) {
207 xx1
= allInter
[i
].x1
;
209 count
+= allInter
[i
].count
;
216 GBool
SplashXPathScanner::getNextSpan(int y
, int *x0
, int *x1
) {
217 int interEnd
, xx0
, xx1
;
219 if (y
< yMin
|| y
> yMax
) {
224 interIdx
= inter
[y
- yMin
];
227 interEnd
= inter
[y
- yMin
+ 1];
228 if (interIdx
>= interEnd
) {
231 xx0
= allInter
[interIdx
].x0
;
232 xx1
= allInter
[interIdx
].x1
;
233 interCount
+= allInter
[interIdx
].count
;
235 while (interIdx
< interEnd
&&
236 (allInter
[interIdx
].x0
<= xx1
||
237 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
238 if (allInter
[interIdx
].x1
> xx1
) {
239 xx1
= allInter
[interIdx
].x1
;
241 interCount
+= allInter
[interIdx
].count
;
249 void SplashXPathScanner::computeIntersections() {
251 SplashCoord segXMin
, segXMax
, segYMin
, segYMax
, xx0
, xx1
;
258 // build the list of all intersections
261 allInter
= (SplashIntersect
*)gmallocn(allInterSize
,
262 sizeof(SplashIntersect
));
263 for (i
= 0; i
< xPath
->length
; ++i
) {
264 seg
= &xPath
->segs
[i
];
265 if (seg
->flags
& splashXPathFlip
) {
272 if (seg
->flags
& splashXPathHoriz
) {
273 y
= splashFloor(seg
->y0
);
274 if (y
>= yMin
&& y
<= yMax
) {
275 if (!addIntersection(segYMin
, segYMax
, seg
->flags
,
276 y
, splashFloor(seg
->x0
), splashFloor(seg
->x1
)))
279 } else if (seg
->flags
& splashXPathVert
) {
280 y0
= splashFloor(segYMin
);
284 y1
= splashFloor(segYMax
);
288 x
= splashFloor(seg
->x0
);
289 for (y
= y0
; y
<= y1
; ++y
) {
290 if (!addIntersection(segYMin
, segYMax
, seg
->flags
, y
, x
, x
))
294 if (seg
->x0
< seg
->x1
) {
301 y0
= splashFloor(segYMin
);
305 y1
= splashFloor(segYMax
);
309 // this loop could just add seg->dxdy to xx1 on each iteration,
310 // but that introduces numerical accuracy problems
311 xx1
= seg
->x0
+ ((SplashCoord
)y0
- seg
->y0
) * seg
->dxdy
;
312 for (y
= y0
; y
<= y1
; ++y
) {
314 xx1
= seg
->x0
+ ((SplashCoord
)(y
+ 1) - seg
->y0
) * seg
->dxdy
;
315 // the segment may not actually extend to the top and/or bottom edges
318 } else if (xx0
> segXMax
) {
323 } else if (xx1
> segXMax
) {
326 if (!addIntersection(segYMin
, segYMax
, seg
->flags
, y
,
327 splashFloor(xx0
), splashFloor(xx1
)))
332 std::sort(allInter
, allInter
+ allInterLen
, cmpIntersectFunctor());
334 // build the list of y pointers
335 inter
= (int *)gmallocn(yMax
- yMin
+ 2, sizeof(int));
337 for (y
= yMin
; y
<= yMax
; ++y
) {
339 while (i
< allInterLen
&& allInter
[i
].y
<= y
) {
343 inter
[yMax
- yMin
+ 1] = i
;
346 GBool
SplashXPathScanner::addIntersection(double segYMin
, double segYMax
,
348 int y
, int x0
, int x1
) {
349 if (allInterLen
== allInterSize
) {
350 unsigned int newInterSize
= ((unsigned int) allInterSize
* 2 > INT_MAX
/ sizeof(SplashIntersect
)) ? allInterSize
+ 32768 : allInterSize
* 2;
351 if (newInterSize
>= INT_MAX
/ sizeof(SplashIntersect
)) {
352 error(errInternal
, -1, "Bogus memory allocation size in SplashXPathScanner::addIntersection {0:d}", newInterSize
);
355 allInterSize
= newInterSize
;
356 allInter
= (SplashIntersect
*)greallocn(allInter
, newInterSize
,
357 sizeof(SplashIntersect
));
359 allInter
[allInterLen
].y
= y
;
361 allInter
[allInterLen
].x0
= x0
;
362 allInter
[allInterLen
].x1
= x1
;
364 allInter
[allInterLen
].x0
= x1
;
365 allInter
[allInterLen
].x1
= x0
;
368 (SplashCoord
)y
< segYMax
&&
369 !(segFlags
& splashXPathHoriz
)) {
370 allInter
[allInterLen
].count
= eo
? 1
371 : (segFlags
& splashXPathFlip
) ? 1 : -1;
373 allInter
[allInterLen
].count
= 0;
379 void SplashXPathScanner::renderAALine(SplashBitmap
*aaBuf
,
380 int *x0
, int *x1
, int y
, GBool adjustVertLine
) {
381 int xx0
, xx1
, xx
, xxMin
, xxMax
, yy
, interEnd
;
385 memset(aaBuf
->getDataPtr(), 0, aaBuf
->getRowSize() * aaBuf
->getHeight());
386 xxMin
= aaBuf
->getWidth();
389 if (splashAASize
* y
< yMin
) {
391 } else if (splashAASize
* y
> yMax
) {
392 interIdx
= inter
[yMax
- yMin
+ 1];
394 interIdx
= inter
[splashAASize
* y
- yMin
];
396 for (yy
= 0; yy
< splashAASize
; ++yy
) {
397 if (splashAASize
* y
+ yy
< yMin
) {
399 } else if (splashAASize
* y
+ yy
> yMax
) {
400 interEnd
= inter
[yMax
- yMin
+ 1];
402 interEnd
= inter
[splashAASize
* y
+ yy
- yMin
+ 1];
405 while (interIdx
< interEnd
) {
406 xx0
= allInter
[interIdx
].x0
;
407 xx1
= allInter
[interIdx
].x1
;
408 interCount
+= allInter
[interIdx
].count
;
410 while (interIdx
< interEnd
&&
411 (allInter
[interIdx
].x0
<= xx1
||
412 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
413 if (allInter
[interIdx
].x1
> xx1
) {
414 xx1
= allInter
[interIdx
].x1
;
416 interCount
+= allInter
[interIdx
].count
;
423 if (xx1
> aaBuf
->getWidth()) {
424 xx1
= aaBuf
->getWidth();
426 // set [xx0, xx1) to 1
429 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
431 mask
= adjustVertLine
? 0xff : 0xff >> (xx
& 7);
432 if (!adjustVertLine
&& (xx
& ~7) == (xx1
& ~7)) {
433 mask
&= (Guchar
)(0xff00 >> (xx1
& 7));
438 for (; xx
+ 7 < xx1
; xx
+= 8) {
442 *p
|= adjustVertLine
? 0xff : (Guchar
)(0xff00 >> (xx1
& 7));
457 *x0
= xxMin
/ splashAASize
;
458 *x1
= (xxMax
- 1) / splashAASize
;
461 void SplashXPathScanner::clipAALine(SplashBitmap
*aaBuf
,
462 int *x0
, int *x1
, int y
) {
463 int xx0
, xx1
, xx
, yy
, interEnd
;
467 for (yy
= 0; yy
< splashAASize
; ++yy
) {
468 xx
= *x0
* splashAASize
;
470 if (splashAASize
* y
+ yy
< yMin
) {
471 interIdx
= interEnd
= inter
[0];
472 } else if (splashAASize
* y
+ yy
> yMax
) {
473 interIdx
= interEnd
= inter
[yMax
- yMin
+ 1];
475 interIdx
= inter
[splashAASize
* y
+ yy
- yMin
];
476 if (splashAASize
* y
+ yy
> yMax
) {
477 interEnd
= inter
[yMax
- yMin
+ 1];
479 interEnd
= inter
[splashAASize
* y
+ yy
- yMin
+ 1];
483 while (interIdx
< interEnd
&& xx
< (*x1
+ 1) * splashAASize
) {
484 xx0
= allInter
[interIdx
].x0
;
485 xx1
= allInter
[interIdx
].x1
;
486 interCount
+= allInter
[interIdx
].count
;
488 while (interIdx
< interEnd
&&
489 (allInter
[interIdx
].x0
<= xx1
||
490 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
491 if (allInter
[interIdx
].x1
> xx1
) {
492 xx1
= allInter
[interIdx
].x1
;
494 interCount
+= allInter
[interIdx
].count
;
497 if (xx0
> aaBuf
->getWidth()) {
498 xx0
= aaBuf
->getWidth();
500 // set [xx, xx0) to 0
502 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
504 mask
= (Guchar
)(0xff00 >> (xx
& 7));
505 if ((xx
& ~7) == (xx0
& ~7)) {
506 mask
|= 0xff >> (xx0
& 7);
511 for (; xx
+ 7 < xx0
; xx
+= 8) {
515 *p
&= 0xff >> (xx0
& 7);
523 xx0
= (*x1
+ 1) * splashAASize
;
524 if (xx0
> aaBuf
->getWidth()) xx0
= aaBuf
->getWidth();
525 // set [xx, xx0) to 0
526 if (xx
< xx0
&& xx
>= 0) {
527 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
529 mask
= (Guchar
)(0xff00 >> (xx
& 7));
530 if ((xx
& ~7) == (xx0
& ~7)) {
531 mask
&= 0xff >> (xx0
& 7);
536 for (; xx
+ 7 < xx0
; xx
+= 8) {
540 *p
&= 0xff >> (xx0
& 7);