Skip to content

Commit

Permalink
More progress, backporting bugfix from Tk 9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jan.nijtmans committed Mar 13, 2024
1 parent cffc7b4 commit 6eb17d2
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 47 deletions.
22 changes: 16 additions & 6 deletions generic/tkInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,27 @@
# define TCL_COMBINE 0
#endif

#undef TclNumUtfChars
#undef TclUtfAtIndex
#undef Tcl_NumUtfChars
#undef Tcl_GetCharLength
#undef Tcl_UtfAtIndex
#if TCL_MAJOR_VERSION > 8
#define Tcl_NumUtfChars \
(tclStubsPtr->tcl_NumUtfChars) /* 669 */
#define Tcl_GetCharLength \
(tclStubsPtr->tcl_GetCharLength) /* 670 */
#define Tcl_UtfAtIndex \
(tclStubsPtr->tcl_UtfAtIndex) /* 671 */
# define TclNumUtfChars \
(tclStubsPtr->tclNumUtfChars) /* 312 */
# define TclUtfAtIndex \
(tclStubsPtr->tclUtfAtIndex) /* 325 */
# define Tcl_NumUtfChars \
(tclStubsPtr->tcl_NumUtfChars) /* 669 */
# define Tcl_GetCharLength \
(tclStubsPtr->tcl_GetCharLength) /* 670 */
# define Tcl_UtfAtIndex \
(tclStubsPtr->tcl_UtfAtIndex) /* 671 */
#else
# define TclNumUtfChars \
(tclStubsPtr->tcl_NumUtfChars) /* 312 */
# define TclUtfAtIndex \
(tclStubsPtr->tcl_UtfAtIndex) /* 325 */
# define Tcl_NumUtfChars (((&tclStubsPtr->tcl_PkgProvideEx)[631]) ? \
((Tcl_Size (*)(const char *, Tcl_Size))(void *)((&tclStubsPtr->tcl_PkgProvideEx)[669])) \
: (tclStubsPtr->tcl_NumUtfChars) /* 312 */)
Expand Down
86 changes: 61 additions & 25 deletions macosx/tkMacOSXFont.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,31 +451,49 @@ startOfClusterObjCmd(
{
TKNSString *S;
const char *stringArg;
Tcl_Size numBytes, index;
Tcl_Size len, idx;
if ((unsigned)(objc - 3) > 1) {
Tcl_WrongNumArgs(interp, 1 , objv, "str start ?locale?");
return TCL_ERROR;
}
stringArg = Tcl_GetStringFromObj(objv[1], &numBytes);
stringArg = Tcl_GetStringFromObj(objv[1], &len);
if (stringArg == NULL) {
return TCL_ERROR;
}
S = [[TKNSString alloc] initWithTclUtfBytes:stringArg length:numBytes];
if (TkGetIntForIndex(objv[2], [S length] - 1, 0, &index) != TCL_OK) {
Tcl_Size ulen = Tcl_GetCharLength(objv[1]);
S = [[TKNSString alloc] initWithTclUtfBytes:stringArg length:len];
len = [S length];
if (TkGetIntForIndex(objv[2], ulen - 1, 0, &idx) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad index \"%s\": must be integer?[+-]integer?, end?[+-]integer?, or \"\"",
Tcl_GetString(objv[2])));
Tcl_SetErrorCode(interp, "TK", "VALUE", "INDEX", NULL);
return TCL_ERROR;
}
if (index >= 0) {
if ((size_t)index >= [S length]) {
index = (Tcl_Size)[S length];
if (idx > 0 && len != ulen) {
/* The string contains codepoints > \uFFFF. Determine UTF-16 index */
Tcl_Size newIdx = 0;
for (Tcl_Size i = 0; i < idx; i++) {
newIdx += 1 + (((newIdx < (Tcl_Size)len-1) && ([S characterAtIndex:newIdx]&0xFC00) == 0xD800) && (([S characterAtIndex:newIdx+1]&0xFC00) == 0xDC00));
}
idx = newIdx;
}
if (idx >= 0) {
if (idx >= len) {
idx = len;
} else {
NSRange range = [S rangeOfComposedCharacterSequenceAtIndex:index];
index = range.location;
NSRange range = [S rangeOfComposedCharacterSequenceAtIndex:idx];
idx = range.location;
}
if (idx > 0 && len != ulen) {
/* The string contains codepoints > \uFFFF. Determine UTF-32 index */
Tcl_Size newIdx = 1;
for (Tcl_Size i = 1; i < idx; i++) {
if ((([S characterAtIndex:i-1]&0xFC00) != 0xD800) || (([S characterAtIndex:i]&0xFC00) != 0xDC00)) newIdx++;
}
idx = newIdx;
}
Tcl_SetObjResult(interp, TkNewIndexObj(index));
Tcl_SetObjResult(interp, TkNewIndexObj(idx));
}
return TCL_OK;
}
Expand All @@ -489,32 +507,50 @@ endOfClusterObjCmd(
{
TKNSString *S;
char *stringArg;
Tcl_Size index, numBytes;
Tcl_Size idx, len;

if ((unsigned)(objc - 3) > 1) {
Tcl_WrongNumArgs(interp, 1 , objv, "str start ?locale?");
return TCL_ERROR;
}
stringArg = Tcl_GetStringFromObj(objv[1], &numBytes);
stringArg = Tcl_GetStringFromObj(objv[1], &len);
if (stringArg == NULL) {
return TCL_ERROR;
}
S = [[TKNSString alloc] initWithTclUtfBytes:stringArg length:numBytes];
if (TkGetIntForIndex(objv[2], [S length] - 1, 0, &index) != TCL_OK) {
Tcl_Size ulen = Tcl_GetCharLength(objv[1]);
S = [[TKNSString alloc] initWithTclUtfBytes:stringArg length:len];
len = [S length];
if (TkGetIntForIndex(objv[2], ulen - 1, 0, &idx) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad index \"%s\": must be integer?[+-]integer?, end?[+-]integer?, or \"\"",
Tcl_GetString(objv[2])));
Tcl_SetErrorCode(interp, "TK", "VALUE", "INDEX", NULL);
return TCL_ERROR;
}
if ((size_t)index + 1 <= [S length]) {
if (index < 0) {
index = 0;
if (idx > 0 && len != ulen) {
/* The string contains codepoints > \uFFFF. Determine UTF-16 index */
Tcl_Size newIdx = 0;
for (Tcl_Size i = 0; i < idx; i++) {
newIdx += 1 + (((newIdx < len-1) && ([S characterAtIndex:newIdx]&0xFC00) == 0xD800) && (([S characterAtIndex:newIdx+1]&0xFC00) == 0xDC00));
}
idx = newIdx;
}
if (idx + 1 <= len) {
if (idx < 0) {
idx = 0;
} else {
NSRange range = [S rangeOfComposedCharacterSequenceAtIndex:index];
index = range.location + range.length;
NSRange range = [S rangeOfComposedCharacterSequenceAtIndex:idx];
idx = range.location + range.length;
if (idx > 0 && len != ulen) {
/* The string contains codepoints > \uFFFF. Determine UTF-32 index */
Tcl_Size newIdx = 1;
for (Tcl_Size i = 1; i < idx; i++) {
if ((([S characterAtIndex:i-1]&0xFC00) != 0xD800) || (([S characterAtIndex:i]&0xFC00) != 0xDC00)) newIdx++;
}
idx = newIdx;
}
}
Tcl_SetObjResult(interp, TkNewIndexObj(index));
Tcl_SetObjResult(interp, TkNewIndexObj(idx));
}
return TCL_OK;
}
Expand Down Expand Up @@ -1030,8 +1066,8 @@ TkpMeasureCharsInContext(
attributes:fontPtr->nsAttributes];
typesetter = CTTypesetterCreateWithAttributedString(
(CFAttributedStringRef)attributedString);
start = Tcl_NumUtfChars(source, rangeStart);
len = Tcl_NumUtfChars(source + rangeStart, rangeLength);
start = TclNumUtfChars(source, rangeStart);
len = TclNumUtfChars(source + rangeStart, rangeLength);
if (start > 0) {
range.length = start;
line = CTTypesetterCreateLine(typesetter, range);
Expand Down Expand Up @@ -1132,7 +1168,7 @@ TkpMeasureCharsInContext(
[attributedString release];
[string release];
length = ceil(width - offset);
fit = (Tcl_UtfAtIndex(source, index) - source) - rangeStart;
fit = (TclUtfAtIndex(source, index) - source) - rangeStart;
done:
#ifdef TK_MAC_DEBUG_FONTS
TkMacOSXDbgMsg("measure: source=\"%s\" range=\"%.*s\" maxLength=%d "
Expand Down Expand Up @@ -1331,8 +1367,8 @@ TkpDrawAngledCharsInContext(
-textX, -textY);
}
CGContextConcatCTM(context, t);
start = Tcl_NumUtfChars(source, rangeStart);
length = Tcl_NumUtfChars(source, rangeStart + rangeLength) - start;
start = TclNumUtfChars(source, rangeStart);
length = TclNumUtfChars(source, rangeStart + rangeLength) - start;
line = CTTypesetterCreateLine(typesetter, CFRangeMake(start, length));
if (start > 0) {

Expand Down
32 changes: 16 additions & 16 deletions tests/cluster.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,53 +15,53 @@ testConstraint needsICU [expr {[catch {info body ::tk::startOfCluster}]}]


test cluster-1.0 {::tk::startOfCluster} -body {
::tk::startOfCluster 🤡 -1
::tk::startOfCluster -1
} -result {}
test cluster-1.1 {::tk::startOfCluster} -body {
::tk::startOfCluster 🤡 0
::tk::startOfCluster 0
} -result 0
test cluster-1.2 {::tk::startOfCluster} -constraints needsICU -body {
::tk::startOfCluster 🤡 1
::tk::startOfCluster 1
} -result 0
test cluster-1.3 {::tk::startOfCluster} -constraints needsICU -body {
::tk::startOfCluster 🤡 2
::tk::startOfCluster 2
} -result 2
test cluster-1.4 {::tk::startOfCluster} -constraints needsICU -body {
::tk::startOfCluster 🤡 3
::tk::startOfCluster 3
} -result 2
test cluster-1.5 {::tk::startOfCluster} -constraints needsICU -body {
::tk::startOfCluster 🤡 end
::tk::startOfCluster end
} -result 0
test cluster-1.6 {::tk::startOfCluster} -body {
::tk::startOfCluster 🤡 {}
::tk::startOfCluster {}
} -result {}
test cluster-1.7 {::tk::startOfCluster} -constraints needsICU -body {
::tk::startOfCluster 🤡 end-1
::tk::startOfCluster end-1
} -result 0

test cluster-2.0 {::tk::endOfCluster} -body {
::tk::endOfCluster 🤡 -1
::tk::endOfCluster -1
} -result 0
test cluster-2.1 {::tk::endOfCluster} -constraints needsICU -body {
::tk::endOfCluster 🤡 0
::tk::endOfCluster 0
} -result 2
test cluster-2.2 {::tk::endOfCluster} -constraints needsICU -body {
::tk::endOfCluster 🤡 1
::tk::endOfCluster 1
} -result 2
test cluster-2.3 {::tk::endOfCluster} -body {
::tk::endOfCluster 🤡 2
::tk::endOfCluster 2
} -result {}
test cluster-2.4 {::tk::endOfCluster} -body {
::tk::endOfCluster 🤡 3
::tk::endOfCluster 3
} -result {}
test cluster-2.5 {::tk::endOfCluster} -constraints needsICU -body {
::tk::endOfCluster 🤡 end
::tk::endOfCluster end
} -result 2
test cluster-2.6 {::tk::endOfCluster} -body {
::tk::endOfCluster 🤡 {}
::tk::endOfCluster {}
} -result 0
test cluster-2.7 {::tk::endOfCluster} -constraints needsICU -body {
::tk::endOfCluster 🤡 end-1
::tk::endOfCluster end-1
} -result 2

test cluster-3.0 {::tk::endOfWord} -body {
Expand Down

0 comments on commit 6eb17d2

Please sign in to comment.