blob: 86438b5bd5f36d3d9cbb2190785240d63149335e [file] [log] [blame]
//========================================================================
//
// SplashClip.cc
//
//========================================================================
#include <config.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stdlib.h>
#include <string.h>
#include "goo/gmem.h"
#include "SplashErrorCodes.h"
#include "SplashMath.h"
#include "SplashPath.h"
#include "SplashXPath.h"
#include "SplashXPathScanner.h"
#include "SplashClip.h"
//------------------------------------------------------------------------
// SplashClip.flags
//------------------------------------------------------------------------
#define splashClipEO 0x01 // use even-odd rule
//------------------------------------------------------------------------
// SplashClip
//------------------------------------------------------------------------
SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
if (x0 < x1) {
xMin = splashFloor(x0);
xMax = splashFloor(x1);
} else {
xMin = splashFloor(x1);
xMax = splashFloor(x0);
}
if (y0 < y1) {
yMin = splashFloor(y0);
yMax = splashFloor(y1);
} else {
yMin = splashFloor(y1);
yMax = splashFloor(y0);
}
paths = NULL;
flags = NULL;
scanners = NULL;
length = size = 0;
}
SplashClip::SplashClip(SplashClip *clip) {
int i;
xMin = clip->xMin;
yMin = clip->yMin;
xMax = clip->xMax;
yMax = clip->yMax;
length = clip->length;
size = clip->size;
paths = (SplashXPath **)gmalloc(size * sizeof(SplashXPath *));
flags = (Guchar *)gmalloc(size * sizeof(Guchar));
scanners = (SplashXPathScanner **)
gmalloc(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 **)grealloc(paths, size * sizeof(SplashXPath *));
flags = (Guchar *)grealloc(flags, size * sizeof(Guchar));
scanners = (SplashXPathScanner **)
grealloc(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 = splashFloor(x0);
xMax = splashFloor(x1);
} else {
xMin = splashFloor(x1);
xMax = splashFloor(x0);
}
if (y0 < y1) {
yMin = splashFloor(y0);
yMax = splashFloor(y1);
} else {
yMin = splashFloor(y1);
yMax = splashFloor(y0);
}
}
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
int x0I, y0I, x1I, y1I;
if (x0 < x1) {
x0I = splashFloor(x0);
x1I = splashFloor(x1);
} else {
x0I = splashFloor(x1);
x1I = splashFloor(x0);
}
if (x0I > xMin) {
xMin = x0I;
}
if (x1I < xMax) {
xMax = x1I;
}
if (y0 < y1) {
y0I = splashFloor(y0);
y1I = splashFloor(y1);
} else {
y0I = splashFloor(y1);
y1I = splashFloor(y0);
}
if (y0I > yMin) {
yMin = y0I;
}
if (y1I < yMax) {
yMax = y1I;
}
return splashOk;
}
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness,
GBool eo) {
SplashXPath *xPath;
xPath = new SplashXPath(path, flatness, gTrue);
// check for an empty path
if (xPath->length == 0) {
xMax = xMin - 1;
yMax = yMin - 1;
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);
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 < xMin || x > xMax || y < yMin || y > yMax) {
return gFalse;
}
// check the paths
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) {
if (rectXMax < xMin || rectXMin > xMax ||
rectYMax < yMin || rectYMin > yMax) {
return splashClipAllOutside;
}
if (rectXMin >= xMin && rectXMax <= xMax &&
rectYMin >= yMin && rectYMax <= yMax &&
length == 0) {
return splashClipAllInside;
}
return splashClipPartial;
}
SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
int i;
if (spanXMax < xMin || spanXMin > xMax ||
spanY < yMin || spanY > yMax) {
return splashClipAllOutside;
}
if (!(spanXMin >= xMin && spanXMax <= xMax &&
spanY >= yMin && spanY <= yMax)) {
return splashClipPartial;
}
for (i = 0; i < length; ++i) {
if (!scanners[i]->testSpan(xMin, xMax, spanY)) {
return splashClipPartial;
}
}
return splashClipAllInside;
}