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