diff options
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc')
-rw-r--r-- | Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc | 569 |
1 files changed, 137 insertions, 432 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc index 86d08414476..e2da940bb41 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc @@ -8,6 +8,10 @@ #include <aconf.h> +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + #include <stdio.h> #include <stdlib.h> #include <stddef.h> @@ -61,11 +65,7 @@ // A large character has a font size larger than // largeCharThreshold * avgFontSize. -#define largeCharThreshold 2.0 - -// Max ratio of large-to-total chars to prefer a large char split over -// a line split. -#define largeCharRatio 0.2 +#define largeCharThreshold 1.5 // A block will be split vertically only if the resulting chunk widths // are greater than minChunkWidth * avgFontSize. However, Blocks of @@ -83,9 +83,9 @@ #define maxWordGapSize 2.5 #define tableModeMaxWordGapSize 1.1 -// Chars whose baseline is within baselineRange * avgFontSize of a -// line's current average baseline are added to the line. -#define baselineRange 0.5 +// Adjacent lines can overlap by at most lineOverlapThreshold * +// lineHeight. +#define lineOverlapThreshold 0.33 // Subscripts (superscripts) must overlap the next (previous) line by // minSubSuperscriptVertOverlap * fontSize. @@ -214,14 +214,12 @@ public: static int cmpX(const void *p1, const void *p2); static int cmpY(const void *p1, const void *p2); - static int cmpBase(const void *p1, const void *p2); static int cmpCharPos(const void *p1, const void *p2); Unicode c; int charPos; int charLen; double xMin, yMin, xMax, yMax; - double base; TextFontInfo *font; double fontSize; double colorR, @@ -251,50 +249,38 @@ TextChar::TextChar(Unicode cA, int charPosA, int charLenA, yMin = yMinA; xMax = xMaxA; yMax = yMaxA; - switch (rotA) { - case 0: - default: base = yMax + fontSizeA * fontA->getDescent(); break; - case 1: base = xMin - fontSizeA * fontA->getDescent(); break; - case 2: base = yMin - fontSizeA * fontA->getDescent(); break; - case 3: base = xMax + fontSizeA * fontA->getDescent(); break; + // this can happen with vertical writing mode, or with odd values + // for the char/word spacing parameters + if (xMin > xMax) { + t = xMin; xMin = xMax; xMax = t; + } + if (yMin > yMax) { + t = yMin; yMin = yMax; yMax = t; } // TextPage::findGaps uses integer coordinates, so clip the char // bbox to fit in a 32-bit int (this is generally only a problem in // damaged PDF files) if (xMin < -1e8) { xMin = -1e8; - } else if (xMin > 1e8) { - xMin = 1e8; } - if (xMax < -1e8) { - xMax = -1e8; - } else if (xMax > 1e8) { + if (xMax > 1e8) { xMax = 1e8; } if (yMin < -1e8) { yMin = -1e8; - } else if (yMin > 1e8) { - yMin = 1e8; } - if (yMax < -1e8) { - yMax = -1e8; - } else if (yMax > 1e8) { + if (yMax > 1e8) { yMax = 1e8; } - // this can happen with vertical writing mode, or with odd values - // for the char/word spacing parameters - if (xMin > xMax) { - t = xMin; xMin = xMax; xMax = t; - } - if (yMin > yMax) { - t = yMin; yMin = yMax; yMax = t; - } - // zero-width/height characters will cause problems in the splitting code - if (xMax - xMin < 1e-6) { - xMax = xMin + 1e-6; - } - if (yMax - yMin < 1e-6) { - yMax = yMin + 1e-6; + // zero-width characters will cause problems in the splitting code + if (rotA & 1) { + if (yMax - yMin < 1e-6) { + yMax = yMin + 1e-6; + } + } else { + if (xMax - xMin < 1e-6) { + xMax = xMin + 1e-6; + } } rot = (Guchar)rotA; rotated = (char)rotatedA; @@ -335,19 +321,6 @@ int TextChar::cmpY(const void *p1, const void *p2) { } } -int TextChar::cmpBase(const void *p1, const void *p2) { - const TextChar *ch1 = *(const TextChar **)p1; - const TextChar *ch2 = *(const TextChar **)p2; - - if (ch1->base < ch2->base) { - return -1; - } else if (ch1->base > ch2->base) { - return 1; - } else { - return ch1->charPos - ch2->charPos; - } -} - int TextChar::cmpCharPos(const void *p1, const void *p2) { const TextChar *ch1 = *(const TextChar **)p1; const TextChar *ch2 = *(const TextChar **)p2; @@ -1012,8 +985,7 @@ TextLine::TextLine(GList *wordsA, double xMinA, double yMinA, } } //~ need to check for other Unicode chars used as hyphens - hyphenated = text[len - 1] == (Unicode)'-' || - text[len - 1] == (Unicode)0xad; + hyphenated = text[len - 1] == (Unicode)'-'; } TextLine::~TextLine() { @@ -1240,7 +1212,6 @@ TextPage::TextPage(TextOutputControl *controlA) { chars = new GList(); fonts = new GList(); - primaryRot = 0; underlines = new GList(); links = new GList(); @@ -1269,15 +1240,6 @@ void TextPage::startPage(GfxState *state) { if (state) { pageWidth = state->getPageWidth(); pageHeight = state->getPageHeight(); - // When rotating characters, the coordinates are flipped using the - // page size. See the comment in TextChar::TextChar() about - // integer coordinates. - if (pageWidth > 1e8) { - pageWidth = 1e8; - } - if (pageHeight > 1e8) { - pageHeight = 1e8; - } } else { pageWidth = pageHeight = 0; } @@ -1304,9 +1266,6 @@ void TextPage::clear() { underlines = new GList(); deleteGList(links, TextLink); links = new GList(); - nVisibleChars = 0; - nInvisibleChars = 0; - nRemovedDupChars = 0; if (findCols) { deleteGList(findCols, TextColumn); @@ -1601,18 +1560,13 @@ void TextPage::addChar(GfxState *state, double x, double y, } else { j = i; } - GBool invisible = state->getRender() == 3 || alpha < 0.001; chars->append(new TextChar(uBuf[j], charPos, nBytes, xMin, yMin, xMax, yMax, - curRot, rotated, clipped, invisible, + curRot, rotated, clipped, + state->getRender() == 3 || alpha < 0.001, curFont, curFontSize, colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b))); - if (invisible) { - ++nInvisibleChars; - } else { - ++nVisibleChars; - } } } @@ -1776,7 +1730,7 @@ void TextPage::writeReadingOrder(void *outputStream, GList *columns; GBool primaryLR; GString *s; - int colIdx, parIdx, lineIdx, n; + int colIdx, parIdx, lineIdx, rot, n; #if 0 //~debug dumpChars(chars); @@ -1786,7 +1740,7 @@ void TextPage::writeReadingOrder(void *outputStream, } else { overlappingChars = NULL; } - primaryRot = rotateChars(chars); + rot = rotateChars(chars); primaryLR = checkPrimaryLR(chars); tree = splitChars(chars); #if 0 //~debug @@ -1794,14 +1748,14 @@ void TextPage::writeReadingOrder(void *outputStream, #endif if (!tree) { // no text - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); return; } columns = buildColumns(tree, primaryLR); delete tree; - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); if (control.html) { - rotateUnderlinesAndLinks(primaryRot); + rotateUnderlinesAndLinks(rot); generateUnderlinesAndLinks(columns); } if (overlappingChars) { @@ -1845,10 +1799,10 @@ GList *TextPage::makeColumns() { GList *overlappingChars; GList *columns; GBool primaryLR; + int rot; if (control.mode == textOutSimple2Layout) { primaryLR = checkPrimaryLR(chars); - primaryRot = 0; rotateCharsToZero(chars); columns = buildSimple2Columns(chars); unrotateCharsFromZero(chars); @@ -1859,7 +1813,7 @@ GList *TextPage::makeColumns() { } else { overlappingChars = NULL; } - primaryRot = rotateChars(chars); + rot = rotateChars(chars); primaryLR = checkPrimaryLR(chars); if ((tree = splitChars(chars))) { columns = buildColumns(tree, primaryLR); @@ -1868,8 +1822,8 @@ GList *TextPage::makeColumns() { // no text columns = new GList(); } - unrotateChars(chars, primaryRot); - unrotateColumns(columns, primaryRot); + unrotateChars(chars, rot); + unrotateColumns(columns, rot); if (control.html) { generateUnderlinesAndLinks(columns); } @@ -1898,7 +1852,7 @@ void TextPage::writePhysLayout(void *outputStream, GList *overlappingChars; GList *columns; GBool primaryLR; - int ph, colIdx, parIdx, lineIdx, y, i; + int ph, colIdx, parIdx, lineIdx, rot, y, i; #if 0 //~debug dumpChars(chars); @@ -1911,7 +1865,7 @@ void TextPage::writePhysLayout(void *outputStream, } else { overlappingChars = NULL; } - primaryRot = rotateChars(chars); + rot = rotateChars(chars); primaryLR = checkPrimaryLR(chars); tree = splitChars(chars); #if 0 //~debug @@ -1919,15 +1873,15 @@ void TextPage::writePhysLayout(void *outputStream, #endif if (!tree) { // no text - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); return; } //~ this doesn't correctly handle the right-to-left case columns = buildColumns(tree, gTrue); delete tree; - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); if (control.html) { - rotateUnderlinesAndLinks(primaryRot); + rotateUnderlinesAndLinks(rot); generateUnderlinesAndLinks(columns); } ph = assignPhysLayoutPositions(columns); @@ -1986,7 +1940,7 @@ void TextPage::writePhysLayout(void *outputStream, if (overlappingChars) { if (overlappingChars->getLength() > 0) { - col = buildOverlappingTextColumn(overlappingChars); + TextColumn *col = buildOverlappingTextColumn(overlappingChars); (*outputFunc)(outputStream, eol, eolLen); for (parIdx = 0; parIdx < col->paragraphs->getLength(); ++parIdx) { par = (TextParagraph *)col->paragraphs->get(parIdx); @@ -2019,12 +1973,12 @@ void TextPage::writeSimpleLayout(void *outputStream, GList *superLines; GString *out; GBool primaryLR; - int x, i, j; + int rot, x, i, j; #if 0 //~debug dumpChars(chars); #endif - primaryRot = rotateChars(chars); + rot = rotateChars(chars); primaryLR = checkPrimaryLR(chars); tree = splitChars(chars); #if 0 //~debug @@ -2032,13 +1986,13 @@ void TextPage::writeSimpleLayout(void *outputStream, #endif if (!tree) { // no text - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); return; } superLines = new GList(); buildSuperLines(tree, superLines); delete tree; - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); assignSimpleLayoutPositions(superLines, uMap); for (i = 0; i < superLines->getLength(); ++i) { @@ -2082,7 +2036,6 @@ void TextPage::writeSimple2Layout(void *outputStream, int colIdx, parIdx, lineIdx; primaryLR = checkPrimaryLR(chars); - primaryRot = 0; rotateCharsToZero(chars); #if 0 //~debug dumpChars(chars); @@ -2121,9 +2074,9 @@ void TextPage::writeLinePrinter(void *outputStream, double pitch, lineSpacing, delta; double yMin0, yShift, xMin0, xShift; double y, x; - int n, i, j, k; + int rot, n, i, j, k; - primaryRot = rotateChars(chars); + rot = rotateChars(chars); chars->sort(&TextChar::cmpX); // don't call removeDuplicates here, because it expects to be // working on a secondary list that doesn't own the TextChar objects @@ -2233,7 +2186,7 @@ void TextPage::writeLinePrinter(void *outputStream, delete line; } - unrotateChars(chars, primaryRot); + unrotateChars(chars, rot); } void TextPage::writeRaw(void *outputStream, @@ -2498,7 +2451,6 @@ int TextPage::rotateChars(GList *charsA) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageWidth - ch->base; ch->rot = (ch->rot + 3) & 3; } t = pageWidth; @@ -2516,7 +2468,6 @@ int TextPage::rotateChars(GList *charsA) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageHeight - ch->base; ch->rot = (ch->rot + 2) & 3; } break; @@ -2564,7 +2515,6 @@ void TextPage::rotateCharsToZero(GList *charsA) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageWidth - ch->base; break; case 2: xMin = pageWidth - ch->xMax; @@ -2575,7 +2525,6 @@ void TextPage::rotateCharsToZero(GList *charsA) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageHeight - ch->base; break; case 3: xMin = pageHeight - ch->yMax; @@ -2705,7 +2654,6 @@ void TextPage::unrotateChars(GList *charsA, int rot) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageWidth - ch->base; ch->rot = (ch->rot + 1) & 3; } break; @@ -2720,7 +2668,6 @@ void TextPage::unrotateChars(GList *charsA, int rot) { ch->xMax = xMax; ch->yMin = yMin; ch->yMax = yMax; - ch->base = pageHeight - ch->base; ch->rot = (ch->rot + 2) & 3; } break; @@ -3273,7 +3220,7 @@ GBool TextPage::checkPrimaryLR(GList *charsA) { // by x for rot=0,2; by y for rot=1,3. void TextPage::removeDuplicates(GList *charsA, int rot) { TextChar *ch, *ch2; - double xDelta, yDelta, xDelta2, yDelta2; + double xDelta, yDelta; int i, j; if (rot & 1) { @@ -3282,10 +3229,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { ch = (TextChar *)charsA->get(i); xDelta = dupMaxSecDelta * ch->fontSize; yDelta = dupMaxPriDelta * ch->fontSize; - yDelta2 = 0.5 * (ch->yMax - ch->yMin); - if (yDelta2 < yDelta) { - yDelta = yDelta2; - } j = i + 1; while (j < charsA->getLength()) { ch2 = (TextChar *)charsA->get(j); @@ -3298,7 +3241,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { fabs(ch2->yMax - ch->yMax) < yDelta) { if (ch->invisible && !ch2->invisible) { charsA->del(i); - ++nRemovedDupChars; --i; break; } @@ -3306,7 +3248,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { ch->spaceAfter = (char)gTrue; } charsA->del(j); - ++nRemovedDupChars; } else { ++j; } @@ -3318,10 +3259,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { while (i < charsA->getLength()) { ch = (TextChar *)charsA->get(i); xDelta = dupMaxPriDelta * ch->fontSize; - xDelta2 = 0.5 * (ch->xMax - ch->xMin); - if (xDelta2 < xDelta) { - xDelta = xDelta2; - } yDelta = dupMaxSecDelta * ch->fontSize; j = i + 1; while (j < charsA->getLength()) { @@ -3335,7 +3272,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { fabs(ch2->yMax - ch->yMax) < yDelta) { if (ch->invisible && !ch2->invisible) { charsA->del(i); - ++nRemovedDupChars; --i; break; } @@ -3343,7 +3279,6 @@ void TextPage::removeDuplicates(GList *charsA, int rot) { ch->spaceAfter = (char)gTrue; } charsA->del(j); - ++nRemovedDupChars; } else { ++j; } @@ -3624,7 +3559,7 @@ TextBlock *TextPage::splitChars(GList *charsA) { } } if (chars2->getLength() > 0) { - tree[rot] = split(chars2, rot); + tree[rot] = split(chars2, rot, gFalse); } } delete chars2; @@ -3655,11 +3590,9 @@ TextBlock *TextPage::splitChars(GList *charsA) { } // merge non-primary-rotation text into the primary-rotation tree - GBool doReorder = control.mode == textOutReadingOrder && - globalParams->getSeparateRotatedText(); for (rot = 1; rot < 4; ++rot) { if (tree[rot]) { - insertIntoTree(tree[rot], tree[0], doReorder); + insertIntoTree(tree[rot], tree[0]); tree[rot] = NULL; } } @@ -3677,7 +3610,7 @@ TextBlock *TextPage::splitChars(GList *charsA) { } // Generate a tree of TextBlocks, marked as columns, lines, and words. -TextBlock *TextPage::split(GList *charsA, int rot) { +TextBlock *TextPage::split(GList *charsA, int rot, GBool vertOnly) { TextBlock *blk; GList *chars2, *chars3; GList *splitLines; @@ -3829,13 +3762,18 @@ TextBlock *TextPage::split(GList *charsA, int rot) { doHorizSplit = doVertSplit = doLineSplit = doLargeCharSplit = gFalse; smallSplit = gFalse; if (rot & 1) { - if (control.mode == textOutSimpleLayout) { + if (vertOnly) { + if (nHorizGaps > 0 && horizGapSize > minGapSize * minFontSize) { + doHorizSplit = gTrue; + smallSplit = horizGapSize < smallSplitThreshold; + } + } else if (control.mode == textOutSimpleLayout) { if (nVertGaps > 0) { doVertSplit = gTrue; } else if (nHorizGaps > 0 && horizGapSize > minGapSize * minFontSize) { doHorizSplit = gTrue; smallSplit = horizGapSize < smallSplitThreshold; - } else if (splitLines->getLength() > 1) { + } else if (!vertOnly && splitLines->getLength() > 1) { doLineSplit = gTrue; } } else if (nHorizGaps > 0 && @@ -3848,15 +3786,19 @@ TextBlock *TextPage::split(GList *charsA, int rot) { smallSplit = horizGapSize < smallSplitThreshold; } else if (nVertGaps > 0) { doVertSplit = gTrue; - } else if (nLargeChars > 0 && - ((nLargeChars < largeCharRatio * charsA->getLength()) || - splitLines->getLength() <= 1)) { + } else if (nLargeChars > 0) { doLargeCharSplit = gTrue; } else if (splitLines->getLength() > 1) { doLineSplit = gTrue; } } else { - if (control.mode == textOutSimpleLayout) { + if (vertOnly) { + if (nVertGaps > 0 && + vertGapSize > minGapSize * minFontSize) { + doVertSplit = gTrue; + smallSplit = vertGapSize < smallSplitThreshold; + } + } else if (control.mode == textOutSimpleLayout) { if (nHorizGaps > 0) { doHorizSplit = gTrue; } else if (nVertGaps > 0 && vertGapSize > minGapSize * minFontSize) { @@ -3875,9 +3817,7 @@ TextBlock *TextPage::split(GList *charsA, int rot) { smallSplit = vertGapSize < smallSplitThreshold; } else if (nHorizGaps > 0) { doHorizSplit = gTrue; - } else if (nLargeChars > 0 && - ((nLargeChars < largeCharRatio * charsA->getLength()) || - splitLines->getLength() <= 1)) { + } else if (nLargeChars > 0) { doLargeCharSplit = gTrue; } else if (splitLines->getLength() > 1) { doLineSplit = gTrue; @@ -3907,13 +3847,13 @@ TextBlock *TextPage::split(GList *charsA, int rot) { 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)); + blk->addChild(split(chars2, rot, vertOnly)); delete chars2; x0 = x1; } } chars2 = getChars(charsA, x0, yMin - 1, xMax + 1, yMax + 1); - blk->addChild(split(chars2, rot)); + blk->addChild(split(chars2, rot, vertOnly)); delete chars2; // split horizontally @@ -3934,13 +3874,13 @@ TextBlock *TextPage::split(GList *charsA, int rot) { 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)); + blk->addChild(split(chars2, rot, gFalse)); delete chars2; y0 = y1; } } chars2 = getChars(charsA, xMin - 1, y0, xMax + 1, yMax + 1); - blk->addChild(split(chars2, rot)); + blk->addChild(split(chars2, rot, gFalse)); delete chars2; // split into larger and smaller chars @@ -3959,7 +3899,7 @@ TextBlock *TextPage::split(GList *charsA, int rot) { chars3->append(ch); } } - blk = split(chars3, rot); + blk = split(chars3, rot, gFalse); chars2->sort((rot & 1) ? &TextChar::cmpY : &TextChar::cmpX); insertLargeChars(chars2, blk); delete chars2; @@ -3985,21 +3925,12 @@ TextBlock *TextPage::split(GList *charsA, int rot) { for (i = 0; i < splitLine->chars->getLength(); ++i) { blk->addChild((TextChar *)splitLine->chars->get(i), gTrue); } -#if 0 //~debug - printf("line-leaf xMin=%g yMin=%g xMax=%g yMax=%g\n", - xMin, pageHeight - yMax, xMax, pageHeight - yMin); - printf(" "); - for (i = 0; i < splitLine->chars->getLength(); ++i) { - printf("%c", ((TextChar *)splitLine->chars->get(i))->c); - } - printf("\n"); -#endif } else { blk = new TextBlock((rot & 1) ? blkVertSplit : blkHorizSplit, rot); blk->smallSplit = gFalse; for (i = 0; i < splitLines->getLength(); ++i) { SplitLine *splitLine = (SplitLine *)splitLines->get(i); - blk->addChild(split(splitLine->chars, rot)); + blk->addChild(split(splitLine->chars, rot, singleLine)); } } @@ -4127,146 +4058,54 @@ void TextPage::findGaps(GList *charsA, int rot, } } - //----- find horizontal gaps + //----- partition into lines and find horizontal gaps if (rot & 1) { charsA->sort(&TextChar::cmpX); - double xxMax = 0; + SplitLine *splitLine = NULL; + double xxMin = 0, xxMax = 0; for (int i = 0; i < charsA->getLength(); ++i) { TextChar *ch = (TextChar *)charsA->get(i); - if (i == 0) { + if (i == 0 || + ch->xMin > xxMax - lineOverlapThreshold * (xxMax - xxMin)) { + if (i > 0 && ch->xMin > xxMax) { + vertGaps->addGap(0.5 * (ch->xMin + xxMax), ch->xMin - xxMax); + } + xxMin = ch->xMin; xxMax = ch->xMax; - } else if (ch->xMin <= xxMax) { + splitLine = new SplitLine(i, i, xxMin, xxMax); + splitLines->append(splitLine); + } else { + splitLine->lastCharIdx = i; if (ch->xMax > xxMax) { xxMax = ch->xMax; + splitLine->yMax = xxMax; } - } else { - vertGaps->addGap(0.5 * (ch->xMin + xxMax), ch->xMin - xxMax); - xxMax = ch->xMax; } } } else { charsA->sort(&TextChar::cmpY); - double yyMax = 0; + SplitLine *splitLine = NULL; + double yyMin = 0, yyMax = 0; for (int i = 0; i < charsA->getLength(); ++i) { TextChar *ch = (TextChar *)charsA->get(i); - if (i == 0) { - yyMax = ch->yMax; - } else if (ch->yMin <= yyMax) { - if (ch->yMax > yyMax) { - yyMax = ch->yMax; + if (i == 0 || + ch->yMin > yyMax - lineOverlapThreshold * (yyMax - yyMin)) { + if (i > 0 && ch->yMin > yyMax) { + horizGaps->addGap(0.5 * (ch->yMin + yyMax), ch->yMin - yyMax); } - } else { - horizGaps->addGap(0.5 * (ch->yMin + yyMax), ch->yMin - yyMax); + yyMin = ch->yMin; yyMax = ch->yMax; - } - } - } - - //----- split into lines - - double baseDelta = baselineRange * avgFontSize; - - if (rot & 1) { - - // split into non-overlapping chunks - int firstChar = 0; - while (firstChar < charsA->getLength()) { - TextChar *ch = (TextChar *)charsA->get(firstChar); - double xxMax = ch->xMax; - int nextChar = firstChar + 1; - while (nextChar < charsA->getLength()) { - ch = (TextChar *)charsA->get(nextChar); - if (ch->xMin > xxMax) { - break; - } - if (ch->xMax > xxMax) { - xxMax = ch->xMax; - } - ++nextChar; - } - - // split the chunk [firstChar, nextChar) into lines - charsA->sort(firstChar, nextChar - firstChar, &TextChar::cmpBase); - int i0 = firstChar; - while (i0 < nextChar) { - ch = (TextChar *)charsA->get(i0); - double baseTotal = ch->base; - double baseAvg = baseTotal; - double xxMin = ch->xMin; - xxMax = ch->xMax; - int i1 = i0 + 1; - while (i1 < nextChar) { - ch = (TextChar *)charsA->get(i1); - if (ch->base > baseAvg + baseDelta) { - break; - } - baseTotal += ch->base; - if (ch->xMin < xxMin) { - xxMin = ch->xMin; - } - if (ch->xMax > xxMax) { - xxMax = ch->xMax; - } - ++i1; - baseAvg = baseTotal / (i1 - i0); - } - splitLines->append(new SplitLine(i0, i1 - 1, xxMin, xxMax)); - i0 = i1; - } - firstChar = nextChar; - } - - } else { - - // split into non-overlapping chunks - int firstChar = 0; - while (firstChar < charsA->getLength()) { - TextChar *ch = (TextChar *)charsA->get(firstChar); - double yyMax = ch->yMax; - int nextChar = firstChar + 1; - while (nextChar < charsA->getLength()) { - ch = (TextChar *)charsA->get(nextChar); - if (ch->yMin > yyMax) { - break; - } + splitLine = new SplitLine(i, i, yyMin, yyMax); + splitLines->append(splitLine); + } else { + splitLine->lastCharIdx = i; if (ch->yMax > yyMax) { yyMax = ch->yMax; + splitLine->yMax = yyMax; } - ++nextChar; - } - - // split the chunk [firstChar, nextChar) into lines - charsA->sort(firstChar, nextChar - firstChar, &TextChar::cmpBase); - int i0 = firstChar; - while (i0 < nextChar) { - ch = (TextChar *)charsA->get(i0); - double baseTotal = ch->base; - double baseAvg = baseTotal; - double yyMin = ch->yMin; - yyMax = ch->yMax; - int i1 = i0 + 1; - while (i1 < nextChar) { - ch = (TextChar *)charsA->get(i1); - if (ch->base > baseAvg + baseDelta) { - break; - } - baseTotal += ch->base; - if (ch->yMin < yyMin) { - yyMin = ch->yMin; - } - if (ch->yMax > yyMax) { - yyMax = ch->yMax; - } - ++i1; - baseAvg = baseTotal / (i1 - i0); - } - splitLines->append(new SplitLine(i0, i1 - 1, yyMin, yyMax)); - i0 = i1; } - firstChar = nextChar; } - } } @@ -4358,19 +4197,10 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { // merge sub/superscripts into correct lines if (allSubSuper) { - idxAbove = 0; - idxBelow = 0; for (int idx = 0; idx < splitLine->chars->getLength(); ++idx) { TextChar *ch = (TextChar *)splitLine->chars->get(idx); if (maybeSub && ch->xMin < prevLine->yMax) { - while (idxAbove < prevLine->chars->getLength()) { - TextChar *ch2 = (TextChar *)prevLine->chars->get(idxAbove); - if (ch2->yMin > ch->yMin && ch2->xMin < ch->xMax && ch2->xMax > ch->xMin) { - break; - } - ++idxAbove; - } - prevLine->chars->insert(idxAbove, ch); + prevLine->chars->append(ch); if (ch->xMin < prevLine->yMin) { prevLine->yMin = ch->xMin; } @@ -4378,14 +4208,7 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { prevLine->yMax = ch->xMax; } } else { - while (idxBelow < nextLine->chars->getLength()) { - TextChar *ch2 = (TextChar *)nextLine->chars->get(idxBelow); - if (ch2->yMin > ch->yMin && ch2->xMin < ch->xMax && ch2->xMax > ch->xMin) { - break; - } - ++idxBelow; - } - nextLine->chars->insert(idxBelow, ch); + nextLine->chars->append(ch); if (ch->xMin < nextLine->yMin) { nextLine->yMin = ch->xMin; } @@ -4394,6 +4217,12 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { } } } + if (maybeSub) { + prevLine->chars->sort(&TextChar::cmpY); + } + if (maybeSuper) { + nextLine->chars->sort(&TextChar::cmpY); + } delete splitLine; splitLines->del(i); } @@ -4423,14 +4252,14 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { prevLine = (SplitLine *)splitLines->get(i-1); double minOverlap = minSubSuperscriptVertOverlap * (prevLine->yMax - prevLine->yMin); - maybeSub = prevLine->yMax - splitLine->yMin > minOverlap; + maybeSub = prevLine->yMax - splitLine->yMin > minOverlap; } GBool maybeSuper = gFalse; if (i < splitLines->getLength() - 1) { nextLine = (SplitLine *)splitLines->get(i+1); double minOverlap = minSubSuperscriptVertOverlap * (nextLine->yMax - nextLine->yMin); - maybeSuper = splitLine->yMax - nextLine->yMin > minOverlap; + maybeSuper = splitLine->yMax - nextLine->yMin > minOverlap; } if (!maybeSub && !maybeSuper) { continue; @@ -4486,19 +4315,10 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { // merge sub/superscripts into correct lines if (allSubSuper) { - idxAbove = 0; - idxBelow = 0; for (int idx = 0; idx < splitLine->chars->getLength(); ++idx) { TextChar *ch = (TextChar *)splitLine->chars->get(idx); if (maybeSub && ch->yMin < prevLine->yMax) { - while (idxAbove < prevLine->chars->getLength()) { - TextChar *ch2 = (TextChar *)prevLine->chars->get(idxAbove); - if (ch2->xMin > ch->xMin && ch2->yMin < ch->yMax && ch2->yMax > ch->yMin) { - break; - } - ++idxAbove; - } - prevLine->chars->insert(idxAbove, ch); + prevLine->chars->append(ch); if (ch->yMin < prevLine->yMin) { prevLine->yMin = ch->yMin; } @@ -4506,14 +4326,7 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { prevLine->yMax = ch->yMax; } } else { - while (idxBelow < nextLine->chars->getLength()) { - TextChar *ch2 = (TextChar *)nextLine->chars->get(idxBelow); - if (ch2->xMin > ch->xMin && ch2->yMin < ch->yMax && ch2->yMax > ch->yMin) { - break; - } - ++idxBelow; - } - nextLine->chars->insert(idxBelow, ch); + nextLine->chars->append(ch); if (ch->yMin < nextLine->yMin) { nextLine->yMin = ch->yMin; } @@ -4522,6 +4335,12 @@ void TextPage::mergeSplitLines(GList *charsA, int rot, GList *splitLines) { } } } + if (maybeSub) { + prevLine->chars->sort(&TextChar::cmpX); + } + if (maybeSuper) { + nextLine->chars->sort(&TextChar::cmpX); + } delete splitLine; splitLines->del(i); } @@ -4698,48 +4517,20 @@ void TextPage::insertLargeCharInLeaf(TextChar *ch, TextBlock *blk) { } // Merge blk (rot != 0) into primaryTree (rot == 0). -void TextPage::insertIntoTree(TextBlock *blk, TextBlock *primaryTree, - GBool doReorder) { - // if we're separating each rotation (only supported in reading - // order mode), reorder the block's children as appropriate and then - // append the block - if (doReorder) { - reorderBlocks(blk); - primaryTree->children->append(blk); - - // otherwise, insert blocks into the primary tree in the appropriate - // locations - } else { +void TextPage::insertIntoTree(TextBlock *blk, TextBlock *primaryTree) { + TextBlock *child; - // we insert a whole column at a time - so call insertIntoTree - // recursively until we get to a column (or line) - if (blk->tag == blkTagMulticolumn) { - while (blk->children->getLength()) { - TextBlock *child = (TextBlock *)blk->children->del(0); - insertIntoTree(child, primaryTree, doReorder); - } - delete blk; + // we insert a whole column at a time - so call insertIntoTree + // recursively until we get to a column (or line) - } else { - insertColumnIntoTree(blk, primaryTree); + if (blk->tag == blkTagMulticolumn) { + while (blk->children->getLength()) { + child = (TextBlock *)blk->children->del(0); + insertIntoTree(child, primaryTree); } - } -} - -// Reorder non-primary-rotation blocks as appropriate (for reading -// order mode only). -void TextPage::reorderBlocks(TextBlock *blk) { - if (blk->tag != blkTagMulticolumn) { - return; - } - for (int i = 0; i < blk->children->getLength(); ++i) { - reorderBlocks((TextBlock *)blk->children->get(i)); - } - //~ check/test these conditions - if ((blk->rot == 1 && blk->type == blkVertSplit) || - blk->rot == 2 || - (blk->rot == 3 && blk->type == blkHorizSplit)) { - blk->children->reverse(); + delete blk; + } else { + insertColumnIntoTree(blk, primaryTree); } } @@ -5304,13 +5095,11 @@ TextLine *TextPage::buildLine(GList *charsA, int rot, TextWord *word; double wordSp, lineFontSize, sp; int dir, dir2; - GBool rotated2, spaceAfter, spaceBefore; + GBool rotated, spaceAfter, spaceBefore; int i, j; wordSp = computeWordSpacingThreshold(charsA, rot); - adjustCombiningChars(charsA, rot); - words = new GList(); lineFontSize = 0; spaceBefore = gFalse; @@ -5324,7 +5113,7 @@ TextLine *TextPage::buildLine(GList *charsA, int rot, : (TextChar *)NULL, (i < charsA->getLength() - 1) ? (TextChar *)charsA->get(i+1) : (TextChar *)NULL); - rotated2 = ((TextChar *)charsA->get(i))->rotated; + rotated = ((TextChar *)charsA->get(i))->rotated; for (j = i+1; j < charsA->getLength(); ++j) { ch = (TextChar *)charsA->get(j-1); ch2 = (TextChar *)charsA->get(j); @@ -5345,7 +5134,7 @@ TextLine *TextPage::buildLine(GList *charsA, int rot, : (TextChar *)NULL); if (ch->font != ch2->font || fabs(ch->fontSize - ch2->fontSize) > 0.01 || - (control.splitRotatedWords && ch2->rotated != rotated2) || + (control.splitRotatedWords && ch2->rotated != rotated) || (dir && dir2 && dir2 != dir) || (control.mode == textOutRawOrder && ch2->charPos != ch->charPos + ch->charLen)) { @@ -5356,7 +5145,7 @@ TextLine *TextPage::buildLine(GList *charsA, int rot, } sp = wordSp - 1; } - word = new TextWord(charsA, i, j - i, rot, rotated2, dir, + word = new TextWord(charsA, i, j - i, rot, rotated, dir, (rot >= 2) ? spaceBefore : spaceAfter); spaceBefore = spaceAfter; i = j; @@ -5488,89 +5277,6 @@ double TextPage::computeWordSpacingThreshold(GList *charsA, int rot) { } } -// Move Unicode combining characters around so that they come -// immediately after the correct base characters. -//~ this currently won't work for RtL scripts -void TextPage::adjustCombiningChars(GList *charsA, int rot) { - int i = 1; - while (i < charsA->getLength()) { - TextChar *ch = (TextChar *)charsA->get(i); - - // look for a zero-width combining char - if (!(unicodeTypeCombiningMark(ch->c) && - fabs((rot & 1) ? ch->yMax - ch->yMin // width ~= zero - : ch->xMax - ch->xMin) < 0.01)) { - ++i; - continue; - } - - // look for a sequence of zero-width combining chars at the same - // position (NB: slight negative char spacing can reorder things - // so that diacritics for different base chars appear next to each - // other) - int j; - for (j = i + 1; j < charsA->getLength(); ++j) { - TextChar *ch2 = (TextChar *)charsA->get(j); - if (!(unicodeTypeCombiningMark(ch2->c) && - fabs((rot & 1) ? ch2->yMin - ch->yMax - : ch2->xMin - ch->xMax) < 0.01 * ch->fontSize && - fabs((rot & 1) ? ch->yMax - ch->yMin // width ~= zero - : ch->xMax - ch->xMin) < 0.01)) { - break; - } - } - - // identify the two previous chars - TextChar *prev1 = (i >= 2) ? (TextChar *)charsA->get(i - 2) : NULL; - TextChar *prev2 = (TextChar *)charsA->get(i - 1); - - //~ this code currently makes things worse for RtL scripts, so - //~ skip any RtL text - if (unicodeTypeR(prev2->c)) { - ++i; - continue; - } - - // if the combining chars are placed in the left 3/4 of prev2, - // assume the base char is prev1, not prev2, and reorder the chars - // accordingly - TextChar *base; - if (prev1 && - ((rot & 1) ? (ch->yMin < 0.25 * prev2->yMin + 0.75 * prev2->yMax) - : (ch->xMin < 0.25 * prev2->xMin + 0.75 * prev2->xMax))) { - for (int k = i; k < j; ++k) { - charsA->put(k - 1, charsA->get(k)); - } - charsA->put(j - 1, prev2); - --i; - --j; - base = prev1; - } else { - base = prev2; - } - - // sort the diacritics into content stream order - // (slight negative char spacing, used for kerning, will push - // zero-width diacritics out of order) - if (j - i > 1) { - charsA->sort(i, j - i, &TextChar::cmpCharPos); - } - - // set the diacritics' positions immediately to the right of the - // base char - for (int k = i; k < j; ++k) { - TextChar *ch2 = (TextChar *)charsA->get(k); - if (rot & 1) { - ch2->yMin = ch2->yMax = base->yMax; - } else { - ch2->xMin = ch2->xMax = base->xMax; - } - } - - i = j; - } -} - // Check the character's direction: returns 1 for L or Num; -1 for R; 0 // for others. int TextPage::getCharDirection(TextChar *ch) { @@ -6918,8 +6624,7 @@ void TextOutputDev::endString(GfxState *state) { void TextOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, - CharCode c, int nBytes, Unicode *u, int uLen, - GBool fill, GBool stroke, GBool makePath) { + CharCode c, int nBytes, Unicode *u, int uLen) { text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen); } |