From 662480c9ebe208020fd0484bbd7908dbb0fa7562 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 24 Jan 2015 14:58:03 +0000 Subject: TkTextIndexCount is counting chars. Fix these calls where bytes counting is needed. Among other issues, this fixes horizontal scrolling when typing text at the end of a line containing multi-byte characters. --- generic/tkText.h | 3 ++ generic/tkTextDisp.c | 10 +++--- generic/tkTextIndex.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/textDisp.test | 23 ++++++++++++++ 4 files changed, 117 insertions(+), 6 deletions(-) diff --git a/generic/tkText.h b/generic/tkText.h index 4ffdc8a..6f5f153 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -1071,6 +1071,9 @@ MODULE_SCOPE void TkTextIndexBackChars(const TkText *textPtr, TkTextIndex *dstPtr, TkTextCountType type); MODULE_SCOPE int TkTextIndexCmp(const TkTextIndex *index1Ptr, const TkTextIndex *index2Ptr); +MODULE_SCOPE int TkTextIndexCountBytes(const TkText *textPtr, + const TkTextIndex *index1Ptr, + const TkTextIndex *index2Ptr); MODULE_SCOPE int TkTextIndexCount(const TkText *textPtr, const TkTextIndex *index1Ptr, const TkTextIndex *index2Ptr, diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index a6ab13c..34202bd 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3465,8 +3465,8 @@ TkTextFindDisplayLineEnd( */ *xOffset = DlineXOfIndex(textPtr, dlPtr, - TkTextIndexCount(textPtr, &dlPtr->index, indexPtr, - COUNT_INDICES)); + TkTextIndexCountBytes(textPtr, &dlPtr->index, + indexPtr)); } if (end) { /* @@ -5549,8 +5549,7 @@ TkTextSeeCmd( * they are elided. */ - byteCount = TkTextIndexCount(textPtr, &dlPtr->index, &index, - COUNT_INDICES); + byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, &index); for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL ; chunkPtr = chunkPtr->nextPtr) { if (byteCount < chunkPtr->numBytes) { @@ -7078,8 +7077,7 @@ TkTextIndexBbox( * they are elided. */ - byteCount = TkTextIndexCount(textPtr, &dlPtr->index, indexPtr, - COUNT_INDICES); + byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, indexPtr); for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { if (chunkPtr == NULL) { return -1; diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c index 70c94db..25b4666 100644 --- a/generic/tkTextIndex.c +++ b/generic/tkTextIndex.c @@ -40,6 +40,9 @@ static CONST char * StartEnd(TkText *textPtr, CONST char *string, static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr, TkText *textPtr, CONST char *string, TkTextIndex *indexPtr, int *canCachePtr); +static int IndexCountBytesOrdered(CONST TkText *textPtr, + CONST TkTextIndex *indexPtr1, + CONST TkTextIndex *indexPtr2); /* * The "textindex" Tcl_Obj definition: @@ -1628,6 +1631,90 @@ TkTextIndexForwChars( /* *--------------------------------------------------------------------------- * + * TkTextIndexCountBytes -- + * + * Given a pair of indices in a text widget, this function counts how + * many bytes are between the two indices. The two indices do not need + * to be ordered. + * + * Results: + * The number of bytes in the given range. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TkTextIndexCountBytes( + CONST TkText *textPtr, + CONST TkTextIndex *indexPtr1, /* Index describing one location. */ + CONST TkTextIndex *indexPtr2) /* Index describing second location. */ +{ + int compare = TkTextIndexCmp(indexPtr1, indexPtr2); + + if (compare == 0) { + return 0; + } else if (compare > 0) { + return IndexCountBytesOrdered(textPtr, indexPtr2, indexPtr1); + } else { + return IndexCountBytesOrdered(textPtr, indexPtr1, indexPtr2); + } +} + +static int +IndexCountBytesOrdered( + CONST TkText *textPtr, + CONST TkTextIndex *indexPtr1, + /* Index describing location of character from + * which to count. */ + CONST TkTextIndex *indexPtr2) + /* Index describing location of last character + * at which to stop the count. */ +{ + int byteCount, offset; + TkTextSegment *segPtr, *segPtr1; + TkTextLine *linePtr; + + if (indexPtr1->linePtr == indexPtr2->linePtr) { + return indexPtr2->byteIndex - indexPtr1->byteIndex; + } + + /* + * indexPtr2 is on a line strictly after the line containing indexPtr1. + * Add up: + * bytes between indexPtr1 and end of its line + * bytes in lines strictly between indexPtr1 and indexPtr2 + * bytes between start of the indexPtr2 line and indexPtr2 + */ + + segPtr1 = TkTextIndexToSeg(indexPtr1, &offset); + byteCount = -offset; + for (segPtr = segPtr1; segPtr != NULL; segPtr = segPtr->nextPtr) { + byteCount += segPtr->size; + } + + linePtr = indexPtr1->linePtr->nextPtr; + while (linePtr != indexPtr2->linePtr) { + for (segPtr = linePtr->segPtr; segPtr != NULL; + segPtr = segPtr->nextPtr) { + byteCount += segPtr->size; + } + linePtr = TkBTreeNextLine(textPtr, linePtr); + if (linePtr == NULL) { + Tcl_Panic("TextIndexCountBytesOrdered ran out of lines"); + } + } + + byteCount += indexPtr2->byteIndex; + + return byteCount; +} + +/* + *--------------------------------------------------------------------------- + * * TkTextIndexCount -- * * Given an ordered pair of indices in a text widget, this function diff --git a/tests/textDisp.test b/tests/textDisp.test index 1f85117..44a45b2 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -1664,6 +1664,29 @@ test textDisp-13.10 {TkTextSeeCmd procedure} {} { destroy $w set res } {} +test textDisp-13.11 {TkTextSeeCmd procedure} {} { + # insertion of a character at end of a line containing multi-byte + # characters and calling see at the line end shall actually show + # this character + toplevel .top2 + pack [text .top2.t2 -wrap none] + for {set i 1} {$i < 5} {incr i} { + .top2.t2 insert end [string repeat "Line $i: éèàçù" 5]\n + + } + wm geometry .top2 300x200+0+0 + update + .top2.t2 see "1.0 lineend" + update + set ref [.top2.t2 index @0,0] + .top2.t2 insert "1.0 lineend" ç + .top2.t2 see "1.0 lineend" + update + set new [.top2.t2 index @0,0] + set res [.top2.t2 compare $ref == $new] + destroy .top2 + set res +} {0} wm geom . {} .t configure -wrap none -- cgit v0.12