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 @@
396e5c
 #define combMaxMidDelta 0.3
396e5c
 #define combMaxBaseDelta 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))) ? \
396e5c
+                           gTrue : gFalse)
396e5c
+
396e5c
 static int reorderText(Unicode *text, int len, UnicodeMap *uMap, GBool primaryLR, GooString *s, Unicode* u) {
396e5c
   char lre[8], rle[8], popdf[8], buf[8];
396e5c
   int lreLen = 0, rleLen = 0, popdfLen = 0, n;
396e5c
@@ -4411,11 +4417,37 @@ void TextSelectionSizer::visitLine (TextLine *line,
396e5c
   PDFRectangle *rect;
396e5c
   double x1, y1, x2, y2, margin;
396e5c
 
396e5c
-  margin = (line->yMax - line->yMin) / 8;
396e5c
-  x1 = line->edge[edge_begin];
396e5c
-  y1 = line->yMin - margin;
396e5c
-  x2 = line->edge[edge_end];
396e5c
-  y2 = line->yMax + margin;
396e5c
+  switch (line->rot) {
396e5c
+  default:
396e5c
+  case 0:
396e5c
+    margin = (line->yMax - line->yMin) / 8;
396e5c
+    x1 = line->edge[edge_begin];
396e5c
+    x2 = line->edge[edge_end];
396e5c
+    y1 = line->yMin - margin;
396e5c
+    y2 = line->yMax + margin;
396e5c
+    break;
396e5c
+  case 1:
396e5c
+    margin = (line->xMax - line->xMin) / 8;
396e5c
+    x1 = line->xMin - margin;
396e5c
+    x2 = line->xMax + margin;
396e5c
+    y1 = line->edge[edge_begin];
396e5c
+    y2 = line->edge[edge_end];
396e5c
+    break;
396e5c
+  case 2:
396e5c
+    margin = (line->yMax - line->yMin) / 8;
396e5c
+    x1 = line->edge[edge_end];
396e5c
+    x2 = line->edge[edge_begin];
396e5c
+    y1 = line->yMin - margin;
396e5c
+    y2 = line->yMax + margin;
396e5c
+    break;
396e5c
+  case 3:
396e5c
+    margin = (line->xMax - line->xMin) / 8;
396e5c
+    x1 = line->xMin - margin;
396e5c
+    x2 = line->xMax + margin;
396e5c
+    y1 = line->edge[edge_end];
396e5c
+    y2 = line->edge[edge_begin];
396e5c
+    break;
396e5c
+  }
396e5c
 
396e5c
   rect = new PDFRectangle (floor (x1 * scale), 
396e5c
 			   floor (y1 * scale),
396e5c
@@ -4499,19 +4531,56 @@ void TextSelectionPainter::visitLine (TextLine *line,
396e5c
 {
396e5c
   double x1, y1, x2, y2, margin;
396e5c
 
396e5c
-  margin = (line->yMax - line->yMin) / 8;
396e5c
-  x1 = floor (line->edge[edge_begin]);
396e5c
-  y1 = floor (line->yMin - margin);
396e5c
-  x2 = ceil (line->edge[edge_end]);
396e5c
-  y2 = ceil (line->yMax + margin);
396e5c
+  switch (line->rot) {
396e5c
+  default:
396e5c
+  case 0:
396e5c
+    margin = (line->yMax - line->yMin) / 8;
396e5c
+    x1 = line->edge[edge_begin];
396e5c
+    x2 = line->edge[edge_end];
396e5c
+    y1 = line->yMin - margin;
396e5c
+    y2 = line->yMax + margin;
396e5c
+    break;
396e5c
+  case 1:
396e5c
+    margin = (line->xMax - line->xMin) / 8;
396e5c
+    x1 = line->xMin - margin;
396e5c
+    x2 = line->xMax + margin;
396e5c
+    y1 = line->edge[edge_begin];
396e5c
+    y2 = line->edge[edge_end];
396e5c
+    break;
396e5c
+  case 2:
396e5c
+    margin = (line->yMax - line->yMin) / 8;
396e5c
+    x1 = line->edge[edge_end];
396e5c
+    x2 = line->edge[edge_begin];
396e5c
+    y1 = line->yMin - margin;
396e5c
+    y2 = line->yMax + margin;
396e5c
+    break;
396e5c
+  case 3:
396e5c
+    margin = (line->xMax - line->xMin) / 8;
396e5c
+    x1 = line->xMin - margin;
396e5c
+    x2 = line->xMax + margin;
396e5c
+    y1 = line->edge[edge_end];
396e5c
+    y2 = line->edge[edge_begin];
396e5c
+    break;
396e5c
+  }
396e5c
+
396e5c
+  ctm.transform(x1, y1, &x1, &y1;;
396e5c
+  ctm.transform(x2, y2, &x2, &y2;;
396e5c
 
396e5c
-  ctm.transform(line->edge[edge_begin], line->yMin - margin, &x1, &y1;;
396e5c
-  ctm.transform(line->edge[edge_end], line->yMax + margin, &x2, &y2;;
396e5c
+  if (x1 < x2) {
396e5c
+    x1 = floor (x1);
396e5c
+    x2 = ceil (x2);
396e5c
+  } else {
396e5c
+    x1 = ceil (x1);
396e5c
+    x2 = floor (x2);
396e5c
+  }
396e5c
 
396e5c
-  x1 = floor (x1);
396e5c
-  y1 = floor (y1);
396e5c
-  x2 = ceil (x2);
396e5c
-  y2 = ceil (y2);
396e5c
+  if (y1 < y2) {
396e5c
+    y1 = floor (y1);
396e5c
+    y2 = ceil (y2);
396e5c
+  } else {
396e5c
+    y1 = ceil (y1);
396e5c
+    y2 = floor (y2);
396e5c
+  }
396e5c
 
396e5c
   ictm.transform(x1, y1, &x1, &y1;;
396e5c
   ictm.transform(x2, y2, &x2, &y2;;
396e5c
@@ -4589,17 +4658,27 @@ void TextWord::visitSelection(TextSelectionVisitor *visitor,
396e5c
 			      SelectionStyle style)
396e5c
 {
396e5c
   int i, begin, end;
396e5c
-  double mid;
396e5c
+  double mid, s1, s2;
396e5c
+
396e5c
+  if (rot == 0 || rot == 2) {
396e5c
+    s1 = selection->x1;
396e5c
+    s2 = selection->x2;
396e5c
+  } else {
396e5c
+    s1 = selection->y1;
396e5c
+    s2 = selection->y2;
396e5c
+  }
396e5c
 
396e5c
   begin = len;
396e5c
   end = 0;
396e5c
   for (i = 0; i < len; i++) {
396e5c
     mid = (edge[i] + edge[i + 1]) / 2;
396e5c
-    if (selection->x1 < mid || selection->x2 < mid)
396e5c
-      if (i < begin)
396e5c
-	begin = i;
396e5c
-    if (mid < selection->x1 || mid < selection->x2)
396e5c
-      end = i + 1;
396e5c
+    if (XBetweenAB (mid, s1, s2))
396e5c
+      {
396e5c
+        if (i < begin)
396e5c
+          begin = i;
396e5c
+
396e5c
+        end = i + 1;
396e5c
+      }
396e5c
   }
396e5c
 
396e5c
   /* Skip empty selection. */
396e5c
@@ -4615,30 +4694,41 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
396e5c
   TextWord *p, *begin, *end, *current;
396e5c
   int i, edge_begin, edge_end;
396e5c
   PDFRectangle child_selection;
396e5c
+  double s1, s2, p_min, p_max;
396e5c
+
396e5c
+  if (rot == 0 || rot == 2) {
396e5c
+    s1 = selection->x1;
396e5c
+    s2 = selection->x2;
396e5c
+  } else {
396e5c
+    s1 = selection->y1;
396e5c
+    s2 = selection->y2;
396e5c
+  }
396e5c
 
396e5c
   begin = nullptr;
396e5c
   end = nullptr;
396e5c
   current = nullptr;
396e5c
   for (p = words; p != nullptr; p = p->next) {
396e5c
+    if (rot == 0 || rot == 2) {
396e5c
+      p_min = p->xMin;
396e5c
+      p_max = p->xMax;
396e5c
+    } else {
396e5c
+      p_min = p->yMin;
396e5c
+      p_max = p->yMax;
396e5c
+    }
396e5c
+
396e5c
     if (blk->page->primaryLR) {
396e5c
-      if ((selection->x1 < p->xMax) ||
396e5c
-	  (selection->x2 < p->xMax))
396e5c
-        if (begin == nullptr) 
396e5c
-	  begin = p;
396e5c
+      if (((s1 < p_max) || (s2 < p_max)) && begin == nullptr)
396e5c
+        begin = p;
396e5c
 
396e5c
-      if (((selection->x1 > p->xMin) ||
396e5c
-	   (selection->x2 > p->xMin)) && (begin != nullptr)) {
396e5c
+      if (((s1 > p_min) || (s2 > p_min)) && begin != nullptr) {
396e5c
         end = p->next;
396e5c
         current = p;
396e5c
       }
396e5c
     } else {
396e5c
-      if ((selection->x1 > p->xMin) ||
396e5c
-	  (selection->x2 > p->xMin))
396e5c
-        if (begin == nullptr) 
396e5c
-	  begin = p;
396e5c
+      if (((s1 > p_min) || (s2 > p_min)) && begin == nullptr)
396e5c
+        begin = p;
396e5c
 
396e5c
-      if (((selection->x1 < p->xMax) ||
396e5c
-	   (selection->x2 < p->xMax)) && (begin != nullptr)) {
396e5c
+      if (((s1 < p_max) || (s2 < p_max)) && begin != nullptr) {
396e5c
         end = p->next;
396e5c
         current = p;
396e5c
       }
396e5c
@@ -4650,23 +4740,42 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
396e5c
   
396e5c
   child_selection = *selection;
396e5c
   if (style == selectionStyleWord) {
396e5c
-    child_selection.x1 = begin ? begin->xMin : xMin;
396e5c
-    if (end && end->xMax != -1) {
396e5c
-      child_selection.x2 = current->xMax;
396e5c
+    if (rot == 0 || rot == 2) {
396e5c
+      child_selection.x1 = begin ? begin->xMin : xMin;
396e5c
+      if (end && end->xMax != -1) {
396e5c
+        child_selection.x2 = current->xMax;
396e5c
+      } else {
396e5c
+        child_selection.x2 = xMax;
396e5c
+      }
396e5c
     } else {
396e5c
-      child_selection.x2 = xMax;
396e5c
+      child_selection.y1 = begin ? begin->yMin : yMin;
396e5c
+      if (end && end->yMax != -1) {
396e5c
+        child_selection.y2 = current->yMax;
396e5c
+      } else {
396e5c
+        child_selection.y2 = yMax;
396e5c
+      }
396e5c
     }
396e5c
   }
396e5c
 
396e5c
+  if (rot == 0 || rot == 2) {
396e5c
+    s1 = child_selection.x1;
396e5c
+    s2 = child_selection.x2;
396e5c
+  } else {
396e5c
+    s1 = child_selection.y1;
396e5c
+    s2 = child_selection.y2;
396e5c
+  }
396e5c
+
396e5c
   edge_begin = len;
396e5c
   edge_end = 0;
396e5c
   for (i = 0; i < len; i++) {
396e5c
     double mid = (edge[i] + edge[i + 1]) /  2;
396e5c
-    if (child_selection.x1 < mid || child_selection.x2 < mid)
396e5c
-      if (i < edge_begin)
396e5c
-	edge_begin = i;
396e5c
-    if (mid < child_selection.x2 || mid < child_selection.x1)
396e5c
-      edge_end = i + 1;
396e5c
+    if (XBetweenAB (mid, s1, s2))
396e5c
+      {
396e5c
+        if (i < edge_begin)
396e5c
+          edge_begin = i;
396e5c
+
396e5c
+        edge_end = i + 1;
396e5c
+      }
396e5c
   }
396e5c
 
396e5c
   /* Skip empty selection. */
396e5c
-- 
396e5c
1.8.4.2
396e5c