diff options
Diffstat (limited to 'macosx/tkMacOSXFont.c')
-rw-r--r-- | macosx/tkMacOSXFont.c | 2412 |
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(¤tLine); -#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(¤tLine); - ulen = Tcl_DStringLength(¤tLine) / 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(¤tLine); - Tcl_DStringInit(¤tLine); - currentY = y; - currentLeft = x; - currentFontPtr = fontPtr; - *offset = 0; - } else { - *offset = Tcl_DStringLength(¤tLine) / 2; - } - - Tcl_UtfToUniCharDString(source, numBytes, ¤tLine); - uchars = (const Tcl_UniChar*) Tcl_DStringValue(¤tLine); - ulen = Tcl_DStringLength(¤tLine) / 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; } |