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