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