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