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 @@
780150
 // to read the underlying image. Issue #157
780150
 #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))) ? \
780150
+                           true : false)
db2a8b
+
780150
 namespace {
780150
 
780150
 inline bool isAscii7(Unicode uchar)
db2a8b
@@ -4411,11 +4417,37 @@ void TextSelectionSizer::visitLine (TextLine *line,
780150
     PDFRectangle *rect;
780150
     double x1, y1, x2, y2, margin;
db2a8b
 
780150
-    margin = (line->yMax - line->yMin) / 8;
780150
-    x1 = line->edge[edge_begin];
780150
-    y1 = line->yMin - margin;
780150
-    x2 = line->edge[edge_end];
780150
-    y2 = line->yMax + margin;
780150
+    switch (line->rot) {
780150
+    default:
780150
+    case 0:
780150
+        margin = (line->yMax - line->yMin) / 8;
780150
+        x1 = line->edge[edge_begin];
780150
+        x2 = line->edge[edge_end];
780150
+        y1 = line->yMin - margin;
780150
+        y2 = line->yMax + margin;
780150
+        break;
780150
+    case 1:
780150
+        margin = (line->xMax - line->xMin) / 8;
780150
+        x1 = line->xMin - margin;
780150
+        x2 = line->xMax + margin;
780150
+        y1 = line->edge[edge_begin];
780150
+        y2 = line->edge[edge_end];
780150
+        break;
780150
+    case 2:
780150
+        margin = (line->yMax - line->yMin) / 8;
780150
+        x1 = line->edge[edge_end];
780150
+        x2 = line->edge[edge_begin];
780150
+        y1 = line->yMin - margin;
780150
+        y2 = line->yMax + margin;
780150
+        break;
780150
+    case 3:
780150
+        margin = (line->xMax - line->xMin) / 8;
780150
+        x1 = line->xMin - margin;
780150
+        x2 = line->xMax + margin;
780150
+        y1 = line->edge[edge_end];
780150
+        y2 = line->edge[edge_begin];
780150
+        break;
780150
+    }
db2a8b
 
780150
     rect = new PDFRectangle(floor(x1 * scale), floor(y1 * scale), ceil(x2 * scale), ceil(y2 * scale));
780150
     list->push_back(rect);
db2a8b
@@ -4499,19 +4531,56 @@ void TextSelectionPainter::visitLine (TextLine *line,
db2a8b
 {
780150
     double x1, y1, x2, y2, margin;
db2a8b
 
780150
-    margin = (line->yMax - line->yMin) / 8;
780150
-    x1 = floor(line->edge[edge_begin]);
780150
-    y1 = floor(line->yMin - margin);
780150
-    x2 = ceil(line->edge[edge_end]);
780150
-    y2 = ceil(line->yMax + margin);
780150
+    switch (line->rot) {
780150
+    default:
780150
+    case 0:
780150
+        margin = (line->yMax - line->yMin) / 8;
780150
+        x1 = line->edge[edge_begin];
780150
+        x2 = line->edge[edge_end];
780150
+        y1 = line->yMin - margin;
780150
+        y2 = line->yMax + margin;
780150
+        break;
780150
+    case 1:
780150
+        margin = (line->xMax - line->xMin) / 8;
780150
+        x1 = line->xMin - margin;
780150
+        x2 = line->xMax + margin;
780150
+        y1 = line->edge[edge_begin];
780150
+        y2 = line->edge[edge_end];
780150
+        break;
780150
+    case 2:
780150
+        margin = (line->yMax - line->yMin) / 8;
780150
+        x1 = line->edge[edge_end];
780150
+        x2 = line->edge[edge_begin];
780150
+        y1 = line->yMin - margin;
780150
+        y2 = line->yMax + margin;
780150
+        break;
780150
+    case 3:
780150
+        margin = (line->xMax - line->xMin) / 8;
780150
+        x1 = line->xMin - margin;
780150
+        x2 = line->xMax + margin;
780150
+        y1 = line->edge[edge_end];
780150
+        y2 = line->edge[edge_begin];
780150
+        break;
780150
+    }
db2a8b
+
780150
+    ctm.transform(x1, y1, &x1, &y1;;
780150
+    ctm.transform(x2, y2, &x2, &y2;;
db2a8b
 
780150
-    ctm.transform(line->edge[edge_begin], line->yMin - margin, &x1, &y1;;
780150
-    ctm.transform(line->edge[edge_end], line->yMax + margin, &x2, &y2;;
780150
+    if (x1 < x2) {
780150
+        x1 = floor(x1);
780150
+        x2 = ceil(x2);
780150
+    } else {
780150
+        x1 = ceil(x1);
780150
+        x2 = floor(x2);
780150
+    }
db2a8b
 
780150
-    x1 = floor(x1);
780150
-    y1 = floor(y1);
780150
-    x2 = ceil(x2);
780150
-    y2 = ceil(y2);
780150
+    if (y1 < y2) {
780150
+        y1 = floor(y1);
780150
+        y2 = ceil(y2);
780150
+    } else {
780150
+        y1 = ceil(y1);
780150
+        y2 = floor(y2);
780150
+    }
db2a8b
 
780150
     ictm.transform(x1, y1, &x1, &y1;;
780150
     ictm.transform(x2, y2, &x2, &y2;;
780150
@@ -4589,17 +4658,26 @@ void TextWord::visitSelection(TextSelectionVisitor *visitor,
780150
 void TextWord::visitSelection(TextSelectionVisitor *visitor, const PDFRectangle *selection, SelectionStyle style)
db2a8b
 {
780150
     int i, begin, end;
780150
-    double mid;
780150
+    double mid, s1, s2;
db2a8b
+
780150
+    if (rot == 0 || rot == 2) {
780150
+        s1 = selection->x1;
780150
+        s2 = selection->x2;
780150
+    } else {
780150
+        s1 = selection->y1;
780150
+        s2 = selection->y2;
780150
+    }
db2a8b
 
780150
     begin = len;
780150
     end = 0;
780150
     for (i = 0; i < len; i++) {
780150
         mid = (edge[i] + edge[i + 1]) / 2;
780150
-        if (selection->x1 < mid || selection->x2 < mid)
780150
-            if (i < begin)
780150
-                begin = i;
780150
-        if (mid < selection->x1 || mid < selection->x2)
780150
-            end = i + 1;
780150
+      if (XBetweenAB (mid, s1, s2)) {
780150
+          if (i < begin)
780150
+              begin = i;
db2a8b
+
780150
+          end = i + 1;
db2a8b
+      }
780150
     }
db2a8b
 
780150
     /* Skip empty selection. */
780150
@@ -4615,26 +4694,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
780150
     TextWord *p, *begin, *end, *current;
780150
     int i, edge_begin, edge_end;
780150
     PDFRectangle child_selection;
780150
+    double s1, s2, p_min, p_max;
db2a8b
+
db2a8b
+    if (rot == 0 || rot == 2) {
780150
+        s1 = selection->x1;
780150
+        s2 = selection->x2;
db2a8b
+    } else {
780150
+        s1 = selection->y1;
780150
+        s2 = selection->y2;
db2a8b
+    }
780150
 
780150
     begin = nullptr;
780150
     end = nullptr;
780150
     current = nullptr;
780150
     for (p = words; p != nullptr; p = p->next) {
780150
+        if (rot == 0 || rot == 2) {
780150
+            p_min = p->xMin;
780150
+            p_max = p->xMax;
780150
+        } else {
780150
+            p_min = p->yMin;
780150
+            p_max = p->yMax;
780150
+        }
db2a8b
+
780150
         if (blk->page->primaryLR) {
780150
-            if ((selection->x1 < p->xMax) || (selection->x2 < p->xMax))
780150
-                if (begin == nullptr)
780150
-                    begin = p;
780150
+            if (((s1 < p_max) || (s2 < p_max)) && begin == nullptr)
780150
+                begin = p;
db2a8b
 
780150
-            if (((selection->x1 > p->xMin) || (selection->x2 > p->xMin)) && (begin != nullptr)) {
780150
+            if (((s1 > p_min) || (s2 > p_min)) && begin != nullptr) {
780150
                 end = p->next;
780150
                 current = p;
780150
             }
780150
         } else {
780150
-            if ((selection->x1 > p->xMin) || (selection->x2 > p->xMin))
780150
-                if (begin == nullptr)
780150
-                    begin = p;
780150
+            if (((s1 > p_min) || (s2 > p_min)) && begin == nullptr)
780150
+                begin = p;
db2a8b
 
780150
-            if (((selection->x1 < p->xMax) || (selection->x2 < p->xMax)) && (begin != nullptr)) {
780150
+            if (((s1 < p_max) || (s2 < p_max)) && begin != nullptr) {
780150
                 end = p->next;
780150
                 current = p;
780150
             }
780150
@@ -4650,23 +4740,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
780150
 
780150
     child_selection = *selection;
780150
     if (style == selectionStyleWord) {
780150
-        child_selection.x1 = begin ? begin->xMin : xMin;
780150
-        if (end && end->xMax != -1) {
780150
-            child_selection.x2 = current->xMax;
780150
+        if (rot == 0 || rot == 2) {
780150
+            child_selection.x1 = begin ? begin->xMin : xMin;
780150
+            if (end && end->xMax != -1) {
780150
+                child_selection.x2 = current->xMax;
780150
+            } else {
780150
+                child_selection.x2 = xMax;
780150
+            }
780150
         } else {
780150
-            child_selection.x2 = xMax;
780150
+            child_selection.y1 = begin ? begin->yMin : yMin;
780150
+            if (end && end->yMax != -1) {
780150
+                child_selection.y2 = current->yMax;
780150
+            } else {
780150
+                child_selection.y2 = yMax;
780150
+            }
780150
         }
db2a8b
     }
db2a8b
 
780150
+    if (rot == 0 || rot == 2) {
780150
+        s1 = child_selection.x1;
780150
+        s2 = child_selection.x2;
780150
+    } else {
780150
+        s1 = child_selection.y1;
780150
+        s2 = child_selection.y2;
780150
+    }
db2a8b
+
780150
     edge_begin = len;
780150
     edge_end = 0;
780150
     for (i = 0; i < len; i++) {
780150
         double mid = (edge[i] + edge[i + 1]) / 2;
780150
-        if (child_selection.x1 < mid || child_selection.x2 < mid)
780150
-            if (i < edge_begin)
780150
-                edge_begin = i;
780150
-        if (mid < child_selection.x2 || mid < child_selection.x1)
780150
-            edge_end = i + 1;
780150
+        if (XBetweenAB (mid, s1, s2)) {
780150
+            if (i < edge_begin)
780150
+                edge_begin = i;
db2a8b
+
780150
+            edge_end = i + 1;
780150
+        }
780150
     }
db2a8b
 
780150
     /* Skip empty selection. */
db2a8b
-- 
db2a8b
1.8.4.2
db2a8b