splash/Splash.cc | 9 - splash/SplashXPathScanner.cc | 271 +++++++++++++++++++------------------------ splash/SplashXPathScanner.h | 46 ++++--- 3 files changed, 157 insertions(+), 169 deletions(-)
New commits: commit 0118e221548303b71c2b40a878526d017ef64db5 Author: Stefan Brüns <[email protected]> Date: Mon Aug 27 02:12:08 2018 +0200 SplashXPathScanner: Reduce complexity of sorting spans For complex paths, a significant amount of time is spent in SplashXPathScanner::computeIntersections, more specifically with sorting the spans in y/x order. Instead of using one large array for all spans, use a 2-dimensional structure. As the number of y positions is known upfront, it is possible to create an array for the y dimension and insert the spans directly at the appropriate position. For Y rows with X spans per row, this reduces the complexity for sorting from O( Y*X log Y*X) to O( Y * X log X), i.e. a reduction by log Y. For the documents from #57 (fdo#96728) and #24 (fdo#78728), the runtime/memory is significantly reduced (according to /usr/bin/time -v): (1) $> pdftoppm -r 18 -aa no runsforever-poppler.pdf (2) $> pdftoppm surf-types.pdf Before/After runsforever-poppler | surf-types User time (seconds): 2979.80 / 2348.08 | 9.45 / 7.76 Maximum resident set size (kbytes): 51208 / 46288 | 18084 / 14076 diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc index 41600122..b1121693 100644 --- a/splash/SplashXPathScanner.cc +++ b/splash/SplashXPathScanner.cc @@ -37,17 +37,6 @@ //------------------------------------------------------------------------ -struct SplashIntersect { - int y; - int x0, x1; // intersection of segment with [y, y+1) - int count; // EO/NZWN counter increment -}; - -struct cmpIntersectFunctor { - bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) { - return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0); - } -}; //------------------------------------------------------------------------ // SplashXPathScanner @@ -119,14 +108,10 @@ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, } } - allInter = nullptr; - inter = nullptr; computeIntersections(); } SplashXPathScanner::~SplashXPathScanner() { - gfree(inter); - gfree(allInter); } void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, @@ -138,20 +123,18 @@ void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, } void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { - int interBegin, interEnd, xx, i; - if (y < yMin || y > yMax) { - interBegin = interEnd = 0; - } else { - interBegin = inter[y - yMin]; - interEnd = inter[y - yMin + 1]; + *spanXMin = xMax + 1; + *spanXMax = xMax; + return; } - if (interBegin < interEnd) { - *spanXMin = allInter[interBegin].x0; - xx = allInter[interBegin].x1; - for (i = interBegin + 1; i < interEnd; ++i) { - if (allInter[i].x1 > xx) { - xx = allInter[i].x1; + const auto& line = allIntersections[y - yMin]; + if (!line.empty()) { + *spanXMin = line[0].x0; + int xx = line[0].x1; + for (unsigned int i = 1; i < line.size(); ++i) { + if (line[i].x1 > xx) { + xx = line[i].x1; } } *spanXMax = xx; @@ -162,50 +145,46 @@ void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { } GBool SplashXPathScanner::test(int x, int y) { - int interBegin, interEnd, count, i; - if (y < yMin || y > yMax) { return gFalse; } - interBegin = inter[y - yMin]; - interEnd = inter[y - yMin + 1]; - count = 0; - for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) { - if (x <= allInter[i].x1) { + const auto& line = allIntersections[y - yMin]; + int count = 0; + for (unsigned int i = 0; i < line.size() && line[i].x0 <= x; ++i) { + if (x <= line[i].x1) { return gTrue; } - count += allInter[i].count; + count += line[i].count; } return eo ? (count & 1) : (count != 0); } GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { - int interBegin, interEnd, count, xx1, i; + unsigned int i; if (y < yMin || y > yMax) { return gFalse; } - interBegin = inter[y - yMin]; - interEnd = inter[y - yMin + 1]; - count = 0; - for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) { - count += allInter[i].count; + const auto& line = allIntersections[y - yMin]; + int count = 0; + for (i = 0; i < line.size() && line[i].x1 < x0; ++i) { + count += line[i].count; } // invariant: the subspan [x0,xx1] is inside the path - xx1 = x0 - 1; + int xx1 = x0 - 1; while (xx1 < x1) { - if (i >= interEnd) { + if (i >= line.size()) { return gFalse; } - if (allInter[i].x0 > xx1 + 1 && + if (line[i].x0 > xx1 + 1 && !(eo ? (count & 1) : (count != 0))) { return gFalse; } - if (allInter[i].x1 > xx1) { - xx1 = allInter[i].x1; + if (line[i].x1 > xx1) { + xx1 = line[i].x1; } - count += allInter[i].count; + count += line[i].count; ++i; } @@ -215,20 +194,20 @@ GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { GBool SplashXPathScanIterator::getNextSpan(int *x0, int *x1) { int xx0, xx1; - if (interIdx >= interEnd) { + if (interIdx >= line.size()) { return gFalse; } - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; + xx0 = line[interIdx].x0; + xx1 = line[interIdx].x1; + interCount += line[interIdx].count; ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || + while (interIdx < line.size() && + (line[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; + if (line[interIdx].x1 > xx1) { + xx1 = line[interIdx].x1; } - interCount += allInter[interIdx].count; + interCount += line[interIdx].count; ++interIdx; } *x0 = xx0; @@ -236,22 +215,20 @@ GBool SplashXPathScanIterator::getNextSpan(int *x0, int *x1) { return gTrue; } -SplashXPathScanIterator::SplashXPathScanIterator(const SplashXPathScanner &scanner, int y) { - allInter(nullptr), +SplashXPathScanIterator::SplashXPathScanIterator(const SplashXPathScanner &scanner, int y) : + line( + (y < scanner.yMin || y > scanner.yMax) ? + scanner.allIntersections[0] : + scanner.allIntersections[y - scanner.yMin] + ), interIdx(0), - interEnd(0), interCount(0), eo(scanner.eo) { if (y < scanner.yMin || y > scanner.yMax) { - return; + // set index to line end + interIdx = line.size(); } - - allInter = scanner.allInter; - interIdx = scanner.inter[y - scanner.yMin]; - // no special handling for last row needed, - // last inter entry contains sentinel value, allInterLen - interEnd = scanner.inter[y - scanner.yMin + 1]; } void SplashXPathScanner::computeIntersections() { @@ -264,10 +241,8 @@ void SplashXPathScanner::computeIntersections() { } // build the list of all intersections - allInterLen = 0; - allInterSize = 16; - allInter = (SplashIntersect *)gmallocn(allInterSize, - sizeof(SplashIntersect)); + allIntersections.resize(yMax - yMin + 1); + for (i = 0; i < xPath->length; ++i) { seg = &xPath->segs[i]; if (seg->flags & splashXPathFlip) { @@ -337,56 +312,48 @@ void SplashXPathScanner::computeIntersections() { } } } - std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor()); - - // build the list of y pointers - inter = (int *)gmallocn(yMax - yMin + 2, sizeof(int)); - i = 0; - for (y = yMin; y <= yMax; ++y) { - inter[y - yMin] = i; - while (i < allInterLen && allInter[i].y <= y) { - ++i; - } + for (auto& line : allIntersections) { + std::sort(line.begin(), line.end(), + [](const SplashIntersect &i0, const SplashIntersect &i1) { + return i0.x0 < i1.x0; + }); } - inter[yMax - yMin + 1] = i; } GBool SplashXPathScanner::addIntersection(double segYMin, double segYMax, Guint segFlags, int y, int x0, int x1) { - if (allInterLen == allInterSize) { - unsigned int newInterSize = ((unsigned int) allInterSize * 2 > INT_MAX / sizeof(SplashIntersect)) ? allInterSize + 32768 : allInterSize * 2; - if (newInterSize >= INT_MAX / sizeof(SplashIntersect)) { - error(errInternal, -1, "Bogus memory allocation size in SplashXPathScanner::addIntersection {0:d}", newInterSize); - return gFalse; - } - allInterSize = newInterSize; - allInter = (SplashIntersect *)greallocn(allInter, newInterSize, - sizeof(SplashIntersect)); - } - allInter[allInterLen].y = y; + SplashIntersect intersect; + intersect.y = y; if (x0 < x1) { - allInter[allInterLen].x0 = x0; - allInter[allInterLen].x1 = x1; + intersect.x0 = x0; + intersect.x1 = x1; } else { - allInter[allInterLen].x0 = x1; - allInter[allInterLen].x1 = x0; + intersect.x0 = x1; + intersect.x1 = x0; } if (segYMin <= y && (SplashCoord)y < segYMax && !(segFlags & splashXPathHoriz)) { - allInter[allInterLen].count = eo ? 1 - : (segFlags & splashXPathFlip) ? 1 : -1; + intersect.count = eo ? 1 + : (segFlags & splashXPathFlip) ? 1 : -1; } else { - allInter[allInterLen].count = 0; + intersect.count = 0; + } + + auto& line = allIntersections[y - yMin]; + if (line.empty()) { + line.reserve(4); } - ++allInterLen; + line.push_back(intersect); + return gTrue; } void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) { - int xx0, xx1, xx, xxMin, xxMax, yy, yyMax, interEnd, interIdx, interCount; + int xx0, xx1, xx, xxMin, xxMax, yy, yyMax, interCount; + size_t interIdx; Guchar mask; SplashColorPtr p; @@ -403,23 +370,23 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, if (yyMax + splashAASize * y > yMax) { yyMax = yMax - splashAASize * y; } - interIdx = inter[splashAASize * y + yy - yMin]; for (; yy <= yyMax; ++yy) { - interEnd = inter[splashAASize * y + yy - yMin + 1]; + const auto& line = allIntersections[splashAASize * y + yy - yMin]; + interIdx = 0; interCount = 0; - while (interIdx < interEnd) { - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; + while (interIdx < line.size()) { + xx0 = line[interIdx].x0; + xx1 = line[interIdx].x1; + interCount += line[interIdx].count; ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || + while (interIdx < line.size() && + (line[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; + if (line[interIdx].x1 > xx1) { + xx1 = line[interIdx].x1; } - interCount += allInter[interIdx].count; + interCount += line[interIdx].count; ++interIdx; } if (xx0 < 0) { @@ -466,7 +433,8 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { - int xx0, xx1, xx, yy, yyMin, yyMax, interEnd, interIdx, interCount; + int xx0, xx1, xx, yy, yyMin, yyMax, interCount; + size_t interIdx; Guchar mask; SplashColorPtr p; @@ -482,21 +450,21 @@ void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, for (yy = 0; yy < splashAASize; ++yy) { xx = *x0 * splashAASize; if (yy >= yyMin && yy <= yyMax) { - interIdx = inter[splashAASize * y + yy - yMin]; - interEnd = inter[splashAASize * y + yy - yMin + 1]; + const auto& line = allIntersections[splashAASize * y + yy - yMin]; + interIdx = 0; interCount = 0; - while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) { - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; + while (interIdx < line.size() && xx < (*x1 + 1) * splashAASize) { + xx0 = line[interIdx].x0; + xx1 = line[interIdx].x1; + interCount += line[interIdx].count; ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || + while (interIdx < line.size() && + (line[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; + if (line[interIdx].x1 > xx1) { + xx1 = line[interIdx].x1; } - interCount += allInter[interIdx].count; + interCount += line[interIdx].count; ++interIdx; } if (xx0 > aaBuf->getWidth()) { diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h index d815878a..427448af 100644 --- a/splash/SplashXPathScanner.h +++ b/splash/SplashXPathScanner.h @@ -28,9 +28,16 @@ #include "SplashTypes.h" +#include <vector> + class SplashXPath; class SplashBitmap; -struct SplashIntersect; + +struct SplashIntersect { + int y; + int x0, x1; // intersection of segment with [y, y+1) + int count; // EO/NZWN counter increment +}; //------------------------------------------------------------------------ // SplashXPathScanner @@ -91,10 +98,8 @@ private: int xMin, yMin, xMax, yMax; GBool partialClip; - SplashIntersect *allInter; // array of intersections - int allInterLen; // number of intersections in <allInter> - int allInterSize; // size of the <allInter> array - int *inter; // indexes into <allInter> for each y value + typedef std::vector<SplashIntersect> IntersectionLine; + std::vector<IntersectionLine> allIntersections; friend class SplashXPathScanIterator; }; @@ -108,9 +113,10 @@ public: GBool getNextSpan(int *x0, int *x1); private: - const SplashIntersect *allInter; - int interIdx; // current index into <allInter> - int interEnd; // last index into <allInter>, noninclusive + typedef std::vector<SplashIntersect> IntersectionLine; + const IntersectionLine &line; + + size_t interIdx; // current index into <line> int interCount; // current EO/NZWN counter const GBool eo; }; commit 7ef04b5643c6bad8cd4b6f6fc4aa9b800c49406f Author: Stefan Brüns <[email protected]> Date: Fri Aug 24 00:50:26 2018 +0200 SplashXPathScanner: Clamp y range to yMin/yMax outside the loop Instead of implicitly clamping by setting interIdx == interEnd, calculate the first and last y position outside the loop, and use these as loop bounds. diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc index b41245a7..41600122 100644 --- a/splash/SplashXPathScanner.cc +++ b/splash/SplashXPathScanner.cc @@ -386,7 +386,7 @@ GBool SplashXPathScanner::addIntersection(double segYMin, double segYMax, void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) { - int xx0, xx1, xx, xxMin, xxMax, yy, interEnd, interIdx, interCount; + int xx0, xx1, xx, xxMin, xxMax, yy, yyMax, interEnd, interIdx, interCount; Guchar mask; SplashColorPtr p; @@ -394,21 +394,19 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, xxMin = aaBuf->getWidth(); xxMax = -1; if (yMin <= yMax) { - if (splashAASize * y < yMin) { - interIdx = inter[0]; - } else if (splashAASize * y > yMax) { - interIdx = inter[yMax - yMin + 1]; - } else { - interIdx = inter[splashAASize * y - yMin]; + yy = 0; + yyMax = splashAASize - 1; + // clamp start and end position + if (yMin > splashAASize * y) { + yy = yMin - splashAASize * y; } - for (yy = 0; yy < splashAASize; ++yy) { - if (splashAASize * y + yy < yMin) { - interEnd = inter[0]; - } else if (splashAASize * y + yy > yMax) { - interEnd = inter[yMax - yMin + 1]; - } else { - interEnd = inter[splashAASize * y + yy - yMin + 1]; - } + if (yyMax + splashAASize * y > yMax) { + yyMax = yMax - splashAASize * y; + } + interIdx = inter[splashAASize * y + yy - yMin]; + + for (; yy <= yyMax; ++yy) { + interEnd = inter[splashAASize * y + yy - yMin + 1]; interCount = 0; while (interIdx < interEnd) { xx0 = allInter[interIdx].x0; @@ -468,25 +466,24 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { - int xx0, xx1, xx, yy, interEnd, interIdx, interCount; + int xx0, xx1, xx, yy, yyMin, yyMax, interEnd, interIdx, interCount; Guchar mask; SplashColorPtr p; + yyMin = 0; + yyMax = splashAASize - 1; + // clamp start and end position + if (yMin > splashAASize * y) { + yyMin = yMin - splashAASize * y; + } + if (yyMax + splashAASize * y > yMax) { + yyMax = yMax - splashAASize * y; + } for (yy = 0; yy < splashAASize; ++yy) { xx = *x0 * splashAASize; - if (yMin <= yMax) { - if (splashAASize * y + yy < yMin) { - interIdx = interEnd = inter[0]; - } else if (splashAASize * y + yy > yMax) { - interIdx = interEnd = inter[yMax - yMin + 1]; - } else { - interIdx = inter[splashAASize * y + yy - yMin]; - if (splashAASize * y + yy > yMax) { - interEnd = inter[yMax - yMin + 1]; - } else { - interEnd = inter[splashAASize * y + yy - yMin + 1]; - } - } + if (yy >= yyMin && yy <= yyMax) { + interIdx = inter[splashAASize * y + yy - yMin]; + interEnd = inter[splashAASize * y + yy - yMin + 1]; interCount = 0; while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) { xx0 = allInter[interIdx].x0; commit 68fdbfd0b159e8cf146c480f0d14f5d7adfd5806 Author: Stefan Brüns <[email protected]> Date: Sat May 26 19:51:21 2018 +0200 SplashXPathScanner: Move state out of SplashXPathScanner for iterating spans Iterating through spans is independent of the spans itself. Moving the iteration to a seperate class allows to keep the iteration state out of SplashXPathScanner, and also allows to move invariant code out of getNextSpan(...). diff --git a/splash/Splash.cc b/splash/Splash.cc index e8b76ec0..187b99a7 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -2607,7 +2607,8 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, } } else { for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { + SplashXPathScanIterator iterator(*scanner, y); + while (iterator.getNextSpan(&x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(&pipe, x0, x1, y, gTrue); } else { @@ -2729,7 +2730,8 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) { // draw the spans for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { + SplashXPathScanIterator iterator(*scanner, y); + while (iterator.getNextSpan(&x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(&pipe, x0, x1, y, gTrue); } else { @@ -6491,7 +6493,8 @@ SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox, } else { SplashClipResult clipRes2; for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { + SplashXPathScanIterator iterator(*scanner, y); + while (iterator.getNextSpan(&x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(&pipe, x0, x1, y, gTrue); } else { diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc index 1e48e90b..b41245a7 100644 --- a/splash/SplashXPathScanner.cc +++ b/splash/SplashXPathScanner.cc @@ -122,7 +122,6 @@ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, allInter = nullptr; inter = nullptr; computeIntersections(); - interY = yMin - 1; } SplashXPathScanner::~SplashXPathScanner() { @@ -213,18 +212,9 @@ GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { return gTrue; } -GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { - int interEnd, xx0, xx1; +GBool SplashXPathScanIterator::getNextSpan(int *x0, int *x1) { + int xx0, xx1; - if (y < yMin || y > yMax) { - return gFalse; - } - if (interY != y) { - interY = y; - interIdx = inter[y - yMin]; - interCount = 0; - } - interEnd = inter[y - yMin + 1]; if (interIdx >= interEnd) { return gFalse; } @@ -246,6 +236,24 @@ GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { return gTrue; } +SplashXPathScanIterator::SplashXPathScanIterator(const SplashXPathScanner &scanner, int y) { + allInter(nullptr), + interIdx(0), + interEnd(0), + interCount(0), + eo(scanner.eo) +{ + if (y < scanner.yMin || y > scanner.yMax) { + return; + } + + allInter = scanner.allInter; + interIdx = scanner.inter[y - scanner.yMin]; + // no special handling for last row needed, + // last inter entry contains sentinel value, allInterLen + interEnd = scanner.inter[y - scanner.yMin + 1]; +} + void SplashXPathScanner::computeIntersections() { SplashXPathSeg *seg; SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1; @@ -378,7 +386,7 @@ GBool SplashXPathScanner::addIntersection(double segYMin, double segYMax, void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) { - int xx0, xx1, xx, xxMin, xxMax, yy, interEnd; + int xx0, xx1, xx, xxMin, xxMax, yy, interEnd, interIdx, interCount; Guchar mask; SplashColorPtr p; @@ -460,7 +468,7 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { - int xx0, xx1, xx, yy, interEnd; + int xx0, xx1, xx, yy, interEnd, interIdx, interCount; Guchar mask; SplashColorPtr p; diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h index b6c358d9..d815878a 100644 --- a/splash/SplashXPathScanner.h +++ b/splash/SplashXPathScanner.h @@ -69,13 +69,6 @@ public: // path. GBool testSpan(int x0, int x1, int y); - // Returns the next span inside the path at <y>. If <y> is - // different than the previous call to getNextSpan, this returns the - // first span at <y>; otherwise it returns the next span (relative - // to the previous call to getNextSpan). Returns false if there are - // no more spans at <y>. - GBool getNextSpan(int y, int *x0, int *x1); - // Renders one anti-aliased line into <aaBuf>. Returns the min and // max x coordinates with non-zero pixels in <x0> and <x1>. void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, @@ -102,11 +95,24 @@ private: int allInterLen; // number of intersections in <allInter> int allInterSize; // size of the <allInter> array int *inter; // indexes into <allInter> for each y value - int interY; // current y value - used by getNextSpan - int interIdx; // current index into <inter> - used by - // getNextSpan - int interCount; // current EO/NZWN counter - used by - // getNextSpan + + friend class SplashXPathScanIterator; +}; + +class SplashXPathScanIterator { +public: + SplashXPathScanIterator(const SplashXPathScanner &scanner, int y); + + // Returns the next span inside the path at the current y position + // Returns false if there are no more spans. + GBool getNextSpan(int *x0, int *x1); + +private: + const SplashIntersect *allInter; + int interIdx; // current index into <allInter> + int interEnd; // last index into <allInter>, noninclusive + int interCount; // current EO/NZWN counter + const GBool eo; }; #endif _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
