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