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