Spaces:
Running
Running
//======================================================================== | |
// | |
// SplashClip.cc | |
// | |
//======================================================================== | |
//======================================================================== | |
// | |
// Modified under the Poppler project - http://poppler.freedesktop.org | |
// | |
// All changes made under the Poppler project to this file are licensed | |
// under GPL version 2 or later | |
// | |
// Copyright (C) 2010, 2021 Albert Astals Cid <[email protected]> | |
// Copyright (C) 2013, 2021 Thomas Freitag <[email protected]> | |
// Copyright (C) 2019 Stefan Brüns <[email protected]> | |
// | |
// To see a description of the changes please see the Changelog file that | |
// came with your tarball or type make ChangeLog if you are building from git | |
// | |
//======================================================================== | |
//------------------------------------------------------------------------ | |
// SplashClip.flags | |
//------------------------------------------------------------------------ | |
//------------------------------------------------------------------------ | |
// SplashClip | |
//------------------------------------------------------------------------ | |
SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, bool 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 = splashCeil(xMax) - 1; | |
yMaxI = splashCeil(yMax) - 1; | |
flags = nullptr; | |
length = size = 0; | |
} | |
SplashClip::SplashClip(const 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; | |
flags = (unsigned char *)gmallocn(size, sizeof(unsigned char)); | |
scanners = clip->scanners; | |
for (i = 0; i < length; ++i) { | |
flags[i] = clip->flags[i]; | |
} | |
} | |
SplashClip::~SplashClip() | |
{ | |
gfree(flags); | |
} | |
void SplashClip::grow(int nPaths) | |
{ | |
if (length + nPaths > size) { | |
if (size == 0) { | |
size = 32; | |
} | |
while (size < length + nPaths) { | |
size *= 2; | |
} | |
flags = (unsigned char *)greallocn(flags, size, sizeof(unsigned char)); | |
} | |
} | |
void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) | |
{ | |
gfree(flags); | |
flags = nullptr; | |
scanners = {}; | |
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 = splashCeil(xMax) - 1; | |
yMaxI = splashCeil(yMax) - 1; | |
} | |
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 = splashCeil(xMax) - 1; | |
} | |
} else { | |
if (x1 > xMin) { | |
xMin = x1; | |
xMinI = splashFloor(xMin); | |
} | |
if (x0 < xMax) { | |
xMax = x0; | |
xMaxI = splashCeil(xMax) - 1; | |
} | |
} | |
if (y0 < y1) { | |
if (y0 > yMin) { | |
yMin = y0; | |
yMinI = splashFloor(yMin); | |
} | |
if (y1 < yMax) { | |
yMax = y1; | |
yMaxI = splashCeil(yMax) - 1; | |
} | |
} else { | |
if (y1 > yMin) { | |
yMin = y1; | |
yMinI = splashFloor(yMin); | |
} | |
if (y0 < yMax) { | |
yMax = y0; | |
yMaxI = splashCeil(yMax) - 1; | |
} | |
} | |
return splashOk; | |
} | |
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, bool eo) | |
{ | |
int yMinAA, yMaxAA; | |
SplashXPath xPath(path, matrix, flatness, true); | |
// check for an empty path | |
if (xPath.length == 0) { | |
xMax = xMin - 1; | |
yMax = yMin - 1; | |
xMaxI = splashCeil(xMax) - 1; | |
yMaxI = splashCeil(yMax) - 1; | |
// 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); | |
} else { | |
grow(1); | |
if (antialias) { | |
xPath.aaScale(); | |
} | |
xPath.sort(); | |
flags[length] = eo ? splashClipEO : 0; | |
if (antialias) { | |
yMinAA = yMinI * splashAASize; | |
yMaxAA = (yMaxI + 1) * splashAASize - 1; | |
} else { | |
yMinAA = yMinI; | |
yMaxAA = yMaxI; | |
} | |
scanners.emplace_back(std::make_shared<SplashXPathScanner>(xPath, eo, yMinAA, yMaxAA)); | |
++length; | |
} | |
return splashOk; | |
} | |
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, bool adjustVertLine) | |
{ | |
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 && !adjustVertLine) { | |
*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 && !adjustVertLine) { | |
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); | |
} | |
if (*x0 > *x1) { | |
*x0 = *x1; | |
} | |
if (*x0 < 0) { | |
*x0 = 0; | |
} | |
if ((*x0 >> 1) >= aaBuf->getRowSize()) { | |
xx0 = *x0; | |
*x0 = (aaBuf->getRowSize() - 1) << 1; | |
if (xx0 & 1) { | |
*x0 = *x0 + 1; | |
} | |
} | |
if (*x1 < *x0) { | |
*x1 = *x0; | |
} | |
if ((*x1 >> 1) >= aaBuf->getRowSize()) { | |
xx0 = *x1; | |
*x1 = (aaBuf->getRowSize() - 1) << 1; | |
if (xx0 & 1) { | |
*x1 = *x1 + 1; | |
} | |
} | |
} | |
bool SplashClip::testClipPaths(int x, int y) | |
{ | |
if (antialias) { | |
x *= splashAASize; | |
y *= splashAASize; | |
} | |
for (int i = 0; i < length; ++i) { | |
if (!scanners[i]->test(x, y)) { | |
return false; | |
} | |
} | |
return true; | |
} | |