//======================================================================== // // SplashClip.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "SplashErrorCodes.h" #include "SplashPath.h" #include "SplashXPath.h" #include "SplashXPathScanner.h" #include "SplashBitmap.h" #include "SplashClip.h" //------------------------------------------------------------------------ // SplashClip.flags //------------------------------------------------------------------------ #define splashClipEO 0x01 // use even-odd rule //------------------------------------------------------------------------ // SplashClip //------------------------------------------------------------------------ SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, GBool antialiasA) { antialias = antialiasA; if (x0 < x1) { xMin = x0; xMax = x1; } else { xMin = x1; xMax = x0; } if (y0 < y1) { yMin = y0; yMax = y1; } else { yMin = y1; yMax = y0; } xMinI = splashFloor(xMin); yMinI = splashFloor(yMin); xMaxI = splashFloor(xMax); yMaxI = splashFloor(yMax); paths = NULL; flags = NULL; scanners = NULL; length = size = 0; } SplashClip::SplashClip(SplashClip *clip) { int i; antialias = clip->antialias; xMin = clip->xMin; yMin = clip->yMin; xMax = clip->xMax; yMax = clip->yMax; xMinI = clip->xMinI; yMinI = clip->yMinI; xMaxI = clip->xMaxI; yMaxI = clip->yMaxI; length = clip->length; size = clip->size; paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); flags = (Guchar *)gmallocn(size, sizeof(Guchar)); scanners = (SplashXPathScanner **) gmallocn(size, sizeof(SplashXPathScanner *)); for (i = 0; i < length; ++i) { paths[i] = clip->paths[i]->copy(); flags[i] = clip->flags[i]; scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO); } } SplashClip::~SplashClip() { int i; for (i = 0; i < length; ++i) { delete paths[i]; delete scanners[i]; } gfree(paths); gfree(flags); gfree(scanners); } void SplashClip::grow(int nPaths) { if (length + nPaths > size) { if (size == 0) { size = 32; } while (size < length + nPaths) { size *= 2; } paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); scanners = (SplashXPathScanner **) greallocn(scanners, size, sizeof(SplashXPathScanner *)); } } void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { int i; for (i = 0; i < length; ++i) { delete paths[i]; delete scanners[i]; } gfree(paths); gfree(flags); gfree(scanners); paths = NULL; flags = NULL; scanners = NULL; length = size = 0; if (x0 < x1) { xMin = x0; xMax = x1; } else { xMin = x1; xMax = x0; } if (y0 < y1) { yMin = y0; yMax = y1; } else { yMin = y1; yMax = y0; } xMinI = splashFloor(xMin); yMinI = splashFloor(yMin); xMaxI = splashFloor(xMax); yMaxI = splashFloor(yMax); } SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { if (x0 < x1) { if (x0 > xMin) { xMin = x0; xMinI = splashFloor(xMin); } if (x1 < xMax) { xMax = x1; xMaxI = splashFloor(xMax); } } else { if (x1 > xMin) { xMin = x1; xMinI = splashFloor(xMin); } if (x0 < xMax) { xMax = x0; xMaxI = splashFloor(xMax); } } if (y0 < y1) { if (y0 > yMin) { yMin = y0; yMinI = splashFloor(yMin); } if (y1 < yMax) { yMax = y1; yMaxI = splashFloor(yMax); } } else { if (y1 > yMin) { yMin = y1; yMinI = splashFloor(yMin); } if (y0 < yMax) { yMax = y0; yMaxI = splashFloor(yMax); } } return splashOk; } SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool eo) { SplashXPath *xPath; xPath = new SplashXPath(path, matrix, flatness, gTrue); // check for an empty path if (xPath->length == 0) { xMax = xMin - 1; yMax = yMin - 1; xMaxI = splashFloor(xMax); yMaxI = splashFloor(yMax); delete xPath; // check for a rectangle } else if (xPath->length == 4 && ((xPath->segs[0].x0 == xPath->segs[0].x1 && xPath->segs[0].x0 == xPath->segs[1].x0 && xPath->segs[0].x0 == xPath->segs[3].x1 && xPath->segs[2].x0 == xPath->segs[2].x1 && xPath->segs[2].x0 == xPath->segs[1].x1 && xPath->segs[2].x0 == xPath->segs[3].x0 && xPath->segs[1].y0 == xPath->segs[1].y1 && xPath->segs[1].y0 == xPath->segs[0].y1 && xPath->segs[1].y0 == xPath->segs[2].y0 && xPath->segs[3].y0 == xPath->segs[3].y1 && xPath->segs[3].y0 == xPath->segs[0].y0 && xPath->segs[3].y0 == xPath->segs[2].y1) || (xPath->segs[0].y0 == xPath->segs[0].y1 && xPath->segs[0].y0 == xPath->segs[1].y0 && xPath->segs[0].y0 == xPath->segs[3].y1 && xPath->segs[2].y0 == xPath->segs[2].y1 && xPath->segs[2].y0 == xPath->segs[1].y1 && xPath->segs[2].y0 == xPath->segs[3].y0 && xPath->segs[1].x0 == xPath->segs[1].x1 && xPath->segs[1].x0 == xPath->segs[0].x1 && xPath->segs[1].x0 == xPath->segs[2].x0 && xPath->segs[3].x0 == xPath->segs[3].x1 && xPath->segs[3].x0 == xPath->segs[0].x0 && xPath->segs[3].x0 == xPath->segs[2].x1))) { clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, xPath->segs[2].x0, xPath->segs[2].y0); delete xPath; } else { grow(1); if (antialias) { xPath->aaScale(); } xPath->sort(); paths[length] = xPath; flags[length] = eo ? splashClipEO : 0; scanners[length] = new SplashXPathScanner(xPath, eo); ++length; } return splashOk; } GBool SplashClip::test(int x, int y) { int i; // check the rectangle if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) { return gFalse; } // check the paths if (antialias) { for (i = 0; i < length; ++i) { if (!scanners[i]->test(x * splashAASize, y * splashAASize)) { return gFalse; } } } else { for (i = 0; i < length; ++i) { if (!scanners[i]->test(x, y)) { return gFalse; } } } return gTrue; } SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax) { // This tests the rectangle: // x = [rectXMin, rectXMax + 1) (note: rect coords are ints) // y = [rectYMin, rectYMax + 1) // against the clipping region: // x = [xMin, xMax] (note: clipping coords are fp) // y = [yMin, yMax] if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin > xMax || (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin > yMax) { return splashClipAllOutside; } if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && length == 0) { return splashClipAllInside; } return splashClipPartial; } SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { int i; // This tests the rectangle: // x = [spanXMin, spanXMax + 1) (note: span coords are ints) // y = [spanY, spanY + 1) // against the clipping region: // x = [xMin, xMax] (note: clipping coords are fp) // y = [yMin, yMax] if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin > xMax || (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY > yMax) { return splashClipAllOutside; } if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) { return splashClipPartial; } if (antialias) { for (i = 0; i < length; ++i) { if (!scanners[i]->testSpan(spanXMin * splashAASize, spanXMax * splashAASize + (splashAASize - 1), spanY * splashAASize)) { return splashClipPartial; } } } else { for (i = 0; i < length; ++i) { if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) { return splashClipPartial; } } } return splashClipAllInside; } void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { int xx0, xx1, xx, yy, i; SplashColorPtr p; // zero out pixels with x < xMin xx0 = *x0 * splashAASize; xx1 = splashFloor(xMin * splashAASize); if (xx1 > aaBuf->getWidth()) { xx1 = aaBuf->getWidth(); } if (xx0 < xx1) { xx0 &= ~7; for (yy = 0; yy < splashAASize; ++yy) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); for (xx = xx0; xx + 7 < xx1; xx += 8) { *p++ = 0; } if (xx < xx1) { *p &= 0xff >> (xx1 & 7); } } *x0 = splashFloor(xMin); } // zero out pixels with x > xMax xx0 = splashFloor(xMax * splashAASize) + 1; if (xx0 < 0) { xx0 = 0; } xx1 = (*x1 + 1) * splashAASize; if (xx0 < xx1) { for (yy = 0; yy < splashAASize; ++yy) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); xx = xx0; if (xx & 7) { *p &= 0xff00 >> (xx & 7); xx = (xx & ~7) + 8; ++p; } for (; xx < xx1; xx += 8) { *p++ = 0; } } *x1 = splashFloor(xMax); } // check the paths for (i = 0; i < length; ++i) { scanners[i]->clipAALine(aaBuf, x0, x1, y); } }