1 //========================================================================
3 // SplashXPathScanner.cc
5 //========================================================================
10 #pragma implementation
16 #include "SplashMath.h"
17 #include "SplashXPath.h"
18 #include "SplashBitmap.h"
19 #include "SplashXPathScanner.h"
21 //------------------------------------------------------------------------
23 struct SplashIntersect
{
24 int x0
, x1
; // intersection of segment with [y, y+1)
25 int count
; // EO/NZWN counter increment
28 static int cmpIntersect(const void *p0
, const void *p1
) {
29 return ((SplashIntersect
*)p0
)->x0
- ((SplashIntersect
*)p1
)->x0
;
32 //------------------------------------------------------------------------
34 //------------------------------------------------------------------------
36 SplashXPathScanner::SplashXPathScanner(SplashXPath
*xPathA
, GBool eoA
) {
38 SplashCoord xMinFP
, yMinFP
, xMaxFP
, yMaxFP
;
45 if (xPath
->length
== 0) {
49 seg
= &xPath
->segs
[0];
50 if (seg
->x0
<= seg
->x1
) {
57 if (seg
->flags
& splashXPathFlip
) {
64 for (i
= 1; i
< xPath
->length
; ++i
) {
65 seg
= &xPath
->segs
[i
];
66 if (seg
->x0
< xMinFP
) {
68 } else if (seg
->x0
> xMaxFP
) {
71 if (seg
->x1
< xMinFP
) {
73 } else if (seg
->x1
> xMaxFP
) {
76 if (seg
->flags
& splashXPathFlip
) {
77 if (seg
->y0
> yMaxFP
) {
81 if (seg
->y1
> yMaxFP
) {
86 xMin
= splashFloor(xMinFP
);
87 xMax
= splashFloor(xMaxFP
);
88 yMin
= splashFloor(yMinFP
);
89 yMax
= splashFloor(yMaxFP
);
95 interLen
= interSize
= 0;
98 SplashXPathScanner::~SplashXPathScanner() {
102 void SplashXPathScanner::getBBoxAA(int *xMinA
, int *yMinA
,
103 int *xMaxA
, int *yMaxA
) {
104 *xMinA
= xMin
/ splashAASize
;
105 *yMinA
= yMin
/ splashAASize
;
106 *xMaxA
= xMax
/ splashAASize
;
107 *yMaxA
= yMax
/ splashAASize
;
110 void SplashXPathScanner::getSpanBounds(int y
, int *spanXMin
, int *spanXMax
) {
112 computeIntersections(y
);
115 *spanXMin
= inter
[0].x0
;
116 *spanXMax
= inter
[interLen
- 1].x1
;
118 *spanXMin
= xMax
+ 1;
123 GBool
SplashXPathScanner::test(int x
, int y
) {
127 computeIntersections(y
);
130 for (i
= 0; i
< interLen
&& inter
[i
].x0
<= x
; ++i
) {
131 if (x
<= inter
[i
].x1
) {
134 count
+= inter
[i
].count
;
136 return eo
? (count
& 1) : (count
!= 0);
139 GBool
SplashXPathScanner::testSpan(int x0
, int x1
, int y
) {
143 computeIntersections(y
);
147 for (i
= 0; i
< interLen
&& inter
[i
].x1
< x0
; ++i
) {
148 count
+= inter
[i
].count
;
151 // invariant: the subspan [x0,xx1] is inside the path
157 if (inter
[i
].x0
> xx1
+ 1 &&
158 !(eo
? (count
& 1) : (count
!= 0))) {
161 if (inter
[i
].x1
> xx1
) {
164 count
+= inter
[i
].count
;
171 GBool
SplashXPathScanner::getNextSpan(int y
, int *x0
, int *x1
) {
175 computeIntersections(y
);
177 if (interIdx
>= interLen
) {
180 xx0
= inter
[interIdx
].x0
;
181 xx1
= inter
[interIdx
].x1
;
182 interCount
+= inter
[interIdx
].count
;
184 while (interIdx
< interLen
&&
185 (inter
[interIdx
].x0
<= xx1
||
186 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
187 if (inter
[interIdx
].x1
> xx1
) {
188 xx1
= inter
[interIdx
].x1
;
190 interCount
+= inter
[interIdx
].count
;
198 void SplashXPathScanner::computeIntersections(int y
) {
199 SplashCoord xSegMin
, xSegMax
, ySegMin
, ySegMax
, xx0
, xx1
;
203 // find the first segment that intersects [y, y+1)
204 i
= (y
>= interY
) ? xPathIdx
: 0;
205 while (i
< xPath
->length
&&
206 xPath
->segs
[i
].y0
< y
&& xPath
->segs
[i
].y1
< y
) {
211 // find all of the segments that intersect [y, y+1) and create an
212 // Intersect element for each one
214 for (j
= i
; j
< xPath
->length
; ++j
) {
215 seg
= &xPath
->segs
[j
];
216 if (seg
->flags
& splashXPathFlip
) {
224 // ensure that: ySegMin < y+1
226 if (ySegMin
>= y
+ 1) {
233 if (interLen
== interSize
) {
234 if (interSize
== 0) {
239 inter
= (SplashIntersect
*)greallocn(inter
, interSize
,
240 sizeof(SplashIntersect
));
243 if (seg
->flags
& splashXPathHoriz
) {
246 } else if (seg
->flags
& splashXPathVert
) {
249 if (seg
->x0
< seg
->x1
) {
256 // intersection with top edge
257 xx0
= seg
->x0
+ ((SplashCoord
)y
- seg
->y0
) * seg
->dxdy
;
258 // intersection with bottom edge
259 xx1
= seg
->x0
+ ((SplashCoord
)y
+ 1 - seg
->y0
) * seg
->dxdy
;
260 // the segment may not actually extend to the top and/or bottom edges
263 } else if (xx0
> xSegMax
) {
268 } else if (xx1
> xSegMax
) {
273 inter
[interLen
].x0
= splashFloor(xx0
);
274 inter
[interLen
].x1
= splashFloor(xx1
);
276 inter
[interLen
].x0
= splashFloor(xx1
);
277 inter
[interLen
].x1
= splashFloor(xx0
);
280 (SplashCoord
)y
< ySegMax
&&
281 !(seg
->flags
& splashXPathHoriz
)) {
282 inter
[interLen
].count
= eo
? 1
283 : (seg
->flags
& splashXPathFlip
) ? 1 : -1;
285 inter
[interLen
].count
= 0;
290 qsort(inter
, interLen
, sizeof(SplashIntersect
), &cmpIntersect
);
297 void SplashXPathScanner::renderAALine(SplashBitmap
*aaBuf
,
298 int *x0
, int *x1
, int y
) {
299 int xx0
, xx1
, xx
, xxMin
, xxMax
, yy
;
303 memset(aaBuf
->getDataPtr(), 0, aaBuf
->getRowSize() * aaBuf
->getHeight());
304 xxMin
= aaBuf
->getWidth();
306 for (yy
= 0; yy
< splashAASize
; ++yy
) {
307 computeIntersections(splashAASize
* y
+ yy
);
308 while (interIdx
< interLen
) {
309 xx0
= inter
[interIdx
].x0
;
310 xx1
= inter
[interIdx
].x1
;
311 interCount
+= inter
[interIdx
].count
;
313 while (interIdx
< interLen
&&
314 (inter
[interIdx
].x0
<= xx1
||
315 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
316 if (inter
[interIdx
].x1
> xx1
) {
317 xx1
= inter
[interIdx
].x1
;
319 interCount
+= inter
[interIdx
].count
;
326 if (xx1
> aaBuf
->getWidth()) {
327 xx1
= aaBuf
->getWidth();
329 // set [xx0, xx1) to 1
332 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
334 mask
= 0xff >> (xx
& 7);
335 if ((xx
& ~7) == (xx1
& ~7)) {
336 mask
&= (Guchar
)(0xff00 >> (xx1
& 7));
341 for (; xx
+ 7 < xx1
; xx
+= 8) {
345 *p
|= (Guchar
)(0xff00 >> (xx1
& 7));
356 *x0
= xxMin
/ splashAASize
;
357 *x1
= (xxMax
- 1) / splashAASize
;
360 void SplashXPathScanner::clipAALine(SplashBitmap
*aaBuf
,
361 int *x0
, int *x1
, int y
) {
362 int xx0
, xx1
, xx
, yy
;
366 for (yy
= 0; yy
< splashAASize
; ++yy
) {
367 xx
= *x0
* splashAASize
;
368 computeIntersections(splashAASize
* y
+ yy
);
369 while (interIdx
< interLen
&& xx
< (*x1
+ 1) * splashAASize
) {
370 xx0
= inter
[interIdx
].x0
;
371 xx1
= inter
[interIdx
].x1
;
372 interCount
+= inter
[interIdx
].count
;
374 while (interIdx
< interLen
&&
375 (inter
[interIdx
].x0
<= xx1
||
376 (eo
? (interCount
& 1) : (interCount
!= 0)))) {
377 if (inter
[interIdx
].x1
> xx1
) {
378 xx1
= inter
[interIdx
].x1
;
380 interCount
+= inter
[interIdx
].count
;
383 if (xx0
> aaBuf
->getWidth()) {
384 xx0
= aaBuf
->getWidth();
386 // set [xx, xx0) to 0
388 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
390 mask
= (Guchar
)(0xff00 >> (xx
& 7));
391 if ((xx
& ~7) == (xx0
& ~7)) {
392 mask
|= 0xff >> (xx0
& 7);
397 for (; xx
+ 7 <= xx0
; xx
+= 8) {
401 *p
&= 0xff >> (xx0
& 7);
408 xx0
= (*x1
+ 1) * splashAASize
;
409 // set [xx, xx0) to 0
411 p
= aaBuf
->getDataPtr() + yy
* aaBuf
->getRowSize() + (xx
>> 3);
413 mask
= (Guchar
)(0xff00 >> (xx
& 7));
414 if ((xx
& ~7) == (xx0
& ~7)) {
415 mask
&= 0xff >> (xx0
& 7);
420 for (; xx
+ 7 <= xx0
; xx
+= 8) {
424 *p
&= 0xff >> (xx0
& 7);