summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXFont.c')
-rw-r--r--macosx/tkMacOSXFont.c2412
1 files changed, 509 insertions, 1903 deletions
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c
index eeaef3c..f6d34c9 100644
--- a/macosx/tkMacOSXFont.c
+++ b/macosx/tkMacOSXFont.c
@@ -2,40 +2,16 @@
* tkMacOSXFont.c --
*
* Contains the Macintosh implementation of the platform-independant
- * font package interface. This version uses ATSU instead of Quickdraw.
+ * font package interface.
*
* Copyright 2002-2004 Benjamin Riefenstahl, Benjamin.Riefenstahl@epost.de
- * Copyright (c) 2006-2008 Daniel A. Steffen <das@users.sourceforge.net>
- *
- * Some functions were originally copied verbatim from the QuickDraw version
- * of tkMacOSXFont.c, which had these copyright notices:
- *
- * Copyright (c) 1990-1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2008-2009, Apple Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * Todos:
- *
- * - Get away from Font Manager and Quickdraw functions as much as possible,
- * replace with ATS functions instead.
- *
- * - Use Font Manager functions to translate ids from ATS to Font Manager
- * instead of just assuming that they are the same.
- *
- * - Get a second font register going for fonts that are not assigned to a
- * font family by the OS. On my system I have 27 fonts of that type,
- * Hebrew, Arabic and Hindi fonts that actually come with the system.
- * FMGetFontFamilyInstanceFromFont() returns -981 (kFMInvalidFontFamilyErr)
- * for these and they are not listed when enumerating families, but they
- * are when enumerating fonts directly. The problem that the OS sees may
- * be that at least some of them do not contain any Latin characters. Note
- * that such fonts can not be used for controls, because controls
- * definitely require a family id (this assertion needs testing).
- *
- * RCS: @(#) $Id: tkMacOSXFont.c,v 1.44 2009/03/09 18:50:49 cc_benny Exp $
+ * RCS: @(#) $Id: tkMacOSXFont.c,v 1.45 2009/06/29 14:35:01 das Exp $
*/
#include "tkMacOSXPrivate.h"
@@ -48,19 +24,6 @@
*/
/*
- * Problem: The sum of two parts is not the same as the whole. In particular
- * the width of two separately measured strings will usually be larger than
- * the width of them pasted together. Tk has a design bug here, because it
- * generally assumes that this kind of arithmetic works.
- * To workaround this, #define TK_MAC_COALESCE_LINE to 1 below, we then avoid
- * lines that tremble and shiver while the cursor passes through them by
- * undercutting the system and behind the scenes pasting strings together that
- * look like they are on the same line and adjacent and that are drawn with
- * the same font. To do this we need some global data.
- */
-#define TK_MAC_COALESCE_LINE 0
-
-/*
* The following structure represents our Macintosh-specific implementation
* of a font object.
*/
@@ -69,87 +32,11 @@ typedef struct {
TkFont font; /* Stuff used by generic font package. Must
* be first in structure. */
- /*
- * The ATSU view of the font and other text properties. Used for drawing
- * and measuring.
- */
-
- ATSUFontID atsuFontId; /* == FMFont. */
- ATSUTextLayout atsuLayout; /* ATSU layout object, representing the whole
- * text that ATSU sees with some option
- * bits. */
- ATSUStyle atsuStyle; /* ATSU style object, representing a run of
- * text with the same properties. */
-
- /*
- * The QuickDraw view of the font. Used to configure controls.
- */
-
- FMFontFamily qdFont; /* == FMFontFamilyId, Carbon replacement for
- * QD face numbers. */
- short qdSize; /* Font size in points. */
- short qdStyle; /* QuickDraw style bits. */
+ NSFont *nsFont;
+ NSDictionary *nsAttributes;
} MacFont;
/*
- * Information about font families, initialized at startup time. Font
- * families are described by a mapping from UTF-8 names to MacOS font family
- * IDs. The whole list is kept as the sorted array "familyList", allocated
- * with ckrealloc().
- *
- * Note: This would have been easier, if we could just have used Tcl hash
- * arrays. Unfortunately there seems to be no pre-packaged
- * non-case-sensitive version of that available.
- */
-
-typedef struct {
- const char * name;
- FMFontFamily familyId;
-} MacFontFamily;
-
-static MacFontFamily * familyList = NULL;
-static int
- familyListNextFree = 0, /* The next free slot in familyList. */
- familyListMaxValid = 0, /* The top of the sorted area. */
- familyListSize = 0; /* The size of the whole array. */
-
-/*
- * A simple one-shot sub-allocator for fast and efficient allocation of
- * strings. Used by the familyList array for the names. These strings are
- * only allocated once at startup and never freed. If you ever need to
- * re-initialize this, you can just ckfree() all the StringBlocks in the list
- * and start over.
- */
-
-#define STRING_BLOCK_MAX (1024-8) /* Make sizeof(StringBlock) ==
- * 1024. */
-typedef struct StringBlock {
- struct StringBlock *next; /* Starting from "stringMemory" these
- * blocks form a linked list. */
- int nextFree; /* Top of the used area in the
- * "strings" member. */
- char strings[STRING_BLOCK_MAX]; /* The actual memory managed here. */
-} StringBlock;
-
-static StringBlock *stringMemory = NULL;
-
-#if TK_MAC_COALESCE_LINE
-static Tcl_DString currentLine; /* The current line as seen so far. This
- * contains a Tcl_UniChar DString. */
-static int
- currentY = -1, /* The Y position (row in pixels) of the
- * current line. */
- currentLeft = -1, /* The left edge (pixels) of the current
- * line. */
- currentRight = -1; /* The right edge (pixels) of the current
- * line. */
-static const MacFont *currentFontPtr = NULL;
- /* The font of the current line. */
-#endif /* TK_MAC_COALESCE_LINE */
-
-static int antialiasedTextEnabled;
-
-/*
* The names for our "native" fonts.
*/
@@ -189,175 +76,226 @@ static const struct SystemFontMapEntry systemFontMap[] = {
};
#undef ThemeFont
-/*
- * Procedures used only in this file.
- */
-
-static void LayoutSetString(const MacFont *fontPtr,
- const TkMacOSXDrawingContext *drawingContextPtr,
- const UniChar * uchars, int ulen);
-
-/*
- * The actual workers.
- */
-
-static int MeasureStringWidth(const MacFont *fontPtr, int start, int end);
-
-#if TK_MAC_COALESCE_LINE
-static const Tcl_UniChar *UpdateLineBuffer(const MacFont *fontPtr,
- const TkMacOSXDrawingContext *drawingContextPtr, const char *source,
- int numBytes, int x, int y, int * offset);
-#endif /* TK_MAC_COALESCE_LINE */
-
-/*
- * Initialization and setup of a font data structure.
- */
-
-static const char *FamilyNameForFamilyID(FMFontFamily familyId);
-static void InitFont(FMFontFamily familyId, const char *familyName,
- int size, int qdStyle, MacFont *fontPtr);
-static void InitATSUObjects(FMFontFamily familyId, short qdsize, short qdStyle,
- ATSUFontID *fontIdPtr, ATSUTextLayout *layoutPtr, ATSUStyle *stylePtr);
-static void InitATSUStyle(ATSUFontID fontId, short ptSize, short qdStyle,
- ATSUStyle style);
-static void SetFontFeatures(ATSUFontID fontId, int fixed, short size,
- ATSUStyle style);
-static void AdjustFontHeight(MacFont *fontPtr);
-static void InitATSULayout(const TkMacOSXDrawingContext *drawingContextPtr,
- ATSUTextLayout layout, int fixed);
-static void ReleaseFont(MacFont *fontPtr);
-
-/*
- * Finding fonts by name.
- */
-
-static const MacFontFamily *FindFontFamilyOrAlias(const char *name);
-static const MacFontFamily *FindFontFamilyOrAliasOrFallback(const char *name);
-
-/*
- * Doing interesting things with font families and fonts.
- */
-
-static void InitFontFamilies(void);
-static OSStatus GetFontFamilyName(FMFontFamily fontFamily, char *name,
- int numBytes);
-
-/*
- * Accessor functions and internal utilities for the font family list.
- */
-
-static const MacFontFamily *AddFontFamily(const char *name,
- FMFontFamily familyId);
-static const MacFontFamily *FindFontFamily(const char *name);
-static Tcl_Obj *EnumFontFamilies(void);
+static int antialiasedTextEnabled = -1;
+static NSCharacterSet *whitespaceCharacterSet = nil;
+static NSCharacterSet *lineendingCharacterSet = nil;
-static OSStatus FontFamilyEnumCallback(ATSFontFamilyRef family, void *refCon);
-static void SortFontFamilies(void);
-static int CompareFontFamilies(const void *vp1, const void *vp2);
-static const char *AddString(const char *in);
-
-static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId,
- FMFontFamily *fontFamily, unsigned char *fontName, SInt16 *fontSize,
- Style *fontStyle);
-static void InitSystemFonts(TkMainInfo *mainPtr);
+static void GetTkFontAttributesForNSFont(NSFont *nsFont,
+ TkFontAttributes *faPtr);
+static NSFont *FindNSFont(const char *familyName, NSFontTraitMask traits,
+ NSInteger weight, CGFloat size, int fallbackToDefault);
+static void InitFont(NSFont *nsFont, const TkFontAttributes *reqFaPtr,
+ MacFont * fontPtr);
static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin,
const char* name, TkFontAttributes *faPtr);
-static void DrawCharsInContext(Display *display,
- Drawable drawable, GC gc, Tk_Font tkfont,
- const char *source, int numBytes, int rangeStart,
- int rangeLength, int x, int y, double angle);
+static void DrawCharsInContext(Display *display, Drawable drawable, GC gc,
+ Tk_Font tkfont, const char *source, int numBytes, int rangeStart,
+ int rangeLength, int x, int y, double angle);
+
+@interface NSFont(TKFont)
+- (NSFont *)bestMatchingFontForCharacters:(const UTF16Char *)characters
+ length:(NSUInteger)length attributes:(NSDictionary *)attributes
+ actualCoveredLength:(NSUInteger *)coveredLength;
+@end
+
+#pragma mark -
+#pragma mark Font Helpers:
+
+#define GetNSFontTraitsFromTkFontAttributes(faPtr) \
+ ((faPtr)->weight == TK_FW_BOLD ? NSBoldFontMask : NSUnboldFontMask) | \
+ ((faPtr)->slant == TK_FS_ITALIC ? NSItalicFontMask : NSUnitalicFontMask)
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * TkpFontPkgInit --
+ * GetTkFontAttributesForNSFont --
*
- * This procedure is called when an application is created. It
- * initializes all the structures that are used by the
- * platform-dependant code on a per application basis.
+ * Fill in TkFontAttributes for given NSFont.
*
* Results:
* None.
*
* Side effects:
- * Initialization of variables local to this file.
+ * None.
*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
-void
-TkpFontPkgInit(
- TkMainInfo *mainPtr) /* The application being created. */
+static void
+GetTkFontAttributesForNSFont(
+ NSFont *nsFont,
+ TkFontAttributes *faPtr)
{
- InitFontFamilies();
- InitSystemFonts(mainPtr);
+ NSFontTraitMask traits = [[NSFontManager sharedFontManager]
+ traitsOfFont:nsFont];
-#if TK_MAC_COALESCE_LINE
- Tcl_DStringInit(&currentLine);
-#endif
+ faPtr->family = Tk_GetUid([[nsFont familyName] UTF8String]);
+ faPtr->size = [nsFont pointSize];
+ faPtr->weight = (traits & NSBoldFontMask ? TK_FW_BOLD : TK_FW_NORMAL);
+ faPtr->slant = (traits & NSItalicFontMask ? TK_FS_ITALIC : TK_FS_ROMAN);
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * InitSystemFonts --
+ * FindNSFont --
*
- * Initialize named system fonts.
+ * Find NSFont for given attributes. Use default values for missing
+ * attributes, and do a case-insensitive search for font family names
+ * if necessary. If fallbackToDefault flag is set, use the system font
+ * as a last resort.
*
* Results:
- *
* None.
*
* Side effects:
- *
* None.
*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
-static void
-InitSystemFonts(
- TkMainInfo *mainPtr)
+static NSFont *
+FindNSFont(
+ const char *familyName,
+ NSFontTraitMask traits,
+ NSInteger weight,
+ CGFloat size,
+ int fallbackToDefault)
{
- Tcl_Interp *interp = mainPtr->interp;
- Tk_Window tkwin = (Tk_Window) mainPtr->winPtr;
- const struct SystemFontMapEntry *systemFont = systemFontMap;
- TkFontAttributes fa;
+ NSFontManager *fm = [NSFontManager sharedFontManager];
+ NSFont *nsFont, *dflt = nil;
+ #define defaultFont (dflt ? dflt : (dflt = [NSFont systemFontOfSize:0]))
+ NSString *family;
- /* force this for now */
- if (!mainPtr->winPtr->mainPtr) {
- mainPtr->winPtr->mainPtr = mainPtr;
+ if (familyName) {
+ family = [[[NSString alloc] initWithUTF8String:familyName] autorelease];
+ } else {
+ family = [defaultFont familyName];
}
- TkInitFontAttributes(&fa);
- while (systemFont->systemName) {
- Str255 fontName;
- SInt16 fontSize;
- Style fontStyle;
-
- if (GetThemeFont(systemFont->id, smSystemScript, fontName,
- &fontSize, &fontStyle) == noErr) {
- CopyPascalStringToC(fontName, (char*)fontName);
- fa.family = Tk_GetUid((char*)fontName);
- fa.size = fontSize;
- fa.weight = (fontStyle & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
- fa.slant = (fontStyle & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
- fa.underline = ((fontStyle & underline) != 0);
- CreateNamedSystemFont(interp, tkwin, systemFont->systemName, &fa);
- if (systemFont->tkName) {
- CreateNamedSystemFont(interp, tkwin, systemFont->tkName, &fa);
- }
- if (systemFont->tkName1) {
- CreateNamedSystemFont(interp, tkwin, systemFont->tkName1, &fa);
+ if (size == 0.0) {
+ size = [defaultFont pointSize];
+ }
+ nsFont = [fm fontWithFamily:family traits:traits weight:weight size:size];
+ if (!nsFont) {
+ NSArray *availableFamilies = [fm availableFontFamilies];
+ NSString *caseFamily = nil;
+
+ for (NSString *f in availableFamilies) {
+ if ([family caseInsensitiveCompare:f] == NSOrderedSame) {
+ caseFamily = f;
+ break;
}
}
- systemFont++;
+ if (caseFamily) {
+ nsFont = [fm fontWithFamily:caseFamily traits:traits weight:weight
+ size:size];
+ }
}
- fa.family = Tk_GetUid("monaco");
- fa.size = 11;
- fa.weight = TK_FW_NORMAL;
- fa.slant = TK_FS_ROMAN;
- fa.underline = 0;
- CreateNamedSystemFont(interp, tkwin, "TkFixedFont", &fa);
+ if (!nsFont) {
+ nsFont = [NSFont fontWithName:family size:size];
+ }
+ if (!nsFont && fallbackToDefault) {
+ nsFont = [fm convertFont:defaultFont toFamily:family];
+ nsFont = [fm convertFont:nsFont toSize:size];
+ nsFont = [fm convertFont:nsFont toHaveTrait:traits];
+ }
+ #undef defaultFont
+ return nsFont;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitFont --
+ *
+ * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
+ *
+ * Results:
+ * Fills the MacFont structure.
+ *
+ * Side effects:
+ * Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitFont(
+ NSFont *nsFont,
+ const TkFontAttributes *reqFaPtr, /* Can be NULL */
+ MacFont *fontPtr)
+{
+ TkFontAttributes *faPtr;
+ TkFontMetrics *fmPtr;
+ NSDictionary *nsAttributes;
+ NSRect bounds;
+ CGFloat kern = 0.0;
+ NSFontRenderingMode renderingMode = NSFontDefaultRenderingMode;
+ int ascent, descent, dontAA;
+ static const UniChar ch[] = {'.', 'W', ' ', 0xc4, 0xc1, 0xc2, 0xc3, 0xc7};
+ /* ., W, Space, Auml, Aacute, Acirc, Atilde, Ccedilla */
+ #define nCh (sizeof(ch) / sizeof(UniChar))
+ CGGlyph glyphs[nCh];
+ CGRect boundingRects[nCh];
+
+ fontPtr->font.fid = (Font) fontPtr;
+ faPtr = &fontPtr->font.fa;
+ if (reqFaPtr) {
+ *faPtr = *reqFaPtr;
+ } else {
+ TkInitFontAttributes(faPtr);
+ }
+ fontPtr->nsFont = nsFont;
+ dontAA = [nsFont isFixedPitch] && fontPtr->font.fa.size <= 10;
+ if (antialiasedTextEnabled >= 0 || dontAA) {
+ renderingMode = (antialiasedTextEnabled == 0 || dontAA) ?
+ NSFontIntegerAdvancementsRenderingMode :
+ NSFontAntialiasedRenderingMode;
+ }
+ nsFont = [nsFont screenFontWithRenderingMode:renderingMode];
+ GetTkFontAttributesForNSFont(nsFont, faPtr);
+ fmPtr = &fontPtr->font.fm;
+ fmPtr->ascent = floor([nsFont ascender] + [nsFont leading] + 0.5);
+ fmPtr->descent = floor(-[nsFont descender] + 0.5);
+ fmPtr->maxWidth = [nsFont maximumAdvancement].width;
+ fmPtr->fixed = [nsFont isFixedPitch]; /* Does not work for all fonts */
+
+ /*
+ * The ascent, descent and fixed fields are not correct for all fonts, as
+ * a workaround deduce that info from the metrics of some typical glyphs,
+ * along with screenfont kerning (space advance difference to printer font)
+ */
+
+ bounds = [nsFont boundingRectForFont];
+ if (CTFontGetGlyphsForCharacters((CTFontRef) nsFont, ch, glyphs, nCh)) {
+ fmPtr->fixed = [nsFont advancementForGlyph:glyphs[0]].width ==
+ [nsFont advancementForGlyph:glyphs[1]].width;
+ bounds = NSRectFromCGRect(CTFontGetBoundingRectsForGlyphs((CTFontRef)
+ nsFont, kCTFontDefaultOrientation, ch, boundingRects, nCh));
+ kern = [nsFont advancementForGlyph:glyphs[2]].width -
+ [fontPtr->nsFont advancementForGlyph:glyphs[2]].width;
+ }
+ descent = floor(-bounds.origin.y + 0.5);
+ ascent = floor(bounds.size.height + bounds.origin.y + 0.5);
+ if (ascent > fmPtr->ascent) {
+ fmPtr->ascent = ascent;
+ }
+ if (descent > fmPtr->descent) {
+ fmPtr->descent = descent;
+ }
+ nsAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ nsFont, NSFontAttributeName,
+ [NSNumber numberWithInt:faPtr->underline ?
+ NSUnderlineStyleSingle|NSUnderlinePatternSolid :
+ NSUnderlineStyleNone], NSUnderlineStyleAttributeName,
+ [NSNumber numberWithInt:faPtr->overstrike ?
+ NSUnderlineStyleSingle|NSUnderlinePatternSolid :
+ NSUnderlineStyleNone], NSStrikethroughStyleAttributeName,
+ [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1],
+ NSLigatureAttributeName,
+ [NSNumber numberWithDouble:kern], NSKernAttributeName, nil];
+ fontPtr->nsAttributes = TkMacOSXMakeUncollectableAndRetain(nsAttributes);
+ #undef nCh
}
/*
@@ -388,37 +326,84 @@ CreateNamedSystemFont(
TkDeleteNamedFont(NULL, tkwin, name);
return TkCreateNamedFont(interp, tkwin, name, faPtr);
}
+
+#pragma mark -
+#pragma mark Font handling:
/*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*
- * GetThemeFontAndFamily --
+ * TkpFontPkgInit --
+ *
+ * This procedure is called when an application is created. It
+ * initializes all the structures that are used by the
+ * platform-dependant code on a per application basis.
+ * Note that this is called before TkpInit() !
*
- * Wrapper around the GetThemeFont and FMGetFontFamilyFromName APIs.
+ * Results:
+ * None.
*
- *---------------------------------------------------------------------------
+ * Side effects:
+ * Initialize named system fonts.
+ *
+ *-------------------------------------------------------------------------
*/
-OSStatus
-GetThemeFontAndFamily(
- const ThemeFontID themeFontId,
- FMFontFamily* fontFamily,
- unsigned char *fontName,
- SInt16 *fontSize,
- Style *fontStyle)
+void
+TkpFontPkgInit(
+ TkMainInfo *mainPtr) /* The application being created. */
{
- OSStatus err = ChkErr(GetThemeFont, themeFontId, smSystemScript, fontName,
- fontSize, fontStyle);
+ Tcl_Interp *interp = mainPtr->interp;
+ Tk_Window tkwin = (Tk_Window) mainPtr->winPtr;
+ const struct SystemFontMapEntry *systemFont = systemFontMap;
+ NSFont *nsFont;
+ TkFontAttributes fa;
+ NSMutableCharacterSet *cs;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
- if (err == noErr) {
- *fontFamily = FMGetFontFamilyFromName(fontName);
- if (*fontFamily == kInvalidFontFamily) {
- err = kFMInvalidFontFamilyErr;
- TkMacOSXDbgMsg("FMGetFontFamilyFromName failed.");
+ /* force this for now */
+ if (!mainPtr->winPtr->mainPtr) {
+ mainPtr->winPtr->mainPtr = mainPtr;
+ }
+ while (systemFont->systemName) {
+ nsFont = (NSFont*) CTFontCreateUIFontForLanguage(
+ HIThemeGetUIFontType(systemFont->id), 0, NULL);
+ if (nsFont) {
+ TkInitFontAttributes(&fa);
+ GetTkFontAttributesForNSFont(nsFont, &fa);
+ CreateNamedSystemFont(interp, tkwin, systemFont->systemName, &fa);
+ if (systemFont->tkName) {
+ CreateNamedSystemFont(interp, tkwin, systemFont->tkName, &fa);
+ }
+ if (systemFont->tkName1) {
+ CreateNamedSystemFont(interp, tkwin, systemFont->tkName1, &fa);
+ }
+ CFRelease(nsFont);
}
+ systemFont++;
}
-
- return err;
+ TkInitFontAttributes(&fa);
+ nsFont = (NSFont*) CTFontCreateUIFontForLanguage(
+ kCTFontUserFixedPitchFontType, 11, NULL);
+ if (nsFont) {
+ GetTkFontAttributesForNSFont(nsFont, &fa);
+ CFRelease(nsFont);
+ } else {
+ fa.family = Tk_GetUid("Monaco");
+ fa.size = 11;
+ fa.weight = TK_FW_NORMAL;
+ fa.slant = TK_FS_ROMAN;
+ }
+ CreateNamedSystemFont(interp, tkwin, "TkFixedFont", &fa);
+ if (!whitespaceCharacterSet) {
+ whitespaceCharacterSet = [[NSCharacterSet
+ whitespaceAndNewlineCharacterSet] retain];
+ cs = [whitespaceCharacterSet mutableCopy];
+ [cs removeCharactersInString:@" "];
+ lineendingCharacterSet = [cs copy];
+ [cs release];
+ }
+ [pool drain];
}
/*
@@ -452,12 +437,9 @@ TkpGetNativeFont(
Tk_Window tkwin, /* For display where font will be used. */
const char *name) /* Platform-specific font name. */
{
+ MacFont *fontPtr = NULL;
ThemeFontID themeFontId;
- FMFontFamily fontFamily;
- Str255 fontName;
- SInt16 fontSize;
- Style fontStyle;
- MacFont *fontPtr;
+ CTFontRef ctFont;
if (strcmp(name, SYSTEMFONT_NAME) == 0) {
themeFontId = kThemeSystemFont;
@@ -468,14 +450,12 @@ TkpGetNativeFont(
} else {
return NULL;
}
- if (GetThemeFontAndFamily(themeFontId, &fontFamily, fontName, &fontSize,
- &fontStyle) != noErr) {
- return NULL;
+ ctFont = CTFontCreateUIFontForLanguage(HIThemeGetUIFontType(
+ themeFontId), 0, NULL);
+ if (ctFont) {
+ fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
+ InitFont((NSFont*) ctFont, NULL, fontPtr);
}
- CopyPascalStringToC(fontName, (char*)fontName);
-
- fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
- InitFont(fontFamily, (char*)fontName, fontSize, fontStyle, fontPtr);
return (TkFont *) fontPtr;
}
@@ -521,41 +501,34 @@ TkpGetFontFromAttributes(
const TkFontAttributes *faPtr)
/* Set of attributes to match. */
{
- short qdStyle;
- FMFontFamily familyId;
- const char *name;
- const MacFontFamily *familyPtr;
MacFont *fontPtr;
+ int points = TkFontGetPoints(tkwin, faPtr->size);
+ NSFontTraitMask traits = GetNSFontTraitsFromTkFontAttributes(faPtr);
+ NSInteger weight = (faPtr->weight == TK_FW_BOLD ? 9 : 5);
+ NSFont *nsFont;
- familyId = GetAppFont();
- name = NULL;
- qdStyle = 0;
+ nsFont = FindNSFont(faPtr->family, traits, weight, points, 0);
+ if (!nsFont) {
+ const char *const *aliases = TkFontGetAliasList(faPtr->family);
- if (faPtr->family != NULL) {
- familyPtr = FindFontFamilyOrAliasOrFallback(faPtr->family);
- if (familyPtr != NULL) {
- name = familyPtr->name;
- familyId = familyPtr->familyId;
+ while (aliases && !nsFont) {
+ nsFont = FindNSFont(*aliases++, traits, weight, points, 0);
}
}
-
- if (faPtr->weight != TK_FW_NORMAL) {
- qdStyle |= bold;
- }
- if (faPtr->slant != TK_FS_ROMAN) {
- qdStyle |= italic;
+ if (!nsFont) {
+ nsFont = FindNSFont(faPtr->family, traits, weight, points, 1);
}
- if (faPtr->underline) {
- qdStyle |= underline;
+ if (!nsFont) {
+ Tcl_Panic("Could not deternmine NSFont from TkFontAttributes");
}
if (tkFontPtr == NULL) {
fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
} else {
fontPtr = (MacFont *) tkFontPtr;
- ReleaseFont(fontPtr);
+ TkpDeleteFont(tkFontPtr);
}
- InitFont(familyId, name, TkFontGetPoints(tkwin, faPtr->size),
- qdStyle, fontPtr);
+ CFRetain(nsFont); /* Always needed to allow unconditional CFRelease below */
+ InitFont(nsFont, faPtr, fontPtr);
return (TkFont *) fontPtr;
}
@@ -583,7 +556,10 @@ void
TkpDeleteFont(
TkFont *tkFontPtr) /* Token of font to be deleted. */
{
- ReleaseFont((MacFont *) tkFontPtr);
+ MacFont *fontPtr = (MacFont *) tkFontPtr;
+
+ TkMacOSXMakeCollectableAndRelease(fontPtr->nsAttributes);
+ CFRelease(fontPtr->nsFont); /* Either a CTFontRef or a CFRetained NSFont */
}
/*
@@ -609,7 +585,14 @@ TkpGetFontFamilies(
Tcl_Interp *interp, /* Interp to hold result. */
Tk_Window tkwin) /* For display to query. */
{
- Tcl_SetObjResult(interp, EnumFontFamilies());
+ Tcl_Obj *resultPtr = Tcl_NewListObj(0, NULL);
+ NSArray *list = [[NSFontManager sharedFontManager] availableFontFamilies];
+
+ for (NSString *family in list) {
+ Tcl_ListObjAppendElement(NULL, resultPtr,
+ Tcl_NewStringObj([family UTF8String], -1));
+ }
+ Tcl_SetObjResult(interp, resultPtr);
}
/*
@@ -635,10 +618,23 @@ TkpGetSubFonts(
Tcl_Interp *interp, /* Interp to hold result. */
Tk_Font tkfont) /* Font object to query. */
{
- /* We don't know much about our fallback fonts, ATSU does all that for
- * us. We could use ATSUMatchFont to implement this function. But as
- * the information is only used for testing, such an effort seems not
- * very useful. */
+ MacFont *fontPtr = (MacFont *) tkfont;
+ Tcl_Obj *resultPtr = Tcl_NewListObj(0, NULL);
+
+ if (fontPtr->nsFont) {
+ NSArray *list = [[fontPtr->nsFont fontDescriptor]
+ objectForKey:NSFontCascadeListAttribute];
+
+ for (NSFontDescriptor *subFontDesc in list) {
+ NSString *family = [subFontDesc objectForKey:NSFontFamilyAttribute];
+
+ if (family) {
+ Tcl_ListObjAppendElement(NULL, resultPtr,
+ Tcl_NewStringObj([family UTF8String], -1));
+ }
+ }
+ }
+ Tcl_SetObjResult(interp, resultPtr);
}
/*
@@ -665,72 +661,23 @@ TkpGetFontAttrsForChar(
Tcl_UniChar c, /* Character of interest */
TkFontAttributes* faPtr) /* Output: Font attributes */
{
- const MacFont * fontPtr = (const MacFont *) tkfont;
- UniChar uchar = c;
- TkMacOSXDrawingContext drawingContext;
- OSStatus err;
- ATSUFontID fontId;
- UniCharArrayOffset changedOffset;
- UniCharCount changedLength;
-
- /*
- * Most of the attributes are just copied from the base font. This
- * assumes that all fonts can have all attributes.
- */
+ MacFont *fontPtr = (MacFont *) tkfont;
+ NSFont *nsFont = fontPtr->nsFont;
*faPtr = fontPtr->font.fa;
+ if (nsFont && ![[nsFont coveredCharacterSet] characterIsMember:c]) {
+ UTF16Char ch = c;
- /*
- * But the name of the actual font may still differ, so we activate the
- * string as an ATSU layout and ask ATSU about the fallback.
- */
- if (!TkMacOSXSetupDrawingContext(Tk_WindowId(tkwin), NULL, 1,
- &drawingContext)) {
- Tcl_Panic("TkpGetFontAttrsForChar: drawingContext not setup");
- }
-
- LayoutSetString(fontPtr, &drawingContext, &uchar, 1);
-
- fontId = fontPtr->atsuFontId;
- err = ATSUMatchFontsToText(
- fontPtr->atsuLayout, 0, 1,
- &fontId, &changedOffset, &changedLength);
- if (err != kATSUFontsMatched && err != noErr) {
- TkMacOSXDbgMsg("Can't match \\u%04X", (unsigned) c);
- }
-
- if (err == kATSUFontsMatched) {
- /*
- * A fallback was used and the actual font is in fontId. Determine
- * the name.
- */
-
- FMFontFamily fontFamilyId;
- FMFontStyle fontStyle;
- int i;
-
- err = ChkErr(FMGetFontFamilyInstanceFromFont, fontId, &fontFamilyId,
- &fontStyle);
- if (err == noErr) {
- /*
- * Find the canonical name in our global list.
- */
-
- for (i=0; i<familyListMaxValid; ++i) {
- if (fontFamilyId == familyList[i].familyId) {
- faPtr->family = familyList[i].name;
- break;
- }
- }
- if (i >= familyListMaxValid) {
- TkMacOSXDbgMsg("Can't find font %d for \\u%04X", fontFamilyId,
- (unsigned) c);
- }
+ nsFont = [nsFont bestMatchingFontForCharacters:&ch
+ length:1 attributes:nil actualCoveredLength:NULL];
+ if (nsFont) {
+ GetTkFontAttributesForNSFont(nsFont, faPtr);
}
}
-
- TkMacOSXRestoreDrawingContext(&drawingContext);
}
+
+#pragma mark -
+#pragma mark Measuring and drawing:
/*
*---------------------------------------------------------------------------
@@ -842,263 +789,116 @@ TkpMeasureCharsInContext(
* terminating character. */
{
const MacFont *fontPtr = (const MacFont *) tkfont;
- int curX = -1, curByte = 0;
- UniChar *uchars;
- int ulen;
- UniCharArrayOffset urstart, urlen, urend;
- Tcl_DString ucharBuffer;
- int forceCharacterMode = 0;
-
- /*
- * Sanity checks.
- */
-
- if (rangeStart < 0 || (rangeStart+rangeLength) > numBytes) {
- TkMacOSXDbgMsg("Bad parameters");
+ NSString *string;
+ NSAttributedString *attributedString;
+ CTTypesetterRef typesetter;
+ CFIndex start, len;
+ CFRange range = {0, 0};
+ CTLineRef line;
+ CGFloat offset = 0;
+ CFIndex index;
+ double width;
+ int length, fit;
+
+ if (rangeStart < 0 || rangeLength <= 0 ||
+ rangeStart + rangeLength > numBytes ||
+ (maxLength == 0 && !(flags & TK_AT_LEAST_ONE))) {
*lengthPtr = 0;
return 0;
}
-
- /*
- * Get simple no-brainers out of the way.
- */
-
- if (rangeLength == 0 || (maxLength == 0 && !(flags & TK_AT_LEAST_ONE))) {
- *lengthPtr = 0;
- return 0;
+#if 0
+ /* Back-compatibility with ATSUI renderer, appears not to be needed */
+ if (rangeStart == 0 && maxLength == 1 && (flags & TK_ISOLATE_END) &&
+ !(flags & TK_AT_LEAST_ONE)) {
+ length = 0;
+ fit = 0;
+ goto done;
+ }
+#endif
+ if (maxLength > 32767) {
+ maxLength = 32767;
+ }
+ string = [[NSString alloc] initWithBytesNoCopy:(void*)source
+ length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO];
+ if (!string) {
+ length = 0;
+ fit = rangeLength;
+ goto done;
+ }
+ attributedString = [[NSAttributedString alloc] initWithString:string
+ attributes:fontPtr->nsAttributes];
+ typesetter = CTTypesetterCreateWithAttributedString(
+ (CFAttributedStringRef)attributedString);
+ start = Tcl_NumUtfChars(source, rangeStart);
+ len = Tcl_NumUtfChars(source, rangeStart + rangeLength);
+ if (start > 0) {
+ range.length = start;
+ line = CTTypesetterCreateLine(typesetter, range);
+ offset = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
+ CFRelease(line);
}
-
- Tcl_DStringInit(&ucharBuffer);
- uchars = Tcl_UtfToUniCharDString(source, numBytes, &ucharBuffer);
- ulen = Tcl_DStringLength(&ucharBuffer) / sizeof(Tcl_UniChar);
- LayoutSetString(fontPtr, NULL, uchars, ulen);
-
- urstart = Tcl_NumUtfChars(source, rangeStart);
- urlen = Tcl_NumUtfChars(source+rangeStart,rangeLength);
- urend = urstart + urlen;
-
if (maxLength < 0) {
- curX = MeasureStringWidth(fontPtr, urstart, urend);
- curByte = rangeLength;
+ index = len;
+ range.length = len;
+ line = CTTypesetterCreateLine(typesetter, range);
+ width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
+ CFRelease(line);
} else {
- UniCharArrayOffset offset = 0;
- OSStatus err;
-
- /*
- * Have some upper limit on the size actually used.
- */
-
- if (maxLength > 32767) {
- maxLength = 32767;
- }
-
- offset = urstart;
- err = noErr;
-
- if (maxLength > 1) {
- /*
- * Let the system do some work by calculating a line break.
- *
- * Somehow ATSUBreakLine seems to assume that it needs at least
- * one pixel padding. So we add one to the limit. Note also
- * that ATSUBreakLine sometimes runs into an endless loop when
- * the third parameter is equal or less than IntToFixed(2), so we
- * need at least IntToFixed(3) (at least that's the current state
- * of my knowledge).
- */
-
- err = ATSUBreakLine(fontPtr->atsuLayout, urstart,
- IntToFixed(maxLength+1), false, /* !iUseAsSoftLineBreak */
- &offset);
-
- /*
- * There is no way to signal an error from this routine, so we
- * use predefined offset=urstart and otherwise ignore the
- * possibility.
- */
-
- if ((err != noErr) && (err != kATSULineBreakInWord)) {
- TkMacOSXDbgMsg("ATSUBreakLine failed: %ld for '%.*s'", err,
- rangeLength, source+rangeStart);
- }
-
-#ifdef TK_MAC_DEBUG_FONTS
- TkMacOSXDbgMsg("measure: '%.*s', break offset=%ld, errcode=%ld",
- rangeLength, source+rangeStart, offset, err);
-#endif
-
- /*
- * ATSUBreakLine includes the whitespace that separates words,
- * but we don't want that. Besides, ATSUBreakLine thinks that
- * spaces don't occupy pixels at the end of the break, which is
- * also something we like to decide for ourself.
- */
-
- while ((offset > urstart) && (uchars[offset-1] == ' ')) {
- offset--;
- }
- }
-
- /*
- * Fix up left-overs for the TK_WHOLE_WORDS case.
- */
+ double maxWidth = maxLength + offset;
+ NSCharacterSet *cs;
+ index = start;
if (flags & TK_WHOLE_WORDS) {
- if ((flags & TK_AT_LEAST_ONE) && ((offset == urstart)
- || ((offset != urend) && (uchars[offset] != ' ')))) {
- /*
- * With TK_AT_LEAST_ONE, if we are the the start of the
- * range, we need to add at least one character. If we are
- * not at the end of a word, we must be in the middle of the
- * first word still and we want to just use what we have so
- * far. In both cases we still need to find the right
- * character boundary, so we set a flag that gets us into the
- * code for character mode below.
- */
-
- forceCharacterMode = 1;
-
- } else {
- /*
- * If we are not at the end of a word, we must be in the
- * middle of the first word still. Return 0.
- */
-
- if ((offset != urend) && (uchars[offset] != ' ')) {
- offset = urstart;
- curX = 0;
- }
+ index = CTTypesetterSuggestLineBreak(typesetter, 0, maxWidth);
+ if (index <= start && (flags & TK_AT_LEAST_ONE)) {
+ flags &= ~TK_WHOLE_WORDS;
}
}
-
- if (offset > urend) {
- offset = urend;
+ if (index <= start && !(flags & TK_WHOLE_WORDS)) {
+ index = CTTypesetterSuggestClusterBreak(typesetter, 0, maxWidth);
}
-
- /*
- * If "flags" says that we don't actually want a word break, we need
- * to find the next character break ourself, as ATSUBreakLine will
- * only give us word breaks. Do a simple linear search.
- *
- * Even do this, if ATSUBreakLine returned kATSULineBreakInWord,
- * because we have not accounted correctly for all of the flags yet,
- * like TK_AT_LEAST_ONE.
- */
-
- if ((!(flags & TK_WHOLE_WORDS) || forceCharacterMode) && (offset <= urend)) {
- UniCharArrayOffset lastOffset = offset;
- UniCharArrayOffset nextoffset;
- int lastX = -1;
- int wantonemorechar = -1; /* undecided */
-
- while (offset <= urend) {
- if (flags & TK_ISOLATE_END) {
- LayoutSetString(fontPtr, NULL, uchars, offset);
- }
- curX = MeasureStringWidth(fontPtr, urstart, offset);
-
-#ifdef TK_MAC_DEBUG_FONTS
- TkMacOSXDbgMsg("measure: '%.*s', try until=%ld, width=%d",
- rangeLength, source+rangeStart, offset, curX);
-#endif
-
- if (curX > maxLength) {
- /*
- * Even if we are over the limit, we may want another
- * character in some situations. Than we keep looking
- * for one more character.
- */
-
- if (wantonemorechar == -1) {
- wantonemorechar = ((flags & TK_AT_LEAST_ONE) &&
- (lastOffset == urstart)) ||
- ((flags & TK_PARTIAL_OK) &&
- (lastX != maxLength));
- if (!wantonemorechar) {
- break;
- }
- lastX = curX;
- }
-
- /*
- * There may belong combining marks to this character.
- * Wait for a new curX to collect them all.
- */
-
- if (lastX != curX) {
- break;
- }
- }
-
- /*
- * Save this position, so we can come back to it.
- */
-
- lastX = curX;
- lastOffset = offset;
-
- /*
- * Increment offset by one character, taking combining marks
- * into account.
- */
-
- if (offset >= urend) {
- break;
- }
- nextoffset = 0;
- if (flags & TK_ISOLATE_END) {
- LayoutSetString(fontPtr, NULL, uchars, ulen);
- }
- err = ChkErr(ATSUNextCursorPosition, fontPtr->atsuLayout,
- offset, kATSUByCluster, &nextoffset);
- if (err != noErr) {
- break;
- }
- if (nextoffset <= offset) {
-#ifdef TK_MAC_DEBUG_FONTS
- TkMacOSXDbgMsg("ATSUNextCursorPosition: Can't move further"
- " (shouldn't happen, bad data?)");
-#endif
- break;
- }
-
- offset = nextoffset;
- }
-
- /*
- * We have overshot one character, so backup one position.
- */
-
- curX = lastX;
- offset = lastOffset;
+ cs = (index < len || (flags & TK_WHOLE_WORDS)) ?
+ whitespaceCharacterSet : lineendingCharacterSet;
+ while (index > start &&
+ [cs characterIsMember:[string characterAtIndex:(index - 1)]]) {
+ index--;
}
-
- if (curX < 0) {
- if (flags & TK_ISOLATE_END) {
- LayoutSetString(fontPtr, NULL, uchars, offset);
- }
- curX = MeasureStringWidth(fontPtr, urstart, offset);
+ if (index <= start && (flags & TK_AT_LEAST_ONE)) {
+ index = start + 1;
+ }
+ if (index > 0) {
+ range.length = index;
+ line = CTTypesetterCreateLine(typesetter, range);
+ width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
+ CFRelease(line);
+ } else {
+ width = 0;
+ }
+ if (width < maxWidth && (flags & TK_PARTIAL_OK) && index < len) {
+ range.length = ++index;
+ line = CTTypesetterCreateLine(typesetter, range);
+ width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
+ CFRelease(line);
}
-
- curByte = Tcl_UtfAtIndex(source, offset) - source;
- curByte -= rangeStart;
}
-
- Tcl_DStringFree(&ucharBuffer);
-
+ CFRelease(typesetter);
+ [attributedString release];
+ [string release];
+ length = lround(width - offset);
+ fit = (Tcl_UtfAtIndex(source, index) - source) - rangeStart;
+done:
#ifdef TK_MAC_DEBUG_FONTS
- TkMacOSXDbgMsg("measure: '%.*s', maxLength=%d, flags=%s%s%s%s "
- "-> width=%d, bytes=%d",
- rangeLength, source+rangeStart, maxLength,
+ TkMacOSXDbgMsg("measure: source=\"%s\" range=\"%.*s\" maxLength=%d "
+ "flags='%s%s%s%s' -> width=%d bytesFit=%d\n", source, rangeLength,
+ source+rangeStart, maxLength,
flags & TK_PARTIAL_OK ? "partialOk " : "",
flags & TK_WHOLE_WORDS ? "wholeWords " : "",
flags & TK_AT_LEAST_ONE ? "atLeastOne " : "",
flags & TK_ISOLATE_END ? "isolateEnd " : "",
- curX, curByte);
+ length, fit);
#endif
-
- *lengthPtr = curX;
- return curByte;
+ *lengthPtr = length;
+ return fit;
}
/*
@@ -1232,1229 +1032,122 @@ DrawCharsInContext(
* drawing. */
double angle)
{
- const MacFont * fontPtr = (const MacFont *) tkfont;
+ const MacFont *fontPtr = (const MacFont *) tkfont;
+ NSString *string;
+ NSMutableDictionary *attributes;
+ NSAttributedString *attributedString;
+ CTTypesetterRef typesetter;
+ CFIndex start, len;
+ CTLineRef line;
MacDrawable *macWin = (MacDrawable *) drawable;
- Fixed fx, fy;
- int ulen, urstart, urlen;
- const UniChar * uchars;
- int lineOffset;
TkMacOSXDrawingContext drawingContext;
-#if !TK_MAC_COALESCE_LINE
- Tcl_DString runString;
-#endif
-
- if (!TkMacOSXSetupDrawingContext(drawable, gc, tkMacOSXUseCGDrawing,
- &drawingContext)) {
+ CGContextRef context;
+ CGColorRef fg;
+ NSFont *nsFont;
+ CGAffineTransform t;
+ int h;
+
+ if (rangeStart < 0 || rangeLength <= 0 ||
+ rangeStart + rangeLength > numBytes ||
+ !TkMacOSXSetupDrawingContext(drawable, gc, 1, &drawingContext)) {
return;
}
-
-#if 0
- /*
- * TODO: implement stippled text drawing
- */
-
- if ((gc->fill_style == FillStippled
- || gc->fill_style == FillOpaqueStippled)
- && gc->stipple != None) {
- #error Stippling not implemented
+ string = [[NSString alloc] initWithBytesNoCopy:(void*)source
+ length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO];
+ if (!string) {
+ return;
}
-#endif
-
+ context = drawingContext.context;
+ fg = TkMacOSXCreateCGColor(gc, gc->foreground);
+ attributes = [fontPtr->nsAttributes mutableCopy];
+ [attributes setObject:(id)fg forKey:(id)kCTForegroundColorAttributeName];
+ CFRelease(fg);
+ nsFont = [attributes objectForKey:NSFontAttributeName];
+ [nsFont setInContext:[NSGraphicsContext graphicsContextWithGraphicsPort:
+ context flipped:NO]];
+ CGContextSetTextMatrix(context, CGAffineTransformIdentity);
+ attributedString = [[NSAttributedString alloc] initWithString:string
+ attributes:attributes];
+ typesetter = CTTypesetterCreateWithAttributedString(
+ (CFAttributedStringRef)attributedString);
x += macWin->xOff;
y += macWin->yOff;
- /* Turn the y coordinate upside-down for Quarz drawing. */
- if (drawingContext.context) {
- CGContextConcatCTM(drawingContext.context, CGAffineTransformMake(1.0,
- 0.0, 0.0, -1.0, 0.0, drawingContext.portBounds.bottom -
- drawingContext.portBounds.top));
- y = drawingContext.portBounds.bottom -
- drawingContext.portBounds.top - y;
+ h = drawingContext.portBounds.size.height;
+ y = h - y;
+ t = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, h);
+ if (angle != 0.0) {
+ t = CGAffineTransformTranslate(CGAffineTransformRotate(
+ CGAffineTransformTranslate(t, x, y), angle*PI/180.0), -x, -y);
}
- fy = IntToFixed(y);
-
-#if TK_MAC_COALESCE_LINE
- UpdateLineBuffer(
- fontPtr, &drawingContext, source, numBytes, x, y, &lineOffset);
-
- fx = IntToFixed(currentLeft);
-
- uchars = (const Tcl_UniChar*) Tcl_DStringValue(&currentLine);
- ulen = Tcl_DStringLength(&currentLine) / sizeof(uchars[0]);
-#else
- lineOffset = 0;
- fx = IntToFixed(x);
-
- Tcl_DStringInit(&runString);
- uchars = Tcl_UtfToUniCharDString(source, numBytes, &runString);
- ulen = Tcl_DStringLength(&runString) / sizeof(uchars[0]);
-
- LayoutSetString(fontPtr, &drawingContext, uchars, ulen);
-#endif
-
- urstart = Tcl_NumUtfChars(source, rangeStart);
- urlen = Tcl_NumUtfChars(source+rangeStart,rangeLength);
-
- /*
- * Rotate the coordinate system for Quarz drawing.
- */
-
- if (drawingContext.context && angle != 0.0) {
- CGContextConcatCTM(drawingContext.context, CGAffineTransformTranslate(
- CGAffineTransformRotate(CGAffineTransformMakeTranslation(
- x, y), angle * PI/180.0), -x, -y));
+ CGContextConcatCTM(context, t);
+ CGContextSetTextPosition(context, x, y);
+ start = Tcl_NumUtfChars(source, rangeStart);
+ len = Tcl_NumUtfChars(source, rangeStart + rangeLength);
+ if (start > 0) {
+ CGRect clipRect = CGRectInfinite, startBounds;
+ line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start));
+ startBounds = CTLineGetImageBounds(line, context);
+ CFRelease(line);
+ clipRect.origin.x = startBounds.origin.x + startBounds.size.width;
+ CGContextClipToRect(context, clipRect);
}
-
- ChkErr(ATSUDrawText, fontPtr->atsuLayout, lineOffset+urstart, urlen, fx,
- fy);
-
-#if !TK_MAC_COALESCE_LINE
- Tcl_DStringFree(&runString);
-#endif
-
+ line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, len));
+ CTLineDraw(line, context);
+ CFRelease(line);
+ CFRelease(typesetter);
+ [attributedString release];
+ [string release];
+ [attributes release];
TkMacOSXRestoreDrawingContext(&drawingContext);
}
-
-/*
- *---------------------------------------------------------------------------
- *
- * MeasureStringWidth --
- *
- * Low-level measuring of strings.
- *
- * Results:
- * The width of the string in pixels.
- *
- * Side effects:
- * None.
- *
- * Assumptions:
- * fontPtr->atsuLayout is setup with the actual string data to measure.
- *
- *---------------------------------------------------------------------------
- */
-static int
-MeasureStringWidth(
- const MacFont *fontPtr, /* Contains font, ATSU layout and string data
- * to measure. */
- int start, int end) /* Start and end positions to measure in that
- * string. */
-{
- /*
- * This implementation of measuring via ATSUGetGlyphBounds() does not
- * quite conform with the specification given for [font measure]:
- *
- * The return value is the total width in pixels of text, not
- * including the extra pixels used by highly exagerrated characters
- * such as cursive "f".
- *
- * Instead the result of ATSUGetGlyphBounds() *does* include these
- * "extra pixels".
- */
-
- ATSTrapezoid bounds;
- ItemCount numBounds;
-
- if (end <= start) {
- return 0;
- }
-
- bounds.upperRight.x = bounds.upperLeft.x = 0;
- ChkErr(ATSUGetGlyphBounds, fontPtr->atsuLayout, 0, 0, start, end-start,
- kATSUseFractionalOrigins, 1, &bounds, &numBounds);
-#ifdef TK_MAC_DEBUG_FONTS
- if (numBounds < 1 || numBounds > 1) {
- TkMacOSXDbgMsg("ATSUGetGlyphBounds: %s output",
- numBounds < 1 ? "No " : "More");
- }
-#endif
-
- return FixedToInt(bounds.upperRight.x - bounds.upperLeft.x);
-}
-
-#if TK_MAC_COALESCE_LINE
-/*
- *-------------------------------------------------------------------------
- *
- * UpdateLineBuffer --
- *
- * See the general dicussion of TK_MAC_COALESCE_LINE on the header
- * pages. This function maintains the data for this feature.
- *
- * Results:
- *
- * The Tcl_UniChar string of the whole line as seen so far.
- *
- * Side effects:
- * "*offset" is filled with the index of the first new character in
- * "currentLine". The globals currentLine, currentY, currentLeft,
- * currentRight and currentFontPtr are updated as necessary.
- *
- * The currentLine string is set as the current text in
- * fontPtr->atsuLayout (see LayoutSetString()).
- *
- *-------------------------------------------------------------------------
- */
-
-static const Tcl_UniChar *
-UpdateLineBuffer(
- const MacFont *fontPtr, /* The font to be used for the new piece of
- * text. */
- const TkMacOSXDrawingContext *drawingContextPtr,
- /* The Quarz drawing parameters. Needed for
- * measuring the new piece. */
- const char *source, /* A new piece of line to be added. */
- int numBytes, /* Length of the new piece. */
- int x, int y, /* Position of the new piece in the window. */
- int *offset) /* Filled with the offset of the new piece in
- * currentLine. */
-{
- const Tcl_UniChar * uchars;
- int ulen;
-
- if (y != currentY
- || x < currentRight-1 || x > currentRight+2
- || currentFontPtr != fontPtr) {
- Tcl_DStringFree(&currentLine);
- Tcl_DStringInit(&currentLine);
- currentY = y;
- currentLeft = x;
- currentFontPtr = fontPtr;
- *offset = 0;
- } else {
- *offset = Tcl_DStringLength(&currentLine) / 2;
- }
-
- Tcl_UtfToUniCharDString(source, numBytes, &currentLine);
- uchars = (const Tcl_UniChar*) Tcl_DStringValue(&currentLine);
- ulen = Tcl_DStringLength(&currentLine) / sizeof(*uchars);
- LayoutSetString(fontPtr, drawingContextPtr, uchars, ulen);
- currentRight = x + MeasureStringWidth(fontPtr, *offset, ulen);
-
- return uchars;
-}
-#endif /* TK_MAC_COALESCE_LINE */
-
-/*
- *---------------------------------------------------------------------------
- *
- * FamilyNameForFamilyID --
- *
- * Helper for InitFont() and TkMacOSXFontDescriptionForFMFontInfo().
- * Retrieves font family names for a given font family ID.
- *
- * Results:
- * Font family name or NULL.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static const char *
-FamilyNameForFamilyID(
- FMFontFamily familyId)
-{
- OSStatus err;
- char name[256] = "";
- const MacFontFamily * familyPtr = NULL;
-
- err = ChkErr(GetFontFamilyName, familyId, name, sizeof(name));
- if (err == noErr) {
- /*
- * We find the canonical font name, so we can avoid unnecessary
- * memory management.
- */
-
- familyPtr = FindFontFamily(name);
-#ifdef TK_MAC_DEBUG_FONTS
- if (!familyPtr) {
- TkMacOSXDbgMsg("Font family '%s' not found", name);
- }
-#endif
- }
- return familyPtr ? familyPtr->name : NULL;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitFont --
- *
- * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
- * Initializes the memory for a MacFont that wraps the
- * platform-specific data.
- *
- * The caller is responsible for initializing the fields of the TkFont
- * that are used exclusively by the generic TkFont code, and for
- * releasing those fields before calling TkpDeleteFont().
- *
- * Results:
- * Fills the MacFont structure.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitFont(
- FMFontFamily familyId, /* The font family to initialize for. */
- const char * familyName, /* The font family name, if known. Otherwise
- * this can be NULL. */
- int size, /* Point size for the font. */
- int qdStyle, /* QuickDraw style bits. */
- MacFont * fontPtr) /* Filled with information constructed from the
- * above arguments. */
-{
- FontInfo fi;
- TkFontAttributes * faPtr;
- TkFontMetrics * fmPtr;
- int periodWidth, wWidth;
-
- if (size == 0) {
- size = GetDefFontSize();
- }
- ChkErr(FetchFontInfo, familyId, size, qdStyle, &fi);
- if (!familyName) {
- familyName = FamilyNameForFamilyID(familyId);
- }
-
- fontPtr->font.fid = (Font) fontPtr;
-
- faPtr = &fontPtr->font.fa;
- faPtr->family = familyName;
- faPtr->size = size;
- faPtr->weight = (qdStyle & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
- faPtr->slant = (qdStyle & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
- faPtr->underline = ((qdStyle & underline) != 0);
- faPtr->overstrike = 0;
-
- fmPtr = &fontPtr->font.fm;
-
- /*
- * Note: Macs measure the line height as ascent + descent +
- * leading. Leading as a separate entity does not exist in X11
- * and Tk. We add it to the ascent at the moment, because adding
- * it to the descent, as the Mac docs would indicate, would change
- * the position of self-drawn underlines.
- */
-
- fmPtr->ascent = fi.ascent + fi.leading;
- fmPtr->descent = fi.descent;
- fmPtr->maxWidth = fi.widMax;
-
- fontPtr->qdFont = familyId;
- fontPtr->qdSize = size;
- fontPtr->qdStyle = (short) qdStyle;
-
- InitATSUObjects(familyId, size, qdStyle, &fontPtr->atsuFontId,
- &fontPtr->atsuLayout, &fontPtr->atsuStyle);
-
- Tk_MeasureChars((Tk_Font)fontPtr, ".", 1, -1, 0, &periodWidth);
- Tk_MeasureChars((Tk_Font)fontPtr, "W", 1, -1, 0, &wWidth);
- fmPtr->fixed = periodWidth == wWidth;
-
- SetFontFeatures(fontPtr->atsuFontId, fmPtr->fixed, size,
- fontPtr->atsuStyle);
-
- AdjustFontHeight(fontPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitATSUObjects --
- *
- * Helper for InitFont(). Initializes the ATSU data handles for a
- * MacFont.
- *
- * Results:
- * Sets up all we know and can do at this point in time in fontIdPtr,
- * layoutPtr and stylePtr.
- *
- * Side effects:
- * Allocates data structures inside of ATSU.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitATSUObjects(
- FMFontFamily familyId, /* The font family to use. */
- short ptSize, short qdStyles,
- /* The additional font parameters. */
- ATSUFontID *fontIdPtr, /* Filled with the font id. */
- ATSUTextLayout *layoutPtr, /* Filled with the ATSU layout handle. */
- ATSUStyle *stylePtr) /* Filled with the ATSU style handle,
- * configured with all parameters. */
-{
- FMFontStyle stylesDone, stylesLeft;
-
- /*
- * Defaults in case of error.
- */
-
- *fontIdPtr = GetAppFont();
- *stylePtr = 0;
- *layoutPtr = 0;
-
- /*
- * Generate a font id from family id and QD style bits.
- */
-
- ChkErr(FMGetFontFromFontFamilyInstance, familyId, qdStyles, fontIdPtr,
- &stylesDone);
-
- /*
- * We see what style bits are left and tell ATSU to synthesize what's
- * left like QD does it.
- */
-
- stylesLeft = qdStyles & ~(unsigned)stylesDone;
-
- /*
- * Create the style and set its attributes.
- */
-
- ChkErr(ATSUCreateStyle, stylePtr);
- InitATSUStyle(*fontIdPtr, ptSize, stylesLeft, *stylePtr);
-
- /*
- * Create the layout. Note: We can't set the layout attributes here,
- * because the text and the style must be set first.
- */
-
- ChkErr(ATSUCreateTextLayout, layoutPtr);
- /*InitATSULayout(*layoutPtr);*/
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitATSUStyle --
- *
- * Helper for InitATSUObjects(). Initializes the ATSU style for a
- * MacFont.
- *
- * Results:
- * Sets up all parameters needed for an ATSU style.
- *
- * Side effects:
- * Allocates data structures for the style inside of ATSU.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitATSUStyle(
- ATSUFontID fontId, /* The font id to use. */
- short ptSize, short qdStyles,
- /* Additional font parameters. */
- ATSUStyle style) /* The style handle to configure. */
-{
- /*
- * Attributes for the style.
- */
-
- Fixed fsize = IntToFixed(ptSize);
- Boolean
- isBold = (qdStyles&bold) != 0,
- isUnderline = (qdStyles&underline) != 0,
- isItalic = (qdStyles&italic) != 0;
-
- ATSStyleRenderingOptions options =
- antialiasedTextEnabled == -1 ? kATSStyleNoOptions :
- antialiasedTextEnabled == 0 ? kATSStyleNoAntiAliasing :
- kATSStyleApplyAntiAliasing;
- static const ATSUAttributeTag styleTags[] = {
- kATSUFontTag, kATSUSizeTag,
- kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag,
- kATSUStyleRenderingOptionsTag,
- };
- static const ByteCount styleSizes[] = {
- sizeof(ATSUFontID), sizeof(Fixed),
- sizeof(Boolean), sizeof(Boolean), sizeof(Boolean),
- sizeof(ATSStyleRenderingOptions),
- };
- const ATSUAttributeValuePtr styleValues[] = {
- &fontId, &fsize,
- &isBold, &isItalic, &isUnderline,
- &options,
- };
-
- ChkErr(ATSUSetAttributes, style, sizeof(styleTags)/sizeof(styleTags[0]),
- styleTags, styleSizes, styleValues);
-}
+#pragma mark -
+#pragma mark Accessors:
/*
*---------------------------------------------------------------------------
*
- * SetFontFeatures --
+ * TkMacOSXNSFontForFont --
*
- * Helper for InitFont(). Request specific font features of the ATSU
- * style object for a MacFont.
+ * Return an NSFont for the given Tk_Font.
*
* Results:
- * None.
+ * NSFont*.
*
* Side effects:
- * Specific font features are enabled on the ATSU style object.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-SetFontFeatures(
- ATSUFontID fontId, /* The font id to use. */
- int fixed, /* Is this a fixed font? */
- short size, /* Size of the font */
- ATSUStyle style) /* The style handle to configure. */
-{
- /*
- * Don't use the standard latin ligatures, if this is determined to be a
- * fixed-width font.
- */
-
- static const ATSUFontFeatureType fixed_featureTypes[] = {
- kLigaturesType, kLigaturesType
- };
- static const ATSUFontFeatureSelector fixed_featureSelectors[] = {
- kCommonLigaturesOffSelector, kRareLigaturesOffSelector
- };
-
- if (fixed) {
- ChkErr(ATSUSetFontFeatures, style, sizeof(fixed_featureTypes) /
- sizeof(fixed_featureTypes[0]), fixed_featureTypes,
- fixed_featureSelectors);
- if (size <= 10) {
- /*
- * Disable antialiasing of fixed-width fonts with sizes <= 10
- */
-
- const ATSStyleRenderingOptions options = kATSStyleNoAntiAliasing;
- const ATSUAttributeTag styleTag = kATSUStyleRenderingOptionsTag;
- const ByteCount styleSize = sizeof(ATSStyleRenderingOptions);
- const ConstATSUAttributeValuePtr styleValue = &options;
-
- ChkErr(ATSUSetAttributes, style, 1, &styleTag, &styleSize,
- (ATSUAttributeValuePtr*) &styleValue);
- }
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * AdjustFontHeight --
- *
- * Helper for InitFont(). Check font height against some real world
- * examples.
- *
- * Results:
* None.
*
- * Side effects:
- * The metrics in fontPtr->font.fm are adjusted so that typical combined
- * characters fit into ascent+descent.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-AdjustFontHeight(
- MacFont * fontPtr)
-{
- /*
- * The standard values for ascent, descent and leading as determined in
- * InitFont do not take composition into account, they are designed for
- * plain ASCII characters. This code measures the actual size of some
- * typical composed characters from the Latin-1 range and corrects these
- * factors, especially the ascent.
- *
- * A font requested with a pixel size may thus have a larger line height
- * than requested.
- *
- * An alternative would be to instruct ATSU to shrink oversized combined
- * characters. I think I have seen that feature somewhere, but I can't
- * find it now [BR].
- */
-
- static const UniChar chars[]
- /* Auml, Aacute, Acirc, Atilde, Ccedilla */
- = {0x00C4, 0x00C1, 0x00C2, 0x00C3, 0x00C7};
- static const int charslen = sizeof(chars) / sizeof(chars[0]);
- Rect size;
- OSStatus err;
-
- LayoutSetString(fontPtr, NULL, chars, charslen);
-
- size.top = size.bottom = 0;
- err = ChkErr(ATSUMeasureTextImage, fontPtr->atsuLayout, 0, charslen, 0, 0,
- &size);
-
- if (err == noErr) {
- TkFontMetrics * fmPtr = &fontPtr->font.fm;
- int ascent = -size.top;
- int descent = size.bottom;
-
- if (ascent > fmPtr->ascent) {
- fmPtr->ascent = ascent;
- }
- if (descent > fmPtr->descent) {
- fmPtr->descent = descent;
- }
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitATSULayout --
- *
- * Helper for LayoutSetString(). Initializes the ATSU layout
- * object for a MacFont and a specific string.
- *
- * Results:
- * Sets up all parameters needed for an ATSU layout object.
- *
- * Side effects:
- * Allocates data structures for the layout object inside of ATSU.
- *
- * Assumptions:
- * The actual string data and style information is already set by
- * ATSUSetTextPointerLocation() and ATSUSetRunStyle() (see
- * LayoutSetString()).
- *
*---------------------------------------------------------------------------
*/
-static void
-InitATSULayout(
- const TkMacOSXDrawingContext *drawingContextPtr,
- /* Specifies the CGContext to use. */
- ATSUTextLayout layout, /* The layout object to configure. */
- int fixed) /* Is this a fixed font? */
+MODULE_SCOPE NSFont*
+TkMacOSXNSFontForFont(
+ Tk_Font tkfont)
{
- /*
- * Attributes for the layout.
- */
-
- ATSLineLayoutOptions layoutOptions = 0
-#if TK_MAC_COALESCE_LINE
- /*
- * Options to use unconditionally when we try to do coalescing.
- */
- | kATSLineDisableAllLayoutOperations
- | kATSLineFractDisable
- | kATSLineUseDeviceMetrics
-#endif
- ;
- CGContextRef context = drawingContextPtr ?
- drawingContextPtr->context : NULL;
-
- static const ATSUAttributeTag layoutTags[] = {
- kATSUCGContextTag,
- kATSULineLayoutOptionsTag,
- };
- static const ByteCount layoutSizes[] = {
- sizeof(CGContextRef),
- sizeof(ATSLineLayoutOptions),
- };
- const ATSUAttributeValuePtr layoutValues[] = {
- &context,
- &layoutOptions,
- };
-
- /*
- * Ensure W(abcdefg) == W(a)*7 for fixed fonts (Latin scripts only).
- */
-
- if (fixed) {
- layoutOptions |= kATSLineFractDisable | kATSLineUseDeviceMetrics;
- }
-
- ChkErr(ATSUSetLayoutControls, layout, sizeof(layoutTags) /
- sizeof(layoutTags[0]), layoutTags, layoutSizes, layoutValues);
- ChkErr(ATSUSetTransientFontMatching, layout, true);
+ return tkfont ? ((MacFont *)tkfont)->nsFont : nil;
}
/*
*---------------------------------------------------------------------------
*
- * LayoutSetString --
+ * TkMacOSXNSFontAttributesForFont --
*
- * Setup the MacFont for a specific string.
+ * Return an NSDictionary of font attributes for the given Tk_Font.
*
* Results:
- * Sets up all parameters so that ATSU can work with the objects in
- * MacFont.
+ * NSFont*.
*
* Side effects:
- * Sets parameters on the layout object fontPtr->atsuLayout.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-LayoutSetString(
- const MacFont *fontPtr, /* The fontPtr to configure. */
- const TkMacOSXDrawingContext *drawingContextPtr,
- /* For the CGContext to be used.*/
- const UniChar *uchars, int ulen)
- /* The UniChar string to set into
- * fontPtr->atsuLayout. */
-{
- ChkErr(ATSUSetTextPointerLocation, fontPtr->atsuLayout, uchars,
- kATSUFromTextBeginning, ulen, ulen);
-
- /*
- * Styles can only be set after the text is set.
- */
-
- ChkErr(ATSUSetRunStyle, fontPtr->atsuLayout, fontPtr->atsuStyle,
- kATSUFromTextBeginning, kATSUToTextEnd);
-
- /*
- * Layout attributes can only be set after the styles are set.
- */
-
- InitATSULayout(drawingContextPtr, fontPtr->atsuLayout,
- fontPtr->font.fm.fixed);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * ReleaseFont --
- *
- * Called to release the Macintosh-specific contents of a TkFont. The
- * caller is responsible for freeing the memory used by the font
- * itself.
- *
- * Results:
* None.
*
- * Side effects:
- * Memory is freed.
- *
*---------------------------------------------------------------------------
*/
-static void
-ReleaseFont(
- MacFont *fontPtr) /* The font to delete. */
-{
- ATSUDisposeTextLayout(fontPtr->atsuLayout);
- ATSUDisposeStyle(fontPtr->atsuStyle);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FindFontFamilyOrAlias, FindFontFamilyOrAliasOrFallback --
- *
- * Determine if any physical screen font exists on the system with the
- * given family name. If the family exists, then it should be possible
- * to construct some physical screen font with that family name.
- *
- * FindFontFamilyOrAlias also considers font aliases as determined by
- * TkFontGetAliasList().
- *
- * FindFontFamilyOrAliasOrFallback also considers font aliases as
- * determined by TkFontGetFallbacks().
- *
- * The overall algorithm to get the closest font to the one requested is
- * this:
- *
- * try fontname
- * try all aliases for fontname
- * foreach fallback for fontname
- * try the fallback
- * try all aliases for the fallback
- *
- * Results:
- *
- * The return value is NULL if the specified font family does not exist,
- * a valid MacFontFamily* otherwise.
- *
- * Side effects:
- *
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static const MacFontFamily *
-FindFontFamilyOrAlias(
- const char *name) /* Name or alias name of the font to find. */
-{
- const MacFontFamily * familyPtr;
- const char *const * aliases;
- int i;
-
- familyPtr = FindFontFamily(name);
- if (familyPtr != NULL) {
- return familyPtr;
- }
-
- aliases = TkFontGetAliasList(name);
- if (aliases != NULL) {
- for (i = 0; aliases[i] != NULL; i++) {
- familyPtr = FindFontFamily(aliases[i]);
- if (familyPtr != NULL) {
- return familyPtr;
- }
- }
- }
- return NULL;
-}
-
-static const MacFontFamily *
-FindFontFamilyOrAliasOrFallback(
- const char *name) /* Name or alias name of the font to find. */
-{
- const MacFontFamily * familyPtr;
- const char * fallback;
- const char *const *const * fallbacks;
- int i, j;
-
- familyPtr = FindFontFamilyOrAlias(name);
- if (familyPtr != NULL) {
- return familyPtr;
- }
- fallbacks = TkFontGetFallbacks();
- for (i = 0; fallbacks[i] != NULL; i++) {
- for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
- if (strcasecmp(name, fallback) == 0) {
- for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
- familyPtr = FindFontFamilyOrAlias(fallback);
- if (familyPtr != NULL) {
- return familyPtr;
- }
- }
- }
- break; /* benny: This "break" is a carry-over from
- * tkMacOSXFont.c, but what is actually its purpose
- * ???? */
- }
- }
-
-
- /*
- * FIXME: We would have liked to recover by re-enumerating fonts. But
- * that doesn't work, because Carbon seems to cache the inital list of
- * fonts. Fonts newly installed don't show up with
- * FMCreateFontFamilyIterator()/FMGetNextFontFamily() without a restart
- * of the app. Similar problem with fonts removed.
- */
-
-#ifdef TK_MAC_DEBUG_FONTS
- TkMacOSXDbgMsg("Font family '%s' not found", name);
-#endif
-
- return NULL;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * InitFontFamilies --
- *
- * Helper to TkpFontPkgInit. Use the Font Manager to fill in the
- * familyList global array.
- *
- * Results:
- *
- * None.
- *
- * Side effects:
- *
- * Allocates memory.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-InitFontFamilies(void)
+MODULE_SCOPE NSDictionary*
+TkMacOSXNSFontAttributesForFont(
+ Tk_Font tkfont)
{
- FMFontFamily fontFamily;
- Str255 fontName;
- SInt16 fontSize;
- Style fontStyle;
-
- /*
- * Has this been called before?
- */
-
- if (familyListNextFree > 0) {
- return;
- }
-
- ChkErr(ATSFontFamilyApplyFunction, FontFamilyEnumCallback,NULL);
-
- if (GetThemeFontAndFamily(kThemeSystemFont, &fontFamily, fontName,
- &fontSize, &fontStyle) == noErr) {
- AddFontFamily(SYSTEMFONT_NAME, fontFamily);
- }
- if (GetThemeFontAndFamily(kThemeApplicationFont, &fontFamily, fontName,
- &fontSize, &fontStyle) == noErr) {
- AddFontFamily(APPLFONT_NAME, fontFamily);
- }
- if (GetThemeFontAndFamily(kThemeMenuItemFont, &fontFamily, fontName,
- &fontSize, &fontStyle) == noErr) {
- AddFontFamily(MENUITEMFONT_NAME, fontFamily);
- }
-
- SortFontFamilies();
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FontFamilyEnumCallback --
- *
- * Callback for ATSFontFamilyApplyFunction().
- *
- * Results:
- *
- * noErr.
- *
- * Side effects:
- *
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static OSStatus
-FontFamilyEnumCallback(
- ATSFontFamilyRef family,
- void *refCon)
-{
- OSStatus err;
- char name[260] = "";
-
- (void) refCon;
-
- err = ChkErr(GetFontFamilyName, family, name, sizeof(name));
- if (err == noErr) {
- AddFontFamily(name, family);
- }
-
- return noErr;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * GetFontFamilyName --
- *
- * Use the Font Manager to get the name of a given FMFontfamily. This
- * currently gets the standard, non-localized QuickDraw name. Other
- * names would be possible, see docs for ATSUFindFontName for a
- * selection. The MacOSX font selector seems to use the localized
- * family name given by ATSUFindFontName(kFontFamilyName), but that API
- * doesn't give us a name at all for some fonts.
- *
- * Results:
- * An OS error code, noErr on success. name is filled with the
- * resulting name.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static OSStatus
-GetFontFamilyName(
- FMFontFamily fontFamily, /* The font family for which to find the
- * name. */
- char * name, int numBytes) /* Filled with the result. */
-{
- OSStatus err;
- Str255 nativeName;
- CFStringRef cfString;
- TextEncoding encoding;
- ScriptCode nameencoding;
-
- nativeName[0] = 0;
- name[0] = 0;
- err = ChkErr(FMGetFontFamilyName, fontFamily, nativeName);
- if (err != noErr) {
- return err;
- }
-
- /*
- * QuickDraw font names are encoded with the script that the font uses.
- * So we determine that encoding and than we reencode the name. We
- * pre-set the encoding with the default value, so we do not need to
- * check result codes here.
- */
-
- encoding = kTextEncodingMacRoman;
- ChkErr(FMGetFontFamilyTextEncoding, fontFamily, &encoding);
- nameencoding = encoding;
- ChkErr(RevertTextEncodingToScriptInfo, encoding, &nameencoding, NULL,
- NULL);
-
- /*
- * Note: We could use Tcl facilities to do the re-encoding here. We'd
- * have to maintain tables to map OS encoding codes to Tcl encoding names
- * like tkMacOSXFont.c did. Using native re-encoding directly instead is
- * a lot easier and future-proof than that. There is one snag, though: I
- * have seen CFStringGetCString() crash with invalid encoding ids. But
- * than if that happens it would be a bug in
- * FMGetFontFamilyTextEncoding() or RevertTextEncodingToScriptInfo().
- * Another problem is that users have seen CFStringCreate return null
- * (Bug #2548661). This is due to font names with a bad encoding.
- */
-
- cfString = CFStringCreateWithPascalStringNoCopy(
- NULL, nativeName, nameencoding, kCFAllocatorNull);
- if (cfString == NULL) {
- TkMacOSXDbgMsg("CFStringCreate: "
- "'%.*s' could not be decoded with encoding %d",
- nativeName[0], nativeName+1, (int) nameencoding);
- return kTextMalformedInputErr;
- }
-
- CFStringGetCString(cfString, name, numBytes, kCFStringEncodingUTF8);
- CFRelease(cfString);
-
- return noErr;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FindFontFamily --
- *
- * Find the font family with the given name in the global familyList.
- * Uses bsearch() for convenient access. Comparision is done
- * non-case-sensitively with CompareFontFamilies() which see.
- *
- * Results:
- *
- * MacFontFamily: A pair of family id and the actual name registered for
- * the font.
- *
- * Side effects:
- *
- * None.
- *
- * Assumption:
- *
- * Requires the familyList array to be sorted.
- *
- *-------------------------------------------------------------------------
- */
-
-static const MacFontFamily *
-FindFontFamily(
- const char *name) /* The family name. Note: Names are compared
- * non-case-sensitive. */
-{
- const MacFontFamily key = {name,-1};
-
- if(familyListMaxValid <= 0) {
- return NULL;
- }
-
- return bsearch(&key, familyList, familyListMaxValid, sizeof(*familyList),
- CompareFontFamilies);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * EnumFontFamilies --
- *
- * Create a Tcl list with the registered names in the global familyList.
- *
- * Results:
- * A Tcl list of names.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static Tcl_Obj *
-EnumFontFamilies(void)
-{
- int i;
- Tcl_Obj * tclList;
-
- tclList = Tcl_NewListObj(0, NULL);
- for (i=0; i<familyListMaxValid; ++i) {
- Tcl_ListObjAppendElement(NULL, tclList,
- Tcl_NewStringObj(familyList[i].name, -1));
- }
-
- return tclList;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * AddFontFamily --
- *
- * Register a font family in familyList. Until SortFontFamilies() is
- * called, this is not actually available for FindFontFamily().
- *
- * Results:
- *
- * MacFontFamily: The new pair of family id and the actual name
- * registered for the font.
- *
- * Side effects:
- *
- * New entry in familyList and familyListNextFree updated.
- *
- *-------------------------------------------------------------------------
- */
-
-static const MacFontFamily *
-AddFontFamily(
- const char *name, /* Font family name to register. */
- FMFontFamily familyId) /* Font family id to register. */
-{
- MacFontFamily * familyPtr;
-
- if (familyListNextFree >= familyListSize) {
- familyListSize += 100;
- familyList = (MacFontFamily *) ckrealloc((void*) familyList,
- familyListSize * sizeof(*familyList));
- }
-
- familyPtr = familyList + familyListNextFree;
- ++familyListNextFree;
-
- familyPtr->name = AddString(name);
- familyPtr->familyId = familyId;
-
- return familyPtr;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * SortFontFamilies --
- *
- * Sort the entries in familyList. Only after calling
- * SortFontFamilies(), the new families registered with AddFontFamily()
- * are actually available for FindFontFamily(), because FindFontFamily()
- * requires the array to be sorted.
- *
- * Results:
- *
- * None.
- *
- * Side effects:
- *
- * familyList is sorted and familyListMaxValid is updated.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-SortFontFamilies(void)
-{
- if (familyListNextFree > 0) {
- qsort(familyList, familyListNextFree, sizeof(*familyList),
- CompareFontFamilies);
- }
- familyListMaxValid = familyListNextFree;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * CompareFontFamilies --
- *
- * Comparison function used by SortFontFamilies() and FindFontFamily().
- *
- * Results:
- * Result as required to generate a stable sort order for bsearch() and
- * qsort(). The ordering is not case-sensitive as far as
- * Tcl_UtfNcasecmp() (which see) can provide that.
- *
- * Note: It would be faster to compare first the length and the actual
- * strings only as a tie-breaker, but than the ordering wouldn't look so
- * pretty in [font families] ;-).
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-CompareFontFamilies(
- const void * vp1,
- const void * vp2)
-{
- const char * name1;
- const char * name2;
- int len1, len2, diff;
-
- name1 = ((const MacFontFamily *) vp1)->name;
- name2 = ((const MacFontFamily *) vp2)->name;
-
- len1 = Tcl_NumUtfChars(name1, -1);
- len2 = Tcl_NumUtfChars(name2, -1);
-
- diff = Tcl_UtfNcasecmp(name1, name2, len1<len2 ? len1 : len2);
-
- return diff == 0 ? len1-len2 : diff;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * AddString --
- *
- * Helper for AddFontFamily(). Allocates a string in the one-shot
- * allocator.
- *
- * Results:
- * A duplicated string in the one-shot allocator.
- *
- * Side effects:
- * May allocate a new memory block.
- *
- *-------------------------------------------------------------------------
- */
-
-static const char *
-AddString(
- const char *in) /* String to add, zero-terminated. */
-{
- int len;
- char *result;
-
- len = strlen(in) +1;
-
- if (stringMemory == NULL
- || (stringMemory->nextFree+len) > STRING_BLOCK_MAX) {
- StringBlock * newblock = (StringBlock *) ckalloc(sizeof(StringBlock));
-
- newblock->next = stringMemory;
- newblock->nextFree = 0;
- stringMemory = newblock;
- }
-
- result = stringMemory->strings + stringMemory->nextFree;
- stringMemory->nextFree += len;
-
- memcpy(result, in, len);
-
- return result;
+ return tkfont ? ((MacFont *)tkfont)->nsAttributes : nil;
}
/*
@@ -2479,97 +1172,15 @@ TkMacOSXIsCharacterMissing(
Tk_Font tkfont, /* The font we are looking in. */
unsigned int searchChar) /* The character we are looking for. */
{
- /* Background: This function is private and only used in
- * tkMacOSXMenu.c:FindMarkCharacter().
- *
- * We could use ATSUMatchFont() to implement. We'd have to change the
- * definition of the encoding of the parameter searchChar from MacRoman
- * to UniChar for that.
- *
- * The system uses font fallback for controls, so we don't really need
- * this. */
-
return 0;
}
/*
*----------------------------------------------------------------------
*
- * TkMacOSXInitControlFontStyle --
- *
- * This procedure sets up the appropriate ControlFontStyleRec
- * for a Mac control.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkMacOSXInitControlFontStyle(
- Tk_Font tkfont, /* Tk font object to use for the control. */
- ControlFontStylePtr fsPtr) /* The style object to configure. */
-{
- const MacFont * fontPtr = (MacFont *) tkfont;
-
- fsPtr->flags = kControlUseFontMask | kControlUseSizeMask |
- kControlUseFaceMask | kControlUseJustMask;
- fsPtr->font = fontPtr->qdFont;
- fsPtr->size = fontPtr->qdSize;
- fsPtr->style = fontPtr->qdStyle;
- fsPtr->just = teCenter;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXFMFontInfoForFont --
- *
- * Retrieve FontManager/ATSUI font information for a Tk font.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-MODULE_SCOPE void
-TkMacOSXFMFontInfoForFont(
- Tk_Font tkfont,
- FMFontFamily *fontFamilyPtr,
- FMFontStyle *fontStylePtr,
- FMFontSize *fontSizePtr,
- ATSUStyle *fontATSUStylePtr)
-{
- const MacFont * fontPtr = (MacFont *) tkfont;
-
- if (fontFamilyPtr) {
- *fontFamilyPtr = fontPtr->qdFont;
- }
- if (fontStylePtr) {
- *fontStylePtr = fontPtr->qdStyle;
- }
- if (fontSizePtr) {
- *fontSizePtr = fontPtr->qdSize;
- }
- if (fontATSUStylePtr) {
- *fontATSUStylePtr = fontPtr->atsuStyle;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXFontDescriptionForFMFontInfo --
+ * TkMacOSXFontDescriptionForNSFontAndNSFontAttributes --
*
- * Get text description of a font specified by FontManager info.
+ * Get text description of a font specified by NSFont and attributes.
*
* Results:
* List object or NULL.
@@ -2581,42 +1192,37 @@ TkMacOSXFMFontInfoForFont(
*/
MODULE_SCOPE Tcl_Obj *
-TkMacOSXFontDescriptionForFMFontInfo(
- FMFontFamily fontFamily,
- FMFontStyle fontStyle,
- FMFontSize fontSize,
- FMFont fontID)
+TkMacOSXFontDescriptionForNSFontAndNSFontAttributes(
+ NSFont *nsFont,
+ NSDictionary *nsAttributes)
{
Tcl_Obj *objv[6];
int i = 0;
-
- if (fontFamily != kInvalidFontFamily && fontStyle != -1) {
- const char *familyName = FamilyNameForFamilyID(fontFamily);
-
- if (familyName) {
- objv[i++] = Tcl_NewStringObj(familyName, -1);
- objv[i++] = Tcl_NewIntObj(fontSize);
+ const char *familyName = [[nsFont familyName] UTF8String];
+
+ if (nsFont && familyName) {
+ NSFontTraitMask traits = [[NSFontManager sharedFontManager]
+ traitsOfFont:nsFont];
+ id underline = [nsAttributes objectForKey:
+ NSUnderlineStyleAttributeName];
+ id strikethrough = [nsAttributes objectForKey:
+ NSStrikethroughStyleAttributeName];
+ objv[i++] = Tcl_NewStringObj(familyName, -1);
+ objv[i++] = Tcl_NewIntObj([nsFont pointSize]);
#define S(s) Tcl_NewStringObj(STRINGIFY(s),(int)(sizeof(STRINGIFY(s))-1))
- objv[i++] = (fontStyle & bold) ? S(bold) : S(normal);
- objv[i++] = (fontStyle & italic) ? S(italic) : S(roman);
- if (fontStyle & underline) objv[i++] = S(underline);
- /*if (fontStyle & overstrike) objv[i++] = S(overstrike);*/
-#undef S
+ objv[i++] = (traits & NSBoldFontMask) ? S(bold) : S(normal);
+ objv[i++] = (traits & NSItalicFontMask) ? S(italic) : S(roman);
+ if ([underline respondsToSelector:@selector(intValue)] &&
+ ([underline intValue] & (NSUnderlineStyleSingle |
+ NSUnderlineStyleThick | NSUnderlineStyleDouble))) {
+ objv[i++] = S(underline);
}
- } else if (fontID != kInvalidFont) {
- CFStringRef fontName = NULL;
- Tcl_Obj *fontNameObj = NULL;
-
- ChkErr(ATSFontGetName, FMGetATSFontRefFromFont(fontID),
- kATSOptionFlagsDefault, &fontName);
- if (fontName) {
- fontNameObj = TkMacOSXGetStringObjFromCFString(fontName);
- CFRelease(fontName);
- }
- if (fontNameObj) {
- objv[i++] = fontNameObj;
- objv[i++] = Tcl_NewIntObj(fontSize);
+ if ([strikethrough respondsToSelector:@selector(intValue)] &&
+ ([strikethrough intValue] & (NSUnderlineStyleSingle |
+ NSUnderlineStyleThick | NSUnderlineStyleDouble))) {
+ objv[i++] = S(overstrike);
}
+#undef S
}
return i ? Tcl_NewListObj(i, objv) : NULL;
}