summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfvogel <fvogelnew1@free.fr>2015-01-24 14:58:03 (GMT)
committerfvogel <fvogelnew1@free.fr>2015-01-24 14:58:03 (GMT)
commit662480c9ebe208020fd0484bbd7908dbb0fa7562 (patch)
treef38ea602db1991d6f158b487369145dfa7ac873f
parent2a1df1da7fd04bf2163249f588314d1ae33d12f5 (diff)
downloadtk-662480c9ebe208020fd0484bbd7908dbb0fa7562.zip
tk-662480c9ebe208020fd0484bbd7908dbb0fa7562.tar.gz
tk-662480c9ebe208020fd0484bbd7908dbb0fa7562.tar.bz2
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.
-rw-r--r--generic/tkText.h3
-rw-r--r--generic/tkTextDisp.c10
-rw-r--r--generic/tkTextIndex.c87
-rw-r--r--tests/textDisp.test23
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