[poppler] 3 commits - splash/Splash.cc splash/SplashXPathScanner.cc splash/SplashXPathScanner.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Oct 5 22:35:24 UTC 2018


 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 <stefan.bruens at rwth-aachen.de>
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 <stefan.bruens at rwth-aachen.de>
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 <stefan.bruens at rwth-aachen.de>
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


More information about the poppler mailing list