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