diff options
Diffstat (limited to 'macosx/tkMacOSXFont.c')
-rw-r--r-- | macosx/tkMacOSXFont.c | 141 |
1 files changed, 137 insertions, 4 deletions
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 41da390..a402345 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -101,6 +101,141 @@ static void DrawCharsInContext(Display *display, Drawable drawable, #pragma mark - #pragma mark Font Helpers: +/* + *--------------------------------------------------------------------------- + * + * TkUtfToNSString -- + * + * When Tcl is compiled with TCL_UTF_MAX = 3 (the default for 8.6) it cannot + * deal directly with UTF-8 encoded non-BMP characters, since their UTF-8 + * encoding requires 4 bytes. + * + * As a workaround, these versions of Tcl encode non-BMP characters as a string + * of length 6 in which the high and low UTF-16 surrogates have been encoded + * using the UTF-8 algorithm. The UTF-8 encoding does not allow encoding + * surrogates, so these 6-byte strings are not valid UTF-8, and hence Apple's + * NString class will refuse to instantiate an NSString from the 6-byte + * encoding. This function allows creating an NSString from a C-string which + * has been encoded using this scheme. + * + * Results: + * An NSString, which may be nil. + * + * Side effects: + * None. + *--------------------------------------------------------------------------- + */ + +MODULE_SCOPE NSString* +TkUtfToNSString( + const char *source, + size_t numBytes) +{ + NSString *string; + Tcl_DString ds; + + Tcl_DStringInit(&ds); + Tcl_UtfToUniCharDString(source, numBytes, &ds); + string = [[NSString alloc] initWithCharacters:(const unichar *)Tcl_DStringValue(&ds) + length:(Tcl_DStringLength(&ds)>>1)]; + Tcl_DStringFree(&ds); + return string; +} + +/* + *--------------------------------------------------------------------------- + * + * TkUtfAtIndex -- + * + * Write a sequence of bytes up to length 6 which is an encoding of a UTF-16 + * character in an NSString. Also record the unicode code point of the character. + * this may be a non-BMP character constructed by reading two surrogates from + * the NSString. + * + * Results: + * Returns the number of bytes written. + * + * Side effects: + * Bytes are written to the char array referenced by the pointer uni and + * the unicode code point is written to the integer referenced by the + * pointer code. + * + */ + +MODULE_SCOPE int +TkUtfAtIndex( + NSString *string, + int index, + char *uni, + unsigned int *code) +{ + char *ptr = uni; + UniChar uniChar = [string characterAtIndex: index]; + if (CFStringIsSurrogateHighCharacter(uniChar)) { + UniChar lowChar = [string characterAtIndex: ++index]; + *code = CFStringGetLongCharacterForSurrogatePair( + uniChar, lowChar); + ptr += Tcl_UniCharToUtf(uniChar, ptr); + ptr += Tcl_UniCharToUtf(lowChar, ptr); + return ptr - uni; + } else { + *code = (int) uniChar; + [[string substringWithRange: NSMakeRange(index, 1)] + getCString: uni + maxLength: XMaxTransChars + encoding: NSUTF8StringEncoding]; + return strlen(uni); + } +} + +/* + *--------------------------------------------------------------------------- + * + * TkNSStringToUtf -- + * + * Encodes the unicode string represented by an NSString object with the + * internal encoding that Tcl uses when TCL_UTF_MAX = 3. This encoding + * is similar to UTF-8 except that non-BMP characters are encoded as two + * successive 3-byte sequences which are constructed from UTF-16 surrogates + * by applying the UTF-8 algorithm. Even though the UTF-8 encoding does not + * allow encoding surrogates, the algorithm does produce a well-defined + * 3-byte sequence. + * + * Results: + * Returns a pointer to a null-terminated byte array which encodes the + * NSString. + * + * Side effects: + * Memory is allocated to hold the byte array, which must be freed with + * ckalloc. If the pointer numBytes is not NULL the number of non-null + * bytes written to the array is stored in the integer it references. + */ + +MODULE_SCOPE char* +TkNSStringToUtf( + NSString *string, + int *numBytes) +{ + unsigned int code; + size_t i; + char *ptr, *bytes = ckalloc(6*[string length] + 1); + + ptr = bytes; + if (ptr) { + for (i = 0; i < [string length]; i++) { + ptr += TkUtfAtIndex(string, i, ptr, &code); + if (code > 0xffff){ + i++; + } + } + *ptr = '\0'; + } + if (numBytes) { + *numBytes = ptr - bytes; + } + return bytes; +} + #define GetNSFontTraitsFromTkFontAttributes(faPtr) \ ((faPtr)->weight == TK_FW_BOLD ? NSBoldFontMask : NSUnboldFontMask) | \ ((faPtr)->slant == TK_FS_ITALIC ? NSItalicFontMask : NSUnitalicFontMask) @@ -844,8 +979,7 @@ TkpMeasureCharsInContext( if (maxLength > 32767) { maxLength = 32767; } - string = [[NSString alloc] initWithBytesNoCopy:(void*)source - length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO]; + string = TkUtfToNSString((const char *)source, numBytes); if (!string) { length = 0; fit = rangeLength; @@ -1124,8 +1258,7 @@ DrawCharsInContext( !TkMacOSXSetupDrawingContext(drawable, gc, 1, &drawingContext)) { return; } - string = [[NSString alloc] initWithBytesNoCopy:(void*)source - length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO]; + string = TkUtfToNSString((const char *)source, numBytes); if (!string) { return; } |