diff options
Diffstat (limited to 'splash/SplashXPathScanner.cc')
-rw-r--r-- | splash/SplashXPathScanner.cc | 899 |
1 files changed, 464 insertions, 435 deletions
diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc index abe4593..aee60cc 100644 --- a/splash/SplashXPathScanner.cc +++ b/splash/SplashXPathScanner.cc @@ -2,6 +2,8 @@ // // SplashXPathScanner.cc // +// Copyright 2003-2013 Glyph & Cog, LLC +// //======================================================================== #include <aconf.h> @@ -16,523 +18,550 @@ #include <algorithm> #endif #include "gmem.h" +#include "GList.h" #include "SplashMath.h" #include "SplashXPath.h" -#include "SplashBitmap.h" #include "SplashXPathScanner.h" //------------------------------------------------------------------------ -struct SplashIntersect { - int y; - int x0, x1; // intersection of segment with [y, y+1) - int count; // EO/NZWN counter increment -}; - -#if HAVE_STD_SORT - -struct cmpIntersectFunctor { - bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) { - return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0); - } -}; - -#else // HAVE_STD_SORT +#define minVertStep 0.05 -static int cmpIntersect(const void *p0, const void *p1) { - SplashIntersect *i0 = (SplashIntersect *)p0; - SplashIntersect *i1 = (SplashIntersect *)p1; - int cmp; - - if ((cmp = i0->y - i1->y) == 0) { - cmp = i0->x0 - i1->x0; - } - return cmp; -} - -#endif // HAVE_STD_SORT - -//------------------------------------------------------------------------ -// SplashXPathScanner //------------------------------------------------------------------------ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, - int clipYMin, int clipYMax) { - SplashXPathSeg *seg; - SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; - int i; - + int yMinA, int yMaxA) { xPath = xPathA; eo = eoA; - partialClip = gFalse; + yMin = yMinA; + yMax = yMaxA; - // compute the bbox - if (xPath->length == 0) { - xMin = yMin = 1; - xMax = yMax = 0; - } else { - seg = &xPath->segs[0]; - if (seg->x0 <= seg->x1) { - xMinFP = seg->x0; - xMaxFP = seg->x1; - } else { - xMinFP = seg->x1; - xMaxFP = seg->x0; - } - if (seg->flags & splashXPathFlip) { - yMinFP = seg->y1; - yMaxFP = seg->y0; - } else { - yMinFP = seg->y0; - yMaxFP = seg->y1; - } - for (i = 1; i < xPath->length; ++i) { - seg = &xPath->segs[i]; - if (seg->x0 < xMinFP) { - xMinFP = seg->x0; - } else if (seg->x0 > xMaxFP) { - xMaxFP = seg->x0; - } - if (seg->x1 < xMinFP) { - xMinFP = seg->x1; - } else if (seg->x1 > xMaxFP) { - xMaxFP = seg->x1; + activeSegs = new GList(); + nextSeg = 0; + yNext = xPath->yMin; +} + +SplashXPathScanner::~SplashXPathScanner() { + delete activeSegs; +} + +void SplashXPathScanner::getSpan(Guchar *line, int y, int x0, int x1) { + SplashXPathSeg *seg, *seg0; + SplashCoord y0, y1, y1p; + GBool intersect, last; + int eoMask, state0, state1, count, i; + + //--- clear the scan line buffer + memset(line + x0, 0, x1 - x0 + 1); + + //--- reset the path + if (yNext != y) { + delete activeSegs; + activeSegs = new GList(); + nextSeg = 0; + while (nextSeg < xPath->length) { + seg = &xPath->segs[nextSeg]; + if (seg->y0 >= y) { + break; } - if (seg->flags & splashXPathFlip) { - if (seg->y0 > yMaxFP) { - yMaxFP = seg->y0; - } - } else { - if (seg->y1 > yMaxFP) { - yMaxFP = seg->y1; + if (seg->y0 != seg->y1 && seg->y1 > y) { + if (seg->y0 == y) { + seg->xCur0 = seg->x0; + } else { + seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; } + activeSegs->append(seg); } + ++nextSeg; } - xMin = splashFloor(xMinFP); - xMax = splashFloor(xMaxFP); - yMin = splashFloor(yMinFP); - yMax = splashFloor(yMaxFP); - if (clipYMin > yMin) { - yMin = clipYMin; - partialClip = gTrue; - } - if (clipYMax < yMax) { - yMax = clipYMax; - partialClip = gTrue; - } + activeSegs->sort(&SplashXPathSeg::cmpXi); } - allInter = NULL; - inter = NULL; - computeIntersections(); - interY = yMin - 1; -} + //--- process the scan line + y0 = y; + while (y0 < y + 1) { -SplashXPathScanner::~SplashXPathScanner() { - gfree(inter); - gfree(allInter); -} + //--- delete finished segs + i = 0; + while (i < activeSegs->getLength()) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y1 <= y0) { + activeSegs->del(i); + } else { + ++i; + } + } -void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, - int *xMaxA, int *yMaxA) { - *xMinA = xMin / splashAASize; - *yMinA = yMin / splashAASize; - *xMaxA = xMax / splashAASize; - *yMaxA = yMax / splashAASize; -} + //--- check for bottom of path + if (!activeSegs->getLength() && nextSeg >= xPath->length) { + break; + } -void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { - int interBegin, interEnd, xx, i; + //--- sort activeSegs + sortActiveSegs(); - if (y < yMin || y > yMax) { - interBegin = interEnd = 0; - } else { - interBegin = inter[y - yMin]; - interEnd = inter[y - yMin + 1]; - } - 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; + //--- add waiting segs + while (nextSeg < xPath->length) { + seg = &xPath->segs[nextSeg]; + if (seg->y0 > y0) { + break; + } + if (seg->y0 != seg->y1) { + seg->xCur0 = seg->x0; + insertActiveSeg(seg); } + ++nextSeg; } - *spanXMax = xx; - } else { - *spanXMin = xMax + 1; - *spanXMax = xMax; - } -} -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) { - return gTrue; + //--- get the next "interesting" y value + y1 = y + 1; + if (nextSeg < xPath->length && xPath->segs[nextSeg].y0 < y1) { + y1 = xPath->segs[nextSeg].y0; + } + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y1 < y1) { + y1 = seg->y1; + } } - count += allInter[i].count; - } - return eo ? (count & 1) : (count != 0); -} -GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { - int interBegin, interEnd, count, xx1, i; + //--- compute xCur1 values, check for intersections + seg0 = NULL; + intersect = gFalse; + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y1 == y1) { + seg->xCur1 = seg->x1; + } else { + seg->xCur1 = seg->x0 + (y1 - seg->y0) * seg->dxdy; + } + if (seg0 && seg0->xCur1 > seg->xCur1) { + intersect = gTrue; + } + seg0 = seg; + } - 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; - } + //--- draw rectangles + if (intersect) { + for (; y0 < y1; y0 += minVertStep) { + if ((y1p = y0 + minVertStep) >= y1) { + y1p = y1; + last = gTrue; + } else { + last = gFalse; + } + state0 = state1 = count = 0; + seg0 = NULL; + eoMask = eo ? 1 : 0xffffffff; + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (last && seg->y1 == y1) { + seg->xCur1 = seg->x1; + } else { + seg->xCur1 = seg->x0 + (y1p - seg->y0) * seg->dxdy; + } + count += seg->count; + state1 = count & eoMask; + if (!state0 && state1) { + seg0 = seg; + } else if (state0 && !state1) { + drawRectangle(line, x0, x1, y0, y1p, seg0->xCur0, seg->xCur0); + } + state0 = state1; + } + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + seg->xCur0 = seg->xCur1; + } + sortActiveSegs(); + } - // invariant: the subspan [x0,xx1] is inside the path - xx1 = x0 - 1; - while (xx1 < x1) { - if (i >= interEnd) { - return gFalse; - } - if (allInter[i].x0 > xx1 + 1 && - !(eo ? (count & 1) : (count != 0))) { - return gFalse; - } - if (allInter[i].x1 > xx1) { - xx1 = allInter[i].x1; + //--- draw trapezoids + } else { + state0 = state1 = count = 0; + seg0 = NULL; + eoMask = eo ? 1 : 0xffffffff; + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + count += seg->count; + state1 = count & eoMask; + if (!state0 && state1) { + seg0 = seg; + } else if (state0 && !state1) { + drawTrapezoid(line, x0, x1, y0, y1, + seg0->xCur0, seg0->xCur1, seg0->dydx, + seg->xCur0, seg->xCur1, seg->dydx); + } + state0 = state1; + } + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + seg->xCur0 = seg->xCur1; + } } - count += allInter[i].count; - ++i; + + //--- next slice + y0 = y1; } - return gTrue; + yNext = y + 1; } -GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { - int interEnd, 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; +void SplashXPathScanner::getSpanBinary(Guchar *line, int y, int x0, int x1) { + SplashXPathSeg *seg; + int xx0, xx1, xx; + int eoMask, state0, state1, count, i; + + //--- clear the scan line buffer + memset(line + x0, 0, x1 - x0 + 1); + + //--- reset the path + if (yNext != y) { + delete activeSegs; + activeSegs = new GList(); + nextSeg = 0; + while (nextSeg < xPath->length) { + seg = &xPath->segs[nextSeg]; + if (seg->y0 >= y) { + break; + } + if (seg->y1 > y) { + if (seg->y0 == y) { + seg->xCur0 = seg->x0; + } else { + seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; + } + activeSegs->append(seg); + } + ++nextSeg; + } + activeSegs->sort(&SplashXPathSeg::cmpXi); } - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; - ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || - (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; + + //--- delete finished segs + i = 0; + while (i < activeSegs->getLength()) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y1 <= y) { + activeSegs->del(i); + } else { + ++i; } - interCount += allInter[interIdx].count; - ++interIdx; } - *x0 = xx0; - *x1 = xx1; - return gTrue; -} -void SplashXPathScanner::computeIntersections() { - SplashXPathSeg *seg; - SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1; - int x, y, y0, y1, i; + //--- sort activeSegs + sortActiveSegs(); - if (yMin > yMax) { - return; + //--- add waiting segs + while (nextSeg < xPath->length) { + seg = &xPath->segs[nextSeg]; + if (seg->y0 >= y + 1) { + break; + } + seg->xCur0 = seg->x0; + insertActiveSeg(seg); + ++nextSeg; } - // build the list of all intersections - allInterLen = 0; - allInterSize = 16; - allInter = (SplashIntersect *)gmallocn(allInterSize, - sizeof(SplashIntersect)); - for (i = 0; i < xPath->length; ++i) { - seg = &xPath->segs[i]; - if (seg->flags & splashXPathFlip) { - segYMin = seg->y1; - segYMax = seg->y0; + //--- compute xCur1 values + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y1 <= y + 1) { + seg->xCur1 = seg->x1; } else { - segYMin = seg->y0; - segYMax = seg->y1; + seg->xCur1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy; } - if (seg->flags & splashXPathHoriz) { - y = splashFloor(seg->y0); - if (y >= yMin && y <= yMax) { - addIntersection(segYMin, segYMax, seg->flags, - y, splashFloor(seg->x0), splashFloor(seg->x1)); - } - } else if (seg->flags & splashXPathVert) { - y0 = splashFloor(segYMin); - if (y0 < yMin) { - y0 = yMin; + } + + //--- draw spans + state0 = state1 = count = 0; + eoMask = eo ? 1 : 0xffffffff; + xx0 = xx1 = 0; // make gcc happy + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + if (seg->y0 <= y && seg->y0 < seg->y1) { + count += seg->count; + state1 = count & eoMask; + } + if (state0) { + xx = splashCeil(seg->xCur0) - 1; + if (xx > xx1) { + xx1 = xx; } - y1 = splashFloor(segYMax); - if (y1 > yMax) { - y1 = yMax; + xx = splashFloor(seg->xCur1); + if (xx < xx0) { + xx0 = xx; } - x = splashFloor(seg->x0); - for (y = y0; y <= y1; ++y) { - addIntersection(segYMin, segYMax, seg->flags, y, x, x); + xx = splashCeil(seg->xCur1) - 1; + if (xx > xx1) { + xx1 = xx; } } else { - if (seg->x0 < seg->x1) { - segXMin = seg->x0; - segXMax = seg->x1; + if (seg->xCur0 < seg->xCur1) { + xx0 = splashFloor(seg->xCur0); + xx1 = splashCeil(seg->xCur1) - 1; } else { - segXMin = seg->x1; - segXMax = seg->x0; + xx0 = splashFloor(seg->xCur1); + xx1 = splashCeil(seg->xCur0) - 1; } - y0 = splashFloor(segYMin); - if (y0 < yMin) { - y0 = yMin; + } + if (!state1) { + if (xx0 < x0) { + xx0 = x0; } - y1 = splashFloor(segYMax); - if (y1 > yMax) { - y1 = yMax; + if (xx1 > x1) { + xx1 = x1; } - // this loop could just add seg->dxdy to xx1 on each iteration, - // but that introduces numerical accuracy problems - xx1 = seg->x0 + ((SplashCoord)y0 - seg->y0) * seg->dxdy; - for (y = y0; y <= y1; ++y) { - xx0 = xx1; - xx1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy; - // the segment may not actually extend to the top and/or bottom edges - if (xx0 < segXMin) { - xx0 = segXMin; - } else if (xx0 > segXMax) { - xx0 = segXMax; - } - if (xx1 < segXMin) { - xx1 = segXMin; - } else if (xx1 > segXMax) { - xx1 = segXMax; - } - addIntersection(segYMin, segYMax, seg->flags, y, - splashFloor(xx0), splashFloor(xx1)); + for (xx = xx0; xx <= xx1; ++xx) { + line[xx] = 0xff; } } + state0 = state1; } -#if HAVE_STD_SORT - std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor()); -#else - qsort(allInter, allInterLen, sizeof(SplashIntersect), cmpIntersect); -#endif - // 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; - } + //--- update xCur0 values + for (i = 0; i < activeSegs->getLength(); ++i) { + seg = (SplashXPathSeg *)activeSegs->get(i); + seg->xCur0 = seg->xCur1; } - inter[yMax - yMin + 1] = i; + + yNext = y + 1; } -void SplashXPathScanner::addIntersection(double segYMin, double segYMax, - Guint segFlags, - int y, int x0, int x1) { - if (allInterLen == allInterSize) { - allInterSize *= 2; - allInter = (SplashIntersect *)greallocn(allInter, allInterSize, - sizeof(SplashIntersect)); +inline void SplashXPathScanner::addArea(Guchar *line, int x, SplashCoord a) { + int a2, t; + + a2 = splashRound(a * 255); + if (a2 <= 0) { + return; + } + t = line[x] + a2; + if (t > 255) { + t = 255; + } + line[x] = t; +} + +// Draw a trapezoid with edges: +// top: (xa0, y0) - (xb0, y0) +// left: (xa0, y0) - (xa1, y1) +// right: (xb0, y0) - (xb1, y1) +// bottom: (xa1, y1) - (xb1, y1) +void SplashXPathScanner::drawTrapezoid(Guchar *line, int xMin, int xMax, + SplashCoord y0, SplashCoord y1, + SplashCoord xa0, SplashCoord xa1, + SplashCoord dydxa, + SplashCoord xb0, SplashCoord xb1, + SplashCoord dydxb) { + SplashCoord a, dy; + int x0, x1, x2, x3, x; + + // check for a rectangle + if (dydxa == 0 && dydxb == 0 && xa0 >= xMin && xb0 <= xMax) { + x0 = splashFloor(xa0); + x3 = splashFloor(xb0); + dy = y1 - y0; + if (x0 == x3) { + addArea(line, x0, (xb0 - xa0) * dy); + } else { + addArea(line, x0, ((SplashCoord)1 - (xa0 - x0)) * dy); + for (x = x0 + 1; x <= x3 - 1; ++x) { + addArea(line, x, y1 - y0); + } + addArea(line, x3, (xb0 - x3) * (y1 - y0)); + } + return; } - allInter[allInterLen].y = y; - if (x0 < x1) { - allInter[allInterLen].x0 = x0; - allInter[allInterLen].x1 = x1; + + if (dydxa > 0) { + x0 = splashFloor(xa0); + x1 = splashFloor(xa1); } else { - allInter[allInterLen].x0 = x1; - allInter[allInterLen].x1 = x0; + x0 = splashFloor(xa1); + x1 = splashFloor(xa0); + } + if (x0 < xMin) { + x0 = xMin; } - if (segYMin <= y && - (SplashCoord)y < segYMax && - !(segFlags & splashXPathHoriz)) { - allInter[allInterLen].count = eo ? 1 - : (segFlags & splashXPathFlip) ? 1 : -1; + if (dydxb > 0) { + x2 = splashFloor(xb0); + x3 = splashFloor(xb1); } else { - allInter[allInterLen].count = 0; + x2 = splashFloor(xb1); + x3 = splashFloor(xb0); + } + if (x3 > xMax) { + x3 = xMax; + } + for (x = x0; x <= x3; ++x) { + a = y1 - y0; + if (x <= x1) { + a -= areaLeft(x, xa0, y0, xa1, y1, dydxa); + } + if (x >= x2) { + a -= areaRight(x, xb0, y0, xb1, y1, dydxb); + } + addArea(line, x, a); } - ++allInterLen; } -void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, - int *x0, int *x1, int y) { - int xx0, xx1, xx, xxMin, xxMax, yy, interEnd; - Guchar mask; - SplashColorPtr p; - - memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight()); - 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]; +// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left +// of a trapezoid edge ((x0,y0)-(x1,y1)). +SplashCoord SplashXPathScanner::areaLeft(int xp, + SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord dydx) { + SplashCoord a, ya, yb; + + if (dydx >= 0) { + if (x0 >= xp) { + if (x1 <= xp + 1) { + a = ((x0 + x1) * 0.5 - xp) * (y1 - y0); + } else { + yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; + a = (y1 - y0) - ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5; + } } else { - interIdx = inter[splashAASize * y - yMin]; + if (x1 <= xp + 1) { + ya = y0 + ((SplashCoord)xp - x0) * dydx; + a = (x1 - xp) * (y1 - ya) * 0.5; + } else { + // ya = y1 - (x1 - xp - 0.5) * dydx; + // a = y1 - ya; + a = (x1 - xp - 0.5) * dydx; + } } - 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 { + if (x0 <= xp + 1) { + if (x1 >= xp) { + a = ((x0 + x1) * 0.5 - xp) * (y1 - y0); } else { - interEnd = inter[splashAASize * y + yy - yMin + 1]; + ya = y0 + ((SplashCoord)xp - x0) * dydx; + a = (x0 - xp) * (ya - y0) * 0.5; } - interCount = 0; - while (interIdx < interEnd) { - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; - ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || - (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; - } - interCount += allInter[interIdx].count; - ++interIdx; - } - if (xx0 < 0) { - xx0 = 0; - } - ++xx1; - if (xx1 > aaBuf->getWidth()) { - xx1 = aaBuf->getWidth(); - } - // set [xx0, xx1) to 1 - if (xx0 < xx1) { - xx = xx0; - p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); - if (xx & 7) { - mask = 0xff >> (xx & 7); - if ((xx & ~7) == (xx1 & ~7)) { - mask &= (Guchar)(0xff00 >> (xx1 & 7)); - } - *p++ |= mask; - xx = (xx & ~7) + 8; - } - for (; xx + 7 < xx1; xx += 8) { - *p++ |= 0xff; - } - if (xx < xx1) { - *p |= (Guchar)(0xff00 >> (xx1 & 7)); - } - } - if (xx0 < xxMin) { - xxMin = xx0; - } - if (xx1 > xxMax) { - xxMax = xx1; - } + } else { + if (x1 >= xp) { + yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; + a = (y1 - y0) - ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5; + } else { + // ya = y0 + (xp - x0 + 0.5) * dydx; + // a = ya - y0; + a = ((SplashCoord)xp - x0 + 0.5) * dydx; } } } - *x0 = xxMin / splashAASize; - *x1 = (xxMax - 1) / splashAASize; + return a; } -void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, - int *x0, int *x1, int y) { - int xx0, xx1, xx, yy, interEnd; - Guchar mask; - SplashColorPtr p; - - 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]; +// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left +// of a trapezoid edge ((x0,y0)-(x1,y1)). +SplashCoord SplashXPathScanner::areaRight(int xp, + SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord dydx) { + SplashCoord a, ya, yb; + + if (dydx >= 0) { + if (x0 >= xp) { + if (x1 <= xp + 1) { + a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0); } 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]; - } + yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; + a = ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5; } - interCount = 0; - while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) { - xx0 = allInter[interIdx].x0; - xx1 = allInter[interIdx].x1; - interCount += allInter[interIdx].count; - ++interIdx; - while (interIdx < interEnd && - (allInter[interIdx].x0 <= xx1 || - (eo ? (interCount & 1) : (interCount != 0)))) { - if (allInter[interIdx].x1 > xx1) { - xx1 = allInter[interIdx].x1; - } - interCount += allInter[interIdx].count; - ++interIdx; - } - if (xx0 > aaBuf->getWidth()) { - xx0 = aaBuf->getWidth(); - } - // set [xx, xx0) to 0 - if (xx < xx0) { - p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); - if (xx & 7) { - mask = (Guchar)(0xff00 >> (xx & 7)); - if ((xx & ~7) == (xx0 & ~7)) { - mask |= 0xff >> (xx0 & 7); - } - *p++ &= mask; - xx = (xx & ~7) + 8; - } - for (; xx + 7 < xx0; xx += 8) { - *p++ = 0x00; - } - if (xx < xx0) { - *p &= 0xff >> (xx0 & 7); - } - } - if (xx1 >= xx) { - xx = xx1 + 1; - } + } else { + if (x1 <= xp + 1) { + ya = y0 + ((SplashCoord)xp - x0) * dydx; + a = (y1 - y0) - (x1 - xp) * (y1 - ya) * 0.5; + } else { + // ya = y0 + (xp - x0 + 0.5) * dydx; + // a = ya - y0; + a = ((SplashCoord)xp + 0.5 - x0) * dydx; } } - xx0 = (*x1 + 1) * splashAASize; - // set [xx, xx0) to 0 - if (xx < xx0) { - p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); - if (xx & 7) { - mask = (Guchar)(0xff00 >> (xx & 7)); - if ((xx & ~7) == (xx0 & ~7)) { - mask &= 0xff >> (xx0 & 7); - } - *p++ &= mask; - xx = (xx & ~7) + 8; + } else { + if (x0 <= xp + 1) { + if (x1 >= xp) { + a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0); + } else { + ya = y0 + ((SplashCoord)xp - x0) * dydx; + a = (y1 - y0) - (x0 - xp) * (ya - y0) * 0.5; } - for (; xx + 7 < xx0; xx += 8) { - *p++ = 0x00; + } else { + if (x1 >= xp) { + yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; + a = ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5; + } else { + // ya = y1 - (x1 - xp - 0.5) * dydx; + // a = y1 - ya; + a = (x1 - xp - 0.5) * dydx; } - if (xx < xx0) { - *p &= 0xff >> (xx0 & 7); + } + } + return a; +} + +void SplashXPathScanner::drawRectangle(Guchar *line, int xMin, int xMax, + SplashCoord y0, SplashCoord y1, + SplashCoord x0, SplashCoord x1) { + SplashCoord dy, a; + int xx0, xx1, x; + + xx0 = splashFloor(x0); + if (xx0 < xMin) { + xx0 = xMin; + } + xx1 = splashFloor(x1); + if (xx1 > xMax) { + xx1 = xMax; + } + dy = y1 - y0; + for (x = xx0; x <= xx1; ++x) { + a = dy; + if ((SplashCoord)x < x0) { + a -= (x0 - x) * dy; + } + if ((SplashCoord)(x + 1) > x1) { + a -= ((SplashCoord)(x + 1) - x1) * dy; + } + addArea(line, x, a); + } +} + +void SplashXPathScanner::sortActiveSegs() { + SplashXPathSeg *seg0, *seg1; + int i, j, k; + + if (activeSegs->getLength() < 2) { + return; + } + seg0 = (SplashXPathSeg *)activeSegs->get(0); + for (i = 1; i < activeSegs->getLength(); ++i) { + seg1 = (SplashXPathSeg *)activeSegs->get(i); + if (SplashXPathSeg::cmpX(seg0, seg1) > 0) { + for (j = i - 1; j > 0; --j) { + if (SplashXPathSeg::cmpX((SplashXPathSeg *)activeSegs->get(j - 1), + seg1) <= 0) { + break; + } } + for (k = i; k > j; --k) { + activeSegs->put(k, activeSegs->get(k-1)); + } + activeSegs->put(j, seg1); + } else { + seg0 = seg1; + } + } +} + +void SplashXPathScanner::insertActiveSeg(SplashXPathSeg *seg) { + int i; + + for (i = 0; i < activeSegs->getLength(); ++i) { + if (SplashXPathSeg::cmpX(seg, (SplashXPathSeg *)activeSegs->get(i)) < 0) { + break; } } + activeSegs->insert(i, seg); } |