You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
8.5 KiB
279 lines
8.5 KiB
From 0ab1f29d4ce315b0fca260c0e0f3007024d00342 Mon Sep 17 00:00:00 2001 |
|
From: Marek Kasik <mkasik@redhat.com> |
|
Date: Tue, 28 Jan 2014 15:13:24 +0100 |
|
Subject: [PATCH] TextOutputDev: Respect orientation when selecting words |
|
|
|
Take rotation into account when visiting selection. |
|
This doesn't fix all problems (there are still problems |
|
on line and block levels). |
|
|
|
https://bugs.freedesktop.org/show_bug.cgi?id=16619 |
|
--- |
|
poppler/TextOutputDev.cc | 193 ++++++++++++++++++++++++++++++++++++----------- |
|
1 file changed, 150 insertions(+), 43 deletions(-) |
|
|
|
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc |
|
index 7c2ca78..e93908c 100644 |
|
--- a/poppler/TextOutputDev.cc |
|
+++ b/poppler/TextOutputDev.cc |
|
@@ -178,6 +178,12 @@ |
|
// to read the underlying image. Issue #157 |
|
#define glyphlessSelectionOpacity 0.4 |
|
|
|
+// Returns whether x is between a and b or equal to a or b. |
|
+// a and b don't need to be sorted. |
|
+#define XBetweenAB(x,a,b) (!(((x) > (a) && (x) > (b)) || \ |
|
+ ((x) < (a) && (x) < (b))) ? \ |
|
+ true : false) |
|
+ |
|
namespace { |
|
|
|
inline bool isAscii7(Unicode uchar) |
|
@@ -4411,11 +4417,37 @@ void TextSelectionSizer::visitLine (TextLine *line, |
|
PDFRectangle *rect; |
|
double x1, y1, x2, y2, margin; |
|
|
|
- margin = (line->yMax - line->yMin) / 8; |
|
- x1 = line->edge[edge_begin]; |
|
- y1 = line->yMin - margin; |
|
- x2 = line->edge[edge_end]; |
|
- y2 = line->yMax + margin; |
|
+ switch (line->rot) { |
|
+ default: |
|
+ case 0: |
|
+ margin = (line->yMax - line->yMin) / 8; |
|
+ x1 = line->edge[edge_begin]; |
|
+ x2 = line->edge[edge_end]; |
|
+ y1 = line->yMin - margin; |
|
+ y2 = line->yMax + margin; |
|
+ break; |
|
+ case 1: |
|
+ margin = (line->xMax - line->xMin) / 8; |
|
+ x1 = line->xMin - margin; |
|
+ x2 = line->xMax + margin; |
|
+ y1 = line->edge[edge_begin]; |
|
+ y2 = line->edge[edge_end]; |
|
+ break; |
|
+ case 2: |
|
+ margin = (line->yMax - line->yMin) / 8; |
|
+ x1 = line->edge[edge_end]; |
|
+ x2 = line->edge[edge_begin]; |
|
+ y1 = line->yMin - margin; |
|
+ y2 = line->yMax + margin; |
|
+ break; |
|
+ case 3: |
|
+ margin = (line->xMax - line->xMin) / 8; |
|
+ x1 = line->xMin - margin; |
|
+ x2 = line->xMax + margin; |
|
+ y1 = line->edge[edge_end]; |
|
+ y2 = line->edge[edge_begin]; |
|
+ break; |
|
+ } |
|
|
|
rect = new PDFRectangle(floor(x1 * scale), floor(y1 * scale), ceil(x2 * scale), ceil(y2 * scale)); |
|
list->push_back(rect); |
|
@@ -4499,19 +4531,56 @@ void TextSelectionPainter::visitLine (TextLine *line, |
|
{ |
|
double x1, y1, x2, y2, margin; |
|
|
|
- margin = (line->yMax - line->yMin) / 8; |
|
- x1 = floor(line->edge[edge_begin]); |
|
- y1 = floor(line->yMin - margin); |
|
- x2 = ceil(line->edge[edge_end]); |
|
- y2 = ceil(line->yMax + margin); |
|
+ switch (line->rot) { |
|
+ default: |
|
+ case 0: |
|
+ margin = (line->yMax - line->yMin) / 8; |
|
+ x1 = line->edge[edge_begin]; |
|
+ x2 = line->edge[edge_end]; |
|
+ y1 = line->yMin - margin; |
|
+ y2 = line->yMax + margin; |
|
+ break; |
|
+ case 1: |
|
+ margin = (line->xMax - line->xMin) / 8; |
|
+ x1 = line->xMin - margin; |
|
+ x2 = line->xMax + margin; |
|
+ y1 = line->edge[edge_begin]; |
|
+ y2 = line->edge[edge_end]; |
|
+ break; |
|
+ case 2: |
|
+ margin = (line->yMax - line->yMin) / 8; |
|
+ x1 = line->edge[edge_end]; |
|
+ x2 = line->edge[edge_begin]; |
|
+ y1 = line->yMin - margin; |
|
+ y2 = line->yMax + margin; |
|
+ break; |
|
+ case 3: |
|
+ margin = (line->xMax - line->xMin) / 8; |
|
+ x1 = line->xMin - margin; |
|
+ x2 = line->xMax + margin; |
|
+ y1 = line->edge[edge_end]; |
|
+ y2 = line->edge[edge_begin]; |
|
+ break; |
|
+ } |
|
+ |
|
+ ctm.transform(x1, y1, &x1, &y1); |
|
+ ctm.transform(x2, y2, &x2, &y2); |
|
|
|
- ctm.transform(line->edge[edge_begin], line->yMin - margin, &x1, &y1); |
|
- ctm.transform(line->edge[edge_end], line->yMax + margin, &x2, &y2); |
|
+ if (x1 < x2) { |
|
+ x1 = floor(x1); |
|
+ x2 = ceil(x2); |
|
+ } else { |
|
+ x1 = ceil(x1); |
|
+ x2 = floor(x2); |
|
+ } |
|
|
|
- x1 = floor(x1); |
|
- y1 = floor(y1); |
|
- x2 = ceil(x2); |
|
- y2 = ceil(y2); |
|
+ if (y1 < y2) { |
|
+ y1 = floor(y1); |
|
+ y2 = ceil(y2); |
|
+ } else { |
|
+ y1 = ceil(y1); |
|
+ y2 = floor(y2); |
|
+ } |
|
|
|
ictm.transform(x1, y1, &x1, &y1); |
|
ictm.transform(x2, y2, &x2, &y2); |
|
@@ -4589,17 +4658,26 @@ void TextWord::visitSelection(TextSelectionVisitor *visitor, |
|
void TextWord::visitSelection(TextSelectionVisitor *visitor, const PDFRectangle *selection, SelectionStyle style) |
|
{ |
|
int i, begin, end; |
|
- double mid; |
|
+ double mid, s1, s2; |
|
+ |
|
+ if (rot == 0 || rot == 2) { |
|
+ s1 = selection->x1; |
|
+ s2 = selection->x2; |
|
+ } else { |
|
+ s1 = selection->y1; |
|
+ s2 = selection->y2; |
|
+ } |
|
|
|
begin = len; |
|
end = 0; |
|
for (i = 0; i < len; i++) { |
|
mid = (edge[i] + edge[i + 1]) / 2; |
|
- if (selection->x1 < mid || selection->x2 < mid) |
|
- if (i < begin) |
|
- begin = i; |
|
- if (mid < selection->x1 || mid < selection->x2) |
|
- end = i + 1; |
|
+ if (XBetweenAB (mid, s1, s2)) { |
|
+ if (i < begin) |
|
+ begin = i; |
|
+ |
|
+ end = i + 1; |
|
+ } |
|
} |
|
|
|
/* Skip empty selection. */ |
|
@@ -4615,26 +4694,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor, |
|
TextWord *p, *begin, *end, *current; |
|
int i, edge_begin, edge_end; |
|
PDFRectangle child_selection; |
|
+ double s1, s2, p_min, p_max; |
|
+ |
|
+ if (rot == 0 || rot == 2) { |
|
+ s1 = selection->x1; |
|
+ s2 = selection->x2; |
|
+ } else { |
|
+ s1 = selection->y1; |
|
+ s2 = selection->y2; |
|
+ } |
|
|
|
begin = nullptr; |
|
end = nullptr; |
|
current = nullptr; |
|
for (p = words; p != nullptr; p = p->next) { |
|
+ if (rot == 0 || rot == 2) { |
|
+ p_min = p->xMin; |
|
+ p_max = p->xMax; |
|
+ } else { |
|
+ p_min = p->yMin; |
|
+ p_max = p->yMax; |
|
+ } |
|
+ |
|
if (blk->page->primaryLR) { |
|
- if ((selection->x1 < p->xMax) || (selection->x2 < p->xMax)) |
|
- if (begin == nullptr) |
|
- begin = p; |
|
+ if (((s1 < p_max) || (s2 < p_max)) && begin == nullptr) |
|
+ begin = p; |
|
|
|
- if (((selection->x1 > p->xMin) || (selection->x2 > p->xMin)) && (begin != nullptr)) { |
|
+ if (((s1 > p_min) || (s2 > p_min)) && begin != nullptr) { |
|
end = p->next; |
|
current = p; |
|
} |
|
} else { |
|
- if ((selection->x1 > p->xMin) || (selection->x2 > p->xMin)) |
|
- if (begin == nullptr) |
|
- begin = p; |
|
+ if (((s1 > p_min) || (s2 > p_min)) && begin == nullptr) |
|
+ begin = p; |
|
|
|
- if (((selection->x1 < p->xMax) || (selection->x2 < p->xMax)) && (begin != nullptr)) { |
|
+ if (((s1 < p_max) || (s2 < p_max)) && begin != nullptr) { |
|
end = p->next; |
|
current = p; |
|
} |
|
@@ -4650,23 +4740,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor, |
|
|
|
child_selection = *selection; |
|
if (style == selectionStyleWord) { |
|
- child_selection.x1 = begin ? begin->xMin : xMin; |
|
- if (end && end->xMax != -1) { |
|
- child_selection.x2 = current->xMax; |
|
+ if (rot == 0 || rot == 2) { |
|
+ child_selection.x1 = begin ? begin->xMin : xMin; |
|
+ if (end && end->xMax != -1) { |
|
+ child_selection.x2 = current->xMax; |
|
+ } else { |
|
+ child_selection.x2 = xMax; |
|
+ } |
|
} else { |
|
- child_selection.x2 = xMax; |
|
+ child_selection.y1 = begin ? begin->yMin : yMin; |
|
+ if (end && end->yMax != -1) { |
|
+ child_selection.y2 = current->yMax; |
|
+ } else { |
|
+ child_selection.y2 = yMax; |
|
+ } |
|
} |
|
} |
|
|
|
+ if (rot == 0 || rot == 2) { |
|
+ s1 = child_selection.x1; |
|
+ s2 = child_selection.x2; |
|
+ } else { |
|
+ s1 = child_selection.y1; |
|
+ s2 = child_selection.y2; |
|
+ } |
|
+ |
|
edge_begin = len; |
|
edge_end = 0; |
|
for (i = 0; i < len; i++) { |
|
double mid = (edge[i] + edge[i + 1]) / 2; |
|
- if (child_selection.x1 < mid || child_selection.x2 < mid) |
|
- if (i < edge_begin) |
|
- edge_begin = i; |
|
- if (mid < child_selection.x2 || mid < child_selection.x1) |
|
- edge_end = i + 1; |
|
+ if (XBetweenAB (mid, s1, s2)) { |
|
+ if (i < edge_begin) |
|
+ edge_begin = i; |
|
+ |
|
+ edge_end = i + 1; |
|
+ } |
|
} |
|
|
|
/* Skip empty selection. */ |
|
-- |
|
1.8.4.2 |
|
|
|
|