The patch begins a new word when the font family changed.
This avoids changing or hidden characters and preserves the font
variant/weight/family in the selected words.

When selecting, poppler renders the (e. g. blue) background of a TextLine
and immediately draws the characters on it.
With the patch, the characters are drawn after the background of the whole
selected area is drawn.
Then, no selection background can overlay characters in other TextLines.
This makes selecting LaTeX umlauts
possible (when selecting a larger text block) and displays selected overlaid
texts correctly.

http://imageshack.us/f/828/afterr.png/
http://imageshack.us/f/823/beforebh.png/
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index 3d7ba6d..f508ab8 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -2244,10 +2244,11 @@ void TextPage::addChar(GfxState *state, double x, double y,
     overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize &&
               fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize;
     if (overlap || lastCharOverlap ||
-	sp < -minDupBreakOverlap * curWord->fontSize ||
-	sp > minWordBreakSpace * curWord->fontSize ||
-	fabs(base - curWord->base) > 0.5 ||
-	curFontSize != curWord->fontSize) {
+        sp < -minDupBreakOverlap * curWord->fontSize ||
+        sp > minWordBreakSpace * curWord->fontSize ||
+        fabs(base - curWord->base) > 0.5 ||
+        curFontSize != curWord->fontSize ||
+        !curFont->matches(curWord->font)) {
       endWord();
     }
     lastCharOverlap = overlap;
@@ -4243,44 +4244,42 @@ void TextWord::visitSelection(TextSelectionVisitor *visitor,
 }
 
 void TextLine::visitSelection(TextSelectionVisitor *visitor,
-			      PDFRectangle *selection,
-			      SelectionStyle style) {
-  TextWord *p, *begin, *end, *current;
+                              PDFRectangle *selection,
+                              SelectionStyle style)
+{
+  TextWord *p, *current;
   int i, edge_begin, edge_end;
-  PDFRectangle child_selection;
+  double mid;
 
   begin = NULL;
   end = NULL;
   current = NULL;
   for (p = words; p != NULL; p = p->next) {
     if (blk->page->primaryLR) {
-      if ((selection->x1 < p->xMax) ||
-	  (selection->x2 < p->xMax))
-        if (begin == NULL) 
-	  begin = p;
-
-      if (((selection->x1 > p->xMin) ||
-	   (selection->x2 > p->xMin)) && (begin != NULL)) {
+      if ((selection->x1 < p->xMax || selection->x2 < p->xMax) && !begin) {
+        begin = p;
+      }
+      if ((selection->x1 > p->xMin || selection->x2 > p->xMin) && begin) {
         end = p->next;
         current = p;
       }
-    } else {
-      if ((selection->x1 > p->xMin) ||
-	  (selection->x2 > p->xMin))
-        if (begin == NULL) 
-	  begin = p;
+    }
+    else {
+      if ((selection->x1 > p->xMin || selection->x2 > p->xMin) && !begin) {
+        begin = p;
+      }
 
-      if (((selection->x1 < p->xMax) ||
-	   (selection->x2 < p->xMax)) && (begin != NULL)) {
+      if ((selection->x1 < p->xMax || selection->x2 < p->xMax) && begin) {
         end = p->next;
         current = p;
       }
     }
   }
 
-  if (!current)
+  if (!current) {
     current = begin;
-  
+  }
+
   child_selection = *selection;
   if (style == selectionStyleWord) {
     child_selection.x1 = begin ? begin->xMin : xMin;
@@ -4294,10 +4293,10 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
   edge_begin = len;
   edge_end = 0;
   for (i = 0; i < len; i++) {
-    double mid = (edge[i] + edge[i + 1]) /  2;
+    mid = (edge[i] + edge[i + 1]) /  2;
     if (child_selection.x1 < mid || child_selection.x2 < mid)
       if (i < edge_begin)
-	edge_begin = i;
+        edge_begin = i;
     if (mid < child_selection.x2 || mid < child_selection.x1)
       edge_end = i + 1;
   }
@@ -4306,19 +4305,37 @@ void TextLine::visitSelection(TextSelectionVisitor *visitor,
   if (edge_end <= edge_begin)
     return;
 
-  visitor->visitLine (this, begin, end, edge_begin, edge_end,
-		      &child_selection);
+  visitor->visitLine(this, begin, end, edge_begin, edge_end, &child_selection);
+}
 
-  for (p = begin; p != end; p = p->next)
-    p->visitSelection (visitor, &child_selection, style);
+void TextLine::renderLineSelection(TextSelectionVisitor *visitor,
+                                   SelectionStyle style)
+{
+    TextWord *p = words;
+    for (p = begin; p != end; p = p->next) {
+        p->visitSelection(visitor, &child_selection, style);
+    }
+}
+
+void TextBlock::renderBlockSelection(TextSelectionVisitor *visitor,
+                                     SelectionStyle style)
+{
+  TextLine *p;
+  int stop = (line_start == 0 ? 1 : 0);
+  for (p = best_line[line_start]; p; p = p->next) {
+    p->renderLineSelection(visitor, style);
+    if (p == best_line[stop]) {
+        return;
+    }
+  }
 }
 
 void TextBlock::visitSelection(TextSelectionVisitor *visitor,
 			       PDFRectangle *selection,
 			       SelectionStyle style) {
   PDFRectangle child_selection;
+  TextLine *p;
   double x[2], y[2], d, best_d[2];
-  TextLine *p, *best_line[2];
   int i, count = 0, best_count[2], start, stop;
   GBool all[2];
 
@@ -4401,28 +4418,29 @@ void TextBlock::visitSelection(TextSelectionVisitor *visitor,
     child_selection.y2 = p->yMax;
     if (style == selectionStyleLine) {
       if (p == best_line[start]) {
-	child_selection.x1 = 0;
-	child_selection.y1 = 0;
+        child_selection.x1 = 0;
+        child_selection.y1 = 0;
       }
       if (p == best_line[stop]) {
-	child_selection.x2 = page->pageWidth;
-	child_selection.y2 = page->pageHeight;
+        child_selection.x2 = page->pageWidth;
+        child_selection.y2 = page->pageHeight;
       }
     } else {
       if (p == best_line[start]) {
-	child_selection.x1 = fmax(p->xMin, fmin(p->xMax, x[start]));
-	child_selection.y1 = fmax(p->yMin, fmin(p->yMax, y[start]));
+        child_selection.x1 = fmax(p->xMin, fmin(p->xMax, x[start]));
+        child_selection.y1 = fmax(p->yMin, fmin(p->yMax, y[start]));
       }
       if (p == best_line[stop]) {
-	child_selection.x2 = fmax(p->xMin, fmin(p->xMax, x[stop]));
-	child_selection.y2 = fmax(p->yMin, fmin(p->yMax, y[stop]));
+        child_selection.x2 = fmax(p->xMin, fmin(p->xMax, x[stop]));
+        child_selection.y2 = fmax(p->yMin, fmin(p->yMax, y[stop]));
       }
     }
     p->visitSelection(visitor, &child_selection, style);
     if (p == best_line[stop]) {
-      return;
+      break;
     }
   }
+  line_start = start;
 }
 
 void TextPage::visitSelection(TextSelectionVisitor *visitor,
@@ -4517,7 +4535,8 @@ void TextPage::visitSelection(TextSelectionVisitor *visitor,
     stop = 0;
   }
 
-  for (flow = best_flow[start]; flow; flow = flow->next) {
+  GBool cancel = gFalse;
+  for (flow = best_flow[start]; flow && cancel == gFalse; flow = flow->next) {
     if (flow == best_flow[start]) {
       blk = best_block[start];
     } else {
@@ -4525,25 +4544,44 @@ void TextPage::visitSelection(TextSelectionVisitor *visitor,
     }
     for (; blk; blk = blk->next) {
       if (primaryLR) {
-	child_selection.x1 = blk->xMin;
-	child_selection.x2 = blk->xMax;
+        child_selection.x1 = blk->xMin;
+        child_selection.x2 = blk->xMax;
       } else {
-	child_selection.x1 = blk->xMax;
-	child_selection.x2 = blk->xMin;
+        child_selection.x1 = blk->xMax;
+        child_selection.x2 = blk->xMin;
       }
       child_selection.y1 = blk->yMin;
       child_selection.y2 = blk->yMax;
       if (blk == best_block[start]) {
-	child_selection.x1 = fmax(blk->xMin, fmin(blk->xMax, x[start]));
-	child_selection.y1 = fmax(blk->yMin, fmin(blk->yMax, y[start]));
+        child_selection.x1 = fmax(blk->xMin, fmin(blk->xMax, x[start]));
+        child_selection.y1 = fmax(blk->yMin, fmin(blk->yMax, y[start]));
       }
       if (blk == best_block[stop]) {
-	child_selection.x2 = fmax(blk->xMin, fmin(blk->xMax, x[stop]));
-	child_selection.y2 = fmax(blk->yMin, fmin(blk->yMax, y[stop]));
-	blk->visitSelection(visitor, &child_selection, style);
-	return;
+        child_selection.x2 = fmax(blk->xMin, fmin(blk->xMax, x[stop]));
+        child_selection.y2 = fmax(blk->yMin, fmin(blk->yMax, y[stop]));
+        blk->visitSelection(visitor, &child_selection, style);
+        cancel = gTrue;
+        break;
+      }
+      else {
+        blk->visitSelection(visitor, &child_selection, style);
+      }
+    }
+  }
+
+  for (flow = best_flow[start]; flow; flow = flow->next) {
+    if (flow == best_flow[start]) {
+      blk = best_block[start];
+    }
+    else {
+      blk = flow->blocks;
+    }
+    for (; blk; blk = blk->next) {
+      if (blk == best_block[stop]) {
+        blk->renderBlockSelection(visitor, style);
+        return;
       }
-      blk->visitSelection(visitor, &child_selection, style);
+      blk->renderBlockSelection(visitor, style);
     }
   }
 }
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index 63f3670..5e60506 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -37,6 +37,9 @@
 #include "goo/gtypes.h"
 #include "GfxFont.h"
 #include "GfxState.h"
+#include "Annot.h"
+#include "Page.h"
+#include "PDFDocEncoding.h"
 #include "OutputDev.h"
 
 class GooString;
@@ -274,9 +277,14 @@ public:
 
   void coalesce(UnicodeMap *uMap);
 
+  // Draws the selection background.
   void visitSelection(TextSelectionVisitor *visitor,
 		      PDFRectangle *selection,
-		      SelectionStyle style);
+              SelectionStyle style);
+
+  // Draws the characters of the selection text.
+  void renderLineSelection(TextSelectionVisitor *visitor,
+                           SelectionStyle style);
 
   // Get the head of the linked list of TextWords.
   TextWord *getWords() { return words; }
@@ -295,6 +303,11 @@ private:
   double yMin, yMax;		// bounding box y coordinates
   double base;			// baseline x or y coordinate
   TextWord *words;		// words in this line
+
+  TextWord *begin;  // begin for the iteration through *words
+  TextWord *end;    // end for iteration
+  PDFRectangle child_selection;    // area to render in renderLineSelection
+
   TextWord *lastWord;		// last word in this line
   Unicode *text;		// Unicode text of the line, including
 				//   spaces between words
@@ -349,10 +362,15 @@ public:
   // primary rotation.
   GBool isBelow(TextBlock *blk);
 
+  // Draws the background of all selected text in this TextBlock.
   void visitSelection(TextSelectionVisitor *visitor,
 		      PDFRectangle *selection,
 		      SelectionStyle style);
 
+  // Draws the characters of the selected text.
+  void renderBlockSelection(TextSelectionVisitor *visitor,
+                           SelectionStyle style);
+
   // Get the head of the linked list of TextLines.
   TextLine *getLines() { return lines; }
 
@@ -374,6 +392,9 @@ private:
 		      TextBlock **sorted, int sortPos,
 		      GBool* visited);
 
+  TextLine *best_line[2];   // needed for renderLineSelection
+  int line_start;   // needed for renderLineSelection
+
   TextPage *page;		// the parent page
   int rot;			// text rotation
   double xMin, xMax;		// bounding box x coordinates
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to