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 Albert Astals Cid <aacid@kde.org>
15
// Copyright (C) 2010 PaweÅ Wiejacha <pawel.wiejacha@gmail.com>
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
//========================================================================
24
#ifdef USE_GCC_PRAGMAS
25
#pragma implementation
32
#include "SplashMath.h"
33
#include "SplashXPath.h"
34
#include "SplashBitmap.h"
35
#include "SplashXPathScanner.h"
37
//------------------------------------------------------------------------
39
struct SplashIntersect {
40
int x0, x1; // intersection of segment with [y, y+1)
41
int count; // EO/NZWN counter increment
44
static bool cmpIntersect(const SplashIntersect &p0, const SplashIntersect &p1) {
48
//------------------------------------------------------------------------
50
//------------------------------------------------------------------------
52
SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) {
54
SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP;
61
if (xPath->length == 0) {
65
seg = &xPath->segs[0];
66
if (seg->x0 <= seg->x1) {
73
if (seg->flags & splashXPathFlip) {
80
for (i = 1; i < xPath->length; ++i) {
81
seg = &xPath->segs[i];
82
if (seg->x0 < xMinFP) {
84
} else if (seg->x0 > xMaxFP) {
87
if (seg->x1 < xMinFP) {
89
} else if (seg->x1 > xMaxFP) {
92
if (seg->flags & splashXPathFlip) {
93
if (seg->y0 > yMaxFP) {
97
if (seg->y1 > yMaxFP) {
102
xMin = splashFloor(xMinFP);
103
xMax = splashFloor(xMaxFP);
104
yMin = splashFloor(yMinFP);
105
yMax = splashFloor(yMaxFP);
111
interLen = interSize = 0;
114
SplashXPathScanner::~SplashXPathScanner() {
118
void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
119
int *xMaxA, int *yMaxA) {
120
*xMinA = xMin / splashAASize;
121
*yMinA = yMin / splashAASize;
122
*xMaxA = xMax / splashAASize;
123
*yMaxA = yMax / splashAASize;
126
void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
128
computeIntersections(y);
131
*spanXMin = inter[0].x0;
132
*spanXMax = inter[interLen - 1].x1;
134
*spanXMin = xMax + 1;
139
GBool SplashXPathScanner::test(int x, int y) {
143
computeIntersections(y);
146
for (i = 0; i < interLen && inter[i].x0 <= x; ++i) {
147
if (x <= inter[i].x1) {
150
count += inter[i].count;
152
return eo ? (count & 1) : (count != 0);
155
GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
159
computeIntersections(y);
163
for (i = 0; i < interLen && inter[i].x1 < x0; ++i) {
164
count += inter[i].count;
167
// invariant: the subspan [x0,xx1] is inside the path
173
if (inter[i].x0 > xx1 + 1 &&
174
!(eo ? (count & 1) : (count != 0))) {
177
if (inter[i].x1 > xx1) {
180
count += inter[i].count;
187
GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
191
computeIntersections(y);
193
if (interIdx >= interLen) {
196
xx0 = inter[interIdx].x0;
197
xx1 = inter[interIdx].x1;
198
interCount += inter[interIdx].count;
200
while (interIdx < interLen &&
201
(inter[interIdx].x0 <= xx1 ||
202
(eo ? (interCount & 1) : (interCount != 0)))) {
203
if (inter[interIdx].x1 > xx1) {
204
xx1 = inter[interIdx].x1;
206
interCount += inter[interIdx].count;
214
void SplashXPathScanner::computeIntersections(int y) {
215
SplashCoord xSegMin, xSegMax, ySegMin, ySegMax, xx0, xx1;
219
// find the first segment that intersects [y, y+1)
220
i = (y >= interY) ? xPathIdx : 0;
221
while (i < xPath->length &&
222
xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) {
227
// find all of the segments that intersect [y, y+1) and create an
228
// Intersect element for each one
230
for (j = i; j < xPath->length; ++j) {
231
seg = &xPath->segs[j];
232
if (seg->flags & splashXPathFlip) {
240
// ensure that: ySegMin < y+1
242
if (ySegMin >= y + 1) {
249
if (interLen == interSize) {
250
if (interSize == 0) {
255
inter = (SplashIntersect *)greallocn(inter, interSize,
256
sizeof(SplashIntersect));
259
if (seg->flags & splashXPathHoriz) {
262
} else if (seg->flags & splashXPathVert) {
265
if (seg->x0 < seg->x1) {
272
// intersection with top edge
273
xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy;
274
// intersection with bottom edge
275
xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy;
276
// the segment may not actually extend to the top and/or bottom edges
279
} else if (xx0 > xSegMax) {
284
} else if (xx1 > xSegMax) {
289
inter[interLen].x0 = splashFloor(xx0);
290
inter[interLen].x1 = splashFloor(xx1);
292
inter[interLen].x0 = splashFloor(xx1);
293
inter[interLen].x1 = splashFloor(xx0);
296
(SplashCoord)y < ySegMax &&
297
!(seg->flags & splashXPathHoriz)) {
298
inter[interLen].count = eo ? 1
299
: (seg->flags & splashXPathFlip) ? 1 : -1;
301
inter[interLen].count = 0;
306
std::sort(inter, inter + interLen, cmpIntersect);
313
void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
314
int *x0, int *x1, int y) {
315
int xx0, xx1, xx, xxMin, xxMax, yy;
319
memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight());
320
xxMin = aaBuf->getWidth();
322
for (yy = 0; yy < splashAASize; ++yy) {
323
computeIntersections(splashAASize * y + yy);
324
while (interIdx < interLen) {
325
xx0 = inter[interIdx].x0;
326
xx1 = inter[interIdx].x1;
327
interCount += inter[interIdx].count;
329
while (interIdx < interLen &&
330
(inter[interIdx].x0 <= xx1 ||
331
(eo ? (interCount & 1) : (interCount != 0)))) {
332
if (inter[interIdx].x1 > xx1) {
333
xx1 = inter[interIdx].x1;
335
interCount += inter[interIdx].count;
342
if (xx1 > aaBuf->getWidth()) {
343
xx1 = aaBuf->getWidth();
345
// set [xx0, xx1) to 1
348
p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
350
mask = 0xff >> (xx & 7);
351
if ((xx & ~7) == (xx1 & ~7)) {
352
mask &= (Guchar)(0xff00 >> (xx1 & 7));
357
for (; xx + 7 < xx1; xx += 8) {
361
*p |= (Guchar)(0xff00 >> (xx1 & 7));
372
*x0 = xxMin / splashAASize;
373
*x1 = (xxMax - 1) / splashAASize;
376
void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
377
int *x0, int *x1, int y) {
378
int xx0, xx1, xx, yy;
382
for (yy = 0; yy < splashAASize; ++yy) {
383
xx = *x0 * splashAASize;
384
computeIntersections(splashAASize * y + yy);
385
while (interIdx < interLen && xx < (*x1 + 1) * splashAASize) {
386
xx0 = inter[interIdx].x0;
387
xx1 = inter[interIdx].x1;
388
interCount += inter[interIdx].count;
390
while (interIdx < interLen &&
391
(inter[interIdx].x0 <= xx1 ||
392
(eo ? (interCount & 1) : (interCount != 0)))) {
393
if (inter[interIdx].x1 > xx1) {
394
xx1 = inter[interIdx].x1;
396
interCount += inter[interIdx].count;
399
if (xx0 > aaBuf->getWidth()) {
400
xx0 = aaBuf->getWidth();
402
// set [xx, xx0) to 0
404
p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
406
mask = (Guchar)(0xff00 >> (xx & 7));
407
if ((xx & ~7) == (xx0 & ~7)) {
408
mask |= 0xff >> (xx0 & 7);
413
for (; xx + 7 <= xx0; xx += 8) {
417
*p &= 0xff >> (xx0 & 7);
424
xx0 = (*x1 + 1) * splashAASize;
425
if (xx0 > aaBuf->getWidth()) xx0 = aaBuf->getWidth();
426
// set [xx, xx0) to 0
428
p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
430
mask = (Guchar)(0xff00 >> (xx & 7));
431
if ((xx & ~7) == (xx0 & ~7)) {
432
mask &= 0xff >> (xx0 & 7);
437
for (; xx + 7 <= xx0; xx += 8) {
441
*p &= 0xff >> (xx0 & 7);