summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXFont.c')
-rw-r--r--macosx/tkMacOSXFont.c141
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;
}