Subject: Made FindDLine fully match its header description.

From: fvogel <[email-masked]>
Date: Mon, 8 Feb 2016 21:13:57 +0000

---
 generic/tkTextDisp.c | 33 ++++++++++++++++++++++++++++++---
 tests/textDisp.test  | 11 +----------
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index d45ac73..4d41134 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -6590,6 +6590,7 @@ FindDLine(
     CONST TkTextIndex *indexPtr)/* Index of desired character. */
 {
     DLine *dlPtrPrev;
+    TkTextIndex indexPtr2;
 
     if (dlPtr == NULL) {
 	return NULL;
@@ -6614,7 +6615,6 @@ FindDLine(
         dlPtrPrev = dlPtr;
         dlPtr = dlPtr->nextPtr;
         if (dlPtr == NULL) {
-            TkTextIndex indexPtr2;
             /*
              * We're past the last display line, either because the desired
              * index lies past the visible text, or because the desired index
@@ -6632,14 +6632,41 @@ FindDLine(
             } else {
                 /*
                  * The desired index is past the visible text. There is no
-                 * display line displaying something at the desired index
+                 * display line displaying something at the desired index.
                  * --> return NULL.
                  */
             }
             break;
         }
         if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
-            dlPtr = dlPtrPrev;
+            /*
+             * If we're here then we would normally expect that:
+             *   dlPtrPrev->index  <=  indexPtr  <  dlPtr->index
+             * i.e. we have found the searched display line being dlPtr.
+             * However it is possible that some DLines were unlinked
+             * previously, leading to a situation where going through
+             * the list of display lines skips display lines that did
+             * exist just a moment ago.
+             */
+            indexPtr2 = dlPtrPrev->index;
+            TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
+                    &indexPtr2);
+            if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+                /*
+                 * Confirmed:
+                 *   dlPtrPrev->index  <=  indexPtr  <  dlPtr->index
+                 * --> return dlPtrPrev.
+                 */
+                dlPtr = dlPtrPrev;
+            } else {
+                /*
+                 * The last (rightmost) index shown by dlPtrPrev is still
+                 * before the desired index. This may be because there was
+                 * previously a display line between dlPtrPrev and dlPtr
+                 * and this display line has been unlinked.
+                 * --> return dlPtr.
+                 */
+            }
             break;
         }
     }
diff --git a/tests/textDisp.test b/tests/textDisp.test
index 6aa3721..885c940 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -1181,16 +1181,7 @@ test textDisp-8.12 {TkTextChanged, moving the insert cursor redraws only past an
     .t mark set insert 3.8        ; # within the same line
     update
     lappend res $tk_textRedraw
-    # This last one is tricky: correct result really is {2.0 3.0} when
-    # calling .t mark set insert, two calls to TkTextChanged are done:
-    # (a) to redraw the line of the past position of the cursor
-    # (b) to redraw the line of the new position of the cursor
-    # During (a) the display line showing the cursor gets unlinked,
-    # which leads TkTextChanged in (b) to schedule a redraw starting
-    # one line _before_ the line containing the insert cursor. This is
-    # because during (b) findDLine cannot return the display line the
-    # cursor is in since this display line was just unlinked in (a).
-} {{8.0 9.0} {8.0 12.0} {8.0 12.0} {3.0 8.0} {2.0 3.0}}
+} {{8.0 9.0} {8.0 12.0} {8.0 12.0} {3.0 8.0} {3.0 4.0}}
 test textDisp-8.13 {TkTextChanged, used to crash, see [06c1433906]} {
     .t delete 1.0 end
     .t insert 1.0 \nLine2\nLine3\n
-- 
cgit v0.12