summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc')
-rw-r--r--Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc273
1 files changed, 167 insertions, 106 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
index 9c226af3f31..4f594384915 100644
--- a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
+++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <stddef.h>
#include <math.h>
+#include <limits.h>
#include <ctype.h>
#ifdef _WIN32
#include <fcntl.h> // for O_BINARY
@@ -111,7 +112,7 @@
// In simple layout mode, lines are broken at gaps larger than this
// value multiplied by font size.
-#define simpleLayoutGapThreshold 0.4
+#define simpleLayoutGapThreshold 0.7
// Table cells (TextColumns) are allowed to overlap by this much
// in table layout mode (as a fraction of cell width or height).
@@ -407,19 +408,52 @@ void TextBlock::updateBounds(int childIdx) {
}
//------------------------------------------------------------------------
-// TextGap
+// TextGaps
//------------------------------------------------------------------------
-class TextGap {
+struct TextGap {
+ double x; // center of gap: x for vertical gaps,
+ // y for horizontal gaps
+ double w; // width/height of gap
+};
+
+class TextGaps {
public:
- TextGap(double aXY, double aW): xy(aXY), w(aW) {}
+ TextGaps();
+ ~TextGaps();
+ void addGap(double x, double w);
+ int getLength() { return length; }
+ double getX(int idx) { return gaps[idx].x; }
+ double getW(int idx) { return gaps[idx].w; }
- double xy; // center of gap: x for vertical gaps,
- // y for horizontal gaps
- double w; // width of gap
+private:
+
+ int length;
+ int size;
+ TextGap *gaps;
};
+TextGaps::TextGaps() {
+ length = 0;
+ size = 16;
+ gaps = (TextGap *)gmallocn(size, sizeof(TextGap));
+}
+
+TextGaps::~TextGaps() {
+ gfree(gaps);
+}
+
+void TextGaps::addGap(double x, double w) {
+ if (length == size) {
+ size *= 2;
+ gaps = (TextGap *)greallocn(gaps, size, sizeof(TextGap));
+ }
+ gaps[length].x = x;
+ gaps[length].w = w;
+ ++length;
+}
+
//------------------------------------------------------------------------
// TextSuperLine
//------------------------------------------------------------------------
@@ -508,6 +542,10 @@ TextOutputControl::TextOutputControl() {
discardInvisibleText = gFalse;
discardClippedText = gFalse;
insertBOM = gFalse;
+ marginLeft = 0;
+ marginRight = 0;
+ marginTop = 0;
+ marginBottom = 0;
}
@@ -1136,9 +1174,11 @@ void TextPage::updateFont(GfxState *state) {
if (name && name[0] == 'm' && name[1] == '\0') {
mCode = code;
}
- if (letterCode < 0 && name && name[1] == '\0' &&
+ if (letterCode < 0 &&
+ name &&
((name[0] >= 'A' && name[0] <= 'Z') ||
- (name[0] >= 'a' && name[0] <= 'z'))) {
+ (name[0] >= 'a' && name[0] <= 'z')) &&
+ name[1] == '\0') {
letterCode = code;
}
if (anyCode < 0 && name &&
@@ -1239,9 +1279,12 @@ void TextPage::addChar(GfxState *state, double x, double y,
// throw away chars that aren't inside the page bounds
// (and also do a sanity check on the character size)
state->transform(x, y, &x1, &y1);
- if (x1 + w1 < 0 || x1 > pageWidth ||
- y1 + h1 < 0 || y1 > pageHeight ||
- w1 > pageWidth || h1 > pageHeight) {
+ if (x1 + w1 < control.marginLeft ||
+ x1 > pageWidth - control.marginRight ||
+ y1 + h1 < control.marginTop ||
+ y1 > pageHeight - control.marginBottom ||
+ w1 > pageWidth ||
+ h1 > pageHeight) {
charPos += nBytes;
return;
}
@@ -1876,8 +1919,9 @@ void TextPage::writeRaw(void *outputStream,
if (fabs(ch2->yMin - ch->yMin) > rawModeLineDelta * ch->fontSize ||
ch2->xMin - ch->xMax < -rawModeCharOverlap * ch->fontSize) {
s->append(eol, eolLen);
- } else if (ch2->xMin - ch->xMax >
- rawModeWordSpacing * ch->fontSize) {
+ } else if (ch->spaceAfter ||
+ ch2->xMin - ch->xMax >
+ rawModeWordSpacing * ch->fontSize) {
s->append(space, spaceLen);
}
break;
@@ -1885,8 +1929,9 @@ void TextPage::writeRaw(void *outputStream,
if (fabs(ch->xMax - ch2->xMax) > rawModeLineDelta * ch->fontSize ||
ch2->yMin - ch->yMax < -rawModeCharOverlap * ch->fontSize) {
s->append(eol, eolLen);
- } else if (ch2->yMin - ch->yMax >
- rawModeWordSpacing * ch->fontSize) {
+ } else if (ch->spaceAfter ||
+ ch2->yMin - ch->yMax >
+ rawModeWordSpacing * ch->fontSize) {
s->append(space, spaceLen);
}
break;
@@ -1894,8 +1939,9 @@ void TextPage::writeRaw(void *outputStream,
if (fabs(ch->yMax - ch2->yMax) > rawModeLineDelta * ch->fontSize ||
ch->xMin - ch2->xMax < -rawModeCharOverlap * ch->fontSize) {
s->append(eol, eolLen);
- } else if (ch->xMin - ch2->xMax >
- rawModeWordSpacing * ch->fontSize) {
+ } else if (ch->spaceAfter ||
+ ch->xMin - ch2->xMax >
+ rawModeWordSpacing * ch->fontSize) {
s->append(space, spaceLen);
}
break;
@@ -1903,8 +1949,9 @@ void TextPage::writeRaw(void *outputStream,
if (fabs(ch2->xMin - ch->xMin) > rawModeLineDelta * ch->fontSize ||
ch->yMin - ch2->yMax < -rawModeCharOverlap * ch->fontSize) {
s->append(eol, eolLen);
- } else if (ch->yMin - ch2->yMax >
- rawModeWordSpacing * ch->fontSize) {
+ } else if (ch->spaceAfter ||
+ ch->yMin - ch2->yMax >
+ rawModeWordSpacing * ch->fontSize) {
s->append(space, spaceLen);
}
break;
@@ -2693,12 +2740,11 @@ TextBlock *TextPage::splitChars(GList *charsA) {
TextBlock *TextPage::split(GList *charsA, int rot) {
TextBlock *blk;
GList *chars2, *chars3;
- GList *horizGaps, *vertGaps;
- TextGap *gap;
+ TextGaps *horizGaps, *vertGaps;
TextChar *ch;
double xMin, yMin, xMax, yMax, avgFontSize;
double horizGapSize, vertGapSize, minHorizChunkWidth, minVertChunkWidth;
- double nLines, vertGapThreshold, minChunk;
+ double gap, nLines, vertGapThreshold, minChunk;
double largeCharSize;
double x0, x1, y0, y1;
int nHorizGaps, nVertGaps, nLargeChars;
@@ -2707,8 +2753,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
//----- find all horizontal and vertical gaps
- horizGaps = new GList();
- vertGaps = new GList();
+ horizGaps = new TextGaps();
+ vertGaps = new TextGaps();
findGaps(charsA, rot, &xMin, &yMin, &xMax, &yMax, &avgFontSize,
horizGaps, vertGaps);
@@ -2716,16 +2762,16 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
horizGapSize = 0;
for (i = 0; i < horizGaps->getLength(); ++i) {
- gap = (TextGap *)horizGaps->get(i);
- if (gap->w > horizGapSize) {
- horizGapSize = gap->w;
+ gap = horizGaps->getW(i);
+ if (gap > horizGapSize) {
+ horizGapSize = gap;
}
}
vertGapSize = 0;
for (i = 0; i < vertGaps->getLength(); ++i) {
- gap = (TextGap *)vertGaps->get(i);
- if (gap->w > vertGapSize) {
- vertGapSize = gap->w;
+ gap = vertGaps->getW(i);
+ if (gap > vertGapSize) {
+ vertGapSize = gap;
}
}
@@ -2736,14 +2782,14 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
if (horizGaps->getLength() > 0) {
y0 = yMin;
for (i = 0; i < horizGaps->getLength(); ++i) {
- gap = (TextGap *)horizGaps->get(i);
- if (gap->w > horizGapSize - splitGapSlack * avgFontSize) {
+ gap = horizGaps->getW(i);
+ if (gap > horizGapSize - splitGapSlack * avgFontSize) {
++nHorizGaps;
- y1 = gap->xy - 0.5 * gap->w;
+ y1 = horizGaps->getX(i) - 0.5 * gap;
if (y1 - y0 < minHorizChunkWidth) {
minHorizChunkWidth = y1 - y0;
}
- y0 = y1 + gap->w;
+ y0 = y1 + gap;
}
}
y1 = yMax;
@@ -2756,14 +2802,14 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
if (vertGaps->getLength() > 0) {
x0 = xMin;
for (i = 0; i < vertGaps->getLength(); ++i) {
- gap = (TextGap *)vertGaps->get(i);
- if (gap->w > vertGapSize - splitGapSlack * avgFontSize) {
+ gap = vertGaps->getW(i);
+ if (gap > vertGapSize - splitGapSlack * avgFontSize) {
++nVertGaps;
- x1 = gap->xy - 0.5 * gap->w;
+ x1 = vertGaps->getX(i) - 0.5 * gap;
if (x1 - x0 < minVertChunkWidth) {
minVertChunkWidth = x1 - x0;
}
- x0 = x1 + gap->w;
+ x0 = x1 + gap;
}
}
x1 = xMax;
@@ -2881,9 +2927,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
printf("vert split xMin=%g yMin=%g xMax=%g yMax=%g small=%d\n",
xMin, pageHeight - yMax, xMax, pageHeight - yMin, smallSplit);
for (i = 0; i < vertGaps->getLength(); ++i) {
- gap = (TextGap *)vertGaps->get(i);
- if (gap->w > vertGapSize - splitGapSlack * avgFontSize) {
- printf(" x=%g\n", gap->xy);
+ if (vertGaps->getW(i) > vertGapSize - splitGapSlack * avgFontSize) {
+ printf(" x=%g\n", vertGaps->getX(i));
}
}
#endif
@@ -2891,9 +2936,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
blk->smallSplit = smallSplit;
x0 = xMin - 1;
for (i = 0; i < vertGaps->getLength(); ++i) {
- gap = (TextGap *)vertGaps->get(i);
- if (gap->w > vertGapSize - splitGapSlack * avgFontSize) {
- x1 = gap->xy;
+ if (vertGaps->getW(i) > vertGapSize - splitGapSlack * avgFontSize) {
+ x1 = vertGaps->getX(i);
chars2 = getChars(charsA, x0, yMin - 1, x1, yMax + 1);
blk->addChild(split(chars2, rot));
delete chars2;
@@ -2910,9 +2954,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
printf("horiz split xMin=%g yMin=%g xMax=%g yMax=%g small=%d\n",
xMin, pageHeight - yMax, xMax, pageHeight - yMin, smallSplit);
for (i = 0; i < horizGaps->getLength(); ++i) {
- gap = (TextGap *)horizGaps->get(i);
- if (gap->w > horizGapSize - splitGapSlack * avgFontSize) {
- printf(" y=%g\n", pageHeight - gap->xy);
+ if (horizGaps->getW(i) > horizGapSize - splitGapSlack * avgFontSize) {
+ printf(" y=%g\n", pageHeight - horizGaps->getX(i));
}
}
#endif
@@ -2920,9 +2963,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
blk->smallSplit = smallSplit;
y0 = yMin - 1;
for (i = 0; i < horizGaps->getLength(); ++i) {
- gap = (TextGap *)horizGaps->get(i);
- if (gap->w > horizGapSize - splitGapSlack * avgFontSize) {
- y1 = gap->xy;
+ if (horizGaps->getW(i) > horizGapSize - splitGapSlack * avgFontSize) {
+ y1 = horizGaps->getX(i);
chars2 = getChars(charsA, xMin - 1, y0, xMax + 1, y1);
blk->addChild(split(chars2, rot));
delete chars2;
@@ -2966,8 +3008,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) {
}
}
- deleteGList(horizGaps, TextGap);
- deleteGList(vertGaps, TextGap);
+ delete horizGaps;
+ delete vertGaps;
tagBlock(blk);
@@ -3001,11 +3043,12 @@ void TextPage::findGaps(GList *charsA, int rot,
double *xMinOut, double *yMinOut,
double *xMaxOut, double *yMaxOut,
double *avgFontSizeOut,
- GList *horizGaps, GList *vertGaps) {
+ TextGaps *horizGaps, TextGaps *vertGaps) {
TextChar *ch;
- int *horizProfile, *vertProfile;
+ char *horizProfile, *vertProfile;
double xMin, yMin, xMax, yMax, w;
- double minFontSize, avgFontSize, splitPrecision, ascentAdjust, descentAdjust;
+ double minFontSize, avgFontSize, splitPrecision, invSplitPrecision;
+ double ascentAdjust, descentAdjust;
int xMinI, yMinI, xMaxI, yMaxI, xMinI2, yMinI2, xMaxI2, yMaxI2;
int start, x, y, i;
@@ -3037,6 +3080,7 @@ void TextPage::findGaps(GList *charsA, int rot,
if (splitPrecision < minSplitPrecision) {
splitPrecision = minSplitPrecision;
}
+ invSplitPrecision = 1 / splitPrecision;
*xMinOut = xMin;
*yMinOut = yMin;
*xMaxOut = xMax;
@@ -3045,59 +3089,65 @@ void TextPage::findGaps(GList *charsA, int rot,
//----- compute the horizontal and vertical profiles
+ if (xMin * invSplitPrecision < 0.5 * INT_MIN ||
+ xMax * invSplitPrecision > 0.5 * INT_MAX ||
+ yMin * invSplitPrecision < 0.5 * INT_MIN ||
+ xMax * invSplitPrecision > 0.5 * INT_MAX) {
+ return;
+ }
// add some slack to the array bounds to avoid floating point
// precision problems
- xMinI = (int)floor(xMin / splitPrecision) - 1;
- yMinI = (int)floor(yMin / splitPrecision) - 1;
- xMaxI = (int)floor(xMax / splitPrecision) + 1;
- yMaxI = (int)floor(yMax / splitPrecision) + 1;
- horizProfile = (int *)gmallocn(yMaxI - yMinI + 1, sizeof(int));
- vertProfile = (int *)gmallocn(xMaxI - xMinI + 1, sizeof(int));
- memset(horizProfile, 0, (yMaxI - yMinI + 1) * sizeof(int));
- memset(vertProfile, 0, (xMaxI - xMinI + 1) * sizeof(int));
+ xMinI = (int)floor(xMin * invSplitPrecision) - 1;
+ yMinI = (int)floor(yMin * invSplitPrecision) - 1;
+ xMaxI = (int)floor(xMax * invSplitPrecision) + 1;
+ yMaxI = (int)floor(yMax * invSplitPrecision) + 1;
+ horizProfile = (char *)gmalloc(yMaxI - yMinI + 1);
+ vertProfile = (char *)gmalloc(xMaxI - xMinI + 1);
+ memset(horizProfile, 0, yMaxI - yMinI + 1);
+ memset(vertProfile, 0, xMaxI - xMinI + 1);
for (i = 0; i < charsA->getLength(); ++i) {
ch = (TextChar *)charsA->get(i);
// yMinI2 and yMaxI2 are adjusted to allow for slightly overlapping lines
switch (rot) {
case 0:
default:
- xMinI2 = (int)floor(ch->xMin / splitPrecision);
- xMaxI2 = (int)floor(ch->xMax / splitPrecision);
+ xMinI2 = (int)floor(ch->xMin * invSplitPrecision);
+ xMaxI2 = (int)floor(ch->xMax * invSplitPrecision);
ascentAdjust = ascentAdjustFactor * (ch->yMax - ch->yMin);
- yMinI2 = (int)floor((ch->yMin + ascentAdjust) / splitPrecision);
+ yMinI2 = (int)floor((ch->yMin + ascentAdjust) * invSplitPrecision);
descentAdjust = descentAdjustFactor * (ch->yMax - ch->yMin);
- yMaxI2 = (int)floor((ch->yMax - descentAdjust) / splitPrecision);
+ yMaxI2 = (int)floor((ch->yMax - descentAdjust) * invSplitPrecision);
break;
case 1:
descentAdjust = descentAdjustFactor * (ch->xMax - ch->xMin);
- xMinI2 = (int)floor((ch->xMin + descentAdjust) / splitPrecision);
+ xMinI2 = (int)floor((ch->xMin + descentAdjust) * invSplitPrecision);
ascentAdjust = ascentAdjustFactor * (ch->xMax - ch->xMin);
- xMaxI2 = (int)floor((ch->xMax - ascentAdjust) / splitPrecision);
- yMinI2 = (int)floor(ch->yMin / splitPrecision);
- yMaxI2 = (int)floor(ch->yMax / splitPrecision);
+ xMaxI2 = (int)floor((ch->xMax - ascentAdjust) * invSplitPrecision);
+ yMinI2 = (int)floor(ch->yMin * invSplitPrecision);
+ yMaxI2 = (int)floor(ch->yMax * invSplitPrecision);
break;
case 2:
- xMinI2 = (int)floor(ch->xMin / splitPrecision);
- xMaxI2 = (int)floor(ch->xMax / splitPrecision);
+ xMinI2 = (int)floor(ch->xMin * invSplitPrecision);
+ xMaxI2 = (int)floor(ch->xMax * invSplitPrecision);
descentAdjust = descentAdjustFactor * (ch->yMax - ch->yMin);
- yMinI2 = (int)floor((ch->yMin + descentAdjust) / splitPrecision);
+ yMinI2 = (int)floor((ch->yMin + descentAdjust) * invSplitPrecision);
ascentAdjust = ascentAdjustFactor * (ch->yMax - ch->yMin);
- yMaxI2 = (int)floor((ch->yMax - ascentAdjust) / splitPrecision);
+ yMaxI2 = (int)floor((ch->yMax - ascentAdjust) * invSplitPrecision);
break;
case 3:
ascentAdjust = ascentAdjustFactor * (ch->xMax - ch->xMin);
- xMinI2 = (int)floor((ch->xMin + ascentAdjust) / splitPrecision);
+ xMinI2 = (int)floor((ch->xMin + ascentAdjust) * invSplitPrecision);
descentAdjust = descentAdjustFactor * (ch->xMax - ch->xMin);
- xMaxI2 = (int)floor((ch->xMax - descentAdjust) / splitPrecision);
- yMinI2 = (int)floor(ch->yMin / splitPrecision);
- yMaxI2 = (int)floor(ch->yMax / splitPrecision);
+ xMaxI2 = (int)floor((ch->xMax - descentAdjust) * invSplitPrecision);
+ yMinI2 = (int)floor(ch->yMin * invSplitPrecision);
+ yMaxI2 = (int)floor(ch->yMax * invSplitPrecision);
break;
}
for (y = yMinI2; y <= yMaxI2; ++y) {
- ++horizProfile[y - yMinI];
+ horizProfile[y - yMinI] = 1;
}
for (x = xMinI2; x <= xMaxI2; ++x) {
- ++vertProfile[x - xMinI];
+ vertProfile[x - xMinI] = 1;
}
}
@@ -3112,8 +3162,7 @@ void TextPage::findGaps(GList *charsA, int rot,
} else {
if (horizProfile[y + 1 - yMinI]) {
w = (y - start) * splitPrecision;
- horizGaps->append(new TextGap((start + 1) * splitPrecision + 0.5 * w,
- w));
+ horizGaps->addGap((start + 1) * splitPrecision + 0.5 * w, w);
}
}
}
@@ -3129,8 +3178,7 @@ void TextPage::findGaps(GList *charsA, int rot,
} else {
if (vertProfile[x + 1 - xMinI]) {
w = (x - start) * splitPrecision;
- vertGaps->append(new TextGap((start + 1) * splitPrecision + 0.5 * w,
- w));
+ vertGaps->addGap((start + 1) * splitPrecision + 0.5 * w, w);
}
}
}
@@ -3818,18 +3866,27 @@ double TextPage::computeWordSpacingThreshold(GList *charsA, int rot) {
minGap = 0;
}
- // if spacing is nearly uniform (minGap is close to maxGap), use the
- // SpGap/AdjGap values if available, otherwise assume it's a single
- // word (technically it could be either "ABC" or "A B C", but it's
- // essentially impossible to tell)
+ // if spacing is nearly uniform (minGap is close to maxGap), there
+ // are three cases:
+ // (1) if the SpGap and AdjGap values are both available and
+ // sensible, use them
+ // (2) if only the SpGap values are available, meaning that every
+ // character in the line had a space after it, split after every
+ // character
+ // (3) otherwise assume it's a single word (technically it could be
+ // either "ABC" or "A B C", but it's essentially impossible to
+ // tell)
if (maxGap - minGap < uniformSpacing * avgFontSize) {
- if (minAdjGap <= maxAdjGap &&
- minSpGap <= maxSpGap &&
- minSpGap - maxAdjGap > 0.01) {
- return 0.5 * (maxAdjGap + minSpGap);
- } else {
- return maxGap + 1;
+ if (minSpGap <= maxSpGap) {
+ if (minAdjGap <= maxAdjGap &&
+ minSpGap - maxAdjGap > 0.01) {
+ return 0.5 * (maxAdjGap + minSpGap);
+ } else if (minAdjGap > maxAdjGap &&
+ maxSpGap - minSpGap < uniformSpacing * avgFontSize) {
+ return minSpGap - 1;
+ }
}
+ return maxGap + 1;
// if there is some variation in spacing, but it's small, assume
// there are some inter-word spaces
@@ -4033,8 +4090,8 @@ void TextPage::assignSimpleLayoutPositions(GList *superLines,
UnicodeMap *uMap) {
GList *lines;
TextLine *line0, *line1;
- double xMin;
- int px, sp, i, j;
+ double xMin, xMax;
+ int px, px2, sp, i, j;
// build a list of lines and sort by x
lines = new GList();
@@ -4048,21 +4105,25 @@ void TextPage::assignSimpleLayoutPositions(GList *superLines,
for (i = 0; i < lines->getLength(); ++i) {
line0 = (TextLine *)lines->get(i);
computeLinePhysWidth(line0, uMap);
- line0->px = (int)((line0->xMin - xMin) / (0.5 * line0->fontSize));
+ px = 0;
+ xMax = xMin;
for (j = 0; j < i; ++j) {
line1 = (TextLine *)lines->get(j);
if (line0->xMin > line1->xMax) {
- sp = (int)((line0->xMin - line1->xMax) /
- (0.5 * line0->fontSize) + 0.5);
- if (sp < 1) {
- sp = 1;
+ if (line1->xMax > xMax) {
+ xMax = line1->xMax;
}
- px = line1->px + line1->pw + sp;
- if (px > line0->px) {
- line0->px = px;
+ px2 = line1->px + line1->pw;
+ if (px2 > px) {
+ px = px2;
}
}
}
+ sp = (int)((line0->xMin - xMax) / (0.5 * line0->fontSize) + 0.5);
+ if (sp < 1 && xMax > xMin) {
+ sp = 1;
+ }
+ line0->px = px + sp;
}
delete lines;