Files
DocumentServer-v-9.2.0/core/PdfFile/lib/splash/SplashClip.cc
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

522 lines
11 KiB
C++

//========================================================================
//
// SplashClip.cc
//
// Copyright 2003-2013 Glyph & Cog, LLC
//
//========================================================================
#include <aconf.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stdlib.h>
#include <string.h>
#include "gmem.h"
#include "gmempp.h"
#include "SplashErrorCodes.h"
#include "SplashPath.h"
#include "SplashXPath.h"
#include "SplashXPathScanner.h"
#include "SplashClip.h"
//------------------------------------------------------------------------
// Compute x * y / 255, where x and y are in [0, 255].
static inline Guchar mul255(Guchar x, Guchar y) {
int z;
z = (int)x * (int)y;
return (Guchar)((z + (z >> 8) + 0x80) >> 8);
}
//------------------------------------------------------------------------
// SplashClip
//------------------------------------------------------------------------
SplashClip::SplashClip(int hardXMinA, int hardYMinA,
int hardXMaxA, int hardYMaxA) {
int w;
hardXMin = hardXMinA;
hardYMin = hardYMinA;
hardXMax = hardXMaxA;
hardYMax = hardYMaxA;
xMin = hardXMin;
yMin = hardYMin;
xMax = hardXMax;
yMax = hardYMax;
intBoundsValid = gFalse;
paths = NULL;
eo = NULL;
scanners = NULL;
length = size = 0;
isSimple = gTrue;
prev = NULL;
if ((w = hardXMax + 1) <= 0) {
w = 1;
}
buf = (Guchar *)gmalloc(w);
}
SplashClip::SplashClip(SplashClip *clip) {
int w;
hardXMin = clip->hardXMin;
hardYMin = clip->hardYMin;
hardXMax = clip->hardXMax;
hardYMax = clip->hardYMax;
xMin = clip->xMin;
yMin = clip->yMin;
xMax = clip->xMax;
yMax = clip->yMax;
xMinI = clip->xMinI;
yMinI = clip->yMinI;
xMaxI = clip->xMaxI;
yMaxI = clip->yMaxI;
intBoundsValid = clip->intBoundsValid;
intBoundsStrokeAdjust = clip->intBoundsStrokeAdjust;
paths = NULL;
eo = NULL;
scanners = NULL;
length = size = 0;
isSimple = clip->isSimple;
prev = clip;
if ((w = splashCeil(xMax)) <= 0) {
w = 1;
}
buf = (Guchar *)gmalloc(w);
}
SplashClip::~SplashClip() {
int i;
for (i = 0; i < length; ++i) {
delete scanners[i];
delete paths[i];
}
gfree(paths);
gfree(eo);
gfree(scanners);
gfree(buf);
}
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 *));
eo = (Guchar *)greallocn(eo, size, sizeof(Guchar));
scanners = (SplashXPathScanner **)
greallocn(scanners, size, sizeof(SplashXPathScanner *));
}
}
void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
int w, i;
for (i = 0; i < length; ++i) {
delete paths[i];
delete scanners[i];
}
gfree(paths);
gfree(eo);
gfree(scanners);
gfree(buf);
paths = NULL;
eo = NULL;
scanners = NULL;
length = size = 0;
isSimple = gTrue;
prev = NULL;
if (x0 < x1) {
xMin = x0;
xMax = x1;
} else {
xMin = x1;
xMax = x0;
}
if (y0 < y1) {
yMin = y0;
yMax = y1;
} else {
yMin = y1;
yMax = y0;
}
intBoundsValid = gFalse;
if ((w = splashCeil(xMax)) <= 0) {
w = 1;
}
buf = (Guchar *)gmalloc(w);
}
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
if (x0 < x1) {
if (x0 > xMin) {
xMin = x0;
intBoundsValid = gFalse;
}
if (x1 < xMax) {
xMax = x1;
intBoundsValid = gFalse;
}
} else {
if (x1 > xMin) {
xMin = x1;
intBoundsValid = gFalse;
}
if (x0 < xMax) {
xMax = x0;
intBoundsValid = gFalse;
}
}
if (y0 < y1) {
if (y0 > yMin) {
yMin = y0;
intBoundsValid = gFalse;
}
if (y1 < yMax) {
yMax = y1;
intBoundsValid = gFalse;
}
} else {
if (y1 > yMin) {
yMin = y1;
intBoundsValid = gFalse;
}
if (y0 < yMax) {
yMax = y0;
intBoundsValid = gFalse;
}
}
return splashOk;
}
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness, GBool eoA,
GBool enablePathSimplification,
SplashStrokeAdjustMode strokeAdjust) {
SplashXPath *xPath;
SplashCoord t;
xPath = new SplashXPath(path, matrix, flatness, gTrue,
enablePathSimplification,
strokeAdjust);
// check for an empty path
if (xPath->length == 0) {
xMin = yMin = 1;
xMax = yMax = 0;
intBoundsValid = gFalse;
delete xPath;
return splashOk;
}
// check for a rectangle
if (xPath->isRect) {
clipToRect(xPath->rectX0, xPath->rectY0, xPath->rectX1, xPath->rectY1);
delete xPath;
return splashOk;
}
grow(1);
paths[length] = xPath;
eo[length] = (Guchar)eoA;
if ((t = xPath->getXMin()) > xMin) {
xMin = t;
}
if ((t = xPath->getYMin()) > yMin) {
yMin = t;
}
if ((t = xPath->getXMax() + 1) < xMax) {
xMax = t;
}
if ((t = xPath->getYMax() + 1) < yMax) {
yMax = t;
}
intBoundsValid = gFalse;
scanners[length] = new SplashXPathScanner(xPath, eoA, splashFloor(yMin),
splashCeil(yMax) - 1);
++length;
isSimple = gFalse;
return splashOk;
}
SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
int rectXMax, int rectYMax,
SplashStrokeAdjustMode strokeAdjust) {
// In general, this function tests the rectangle:
// x = [rectXMin, rectXMax + 1) (note: coords are ints)
// y = [rectYMin, rectYMax + 1)
// against the clipping region:
// x = [xMin, xMax) (note: coords are fp)
// y = [yMin, yMax)
if (strokeAdjust != splashStrokeAdjustOff && isSimple) {
// special case for stroke adjustment with a simple clipping
// rectangle -- the clipping region is:
// x = [xMinI, xMaxI + 1)
// y = [yMinI, yMaxI + 1)
updateIntBounds(strokeAdjust);
if (xMinI > xMaxI || yMinI > yMaxI) {
return splashClipAllOutside;
}
if (rectXMax + 1 <= xMinI ||
rectXMin >= xMaxI + 1 ||
rectYMax + 1 <= yMinI ||
rectYMin >= yMaxI + 1) {
return splashClipAllOutside;
}
if (rectXMin >= xMinI &&
rectXMax <= xMaxI &&
rectYMin >= yMinI &&
rectYMax <= yMaxI) {
return splashClipAllInside;
}
} else {
if (xMin >= xMax || yMin >= yMax) {
return splashClipAllOutside;
}
if ((SplashCoord)(rectXMax + 1) <= xMin ||
(SplashCoord)rectXMin >= xMax ||
(SplashCoord)(rectYMax + 1) <= yMin ||
(SplashCoord)rectYMin >= yMax) {
return splashClipAllOutside;
}
if (isSimple &&
(SplashCoord)rectXMin >= xMin &&
(SplashCoord)(rectXMax + 1) <= xMax &&
(SplashCoord)rectYMin >= yMin &&
(SplashCoord)(rectYMax + 1) <= yMax) {
return splashClipAllInside;
}
}
return splashClipPartial;
}
void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1,
SplashStrokeAdjustMode strokeAdjust) {
SplashClip *clip;
SplashCoord d;
int x0a, x1a, x0b, x1b, x, i;
updateIntBounds(strokeAdjust);
//--- clip to the integer rectangle
if (y < yMinI || y > yMaxI ||
x1 < xMinI || x0 > xMaxI) {
memset(line + x0, 0, x1 - x0 + 1);
return;
}
if (x0 > xMinI) {
x0a = x0;
} else {
x0a = xMinI;
memset(line + x0, 0, x0a - x0);
}
if (x1 < xMaxI) {
x1a = x1;
} else {
x1a = xMaxI;
memset(line + x1a + 1, 0, x1 - x1a);
}
if (x0a > x1a) {
return;
}
//--- clip to the floating point rectangle
// (if stroke adjustment is disabled)
if (strokeAdjust == splashStrokeAdjustOff) {
// clip left edge (xMin)
if (x0a == xMinI) {
d = (SplashCoord)(xMinI + 1) - xMin;
line[x0a] = (Guchar)(int)((SplashCoord)line[x0a] * d);
}
// clip right edge (xMax)
if (x1a == xMaxI) {
d = xMax - (SplashCoord)xMaxI;
line[x1a] = (Guchar)(int)((SplashCoord)line[x1a] * d);
}
// clip top edge (yMin)
if (y == yMinI) {
d = (SplashCoord)(yMinI + 1) - yMin;
for (x = x0a; x <= x1a; ++x) {
line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
}
}
// clip bottom edge (yMax)
if (y == yMaxI) {
d = yMax - (SplashCoord)yMaxI;
for (x = x0a; x <= x1a; ++x) {
line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
}
}
}
if (isSimple) {
return;
}
//--- clip to the paths
for (clip = this; clip; clip = clip->prev) {
for (i = 0; i < clip->length; ++i) {
clip->scanners[i]->getSpan(buf, y, x0a, x1a, &x0b, &x1b);
if (x0a < x0b) {
memset(line + x0a, 0, x0b - x0a);
}
for (x = x0b; x <= x1b; ++x) {
line[x] = mul255(line[x], buf[x]);
}
if (x1b < x1a) {
memset(line + x1b + 1, 0, x1a - x1b);
}
}
}
}
GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1,
SplashStrokeAdjustMode strokeAdjust) {
SplashClip *clip;
int x0a, x1a, x0b, x1b, x, i;
Guchar any;
updateIntBounds(strokeAdjust);
if (y < yMinI || y > yMaxI ||
x1 < xMinI || x0 > xMaxI) {
if (x0 <= x1) {
memset(line + x0, 0, x1 - x0 + 1);
}
return gFalse;
}
if (x0 > xMinI) {
x0a = x0;
} else {
x0a = xMinI;
memset(line + x0, 0, x0a - x0);
}
if (x1 < xMaxI) {
x1a = x1;
} else {
x1a = xMaxI;
memset(line + x1a + 1, 0, x1 - x1a);
}
if (x0a > x1a) {
return gFalse;
}
if (isSimple) {
for (x = x0a; x <= x1a; ++x) {
if (line[x]) {
return gTrue;
}
}
return gFalse;
}
any = 0;
for (clip = this; clip; clip = clip->prev) {
for (i = 0; i < clip->length; ++i) {
clip->scanners[i]->getSpanBinary(buf, y, x0a, x1a, &x0b, &x1b);
if (x0a < x0b) {
memset(line + x0a, 0, x0b - x0a);
}
for (x = x0b; x <= x1b; ++x) {
line[x] &= buf[x];
any |= line[x];
}
if (x1b < x1a) {
memset(line + x1b + 1, 0, x1a - x1b);
}
}
}
return any != 0;
}
int SplashClip::getXMinI(SplashStrokeAdjustMode strokeAdjust) {
updateIntBounds(strokeAdjust);
return xMinI;
}
int SplashClip::getXMaxI(SplashStrokeAdjustMode strokeAdjust) {
updateIntBounds(strokeAdjust);
return xMaxI;
}
int SplashClip::getYMinI(SplashStrokeAdjustMode strokeAdjust) {
updateIntBounds(strokeAdjust);
return yMinI;
}
int SplashClip::getYMaxI(SplashStrokeAdjustMode strokeAdjust) {
updateIntBounds(strokeAdjust);
return yMaxI;
}
int SplashClip::getNumPaths() {
SplashClip *clip;
int n;
n = 0;
for (clip = this; clip; clip = clip->prev) {
n += clip->length;
}
return n;
}
void SplashClip::updateIntBounds(SplashStrokeAdjustMode strokeAdjust) {
if (intBoundsValid && strokeAdjust == intBoundsStrokeAdjust) {
return;
}
if (strokeAdjust != splashStrokeAdjustOff && isSimple) {
splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI, strokeAdjust);
splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI, strokeAdjust);
} else {
xMinI = splashFloor(xMin);
yMinI = splashFloor(yMin);
xMaxI = splashCeil(xMax);
yMaxI = splashCeil(yMax);
}
if (xMinI < hardXMin) {
xMinI = hardXMin;
}
if (yMinI < hardYMin) {
yMinI = hardYMin;
}
if (xMaxI > hardXMax) {
xMaxI = hardXMax;
}
if (yMaxI > hardYMax) {
yMaxI = hardYMax;
}
// the clipping code uses [xMinI, xMaxI] instead of [xMinI, xMaxI)
--xMaxI;
--yMaxI;
intBoundsValid = gTrue;
intBoundsStrokeAdjust = strokeAdjust;
}