76f8c5
From 0ab1f29d4ce315b0fca260c0e0f3007024d00342 Mon Sep 17 00:00:00 2001
76f8c5
From: Marek Kasik <mkasik@redhat.com>
76f8c5
Date: Tue, 28 Jan 2014 15:13:24 +0100
76f8c5
Subject: [PATCH] TextOutputDev: Respect orientation when selecting words
76f8c5
76f8c5
Take rotation into account when visiting selection.
76f8c5
This doesn't fix all problems (there are still problems
76f8c5
on line and block levels).
76f8c5
76f8c5
https://bugs.freedesktop.org/show_bug.cgi?id=16619
76f8c5
---
76f8c5
 poppler/TextOutputDev.cc | 193 ++++++++++++++++++++++++++++++++++++-----------
76f8c5
 1 file changed, 150 insertions(+), 43 deletions(-)
76f8c5
76f8c5
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
76f8c5
index 7c2ca78..e93908c 100644
76f8c5
--- a/poppler/TextOutputDev.cc
76f8c5
+++ b/poppler/TextOutputDev.cc
76f8c5
@@ -173,6 +173,12 @@
76f8c5
 // Max distance between edge of text and edge of link border
76f8c5
 #define hyperlinkSlack 2
76f8c5
 
76f8c5
+// Returns whether x is between a and b or equal to a or b.
76f8c5
+// a and b don't need to be sorted.
76f8c5
+#define XBetweenAB(x,a,b) (!(((x) > (a) && (x) > (b)) || \
76f8c5
+                             ((x) < (a) && (x) < (b))) ? \
76f8c5
+                           gTrue : gFalse)
76f8c5
+
76f8c5
 //------------------------------------------------------------------------
76f8c5
 // TextUnderline
76f8c5
 //------------------------------------------------------------------------
76f8c5
@@ -4222,11 +4228,37 @@ void TextSelectionSizer::visitLine (TextLine *line,
76f8c5
   PDFRectangle *rect;
76f8c5
   double x1, y1, x2, y2, margin;
76f8c5
 
76f8c5
-  margin = (line->yMax - line->yMin) / 8;
76f8c5
-  x1 = line->edge[edge_begin];
76f8c5
-  y1 = line->yMin - margin;
76f8c5
-  x2 = line->edge[edge_end];
76f8c5
-  y2 = line->yMax + margin;
76f8c5
+  switch (line->rot) {
76f8c5
+  default:
76f8c5
+  case 0:
76f8c5
+    margin = (line->yMax - line->yMin) / 8;
76f8c5
+    x1 = line->edge[edge_begin];
76f8c5
+    x2 = line->edge[edge_end];
76f8c5
+    y1 = line->yMin - margin;
76f8c5
+    y2 = line->yMax + margin;
76f8c5
+    break;
76f8c5
+  case 1:
76f8c5
+    margin = (line->xMax - line->xMin) / 8;
76f8c5
+    x1 = line->xMin - margin;
76f8c5
+    x2 = line->xMax + margin;
76f8c5
+    y1 = line->edge[edge_begin];
76f8c5
+    y2 = line->edge[edge_end];
76f8c5
+    break;
76f8c5
+  case 2:
76f8c5
+    margin = (line->yMax - line->yMin) / 8;
76f8c5
+    x1 = line->edge[edge_end];
76f8c5
+    x2 = line->edge[edge_begin];
76f8c5
+    y1 = line->yMin - margin;
76f8c5
+    y2 = line->yMax + margin;
76f8c5
+    break;
76f8c5
+  case 3:
76f8c5
+    margin = (line->xMax - line->xMin) / 8;
76f8c5
+    x1 = line->xMin - margin;
76f8c5
+    x2 = line->xMax + margin;
76f8c5
+    y1 = line->edge[edge_end];
76f8c5
+    y2 = line->edge[edge_begin];
76f8c5
+    break;
76f8c5
+  }
76f8c5
 
76f8c5
   rect = new PDFRectangle (floor (x1 * scale), 
76f8c5
 			   floor (y1 * scale),
76f8c5
@@ -4310,19 +4341,56 @@ void TextSelectionPainter::visitLine (TextLine *line,
76f8c5
 {
76f8c5
   double x1, y1, x2, y2, margin;
76f8c5
 
76f8c5
-  margin = (line->yMax - line->yMin) / 8;
76f8c5
-  x1 = floor (line->edge[edge_begin]);
76f8c5
-  y1 = floor (line->yMin - margin);
76f8c5
-  x2 = ceil (line->edge[edge_end]);
76f8c5
-  y2 = ceil (line->yMax + margin);
76f8c5
+  switch (line->rot) {
76f8c5
+  default:
76f8c5
+  case 0:
76f8c5
+    margin = (line->yMax - line->yMin) / 8;
76f8c5
+    x1 = line->edge[edge_begin];
76f8c5
+    x2 = line->edge[edge_end];
76f8c5
+    y1 = line->yMin - margin;
76f8c5
+    y2 = line->yMax + margin;
76f8c5
+    break;
76f8c5
+  case 1:
76f8c5
+    margin = (line->xMax - line->xMin) / 8;
76f8c5
+    x1 = line->xMin - margin;
76f8c5
+    x2 = line->xMax + margin;
76f8c5
+    y1 = line->edge[edge_begin];
76f8c5
+    y2 = line->edge[edge_end];
76f8c5
+    break;
76f8c5
+  case 2:
76f8c5
+    margin = (line->yMax - line->yMin) / 8;
76f8c5
+    x1 = line->edge[edge_end];
76f8c5
+    x2 = line->edge[edge_begin];
76f8c5
+    y1 = line->yMin - margin;
76f8c5
+    y2 = line->yMax + margin;
76f8c5
+    break;
76f8c5
+  case 3:
76f8c5
+    margin = (line->xMax - line->xMin) / 8;
76f8c5
+    x1 = line->xMin - margin;
76f8c5
+    x2 = line->xMax + margin;
76f8c5
+    y1 = line->edge[edge_end];
76f8c5
+    y2 = line->edge[edge_begin];
76f8c5
+    break;
76f8c5
+  }
76f8c5
+
76f8c5
+  ctm.transform(x1, y1, &x1, &y1;;
76f8c5
+  ctm.transform(x2, y2, &x2, &y2;;
76f8c5
 
76f8c5
-  ctm.transform(line->edge[edge_begin], line->yMin - margin, &x1, &y1;;
76f8c5
-  ctm.transform(line->edge[edge_end], line->yMax + margin, &x2, &y2;;
76f8c5
+  if (x1 < x2) {
76f8c5
+    x1 = floor (x1);
76f8c5
+    x2 = ceil (x2);
76f8c5
+  } else {
76f8c5
+    x1 = ceil (x1);
76f8c5
+    x2 = floor (x2);
76f8c5
+  }
76f8c5
 
76f8c5
-  x1 = floor (x1);
76f8c5
-  y1 = floor (y1);
76f8c5
-  x2 = ceil (x2);
76f8c5
-  y2 = ceil (y2);
76f8c5
+  if (y1 < y2) {
76f8c5
+    y1 = floor (y1);
76f8c5
+    y2 = ceil (y2);
76f8c5
+  } else {
76f8c5
+    y1 = ceil (y1);
76f8c5
+    y2 = floor (y2);
76f8c5
+  }
76f8c5
 
76f8c5
   ictm.transform(x1, y1, &x1, &y1;;
76f8c5
   ictm.transform(x2, y2, &x2, &y2;;
76f8c5
@@ -4400,17 +4467,27 @@ void TextWord::visitSelection(TextSelectionVisitor *visitor,
76f8c5
 			      SelectionStyle style)
76f8c5
 {
76f8c5
   int i, begin, end;
76f8c5
-  double mid;
76f8c5
+  double mid, s1, s2;
76f8c5
+
76f8c5
+  if (rot == 0 || rot == 2) {
76f8c5
+    s1 = selection->x1;
76f8c5
+    s2 = selection->x2;
76f8c5
+  } else {
76f8c5
+    s1 = selection->y1;
76f8c5
+    s2 = selection->y2;
76f8c5
+  }
76f8c5
 
76f8c5
   begin = len;
76f8c5
   end = 0;
76f8c5
   for (i = 0; i < len; i++) {
76f8c5
     mid = (edge[i] + edge[i + 1]) / 2;
76f8c5
-    if (selection->x1 < mid || selection->x2 < mid)
76f8c5
-      if (i < begin)
76f8c5
-	begin = i;
76f8c5
-    if (mid < selection->x1 || mid < selection->x2)
76f8c5
-      end = i + 1;
76f8c5
+    if (XBetweenAB (mid, s1, s2))
76f8c5
+      {
76f8c5
+        if (i < begin)
76f8c5
+          begin = i;
76f8c5
+
76f8c5
+        end = i + 1;
76f8c5
+      }
76f8c5
   }
76f8c5
 
76f8c5
   /* Skip empty selection. */
76f8c5
@@ -4426,30 +4503,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
76f8c5
   TextWord *p, *begin, *end, *current;
76f8c5
   int i, edge_begin, edge_end;
76f8c5
   PDFRectangle child_selection;
76f8c5
+  double s1, s2, p_min, p_max;
76f8c5
+
76f8c5
+  if (rot == 0 || rot == 2) {
76f8c5
+    s1 = selection->x1;
76f8c5
+    s2 = selection->x2;
76f8c5
+  } else {
76f8c5
+    s1 = selection->y1;
76f8c5
+    s2 = selection->y2;
76f8c5
+  }
76f8c5
 
76f8c5
   begin = NULL;
76f8c5
   end = NULL;
76f8c5
   current = NULL;
76f8c5
   for (p = words; p != NULL; p = p->next) {
76f8c5
+    if (rot == 0 || rot == 2) {
76f8c5
+      p_min = p->xMin;
76f8c5
+      p_max = p->xMax;
76f8c5
+    } else {
76f8c5
+      p_min = p->yMin;
76f8c5
+      p_max = p->yMax;
76f8c5
+    }
76f8c5
+
76f8c5
     if (blk->page->primaryLR) {
76f8c5
-      if ((selection->x1 < p->xMax) ||
76f8c5
-	  (selection->x2 < p->xMax))
76f8c5
-        if (begin == NULL) 
76f8c5
-	  begin = p;
76f8c5
+      if (((s1 < p_max) || (s2 < p_max)) && begin == NULL)
76f8c5
+        begin = p;
76f8c5
 
76f8c5
-      if (((selection->x1 > p->xMin) ||
76f8c5
-	   (selection->x2 > p->xMin)) && (begin != NULL)) {
76f8c5
+      if (((s1 > p_min) || (s2 > p_min)) && begin != NULL) {
76f8c5
         end = p->next;
76f8c5
         current = p;
76f8c5
       }
76f8c5
     } else {
76f8c5
-      if ((selection->x1 > p->xMin) ||
76f8c5
-	  (selection->x2 > p->xMin))
76f8c5
-        if (begin == NULL) 
76f8c5
-	  begin = p;
76f8c5
+      if (((s1 > p_min) || (s2 > p_min)) && begin == NULL)
76f8c5
+        begin = p;
76f8c5
 
76f8c5
-      if (((selection->x1 < p->xMax) ||
76f8c5
-	   (selection->x2 < p->xMax)) && (begin != NULL)) {
76f8c5
+      if (((s1 < p_max) || (s2 < p_max)) && begin != NULL) {
76f8c5
         end = p->next;
76f8c5
         current = p;
76f8c5
       }
76f8c5
@@ -4461,23 +4549,42 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
76f8c5
   
76f8c5
   child_selection = *selection;
76f8c5
   if (style == selectionStyleWord) {
76f8c5
-    child_selection.x1 = begin ? begin->xMin : xMin;
76f8c5
-    if (end && end->xMax != -1) {
76f8c5
-      child_selection.x2 = current->xMax;
76f8c5
+    if (rot == 0 || rot == 2) {
76f8c5
+      child_selection.x1 = begin ? begin->xMin : xMin;
76f8c5
+      if (end && end->xMax != -1) {
76f8c5
+        child_selection.x2 = current->xMax;
76f8c5
+      } else {
76f8c5
+        child_selection.x2 = xMax;
76f8c5
+      }
76f8c5
     } else {
76f8c5
-      child_selection.x2 = xMax;
76f8c5
+      child_selection.y1 = begin ? begin->yMin : yMin;
76f8c5
+      if (end && end->yMax != -1) {
76f8c5
+        child_selection.y2 = current->yMax;
76f8c5
+      } else {
76f8c5
+        child_selection.y2 = yMax;
76f8c5
+      }
76f8c5
     }
76f8c5
   }
76f8c5
 
76f8c5
+  if (rot == 0 || rot == 2) {
76f8c5
+    s1 = child_selection.x1;
76f8c5
+    s2 = child_selection.x2;
76f8c5
+  } else {
76f8c5
+    s1 = child_selection.y1;
76f8c5
+    s2 = child_selection.y2;
76f8c5
+  }
76f8c5
+
76f8c5
   edge_begin = len;
76f8c5
   edge_end = 0;
76f8c5
   for (i = 0; i < len; i++) {
76f8c5
     double mid = (edge[i] + edge[i + 1]) /  2;
76f8c5
-    if (child_selection.x1 < mid || child_selection.x2 < mid)
76f8c5
-      if (i < edge_begin)
76f8c5
-	edge_begin = i;
76f8c5
-    if (mid < child_selection.x2 || mid < child_selection.x1)
76f8c5
-      edge_end = i + 1;
76f8c5
+    if (XBetweenAB (mid, s1, s2))
76f8c5
+      {
76f8c5
+        if (i < edge_begin)
76f8c5
+          edge_begin = i;
76f8c5
+
76f8c5
+        edge_end = i + 1;
76f8c5
+      }
76f8c5
   }
76f8c5
 
76f8c5
   /* Skip empty selection. */
76f8c5
-- 
76f8c5
1.8.4.2
76f8c5