Commit e17f0956 authored by Albert Astals Cid's avatar Albert Astals Cid

[xpdf303] TextOutputDev and associated changes

parent 548648bf
......@@ -208,24 +208,24 @@ bool page::search(const ustring &text, rectf &r, search_direction_enum direction
double rect_right = r.right();
double rect_bottom = r.bottom();
TextOutputDev td(NULL, gTrue, gFalse, gFalse);
TextOutputDev td(NULL, gTrue, 0, gFalse, gFalse);
d->doc->doc->displayPage(&td, d->index + 1, 72, 72, rotation_value, false, true, false);
TextPage *text_page = td.takeText();
switch (direction) {
case search_from_top:
found = text_page->findText(&u[0], len,
gTrue, gTrue, gFalse, gFalse, sCase, gFalse,
gTrue, gTrue, gFalse, gFalse, sCase, gFalse, gFalse,
&rect_left, &rect_top, &rect_right, &rect_bottom);
break;
case search_next_result:
found = text_page->findText(&u[0], len,
gFalse, gTrue, gTrue, gFalse, sCase, gFalse,
gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse,
&rect_left, &rect_top, &rect_right, &rect_bottom);
break;
case search_previous_result:
found = text_page->findText(&u[0], len,
gFalse, gTrue, gTrue, gFalse, sCase, gTrue,
gFalse, gTrue, gTrue, gFalse, sCase, gTrue, gFalse,
&rect_left, &rect_top, &rect_right, &rect_bottom);
break;
}
......@@ -267,7 +267,7 @@ ustring page::text(const rectf &r, text_layout_enum layout_mode) const
{
std::auto_ptr<GooString> s;
const GBool use_raw_order = (layout_mode == raw_order_layout);
TextOutputDev td(0, gFalse, use_raw_order, gFalse);
TextOutputDev td(0, gFalse, 0, use_raw_order, gFalse);
d->doc->doc->displayPage(&td, d->index + 1, 72, 72, 0, false, true, false);
if (r.is_empty()) {
const PDFRectangle *rect = d->page->getCropBox();
......
......@@ -263,7 +263,7 @@ poppler_page_get_text_page (PopplerPage *page)
TextOutputDev *text_dev;
Gfx *gfx;
text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
text_dev = new TextOutputDev (NULL, gTrue, 0, gFalse, gFalse);
gfx = page->page->createGfx(text_dev,
72.0, 72.0, 0,
gFalse, /* useMediaBox */
......@@ -888,6 +888,7 @@ poppler_page_find_text (PopplerPage *page,
gFalse, gTrue, // startAtTop, stopAtBottom
gFalse, gFalse, // startAtLast, stopAtLast
gFalse, gFalse, // caseSensitive, backwards
gFalse, // wholeWord
&xMin, &yMin, &xMax, &yMax))
{
match = poppler_rectangle_new ();
......@@ -1064,7 +1065,7 @@ poppler_page_render_to_ps (PopplerPage *page,
ps_file->first_page, ps_file->last_page,
psModePS, (int)ps_file->paper_width,
(int)ps_file->paper_height, ps_file->duplex,
0, 0, 0, 0, gFalse, gFalse);
0, 0, 0, 0, gFalse);
ps_file->document->doc->displayPage (ps_file->out, page->index + 1, 72.0, 72.0,
......
......@@ -292,6 +292,7 @@ void ArthurOutputDev::updateFont(GfxState *state)
m_font = NULL;
fileName = NULL;
tmpBuf = NULL;
fontLoc = NULL;
if (!(gfxFont = state->getFont())) {
goto err1;
......
......@@ -246,7 +246,7 @@ void CairoOutputDev::startPage(int pageNum, GfxState *state) {
void CairoOutputDev::endPage() {
if (text) {
text->endPage();
text->coalesce(gTrue, gFalse);
text->coalesce(gTrue, 0, gFalse);
}
}
......
......@@ -2866,7 +2866,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
GfxColor colorA, colorB;
double xa, ya, xb, yb, ra, rb;
double ta, tb, sa, sb;
double sz, sMin, sMax, h;
double sMin, sMax, h;
double sLeft, sRight, sTop, sBottom, sZero, sDiag;
GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
GBool haveSMin, haveSMax;
......@@ -2888,18 +2888,14 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
if (h == 0) {
enclosed = gTrue;
theta = 0; // make gcc happy
sz = 0; // make gcc happy
} else if (r1 - r0 == 0) {
enclosed = gFalse;
theta = 0;
sz = 0; // make gcc happy
} else if (fabs(r1 - r0) >= h) {
enclosed = gTrue;
theta = 0; // make gcc happy
sz = 0; // make gcc happy
} else {
enclosed = gFalse;
sz = -r0 / (r1 - r0);
theta = asin((r1 - r0) / h);
}
......
......@@ -4178,7 +4178,7 @@ GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading,
double xMin, yMin, xMax, yMax;
double x0, y0, r0, x1, y1, r1, t0, t1;
double xa, ya, ra;
double sz, sMin, sMax, h, ta;
double sMin, sMax, h, ta;
double sLeft, sRight, sTop, sBottom, sZero, sDiag;
GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
GBool haveSMin, haveSMax;
......@@ -4206,18 +4206,14 @@ GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading,
if (h == 0) {
enclosed = gTrue;
theta = 0; // make gcc happy
sz = 0; // make gcc happy
} else if (r1 - r0 == 0) {
enclosed = gFalse;
theta = 0;
sz = 0; // make gcc happy
} else if (fabs(r1 - r0) >= h) {
enclosed = gTrue;
theta = 0; // make gcc happy
sz = 0; // make gcc happy
} else {
enclosed = gFalse;
sz = -r0 / (r1 - r0);
theta = asin((r1 - r0) / h);
}
if (enclosed) {
......
......@@ -663,7 +663,7 @@ void TextPool::addWord(TextWord *word) {
// insert the new word
if (cursor && wordBaseIdx == cursorBaseIdx &&
word->primaryCmp(cursor) > 0) {
word->primaryCmp(cursor) >= 0) {
w0 = cursor;
w1 = cursor->next;
} else {
......@@ -1053,7 +1053,7 @@ void TextLineFrag::computeCoords(GBool oneRot) {
xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
base = blk->yMin + base * (blk->yMax - blk->yMin);
base = blk->yMin + d4 * (blk->yMax - blk->yMin);
break;
case 1:
xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
......@@ -1277,15 +1277,15 @@ void TextBlock::addWord(TextWord *word) {
}
}
void TextBlock::coalesce(UnicodeMap *uMap) {
void TextBlock::coalesce(UnicodeMap *uMap, double fixedPitch) {
TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
TextLine *line, *line0, *line1;
int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
int baseIdx, bestWordBaseIdx, idx0, idx1;
double minBase, maxBase;
double fontSize, delta, priDelta, secDelta;
double fontSize, wordSpacing, delta, priDelta, secDelta;
TextLine **lineArray;
GBool found;
GBool found, overlap;
int col1, col2;
int i, j, k;
......@@ -1295,11 +1295,7 @@ void TextBlock::coalesce(UnicodeMap *uMap) {
while (word0) {
priDelta = dupMaxPriDelta * word0->fontSize;
secDelta = dupMaxSecDelta * word0->fontSize;
if (rot == 0 || rot == 3) {
maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
} else {
maxBaseIdx = pool->getBaseIdx(word0->base - secDelta);
}
maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
found = gFalse;
word1 = word2 = NULL; // make gcc happy
for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
......@@ -1396,6 +1392,7 @@ void TextBlock::coalesce(UnicodeMap *uMap) {
maxBase = word0->base + maxIntraLineDelta * fontSize;
minBaseIdx = pool->getBaseIdx(minBase);
maxBaseIdx = pool->getBaseIdx(maxBase);
wordSpacing = fixedPitch ? fixedPitch : maxWordSpacing * fontSize;
// find the rest of the words in this line
while (1) {
......@@ -1404,25 +1401,32 @@ void TextBlock::coalesce(UnicodeMap *uMap) {
// this line
bestWordBaseIdx = 0;
bestWord0 = bestWord1 = NULL;
for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
overlap = gFalse;
for (baseIdx = minBaseIdx;
!overlap && baseIdx <= maxBaseIdx;
++baseIdx) {
for (word0 = NULL, word1 = pool->getPool(baseIdx);
word1;
word0 = word1, word1 = word1->next) {
if (word1->base >= minBase &&
word1->base <= maxBase &&
(delta = lastWord->primaryDelta(word1)) >=
minCharSpacing * fontSize) {
if (delta < maxWordSpacing * fontSize &&
(!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
bestWordBaseIdx = baseIdx;
bestWord0 = word0;
bestWord1 = word1;
word1->base <= maxBase) {
delta = lastWord->primaryDelta(word1);
if (delta < minCharSpacing * fontSize) {
overlap = gTrue;
break;
} else {
if (delta < wordSpacing &&
(!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
bestWordBaseIdx = baseIdx;
bestWord0 = word0;
bestWord1 = word1;
}
break;
}
break;
}
}
}
if (!bestWord1) {
if (overlap || !bestWord1) {
break;
}
......@@ -1469,52 +1473,79 @@ void TextBlock::coalesce(UnicodeMap *uMap) {
// column assignment
nColumns = 0;
for (i = 0; i < nLines; ++i) {
line0 = lineArray[i];
col1 = 0;
for (j = 0; j < i; ++j) {
line1 = lineArray[j];
if (line1->primaryDelta(line0) >= 0) {
col2 = line1->col[line1->len] + 1;
} else {
k = 0; // make gcc happy
switch (rot) {
case 0:
for (k = 0;
k < line1->len &&
line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 1:
for (k = 0;
k < line1->len &&
line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 2:
for (k = 0;
k < line1->len &&
line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 3:
for (k = 0;
k < line1->len &&
line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
}
col2 = line1->col[k];
if (fixedPitch) {
for (i = 0; i < nLines; ++i) {
line0 = lineArray[i];
col1 = 0; // make gcc happy
switch (rot) {
case 0:
col1 = (int)((line0->xMin - xMin) / fixedPitch + 0.5);
break;
case 1:
col1 = (int)((line0->yMin - yMin) / fixedPitch + 0.5);
break;
case 2:
col1 = (int)((xMax - line0->xMax) / fixedPitch + 0.5);
break;
case 3:
col1 = (int)((yMax - line0->yMax) / fixedPitch + 0.5);
break;
}
if (col2 > col1) {
col1 = col2;
for (k = 0; k <= line0->len; ++k) {
line0->col[k] += col1;
}
if (line0->col[line0->len] > nColumns) {
nColumns = line0->col[line0->len];
}
}
for (k = 0; k <= line0->len; ++k) {
line0->col[k] += col1;
}
if (line0->col[line0->len] > nColumns) {
nColumns = line0->col[line0->len];
} else {
for (i = 0; i < nLines; ++i) {
line0 = lineArray[i];
col1 = 0;
for (j = 0; j < i; ++j) {
line1 = lineArray[j];
if (line1->primaryDelta(line0) >= 0) {
col2 = line1->col[line1->len] + 1;
} else {
k = 0; // make gcc happy
switch (rot) {
case 0:
for (k = 0;
k < line1->len &&
line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 1:
for (k = 0;
k < line1->len &&
line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 2:
for (k = 0;
k < line1->len &&
line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
case 3:
for (k = 0;
k < line1->len &&
line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++k) ;
break;
}
col2 = line1->col[k];
}
if (col2 > col1) {
col1 = col2;
}
}
for (k = 0; k <= line0->len; ++k) {
line0->col[k] += col1;
}
if (line0->col[line0->len] > nColumns) {
nColumns = line0->col[line0->len];
}
}
}
gfree(lineArray);
......@@ -2111,6 +2142,8 @@ void TextPage::clear() {
gfree(blocks);
}
deleteGooList(fonts, TextFontInfo);
deleteGooList(underlines, TextUnderline);
deleteGooList(links, TextLink);
curWord = NULL;
charPos = 0;
......@@ -2128,6 +2161,8 @@ void TextPage::clear() {
rawWords = NULL;
rawLastWord = NULL;
fonts = new GooList();
underlines = new GooList();
links = new GooList();
}
void TextPage::updateFont(GfxState *state) {
......@@ -2426,7 +2461,7 @@ void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, AnnotLink *link)
links->append(new TextLink(xMin, yMin, xMax, yMax, link));
}
void TextPage::coalesce(GBool physLayout, GBool doHTML) {
void TextPage::coalesce(GBool physLayout, double fixedPitch, GBool doHTML) {
UnicodeMap *uMap;
TextPool *pool;
TextWord *word0, *word1, *word2;
......@@ -2454,7 +2489,7 @@ void TextPage::coalesce(GBool physLayout, GBool doHTML) {
blkList = NULL;
lastBlk = NULL;
nBlocks = 0;
primaryRot = -1;
primaryRot = 0;
#if 0 // for debugging
printf("*** initial words ***\n");
......@@ -2918,7 +2953,7 @@ void TextPage::coalesce(GBool physLayout, GBool doHTML) {
//~ addition to primary rotation
// coalesce the block, and add it to the list
blk->coalesce(uMap);
blk->coalesce(uMap, fixedPitch);
if (lastBlk) {
lastBlk->next = blk;
} else {
......@@ -2926,11 +2961,12 @@ void TextPage::coalesce(GBool physLayout, GBool doHTML) {
}
lastBlk = blk;
count[rot] += blk->charCount;
if (primaryRot < 0 || count[rot] > count[primaryRot]) {
primaryRot = rot;
}
++nBlocks;
}
if (count[rot] > count[primaryRot]) {
primaryRot = rot;
}
}
#if 0 // for debugging
......@@ -2992,75 +3028,108 @@ void TextPage::coalesce(GBool physLayout, GBool doHTML) {
// sort blocks into xy order for column assignment
if (blocks)
gfree (blocks);
blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
blocks[i] = blk;
}
qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
if (physLayout && fixedPitch) {
// column assignment
for (i = 0; i < nBlocks; ++i) {
blk0 = blocks[i];
col1 = 0;
for (j = 0; j < i; ++j) {
blk1 = blocks[j];
col2 = 0; // make gcc happy
blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
blocks[i] = blk;
col1 = 0; // make gcc happy
switch (primaryRot) {
case 0:
if (blk0->xMin > blk1->xMax) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->xMax == blk1->xMin) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
(blk1->xMax - blk1->xMin)) *
blk1->nColumns);
}
col1 = (int)(blk->xMin / fixedPitch + 0.5);
break;
case 1:
if (blk0->yMin > blk1->yMax) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->yMax == blk1->yMin) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
(blk1->yMax - blk1->yMin)) *
blk1->nColumns);
}
col1 = (int)(blk->yMin / fixedPitch + 0.5);
break;
case 2:
if (blk0->xMax < blk1->xMin) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->xMin == blk1->xMax) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
(blk1->xMin - blk1->xMax)) *
blk1->nColumns);
}
col1 = (int)((pageWidth - blk->xMax) / fixedPitch + 0.5);
break;
case 3:
if (blk0->yMax < blk1->yMin) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->yMin == blk1->yMax) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
(blk1->yMin - blk1->yMax)) *
blk1->nColumns);
}
col1 = (int)((pageHeight - blk->yMax) / fixedPitch + 0.5);
break;
}
if (col2 > col1) {
col1 = col2;
blk->col = col1;
for (line = blk->lines; line; line = line->next) {
for (j = 0; j <= line->len; ++j) {
line->col[j] += col1;
}
}
}
blk0->col = col1;
for (line = blk0->lines; line; line = line->next) {
for (j = 0; j <= line->len; ++j) {
line->col[j] += col1;
} else {
// sort blocks into xy order for column assignment
blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
blocks[i] = blk;
}
qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
// column assignment
for (i = 0; i < nBlocks; ++i) {
blk0 = blocks[i];
col1 = 0;
for (j = 0; j < i; ++j) {
blk1 = blocks[j];
col2 = 0; // make gcc happy
switch (primaryRot) {
case 0:
if (blk0->xMin > blk1->xMax) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->xMax == blk1->xMin) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
(blk1->xMax - blk1->xMin)) *
blk1->nColumns);
}
break;
case 1:
if (blk0->yMin > blk1->yMax) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->yMax == blk1->yMin) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
(blk1->yMax - blk1->yMin)) *
blk1->nColumns);
}
break;
case 2:
if (blk0->xMax < blk1->xMin) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->xMin == blk1->xMax) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
(blk1->xMin - blk1->xMax)) *
blk1->nColumns);
}
break;
case 3:
if (blk0->yMax < blk1->yMin) {
col2 = blk1->col + blk1->nColumns + 3;
} else if (blk1->yMin == blk1->yMax) {
col2 = blk1->col;
} else {
col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
(blk1->yMin - blk1->yMax)) *
blk1->nColumns);
}
break;
}
if (col2 > col1) {
col1 = col2;
}
}
blk0->col = col1;
for (line = blk0->lines; line; line = line->next) {
for (j = 0; j <= line->len; ++j) {
line->col[j] += col1;
}
}
}
}
#if 0 // for debugging
......@@ -3070,7 +3139,7 @@ void TextPage::coalesce(GBool physLayout, GBool doHTML) {
blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
blk->nColumns);
for (line = blk->lines; line; line = line->next) {
printf(" line:\n");
printf(" line: col[0]=%d\n", line->col[0]);
for (word0 = line->words; word0; word0 = word0->next) {
printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
word0->xMin, word0->xMax, word0->yMin, word0->yMax,
......@@ -3470,6 +3539,7 @@ GBool TextPage::findText(Unicode *s, int len,
GBool startAtTop, GBool stopAtBottom,
GBool startAtLast, GBool stopAtLast,
GBool caseSensitive, GBool backward,
GBool wholeWord,
double *xMin, double *yMin,
double *xMax, double *yMax) {
TextBlock *blk;