From 826999acc66391eab23fe2348ff62f3a8af04f9c Mon Sep 17 00:00:00 2001 From: Brian Ewins Date: Sat, 18 Apr 2009 21:38:45 +0100 Subject: [PATCH] Fix bug 3188, text selection across table cells Bug 3188. When selecting text, poppler goes across the whole page then down, rather than across each cell, down that cell, then across to the next cell. This leads to illegible paste results. Teach TextPage to visit the selection in reading order rather than block order. Start with the first block in reading order whose bottom right lies below and right of either the start or end point of the selection. Finish at the first block containing the other selection point, or if there is no such block, at the first block below the selection. --- poppler/TextOutputDev.cc | 118 ++++++++++++++++++++++++++------------------- 1 files changed, 68 insertions(+), 50 deletions(-) diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc index c0599ce..c7c1041 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -3934,73 +3934,91 @@ void TextPage::visitSelection(TextSelectionVisitor *visitor, PDFRectangle *selection, SelectionStyle style) { - int i, begin, end; PDFRectangle child_selection; double start_x, start_y, stop_x, stop_y; - TextBlock *b; + TextFlow *flow, *first_flow; + TextBlock *blk, *first_block, *low_block, *last_block, *stop_block; + + first_flow = NULL; + first_block = NULL; + low_block = NULL; + last_block = NULL; + stop_block = NULL; - begin = nBlocks; - end = 0; start_x = selection->x1; start_y = selection->y1; stop_x = selection->x2; stop_y = selection->y2; - for (i = 0; i < nBlocks; i++) { - b = blocks[i]; - - if (selection->x1 < b->xMax && selection->y1 < b->yMax && - selection->x2 < b->xMax && selection->y2 < b->yMax && i < begin) { - begin = i; - if (selection->y1 < selection->y2) { - start_x = selection->x1; - start_y = selection->y1; - stop_x = selection->x2; - stop_y = selection->y2; - } else { - start_x = selection->x2; - start_y = selection->y2; - stop_x = selection->x1; - stop_y = selection->y1; + for (flow = flows; flow && !stop_block; flow = flow->next) { + for (blk = flow->blocks; blk && !stop_block; blk = blk->next) { + if (!first_block) { + if (selection->x1 < blk->xMax && + selection->y1 < blk->yMax && + (selection->x2 >= blk->xMax || + selection->y2 >= blk->yMax || + selection->y1 < selection->y2)) { + first_block = blk; + first_flow = flow; + } else if (selection->x2 < blk->xMax && + selection->y2 < blk->yMax) { + start_x = selection->x2; + start_y = selection->y2; + stop_x = selection->x1; + stop_y = selection->y1; + first_block = blk; + first_flow = flow; + } + } + if (first_block) { + if (!low_block && stop_y < blk->yMin) { + low_block = blk; + } + if (stop_x > blk->xMin && + stop_y > blk->yMin && + stop_x < blk->xMax && + stop_y < blk->yMax) { + stop_block = blk; + last_block = stop_block->next; + // this assumes flows are never empty. + if (!last_block && flow->next) { + last_block = flow->next->blocks; + } + } } - } else if (selection->x1 < b->xMax && selection->y1 < b->yMax && i < begin) { - begin = i; - start_x = selection->x1; - start_y = selection->y1; - stop_x = selection->x2; - stop_y = selection->y2; - } else if (selection->x2 < b->xMax && selection->y2 < b->yMax && i < begin) { - begin = i; - start_x = selection->x2; - start_y = selection->y2; - stop_x = selection->x1; - stop_y = selection->y1; } - - if ((selection->x1 > b->xMin && selection->y1 > b->yMin) || - (selection->x2 > b->xMin && selection->y2 > b->yMin)) - end = i + 1; } - - for (i = begin; i < end; i++) { - if (blocks[i]->xMin < start_x && start_x < blocks[i]->xMax && - blocks[i]->yMin < start_y && start_y < blocks[i]->yMax) { - child_selection.x1 = start_x; - child_selection.y1 = start_y; + if (!first_block) { + return; + } + if (!stop_block) { + // this happens when the stop point is not in a block. + last_block = low_block; + } + for (flow = first_flow; flow; flow = flow->next) { + if (flow == first_flow) { + blk = first_block; } else { + blk = flow->blocks; + } + for (; blk; blk = blk->next) { + if (blk == last_block) { + return; + } child_selection.x1 = 0; child_selection.y1 = 0; - } - if (blocks[i]->xMin < stop_x && stop_x < blocks[i]->xMax && - blocks[i]->yMin < stop_y && stop_y < blocks[i]->yMax) { - child_selection.x2 = stop_x; - child_selection.y2 = stop_y; - } else { child_selection.x2 = pageWidth; child_selection.y2 = pageHeight; + if (blk == first_block) { + child_selection.x1 = start_x; + child_selection.y1 = start_y; + } + if (blk == stop_block) { + child_selection.x2 = stop_x; + child_selection.y2 = stop_y; + } + blk->visitSelection(visitor, &child_selection, style); } - - blocks[i]->visitSelection(visitor, &child_selection, style); } } -- 1.6.2.2