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