summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXFont.c')
-rw-r--r--macosx/tkMacOSXFont.c3063
1 files changed, 1669 insertions, 1394 deletions
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c
index b09e62e..1cf8951 100644
--- a/macosx/tkMacOSXFont.c
+++ b/macosx/tkMacOSXFont.c
@@ -2,261 +2,264 @@
* tkMacOSXFont.c --
*
* Contains the Macintosh implementation of the platform-independant
- * font package interface.
+ * font package interface. This version uses ATSU instead of Quickdraw.
+ *
+ * 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-2007 Daniel A. Steffen <das@users.sourceforge.net>
*
* 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).
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXFont.h"
-#include "tclInt.h" /* for Tcl_CreateNamespace() */
-
/*
- * Dealing with pascal strings.
- */
-
-#ifndef StrLength
-#define StrLength(s) (*((unsigned char *) (s)))
-#endif
-#ifndef StrBody
-#define StrBody(s) ((char *) (s) + 1)
+#ifdef TK_MAC_DEBUG
+#define TK_MAC_DEBUG_FONTS
#endif
-#define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1)
-#define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1)
+*/
/*
- * The preferred font encodings.
+ * 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.
*/
-
-static const char *encodingList[] = {
- "macRoman", "macJapan", NULL
-};
+#define TK_MAC_COALESCE_LINE 0
/*
- * The following structures are used to map the script/language codes of a
- * font to the name that should be passed to Tcl_GetTextEncoding() to obtain
- * the encoding for that font. The set of numeric constants is fixed and
- * defined by Apple.
+ * The following structure represents our Macintosh-specific implementation
+ * of a font object.
*/
-static TkStateMap scriptMap[] = {
- {smRoman, "macRoman"},
- {smJapanese, "macJapan"},
- {smTradChinese, "macChinese"},
- {smKorean, "macKorean"},
- {smArabic, "macArabic"},
- {smHebrew, "macHebrew"},
- {smGreek, "macGreek"},
- {smCyrillic, "macCyrillic"},
- {smRSymbol, "macRSymbol"},
- {smDevanagari, "macDevanagari"},
- {smGurmukhi, "macGurmukhi"},
- {smGujarati, "macGujarati"},
- {smOriya, "macOriya"},
- {smBengali, "macBengali"},
- {smTamil, "macTamil"},
- {smTelugu, "macTelugu"},
- {smKannada, "macKannada"},
- {smMalayalam, "macMalayalam"},
- {smSinhalese, "macSinhalese"},
- {smBurmese, "macBurmese"},
- {smKhmer, "macKhmer"},
- {smThai, "macThailand"},
- {smLaotian, "macLaos"},
- {smGeorgian, "macGeorgia"},
- {smArmenian, "macArmenia"},
- {smSimpChinese, "macSimpChinese"},
- {smTibetan, "macTIbet"},
- {smMongolian, "macMongolia"},
- {smGeez, "macEthiopia"},
- {smEastEurRoman, "macCentEuro"},
- {smVietnamese, "macVietnam"},
- {smExtArabic, "macSindhi"},
- {0, NULL}
-};
+typedef struct {
+ TkFont font; /* Stuff used by generic font package. Must
+ * be first in structure. */
-static TkStateMap romanMap[] = {
- {langCroatian, "macCroatian"},
- {langSlovenian, "macCroatian"},
- {langIcelandic, "macIceland"},
- {langRomanian, "macRomania"},
- {langTurkish, "macTurkish"},
- {langGreek, "macGreek"},
- {0, NULL}
-};
+ /*
+ * The ATSU view of the font and other text properties. Used for drawing
+ * and measuring.
+ */
-static TkStateMap cyrillicMap[] = {
- {langUkrainian, "macUkraine"},
- {langBulgarian, "macBulgaria"},
- {0, NULL}
-};
+ 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. */
+} MacFont;
/*
- * The following structure represents a font family. It is assumed that
- * all screen fonts constructed from the same "font family" share certain
- * properties; all screen fonts with the same "font family" point to a
- * shared instance of this structure. The most important shared property
- * is the character existence metrics, used to determine if a screen font
- * can display a given Unicode character.
- *
- * Under Macintosh, a "font family" is uniquely identified by its face number.
+ * 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;
-#define FONTMAP_SHIFT 10
+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. */
-#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar) * 8 - FONTMAP_SHIFT))
-#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)
+/*
+ * 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.
+ */
-typedef struct FontFamily {
- struct FontFamily *nextPtr; /* Next in list of all known font families. */
- int refCount; /* How many SubFonts are referring to this
- * FontFamily. When the refCount drops to
- * zero, this FontFamily may be freed. */
- /*
- * Key.
- */
+#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;
- FMFontFamily faceNum; /* Unique face number key for this FontFamily. */
+/*
+ * The names for our "native" fonts.
+ */
- /*
- * Derived properties.
- */
+#define SYSTEMFONT_NAME "system"
+#define APPLFONT_NAME "application"
+#define MENUITEMFONT_NAME "menu"
+
+struct SystemFontMapEntry {
+ const ThemeFontID id;
+ const char *systemName;
+ const char *tkName;
+ const char *tkName1;
+};
- Tcl_Encoding encoding; /* Encoding for this font family. */
- int isSymbolFont; /* Non-zero if this is a symbol family. */
- int isMultiByteFont; /* Non-zero if this is a multi-byte family. */
- char typeTable[256]; /* Table that identfies all lead bytes for a
- * multi-byte family, used when measuring chars.
- * If a byte is a lead byte, the value at the
- * corresponding position in the typeTable is 1,
- * otherwise 0. If this is a single-byte font,
- * all entries are 0. */
- char *fontMap[FONTMAP_PAGES];
- /* Two-level sparse table used to determine
- * quickly if the specified character exists.
- * As characters are encountered, more pages
- * in this table are dynamically added. The
- * contents of each page is a bitmask
- * consisting of FONTMAP_BITSPERPAGE bits,
- * representing whether this font can be used
- * to display the given character at the
- * corresponding bit position. The high bits
- * of the character are used to pick which
- * page of the table is used. */
-} FontFamily;
+#define ThemeFont(n, ...) { kTheme##n##Font, "system" #n "Font", ##__VA_ARGS__ }
+static const struct SystemFontMapEntry systemFontMap[] = {
+ ThemeFont(System, "TkDefaultFont", "TkIconFont"),
+ ThemeFont(EmphasizedSystem, "TkCaptionFont"),
+ ThemeFont(SmallSystem, "TkHeadingFont", "TkTooltipFont"),
+ ThemeFont(SmallEmphasizedSystem),
+ ThemeFont(Application, "TkTextFont"),
+ ThemeFont(Label, "TkSmallCaptionFont"),
+ ThemeFont(Views),
+ ThemeFont(MenuTitle),
+ ThemeFont(MenuItem, "TkMenuFont"),
+ ThemeFont(MenuItemMark),
+ ThemeFont(MenuItemCmdKey),
+ ThemeFont(WindowTitle),
+ ThemeFont(PushButton),
+ ThemeFont(UtilityWindowTitle),
+ ThemeFont(AlertHeader),
+ ThemeFont(Toolbar),
+ ThemeFont(MiniSystem),
+ { kThemeSystemFontDetail, "systemDetailSystemFont" },
+ { kThemeSystemFontDetailEmphasized, "systemDetailEmphasizedSystemFont" },
+ { -1, NULL }
+};
+#undef ThemeFont
/*
- * The following structure encapsulates an individual screen font. A font
- * object is made up of however many SubFonts are necessary to display a
- * stream of multilingual characters.
+ * Procedures used only in this file.
*/
-typedef struct SubFont {
- char **fontMap; /* Pointer to font map from the FontFamily,
- * cached here to save a dereference. */
- FontFamily *familyPtr; /* The FontFamily for this SubFont. */
-} SubFont;
+static void LayoutSetString(const MacFont *fontPtr,
+ const TkMacOSXDrawingContext *drawingContextPtr,
+ const UniChar * uchars, int ulen);
/*
- * The following structure represents Macintosh's implementation of a font
- * object.
+ * The actual workers.
*/
-#define SUBFONT_SPACE 3
+static int MeasureStringWidth(const MacFont *fontPtr, int start, int end);
-typedef struct MacFont {
- TkFont font; /* Stuff used by generic font package. Must
- * be first in structure. */
- SubFont staticSubFonts[SUBFONT_SPACE];
- /* Builtin space for a limited number of
- * SubFonts. */
- int numSubFonts; /* Length of following array. */
- SubFont *subFontArray; /* Array of SubFonts that have been loaded
- * in order to draw/measure all the characters
- * encountered by this font so far. All fonts
- * start off with one SubFont initialized by
- * AllocFont() from the original set of font
- * attributes. Usually points to
- * staticSubFonts, but may point to malloced
- * space if there are lots of SubFonts. */
-
- short size; /* Font size in pixels, constructed from
- * font attributes. */
- short style; /* Style bits, constructed from font
- * attributes. */
-} MacFont;
+#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 */
/*
- * The following structure is used to map between the UTF-8 name for a font and
- * the name that the Macintosh uses to refer to the font, in order to determine
- * if a font exists. The Macintosh names for fonts are stored in the encoding
- * of the font itself.
+ * Initialization and setup of a font data structure.
*/
-typedef struct FontNameMap {
- Tk_Uid utfName; /* The name of the font in UTF-8. */
- StringPtr nativeName; /* The name of the font in the font's encoding. */
- FMFontFamily faceNum; /* Unique face number for this font. */
-} FontNameMap;
+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);
/*
- * The list of font families that are currently loaded. As screen fonts
- * are loaded, this list grows to hold information about what characters
- * exist in each font family.
+ * Finding fonts by name.
*/
-static FontFamily *fontFamilyList = NULL;
+static const MacFontFamily *FindFontFamilyOrAlias(const char *name);
+static const MacFontFamily *FindFontFamilyOrAliasOrFallback(const char *name);
/*
- * Information cached about the system at startup time.
+ * Doing interesting things with font families and fonts.
*/
-static FontNameMap *gFontNameMap = NULL;
-static GWorldPtr gWorld = NULL;
+static void InitFontFamilies(void);
+static OSStatus GetFontFamilyName(FMFontFamily fontFamily, char *name,
+ int numBytes);
/*
- * The names for our "native" fonts.
+ * Accessor functions and internal utilities for the font family list.
*/
-#define SYSTEMFONT_NAME "system"
-#define APPLFONT_NAME "application"
-#define MENUITEMFONT_NAME "menu"
+static const MacFontFamily *AddFontFamily(const char *name,
+ FMFontFamily familyId);
+static const MacFontFamily *FindFontFamily(const char *name);
+static Tcl_Obj *EnumFontFamilies(void);
-/*
- * Procedures used only in this file.
- */
+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 FontFamily * AllocFontFamily(const MacFont *fontPtr, int family);
-static SubFont * CanUseFallback(MacFont *fontPtr, const char *fallbackName, int ch, SubFont **fixSubFontPtrPtr);
-static SubFont * CanUseFallbackWithAliases(MacFont *fontPtr, const char *faceName, int ch, Tcl_DString *nameTriedPtr, SubFont **fixSubFontPtrPtr);
-static SubFont * FindSubFontForChar(MacFont *fontPtr, int ch, SubFont **fixSubFontPtrPtr);
-static void FontMapInsert(SubFont *subFontPtr, int ch);
-static void FontMapLoadPage(SubFont *subFontPtr, int row);
-static int FontMapLookup(SubFont *subFontPtr, int ch);
-static void FreeFontFamily(FontFamily *familyPtr);
-static void InitFont(Tk_Window tkwin, int family, unsigned char *familyName, int size, int style, MacFont *fontPtr);
-static void InitSubFont(const MacFont *fontPtr, int family, SubFont *subFontPtr);
-static void MultiFontDrawText(MacFont *fontPtr, const char *source, int numBytes, int x, int y);
-static void ReleaseFont(MacFont *fontPtr);
-static void ReleaseSubFont(SubFont *subFontPtr);
-static int SeenName(const char *name, Tcl_DString *dsPtr);
-
-static const char * BreakLine(FontFamily *familyPtr, int flags, const char *source, int numBytes, int *widthPtr);
-static int GetFamilyNum(const char *faceName, short *familyPtr);
-static int GetFamilyOrAliasNum(const char *faceName, short *familyPtr);
-static Tcl_Encoding GetFontEncoding(int faceNum, int allowSymbol, int *isSymbolPtr);
-static Tk_Uid GetUtfFaceName(StringPtr faceNameStr);
static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId,
FMFontFamily *fontFamily, unsigned char *fontName, SInt16 *fontSize,
Style *fontStyle);
+static void InitSystemFonts(TkMainInfo *mainPtr);
+static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin,
+ const char* name, TkFontAttributes *faPtr);
/*
@@ -272,7 +275,7 @@ static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId,
* None.
*
* Side effects:
- * See comments below.
+ * Initialization of variables local to this file.
*
*-------------------------------------------------------------------------
*/
@@ -281,107 +284,104 @@ void
TkpFontPkgInit(
TkMainInfo *mainPtr) /* The application being created. */
{
- FMFontFamilyIterator fontFamilyIterator;
- FMFontFamily fontFamily;
- FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr;
- int i, j, numFonts, fontMapOffset, isSymbol;
- Str255 nativeName;
- Tcl_DString ds;
- Tcl_Encoding encoding;
- Tcl_Encoding *encodings;
-
- if (gWorld == NULL) {
- Rect rect = {0, 0, 1, 1};
+ InitFontFamilies();
+ InitSystemFonts(mainPtr);
- SetFractEnable(0);
- /*
- * Used for saving and restoring state while drawing and measuring.
- */
- if (ChkErr(NewGWorld, &gWorld, 32, &rect, NULL, NULL, 0
-#ifdef __LITTLE_ENDIAN__
- | kNativeEndianPixMap
+#if TK_MAC_COALESCE_LINE
+ Tcl_DStringInit(&currentLine);
#endif
- ) != noErr) {
- Tcl_Panic("TkpFontPkgInit: NewGWorld failed");
- }
- /*
- * The name of each font is stored in the encoding of that font.
- * How would we translate a name from UTF-8 into the native encoding
- * of the font unless we knew the encoding of that font? We can't.
- * So, precompute the UTF-8 and native names of all fonts on the
- * system. The when the user asks for font by its UTF-8 name, we
- * lookup the name in that table and really ask for the font by its
- * native name. Any unknown UTF-8 names will be mapped to the system
- * font.
- */
- FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator);
- numFonts = 0;
- while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) {
- numFonts++;
- }
- tmpFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * numFonts);
- encodings = (Tcl_Encoding *) ckalloc(sizeof(Tcl_Encoding) * numFonts);
- mapPtr = tmpFontNameMap;
- FMResetFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator);
- i = 0;
- while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) {
- mapPtr->faceNum = fontFamily;
- encodings[i] = GetFontEncoding(mapPtr->faceNum, 0, &isSymbol);
- FMGetFontFamilyName(fontFamily, nativeName );
- Tcl_ExternalToUtfDString(encodings[i], StrBody(nativeName), StrLength(nativeName), &ds);
- mapPtr->utfName = Tk_GetUid(Tcl_DStringValue(&ds));
- mapPtr->nativeName = (StringPtr) ckalloc(StrLength(nativeName) + 1);
- memcpy(mapPtr->nativeName, nativeName, StrLength(nativeName) + 1);
- Tcl_DStringFree(&ds);
- mapPtr++;
- i++;
- }
- FMDisposeFontFamilyIterator(&fontFamilyIterator);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * InitSystemFonts --
+ *
+ * Initialize named system fonts.
+ *
+ * Results:
+ *
+ * None.
+ *
+ * Side effects:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
- /*
- * Reorder FontNameMap so fonts with the preferred encodings are at
- * the front of the list. The relative order of fonts that all have
- * the same encoding is preserved. Fonts with unknown encodings get
- * stuck at the end.
- */
- newFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * (numFonts + 1));
- fontMapOffset = 0;
- for (i = 0; encodingList[i] != NULL; i++) {
- encoding = Tcl_GetEncoding(NULL, encodingList[i]);
- if (encoding == NULL) {
- continue;
- }
- for (j = 0; j < numFonts; j++) {
- if (encodings[j] == encoding) {
- newFontNameMap[fontMapOffset] = tmpFontNameMap[j];
- fontMapOffset++;
- Tcl_FreeEncoding(encodings[j]);
- tmpFontNameMap[j].utfName = NULL;
- }
+static void
+InitSystemFonts(
+ TkMainInfo *mainPtr)
+{
+ Tcl_Interp *interp = mainPtr->interp;
+ Tk_Window tkwin = (Tk_Window) mainPtr->winPtr;
+ const struct SystemFontMapEntry *systemFont = systemFontMap;
+ TkFontAttributes fa;
+
+ /* force this for now */
+ if (!mainPtr->winPtr->mainPtr) {
+ mainPtr->winPtr->mainPtr = mainPtr;
+ }
+ 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);
}
- Tcl_FreeEncoding(encoding);
- }
- for (i = 0; i < numFonts; i++) {
- if (tmpFontNameMap[i].utfName != NULL) {
- newFontNameMap[fontMapOffset] = tmpFontNameMap[i];
- fontMapOffset++;
- Tcl_FreeEncoding(encodings[i]);
+ if (systemFont->tkName1) {
+ CreateNamedSystemFont(interp, tkwin, systemFont->tkName1, &fa);
}
}
- if (fontMapOffset != numFonts) {
- Tcl_Panic("TkpFontPkgInit: unexpected number of fonts");
- }
-
- mapPtr = &newFontNameMap[numFonts];
- mapPtr->utfName = NULL;
- mapPtr->nativeName = NULL;
- mapPtr->faceNum = 0;
-
- ckfree((char *) tmpFontNameMap);
- ckfree((char *) encodings);
-
- gFontNameMap = newFontNameMap;
+ systemFont++;
}
+ 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);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * CreateNamedSystemFont --
+ *
+ * Register a system font with the Tk named font mechanism.
+ *
+ * Results:
+ *
+ * Result from TkCreateNamedFont().
+ *
+ * Side effects:
+ *
+ * A new named font is added to the Tk font registry.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int
+CreateNamedSystemFont(
+ Tcl_Interp *interp,
+ Tk_Window tkwin,
+ const char* name,
+ TkFontAttributes *faPtr)
+{
+ TkDeleteNamedFont(NULL, tkwin, name);
+ return TkCreateNamedFont(interp, tkwin, name, faPtr);
}
/*
@@ -445,14 +445,14 @@ GetThemeFontAndFamily(
TkFont *
TkpGetNativeFont(
Tk_Window tkwin, /* For display where font will be used. */
- CONST char *name) /* Platform-specific font name. */
+ const char *name) /* Platform-specific font name. */
{
ThemeFontID themeFontId;
FMFontFamily fontFamily;
Str255 fontName;
SInt16 fontSize;
Style fontStyle;
- MacFont * fontPtr;
+ MacFont *fontPtr;
if (strcmp(name, SYSTEMFONT_NAME) == 0) {
themeFontId = kThemeSystemFont;
@@ -467,9 +467,10 @@ TkpGetNativeFont(
&fontStyle) != noErr) {
return NULL;
}
+ CopyPascalStringToC(fontName, (char*)fontName);
fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
- InitFont(tkwin, fontFamily, fontName, fontSize, fontStyle, fontPtr);
+ InitFont(fontFamily, (char*)fontName, fontSize, fontStyle, fontPtr);
return (TkFont *) fontPtr;
}
@@ -512,56 +513,35 @@ TkpGetFontFromAttributes(
* will be released. If NULL, a new TkFont
* structure is allocated. */
Tk_Window tkwin, /* For display where font will be used. */
- CONST TkFontAttributes *faPtr)
+ const TkFontAttributes *faPtr)
/* Set of attributes to match. */
{
- short faceNum, style;
- int i, j;
- const char *faceName, *fallback;
- char ***fallbacks;
+ short qdStyle;
+ FMFontFamily familyId;
+ const char *name;
+ const MacFontFamily *familyPtr;
MacFont *fontPtr;
- /*
- * Algorithm to get the closest font to the one requested.
- *
- * try fontname
- * try all aliases for fontname
- * foreach fallback for fontname
- * try the fallback
- * try all aliases for the fallback
- */
+ familyId = GetAppFont();
+ name = NULL;
+ qdStyle = 0;
- faceNum = 0;
- faceName = faPtr->family;
- if (faceName != NULL) {
- if (GetFamilyOrAliasNum(faceName, &faceNum) != 0) {
- goto found;
- }
- fallbacks = TkFontGetFallbacks();
- for (i = 0; fallbacks[i] != NULL; i++) {
- for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
- if (strcasecmp(faceName, fallback) == 0) {
- for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
- if (GetFamilyOrAliasNum(fallback, &faceNum)) {
- goto found;
- }
- }
- }
- break;
- }
+ if (faPtr->family != NULL) {
+ familyPtr = FindFontFamilyOrAliasOrFallback(faPtr->family);
+ if (familyPtr != NULL) {
+ name = familyPtr->name;
+ familyId = familyPtr->familyId;
}
}
-found:
- style = 0;
if (faPtr->weight != TK_FW_NORMAL) {
- style |= bold;
+ qdStyle |= bold;
}
if (faPtr->slant != TK_FS_ROMAN) {
- style |= italic;
+ qdStyle |= italic;
}
if (faPtr->underline) {
- style |= underline;
+ qdStyle |= underline;
}
if (tkFontPtr == NULL) {
fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
@@ -569,7 +549,8 @@ found:
fontPtr = (MacFont *) tkFontPtr;
ReleaseFont(fontPtr);
}
- InitFont(tkwin, faceNum, NULL, faPtr->size, style, fontPtr);
+ InitFont(familyId, name, TkFontGetPoints(tkwin, faPtr->size),
+ qdStyle, fontPtr);
return (TkFont *) fontPtr;
}
@@ -623,14 +604,7 @@ TkpGetFontFamilies(
Tcl_Interp *interp, /* Interp to hold result. */
Tk_Window tkwin) /* For display to query. */
{
- FontNameMap *mapPtr;
- Tcl_Obj *resultPtr, *strPtr;
-
- resultPtr = Tcl_GetObjResult(interp);
- for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
- strPtr = Tcl_NewStringObj(mapPtr->utfName, -1);
- Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
- }
+ Tcl_SetObjResult(interp, EnumFontFamilies());
}
/*
@@ -656,31 +630,168 @@ TkpGetSubFonts(
Tcl_Interp *interp, /* Interp to hold result. */
Tk_Font tkfont) /* Font object to query. */
{
- int i;
- Tcl_Obj *resultPtr, *strPtr;
- MacFont *fontPtr;
- FontFamily *familyPtr;
- Str255 nativeName;
+ /* 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. */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpGetFontAttrsForChar --
+ *
+ * Retrieve the font attributes of the actual font used to render a
+ * given character.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The font attributes are stored in *faPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpGetFontAttrsForChar(
+ Tk_Window tkwin, /* Window on the font's display */
+ Tk_Font tkfont, /* Font to query */
+ 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;
- resultPtr = Tcl_GetObjResult(interp);
- fontPtr = (MacFont *) tkfont;
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- familyPtr = fontPtr->subFontArray[i].familyPtr;
- GetFontName(familyPtr->faceNum, nativeName);
- strPtr = Tcl_NewStringObj(GetUtfFaceName(nativeName), -1);
- Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
+ /*
+ * Most of the attributes are just copied from the base font. This
+ * assumes that all fonts can have all attributes.
+ */
+
+ *faPtr = fontPtr->font.fa;
+
+ /*
+ * 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);
+ }
+ }
}
+
+ TkMacOSXRestoreDrawingContext(&drawingContext);
}
/*
*---------------------------------------------------------------------------
*
- * Tk_MeasureChars --
+ * Tk_MeasureChars --
+ *
+ * Determine the number of characters from the string that will fit in
+ * the given horizontal span. The measurement is done under the
+ * assumption that Tk_DrawChars() will be used to actually display the
+ * characters.
*
- * Determine the number of characters from the string that will fit
- * in the given horizontal span. The measurement is done under the
- * assumption that Tk_DrawChars() will be used to actually display
- * the characters.
+ * With ATSUI we need the line context to do this right, so we have the
+ * actual implementation in TkpMeasureCharsInContext().
+ *
+ * Results:
+ * The return value is the number of bytes from source that fit into the
+ * span that extends from 0 to maxLength. *lengthPtr is filled with the
+ * x-coordinate of the right edge of the last character that did fit.
+ *
+ * Side effects:
+ * None.
+ *
+ * Todo:
+ * Effects of the "flags" parameter are untested.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+Tk_MeasureChars(
+ Tk_Font tkfont, /* Font in which characters will be drawn. */
+ const char *source, /* UTF-8 string to be displayed. Need not be
+ * '\0' terminated. */
+ int numBytes, /* Maximum number of bytes to consider from
+ * source string. */
+ int maxLength, /* If >= 0, maxLength specifies the longest
+ * permissible line length; don't consider any
+ * character that would cross this x-position.
+ * If < 0, then line length is unbounded and
+ * the flags argument is ignored. */
+ int flags, /* Various flag bits OR-ed together:
+ * TK_PARTIAL_OK means include the last char
+ * which only partially fit on this line.
+ * TK_WHOLE_WORDS means stop on a word
+ * boundary, if possible. TK_AT_LEAST_ONE
+ * means return at least one character even if
+ * no characters fit. */
+ int *lengthPtr) /* Filled with x-location just after the
+ * terminating character. */
+{
+ return TkpMeasureCharsInContext(tkfont, source, numBytes, 0, numBytes,
+ maxLength, flags, lengthPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkpMeasureCharsInContext --
+ *
+ * Determine the number of bytes from the string that will fit in the
+ * given horizontal span. The measurement is done under the assumption
+ * that TkpDrawCharsInContext() will be used to actually display the
+ * characters.
+ *
+ * This one is almost the same as Tk_MeasureChars(), but with access to
+ * all the characters on the line for context.
*
* Results:
* The return value is the number of bytes from source that
@@ -695,150 +806,292 @@ TkpGetSubFonts(
*/
int
-Tk_MeasureChars(
+TkpMeasureCharsInContext(
Tk_Font tkfont, /* Font in which characters will be drawn. */
- CONST char *source, /* UTF-8 string to be displayed. Need not be
+ const char * source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. */
- int numBytes, /* Maximum number of bytes to consider
- * from source string. */
+ int numBytes, /* Maximum number of bytes to consider from
+ * source string in all. */
+ int rangeStart, /* Index of first byte to measure. */
+ int rangeLength, /* Length of range to measure in bytes. */
int maxLength, /* If >= 0, maxLength specifies the longest
* permissible line length; don't consider any
- * character that would cross this
- * x-position. If < 0, then line length is
- * unbounded and the flags argument is
- * ignored. */
+ * character that would cross this x-position.
+ * If < 0, then line length is unbounded and
+ * the flags argument is ignored. */
int flags, /* Various flag bits OR-ed together:
* TK_PARTIAL_OK means include the last char
- * which only partially fit on this line.
+ * which only partially fits on this line.
* TK_WHOLE_WORDS means stop on a word
- * boundary, if possible.
- * TK_AT_LEAST_ONE means return at least one
- * character even if no characters fit. */
+ * boundary, if possible. TK_AT_LEAST_ONE
+ * means return at least one character even
+ * if no characters fit. If TK_WHOLE_WORDS
+ * and TK_AT_LEAST_ONE are set and the first
+ * word doesn't fit, we return at least one
+ * character or whatever characters fit into
+ * maxLength. TK_ISOLATE_END means that the
+ * last character should not be considered in
+ * context with the rest of the string (used
+ * for breaking lines). */
int *lengthPtr) /* Filled with x-location just after the
* terminating character. */
{
- MacFont *fontPtr;
- SubFont *thisSubFontPtr, *lastSubFontPtr;
- CGrafPtr savePort;
- Boolean portChanged;
- int curX, curByte;
+ 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;
/*
- * According to "Inside Macintosh: Text", the Macintosh may
- * automatically substitute
- * ligatures or context-sensitive presentation forms when
- * measuring/displaying text within a font run. We cannot safely
- * measure individual characters and add up the widths w/o errors.
- * However, if we convert a range of text from UTF-8 to, say,
- * Shift-JIS, and get the offset into the Shift-JIS string as to
- * where a word or line break would occur, then can we map that
- * number back to UTF-8?
+ * Sanity checks.
*/
- fontPtr = (MacFont *) tkfont;
+ if (rangeStart < 0 || (rangeStart+rangeLength) > numBytes) {
+ TkMacOSXDbgMsg("Bad parameters");
+ *lengthPtr = 0;
+ return 0;
+ }
- portChanged = QDSwapPort(gWorld, &savePort);
+ /*
+ * Get simple no-brainers out of the way.
+ */
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
+ if (rangeLength == 0 || (maxLength == 0 && !(flags & TK_AT_LEAST_ONE))) {
+ *lengthPtr = 0;
+ return 0;
+ }
- lastSubFontPtr = &fontPtr->subFontArray[0];
+ Tcl_DStringInit(&ucharBuffer);
+ uchars = Tcl_UtfToUniCharDString(source, numBytes, &ucharBuffer);
+ ulen = Tcl_DStringLength(&ucharBuffer) / sizeof(Tcl_UniChar);
+ LayoutSetString(fontPtr, NULL, uchars, ulen);
- if (numBytes == 0) {
- curX = 0;
- curByte = 0;
- } else if (maxLength < 0) {
- const char *p, *end, *next;
- Tcl_UniChar ch;
- FontFamily *familyPtr;
- Tcl_DString runString;
+ urstart = Tcl_NumUtfChars(source, rangeStart);
+ urlen = Tcl_NumUtfChars(source+rangeStart,rangeLength);
+ urend = urstart + urlen;
+
+ if (maxLength < 0) {
+ curX = MeasureStringWidth(fontPtr, urstart, urend);
+ curByte = rangeLength;
+ } else {
+ UniCharArrayOffset offset = 0;
+ OSStatus err;
/*
- * A three step process:
- * 1. Find a contiguous range of characters that can all be
- * represented by a single screen font.
- * 2. Convert those chars to the encoding of that font.
- * 3. Measure converted chars.
+ * Have some upper limit on the size actually used.
*/
- curX = 0;
- end = source + numBytes;
- for (p = source; p < end; ) {
- next = p + Tcl_UtfToUniChar(p, &ch);
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
- if (thisSubFontPtr != lastSubFontPtr) {
- familyPtr = lastSubFontPtr->familyPtr;
- TextFont(familyPtr->faceNum);
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- p - source, &runString);
- curX += TextWidth(Tcl_DStringValue(&runString), 0,
- Tcl_DStringLength(&runString));
- Tcl_DStringFree(&runString);
- lastSubFontPtr = thisSubFontPtr;
- source = p;
+ 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--;
}
- p = next;
}
- familyPtr = lastSubFontPtr->familyPtr;
- TextFont(familyPtr->faceNum);
- Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
- &runString);
- curX += TextWidth(Tcl_DStringValue(&runString), 0,
- Tcl_DStringLength(&runString));
- Tcl_DStringFree(&runString);
- curByte = numBytes;
- } else {
- const char *p, *end, *next, *sourceOrig;
- int widthLeft;
- Tcl_UniChar ch;
- const char *rest = NULL;
/*
- * How many chars will fit in the space allotted?
+ * Fix up left-overs for the TK_WHOLE_WORDS case.
*/
- if (maxLength > 32767) {
- maxLength = 32767;
+ 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;
+ }
+ }
}
- widthLeft = maxLength;
- sourceOrig = source;
- end = source + numBytes;
- for (p = source; p < end; p = next) {
- next = p + Tcl_UtfToUniChar(p, &ch);
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
- if (thisSubFontPtr != lastSubFontPtr) {
- if (p > source) {
- rest = BreakLine(lastSubFontPtr->familyPtr, flags, source,
- p - source, &widthLeft);
- flags &= ~TK_AT_LEAST_ONE;
- if (rest != NULL) {
- p = source;
+ if (offset > urend) {
+ offset = urend;
+ }
+
+ /*
+ * 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;
}
}
- lastSubFontPtr = thisSubFontPtr;
- source = p;
+
+ /*
+ * 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;
}
- }
- if (p > source) {
- rest = BreakLine(lastSubFontPtr->familyPtr, flags, source, p - source,
- &widthLeft);
+ /*
+ * We have overshot one character, so backup one position.
+ */
+
+ curX = lastX;
+ offset = lastOffset;
}
- if (rest == NULL) {
- curByte = numBytes;
- } else {
- curByte = rest - sourceOrig;
+ if (curX < 0) {
+ if (flags & TK_ISOLATE_END) {
+ LayoutSetString(fontPtr, NULL, uchars, offset);
+ }
+ curX = MeasureStringWidth(fontPtr, urstart, offset);
}
- curX = maxLength - widthLeft;
- }
- if (portChanged) {
- QDSwapPort(savePort, NULL);
+ curByte = Tcl_UtfAtIndex(source, offset) - source;
+ curByte -= rangeStart;
}
+ Tcl_DStringFree(&ucharBuffer);
+
+#ifdef TK_MAC_DEBUG_FONTS
+ TkMacOSXDbgMsg("measure: '%.*s', maxLength=%d, flags=%s%s%s%s "
+ "-> width=%d, bytes=%d",
+ 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);
+#endif
+
*lengthPtr = curX;
return curByte;
}
@@ -846,151 +1099,51 @@ Tk_MeasureChars(
/*
*---------------------------------------------------------------------------
*
- * BreakLine --
+ * Tk_DrawChars --
+ *
+ * Draw a string of characters on the screen.
*
- * Determine where the given line of text should be broken so that it
- * fits in the specified range. Before calling this function, the
- * font values and graphics port must be set.
+ * With ATSUI we need the line context to do this right, so we have the
+ * actual implementation in TkpDrawCharsInContext().
*
* Results:
- * The return value is NULL if the specified range is larger that the
- * space the text needs, and *widthLeftPtr is filled with how much
- * space is left in the range after measuring the whole text buffer.
- * Otherwise, the return value is a pointer into the text buffer that
- * indicates where the line should be broken (up to, but not including
- * that character), and *widthLeftPtr is filled with how much space is
- * left in the range after measuring up to that character.
+ * None.
*
* Side effects:
- * None.
+ * Information gets drawn on the screen.
*
*---------------------------------------------------------------------------
*/
-static const char *
-BreakLine(
- FontFamily *familyPtr, /* FontFamily that describes the font values
- * that are already selected into the graphics
- * port. */
- int flags, /* Various flag bits OR-ed together:
- * TK_PARTIAL_OK means include the last char
- * which only partially fit on this line.
- * TK_WHOLE_WORDS means stop on a word
- * boundary, if possible.
- * TK_AT_LEAST_ONE means return at least one
- * character even if no characters fit. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. */
- int numBytes, /* Maximum number of bytes to consider
- * from source string. */
- int *widthLeftPtr) /* On input, specifies size of range into
- * which characters from source buffer should
- * be fit. On output, filled with how much
- * space is left after fitting as many
- * characters as possible into the range.
- * Result may be negative if TK_AT_LEAST_ONE
- * was specified in the flags argument. */
+void
+Tk_DrawChars(
+ Display *display, /* Display on which to draw. */
+ Drawable drawable, /* Window or pixmap in which to draw. */
+ GC gc, /* Graphics context for drawing characters. */
+ Tk_Font tkfont, /* Font in which characters will be drawn; must
+ * be the same as font used in GC. */
+ const char *source, /* UTF-8 string to be displayed. Need not be
+ * '\0' terminated. All Tk meta-characters
+ * (tabs, control characters, and newlines)
+ * should be stripped out of the string that
+ * is passed to this function. If they are not
+ * stripped out, they will be displayed as
+ * regular printing characters. */
+ int numBytes, /* Number of bytes in string. */
+ int x, int y) /* Coordinates at which to place origin of the
+ * string when drawing. */
{
- Fixed pixelWidth, widthLeft;
- StyledLineBreakCode breakCode;
- Tcl_DString runString;
- long textOffset;
- Boolean leadingEdge;
- Point point;
- int charOffset, thisCharWasDoubleByte;
- char *p, *end, *typeTable;
-
- TextFont(familyPtr->faceNum);
- Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes,
- &runString);
- pixelWidth = IntToFixed(*widthLeftPtr) + 1;
- if (flags & TK_WHOLE_WORDS) {
- textOffset = (flags & TK_AT_LEAST_ONE);
- widthLeft = pixelWidth;
- breakCode = StyledLineBreak(Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString), 0, Tcl_DStringLength(&runString),
- 0, &widthLeft, &textOffset);
- if (breakCode != smBreakOverflow) {
- /*
- * StyledLineBreak includes all the space characters at the end of
- * line that we want to suppress.
- */
-
- textOffset = VisibleLength(Tcl_DStringValue(&runString), textOffset);
- goto getoffset;
- }
- } else {
- point.v = 1;
- point.h = 1;
- textOffset = PixelToChar(Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString), 0, pixelWidth, &leadingEdge,
- &widthLeft, smOnlyStyleRun, point, point);
- if (FixedToInt(widthLeft) < 0) {
- goto getoffset;
- }
- }
- *widthLeftPtr = FixedToInt(widthLeft);
- Tcl_DStringFree(&runString);
- return NULL;
-
- /*
- * The conversion routine that converts UTF-8 to the target encoding
- * must map one UTF-8 character to exactly one encoding-specific
- * character, so that the following algorithm works:
- *
- * 1. Get byte offset of where line should be broken.
- * 2. Get char offset corresponding to that byte offset.
- * 3. Map that char offset to byte offset in UTF-8 string.
- */
-
- getoffset:
- thisCharWasDoubleByte = 0;
- if (familyPtr->isMultiByteFont == 0) {
- charOffset = textOffset;
- } else {
- charOffset = 0;
- typeTable = familyPtr->typeTable;
-
- p = Tcl_DStringValue(&runString);
- end = p + textOffset;
- thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
- for ( ; p < end; p++) {
- thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
- p += thisCharWasDoubleByte;
- charOffset++;
- }
- }
-
- if ((flags & TK_WHOLE_WORDS) == 0) {
- if ((flags & TK_PARTIAL_OK) && (leadingEdge != 0)) {
- textOffset += thisCharWasDoubleByte;
- textOffset++;
- charOffset++;
- } else if (((flags & TK_PARTIAL_OK) == 0) && (leadingEdge == 0)) {
- textOffset -= thisCharWasDoubleByte;
- textOffset--;
- charOffset--;
- }
- }
- if ((textOffset == 0) && (Tcl_DStringLength(&runString) > 0)
- && (flags & TK_AT_LEAST_ONE)) {
- p = Tcl_DStringValue(&runString);
- textOffset += familyPtr->typeTable[*((unsigned char *) p)];
- textOffset++;
- charOffset++;
- }
- *widthLeftPtr = FixedToInt(pixelWidth)
- - TextWidth(Tcl_DStringValue(&runString), 0, textOffset);
- Tcl_DStringFree(&runString);
- return Tcl_UtfAtIndex(source, charOffset);
+ TkpDrawCharsInContext(display, drawable, gc, tkfont, source, numBytes,
+ 0, numBytes, x, y);
}
/*
*---------------------------------------------------------------------------
*
- * Tk_DrawChars --
+ * TkpDrawCharsInContext --
*
- * Draw a string of characters on the screen.
+ * Draw a string of characters on the screen like Tk_DrawChars(), with
+ * access to all the characters on the line for context.
*
* Results:
* None.
@@ -998,17 +1151,20 @@ BreakLine(
* Side effects:
* Information gets drawn on the screen.
*
+ * Todo:
+ * Stippled text drawing.
+ *
*---------------------------------------------------------------------------
*/
void
-Tk_DrawChars(
+TkpDrawCharsInContext(
Display *display, /* Display on which to draw. */
Drawable drawable, /* Window or pixmap in which to draw. */
GC gc, /* Graphics context for drawing characters. */
Tk_Font tkfont, /* Font in which characters will be drawn; must
* be the same as font used in GC. */
- CONST char *source, /* UTF-8 string to be displayed. Need not be
+ const char * source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
@@ -1016,151 +1172,214 @@ Tk_DrawChars(
* stripped out, they will be displayed as
* regular printing characters. */
int numBytes, /* Number of bytes in string. */
+ int rangeStart, /* Index of first byte to draw. */
+ int rangeLength, /* Length of range to draw in bytes. */
int x, int y) /* Coordinates at which to place origin of the
- * string when drawing. */
+ * whole (not just the range) string when
+ * drawing. */
{
+ const MacFont * fontPtr = (const MacFont *) tkfont;
MacDrawable *macWin = (MacDrawable *) drawable;
- MacFont *fontPtr = (MacFont *) tkfont;
+ 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, 0, &drawingContext)) {
+ if (!TkMacOSXSetupDrawingContext(drawable, gc, tkMacOSXUseCGDrawing,
+ &drawingContext)) {
return;
}
+
#if 0
/*
- * Stippled QD text drawing only kind of works and is ugly, so disable it
- * for now:
+ * TODO: implement stippled text drawing
*/
+
if ((gc->fill_style == FillStippled
|| gc->fill_style == FillOpaqueStippled)
&& gc->stipple != None) {
- TkMacOSXDrawingContext pixmapDrawingContext;
- BitMapPtr stippleMap;
- Pixmap pixmap;
- Pattern white;
- Rect bounds = drawingContext.portBounds;
-
- OffsetRect(&bounds, macWin->xOff + x, 0);
- stippleMap = TkMacOSXMakeStippleMap(drawable, gc->stipple);
- pixmap = Tk_GetPixmap(display, drawable,
- stippleMap->bounds.right, stippleMap->bounds.bottom, 0);
- if (!TkMacOSXSetupDrawingContext(pixmap, gc, 0,
- &pixmapDrawingContext)) {
- return;
- }
- GetQDGlobalsWhite(&white);
- FillRect(&stippleMap->bounds, &white);
- MultiFontDrawText(fontPtr, source, numBytes, 0, macWin->yOff + y);
- TkMacOSXRestoreDrawingContext(&pixmapDrawingContext);
- CopyDeepMask(GetPortBitMapForCopyBits(TkMacOSXGetDrawablePort(pixmap)),
- stippleMap, GetPortBitMapForCopyBits(
- TkMacOSXGetDrawablePort(drawable)), &stippleMap->bounds,
- &stippleMap->bounds, &bounds, srcOr, NULL);
-
- /* TODO: this doesn't work quite right - it does a blend. You can't
- * draw white text when you have a stipple.
- */
-
- Tk_FreePixmap(display, pixmap);
- ckfree(stippleMap->baseAddr);
- ckfree((char *)stippleMap);
- } else
+ #error Stippling not implemented
+ }
#endif
- {
- MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x,
- macWin->yOff + y);
+
+ 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;
}
+ 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);
+
+ ChkErr(ATSUDrawText, fontPtr->atsuLayout, lineOffset+urstart, urlen, fx,
+ fy);
+
+#if !TK_MAC_COALESCE_LINE
+ Tcl_DStringFree(&runString);
+#endif
+
TkMacOSXRestoreDrawingContext(&drawingContext);
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * MultiFontDrawText --
+ * MeasureStringWidth --
*
- * Helper function for Tk_DrawChars. Draws characters, using the
- * various screen fonts in fontPtr to draw multilingual characters.
- * Note: No bidirectional support.
+ * 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:
- * Information gets drawn on the screen.
- * Contents of fontPtr may be modified if more subfonts were loaded
- * in order to draw all the multilingual characters in the given
- * string.
+ * "*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 void
-MultiFontDrawText(
- MacFont *fontPtr, /* Contains set of fonts to use when drawing
- * following string. */
- const char *source, /* Potentially multilingual UTF-8 string. */
- int numBytes, /* Length of string in bytes. */
- int x, int y) /* Coordinates at which to place origin *
- * of string when drawing. */
+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. */
{
- SubFont *thisSubFontPtr, *lastSubFontPtr;
- FontFamily *familyPtr;
- Tcl_DString runString;
- const char *p, *end, *next;
- Tcl_UniChar ch;
-
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
- lastSubFontPtr = &fontPtr->subFontArray[0];
-
- end = source + numBytes;
- for (p = source; p < end; ) {
- next = p + Tcl_UtfToUniChar(p, &ch);
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
- if (thisSubFontPtr != lastSubFontPtr) {
- if (p > source) {
- familyPtr = lastSubFontPtr->familyPtr;
- TextFont(familyPtr->faceNum);
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- p - source, &runString);
- MoveTo((short) x, (short) y);
- DrawText(Tcl_DStringValue(&runString), 0,
- Tcl_DStringLength(&runString));
- x += TextWidth(Tcl_DStringValue(&runString), 0,
- Tcl_DStringLength(&runString));
- Tcl_DStringFree(&runString);
- source = p;
- }
- lastSubFontPtr = thisSubFontPtr;
- }
- p = next;
- }
- if (p > source) {
- familyPtr = lastSubFontPtr->familyPtr;
- TextFont(familyPtr->faceNum);
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- p - source, &runString);
- MoveTo((short) x, (short) y);
- DrawText(Tcl_DStringValue(&runString), 0,
- Tcl_DStringLength(&runString));
- Tcl_DStringFree(&runString);
+ 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 */
/*
*---------------------------------------------------------------------------
*
- * TkMacOSXIsCharacterMissing --
+ * FamilyNameForFamilyID --
*
- * Given a tkFont and a character determines whether the character has
- * a glyph defined in the font or not. Note that this is potentially
- * not compatible with Mac OS 8 as it looks at the font handle
- * structure directly. Looks into the character array of the font
- * handle to determine whether the glyph is defined or not.
+ * Helper for InitFont() and TkMacOSXFontDescriptionForFMFontInfo().
+ * Retrieves font family names for a given font family ID.
*
* Results:
- * Returns a 1 if the character is missing, a 0 if it is not.
+ * Font family name or NULL.
*
* Side effects:
* None.
@@ -1168,17 +1387,29 @@ MultiFontDrawText(
*---------------------------------------------------------------------------
*/
-int
-TkMacOSXIsCharacterMissing(
- Tk_Font tkfont, /* The font we are looking in. */
- unsigned int searchChar) /* The character we are looking for. */
+static const char *
+FamilyNameForFamilyID(
+ FMFontFamily familyId)
{
- /*
- * For some reason, FMSwapFont always returns a NULL font handle under OS X
- * Until we figure this one out, return 0;
- */
+ OSStatus err;
+ char name[256] = "";
+ const MacFontFamily * familyPtr = NULL;
- return 0;
+ 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;
}
/*
@@ -1187,12 +1418,12 @@ TkMacOSXIsCharacterMissing(
* InitFont --
*
* Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
- * Initializes the memory for a MacFont that wraps the platform-specific
- * data.
+ * 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().
+ * 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.
@@ -1205,784 +1436,893 @@ TkMacOSXIsCharacterMissing(
static void
InitFont(
- Tk_Window tkwin, /* For display where font will be used. */
- int faceNum, /* Macintosh font number. */
- unsigned char *familyName, /* The font family name or NULL. */
- int size, /* Point size for Macintosh font. */
- int style, /* Macintosh style bits. */
- MacFont *fontPtr) /* Filled with information constructed from
- * the above arguments. */
+ 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. */
{
- Str255 nativeName;
FontInfo fi;
- TkFontAttributes *faPtr;
- TkFontMetrics *fmPtr;
- CGrafPtr savePort;
- Boolean portChanged;
- short pixels;
+ TkFontAttributes * faPtr;
+ TkFontMetrics * fmPtr;
+ int periodWidth, wWidth;
if (size == 0) {
- size = -GetDefFontSize();
+ size = GetDefFontSize();
}
- pixels = (short) TkFontGetPixels(tkwin, size);
-
- portChanged = QDSwapPort(gWorld, &savePort);
- TextFont(faceNum);
- TextSize(pixels);
- TextFace(style);
-
- GetFontInfo(&fi);
+ ChkErr(FetchFontInfo, familyId, size, qdStyle, &fi);
if (!familyName) {
- GetFontName(faceNum, nativeName);
- familyName = nativeName;
+ familyName = FamilyNameForFamilyID(familyId);
}
- fontPtr->font.fid = (Font) fontPtr;
+
+ fontPtr->font.fid = (Font) fontPtr;
faPtr = &fontPtr->font.fa;
- faPtr->family = GetUtfFaceName(familyName);
- faPtr->size = TkFontGetPoints(tkwin, size);
- faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
- faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
- faPtr->underline = ((style & underline) != 0);
+ 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;
- fmPtr->ascent = fi.ascent;
+
+ /*
+ * 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;
- fmPtr->fixed = (CharWidth('i') == CharWidth('w'));
- fontPtr->size = pixels;
- fontPtr->style = (short) style;
+ fontPtr->qdFont = familyId;
+ fontPtr->qdSize = size;
+ fontPtr->qdStyle = (short) qdStyle;
- fontPtr->numSubFonts = 1;
- fontPtr->subFontArray = fontPtr->staticSubFonts;
- InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]);
+ InitATSUObjects(familyId, size, qdStyle, &fontPtr->atsuFontId,
+ &fontPtr->atsuLayout, &fontPtr->atsuStyle);
- if (portChanged) {
- QDSwapPort(savePort, NULL);
- }
+ 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);
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * ReleaseFont --
+ * InitATSUObjects --
*
- * Called to release the Macintosh-specific contents of a TkFont.
- * The caller is responsible for freeing the memory used by the
- * font itself.
+ * Helper for InitFont(). Initializes the ATSU data handles for a
+ * MacFont.
*
* Results:
- * None.
+ * Sets up all we know and can do at this point in time in fontIdPtr,
+ * layoutPtr and stylePtr.
*
* Side effects:
- * Memory is freed.
+ * Allocates data structures inside of ATSU.
*
*---------------------------------------------------------------------------
*/
static void
-ReleaseFont(
- MacFont *fontPtr) /* The font to delete. */
+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. */
{
- int i;
+ FMFontStyle stylesDone, stylesLeft;
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- ReleaseSubFont(&fontPtr->subFontArray[i]);
- }
- if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
- ckfree((char *) fontPtr->subFontArray);
- }
+ /*
+ * 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);*/
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * InitSubFont --
+ * InitATSUStyle --
*
- * Wrap a screen font and load the FontFamily that represents
- * it. Used to prepare a SubFont so that characters can be mapped
- * from UTF-8 to the charset of the font.
+ * Helper for InitATSUObjects(). Initializes the ATSU style for a
+ * MacFont.
*
* Results:
- * The subFontPtr is filled with information about the font.
+ * Sets up all parameters needed for an ATSU style.
*
* Side effects:
- * None.
+ * Allocates data structures for the style inside of ATSU.
*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
static void
-InitSubFont(
- const MacFont *fontPtr, /* Font object in which the SubFont will be
- * used. */
- int faceNum, /* The font number. */
- SubFont *subFontPtr) /* Filled with SubFont constructed from
- * above attributes. */
+InitATSUStyle(
+ ATSUFontID fontId, /* The font id to use. */
+ short ptSize, short qdStyles,
+ /* Additional font parameters. */
+ ATSUStyle style) /* The style handle to configure. */
{
- subFontPtr->familyPtr = AllocFontFamily(fontPtr, faceNum);
- subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;
+ /*
+ * 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);
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * ReleaseSubFont --
+ * SetFontFeatures --
*
- * Called to release the contents of a SubFont. The caller is
- * responsible for freeing the memory used by the SubFont itself.
+ * Helper for InitFont(). Request specific font features of the ATSU
+ * style object for a MacFont.
*
* Results:
* None.
*
* Side effects:
- * Memory and resources are freed.
+ * Specific font features are enabled on the ATSU style object.
*
*---------------------------------------------------------------------------
*/
static void
-ReleaseSubFont(
- SubFont *subFontPtr) /* The SubFont to delete. */
+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. */
{
- FreeFontFamily(subFontPtr->familyPtr);
+ /*
+ * 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);
+ }
+ }
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * AllocFontFamily --
+ * AdjustFontHeight --
*
- * Find the FontFamily structure associated with the given font
- * family. The information should be stored by the caller in a
- * SubFont and used when determining if that SubFont supports a
- * character.
+ * Helper for InitFont(). Check font height against some real world
+ * examples.
*
* Results:
- * A pointer to a FontFamily. The reference count in the FontFamily
- * is automatically incremented. When the SubFont is released, the
- * reference count is decremented. When no SubFont is using this
- * FontFamily, it may be deleted.
+ * None.
*
* Side effects:
- * A new FontFamily structure will be allocated if this font family
- * has not been seen.
+ * The metrics in fontPtr->font.fm are adjusted so that typical combined
+ * characters fit into ascent+descent.
*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
-static FontFamily *
-AllocFontFamily(
- const MacFont *fontPtr, /* Font object in which the FontFamily will
- * be used. */
- int faceNum) /* The font number. */
+static void
+AdjustFontHeight(
+ MacFont * fontPtr)
{
- FontFamily *familyPtr;
- int i;
-
- familyPtr = fontFamilyList;
- for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
- if (familyPtr->faceNum == faceNum) {
- familyPtr->refCount++;
- return familyPtr;
- }
- }
-
- familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
- memset(familyPtr, 0, sizeof(FontFamily));
- familyPtr->nextPtr = fontFamilyList;
- fontFamilyList = familyPtr;
-
/*
- * Set key for this FontFamily.
+ * 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].
*/
- familyPtr->faceNum = faceNum;
+ 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;
- /*
- * An initial refCount of 2 means that FontFamily information will
- * persist even when the SubFont that loaded the FontFamily is released.
- * Change it to 1 to cause FontFamilies to be unloaded when not in use.
- */
+ LayoutSetString(fontPtr, NULL, chars, charslen);
- familyPtr->refCount = 2;
- familyPtr->encoding = GetFontEncoding(faceNum, 1, &familyPtr->isSymbolFont);
- familyPtr->isMultiByteFont = 0;
- FillParseTable(familyPtr->typeTable, FontToScript(faceNum));
- for (i = 0; i < 256; i++) {
- if (familyPtr->typeTable[i] != 0) {
- familyPtr->isMultiByteFont = 1;
- break;
+ 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;
}
}
- return familyPtr;
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * FreeFontFamily --
+ * InitATSULayout --
*
- * Called to free a FontFamily when the SubFont is finished using it.
- * Frees the contents of the FontFamily and the memory used by the
- * FontFamily itself.
+ * Helper for LayoutSetString(). Initializes the ATSU layout
+ * object for a MacFont and a specific string.
*
* Results:
- * None.
+ * Sets up all parameters needed for an ATSU layout object.
*
* Side effects:
- * None.
+ * 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
-FreeFontFamily(
- FontFamily *familyPtr) /* The FontFamily to delete. */
+InitATSULayout(
+ const TkMacOSXDrawingContext *drawingContextPtr,
+ /* Specifies the CGContext to use. */
+ ATSUTextLayout layout, /* The layout object to configure. */
+ int fixed) /* Is this a fixed font? */
{
- FontFamily **familyPtrPtr;
- int i;
+ /*
+ * Attributes for the layout.
+ */
- if (familyPtr == NULL) {
- return;
- }
- familyPtr->refCount--;
- if (familyPtr->refCount > 0) {
- return;
- }
- Tcl_FreeEncoding(familyPtr->encoding);
- for (i = 0; i < FONTMAP_PAGES; i++) {
- if (familyPtr->fontMap[i] != NULL) {
- ckfree((char *) familyPtr->fontMap[i]);
- }
- }
+ 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,
+ };
/*
- * Delete from list.
+ * Ensure W(abcdefg) == W(a)*7 for fixed fonts (Latin scripts only).
*/
- for (familyPtrPtr = &fontFamilyList; ; ) {
- if (*familyPtrPtr == familyPtr) {
- *familyPtrPtr = familyPtr->nextPtr;
- break;
- }
- familyPtrPtr = &(*familyPtrPtr)->nextPtr;
+ if (fixed) {
+ layoutOptions |= kATSLineFractDisable | kATSLineUseDeviceMetrics;
}
- ckfree((char *) familyPtr);
+ ChkErr(ATSUSetLayoutControls, layout, sizeof(layoutTags) /
+ sizeof(layoutTags[0]), layoutTags, layoutSizes, layoutValues);
+ ChkErr(ATSUSetTransientFontMatching, layout, true);
}
/*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
- * FindSubFontForChar --
+ * LayoutSetString --
*
- * Determine which physical screen font is necessary to use to
- * display the given character. If the font object does not have
- * a screen font that can display the character, another screen font
- * may be loaded into the font object, following a set of preferred
- * fallback rules.
+ * Setup the MacFont for a specific string.
*
* Results:
- * The return value is the SubFont to use to display the given
- * character.
+ * Sets up all parameters so that ATSU can work with the objects in
+ * MacFont.
*
* Side effects:
- * The contents of fontPtr are modified to cache the results
- * of the lookup and remember any SubFonts that were dynamically
- * loaded. The table of SubFonts might be extended, and if a non-NULL
- * reference to a subfont pointer is available, it is updated if it
- * previously pointed into the old subfont table.
+ * Sets parameters on the layout object fontPtr->atsuLayout.
*
- *-------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
-static SubFont *
-FindSubFontForChar(
- MacFont *fontPtr, /* The font object with which the character
- * will be displayed. */
- int ch, /* The Unicode character to be displayed. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
+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. */
{
- int i, j, k;
- const char *fallbackName;
- char **aliases;
- SubFont *subFontPtr;
- FontNameMap *mapPtr;
- Tcl_DString faceNames;
- char ***fontFallbacks;
- char **anyFallbacks;
-
- if (FontMapLookup(&fontPtr->subFontArray[0], ch)) {
- return &fontPtr->subFontArray[0];
- }
-
- for (i = 1; i < fontPtr->numSubFonts; i++) {
- if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
- return &fontPtr->subFontArray[i];
- }
- }
+ ChkErr(ATSUSetTextPointerLocation, fontPtr->atsuLayout, uchars,
+ kATSUFromTextBeginning, ulen, ulen);
/*
- * Keep track of all face names that we check, so we don't check some
- * name multiple times if it can be reached by multiple paths.
+ * Styles can only be set after the text is set.
*/
- Tcl_DStringInit(&faceNames);
+ ChkErr(ATSUSetRunStyle, fontPtr->atsuLayout, fontPtr->atsuStyle,
+ kATSUFromTextBeginning, kATSUToTextEnd);
- aliases = TkFontGetAliasList(fontPtr->font.fa.family);
+ /*
+ * Layout attributes can only be set after the styles are set.
+ */
- subFontPtr = NULL;
- fontFallbacks = TkFontGetFallbacks();
- for (i = 0; fontFallbacks[i] != NULL; i++) {
- for (j = 0; fontFallbacks[i][j] != NULL; j++) {
- fallbackName = fontFallbacks[i][j];
- if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) {
- /*
- * If the base font has a fallback...
- */
+ 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.
+ *
+ *---------------------------------------------------------------------------
+ */
- goto tryfallbacks;
- } else if (aliases != NULL) {
- /*
- * Or if an alias for the base font has a fallback...
- */
+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.
+ *
+ *-------------------------------------------------------------------------
+ */
- for (k = 0; aliases[k] != NULL; k++) {
- if (strcasecmp(aliases[k], fallbackName) == 0) {
- goto tryfallbacks;
- }
- }
- }
- }
- continue;
+static const MacFontFamily *
+FindFontFamilyOrAlias(
+ const char *name) /* Name or alias name of the font to find. */
+{
+ const MacFontFamily * familyPtr;
+ char ** aliases;
+ int i;
- /*
- * ...then see if we can use one of the fallbacks, or an
- * alias for one of the fallbacks.
- */
+ familyPtr = FindFontFamily(name);
+ if (familyPtr != NULL) {
+ return familyPtr;
+ }
- tryfallbacks:
- for (j = 0; fontFallbacks[i][j] != NULL; j++) {
- fallbackName = fontFallbacks[i][j];
- subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName,
- ch, &faceNames, fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
+ 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;
+ char *** fallbacks;
+ int i, j;
- /*
- * See if we can use something from the global fallback list.
- */
-
- anyFallbacks = TkFontGetGlobalClass();
- for (i = 0; anyFallbacks[i] != NULL; i++) {
- fallbackName = anyFallbacks[i];
- subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, ch,
- &faceNames, fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
- }
+ familyPtr = FindFontFamilyOrAlias(name);
+ if (familyPtr != NULL) {
+ return familyPtr;
}
-
- /*
- * Try all face names available in the whole system until we
- * find one that can be used.
- */
-
- for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
- fallbackName = mapPtr->utfName;
- if (SeenName(fallbackName, &faceNames) == 0) {
- subFontPtr = CanUseFallback(fontPtr, fallbackName, ch,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
+ 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
+ * ???? */
}
}
- end:
- Tcl_DStringFree(&faceNames);
- if (subFontPtr == NULL) {
- /*
- * No font can display this character. We will use the base font
- * and have it display the "unknown" character.
- */
+ /*
+ * 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.
+ */
- subFontPtr = &fontPtr->subFontArray[0];
- FontMapInsert(subFontPtr, ch);
- }
- return subFontPtr;
+#ifdef TK_MAC_DEBUG_FONTS
+ TkMacOSXDbgMsg("Font family '%s' not found", name);
+#endif
+
+ return NULL;
}
/*
*-------------------------------------------------------------------------
*
- * FontMapLookup --
+ * InitFontFamilies --
*
- * See if the screen font can display the given character.
+ * Helper to TkpFontPkgInit. Use the Font Manager to fill in the
+ * familyList global array.
*
* Results:
- * The return value is 0 if the screen font cannot display the
- * character, non-zero otherwise.
+ *
+ * None.
*
* Side effects:
- * New pages are added to the font mapping cache whenever the
- * character belongs to a page that hasn't been seen before.
- * When a page is loaded, information about all the characters on
- * that page is stored, not just for the single character in
- * question.
+ *
+ * Allocates memory.
*
*-------------------------------------------------------------------------
*/
-static int
-FontMapLookup(
- SubFont *subFontPtr, /* Contains font mapping cache to be queried
- * and possibly updated. */
- int ch) /* Character to be tested. */
+static void
+InitFontFamilies(void)
{
- int row, bitOffset;
+ FMFontFamily fontFamily;
+ Str255 fontName;
+ SInt16 fontSize;
+ Style fontStyle;
- row = ch >> FONTMAP_SHIFT;
- if (subFontPtr->fontMap[row] == NULL) {
- FontMapLoadPage(subFontPtr, row);
+ /*
+ * 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);
}
- bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
- return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
+
+ SortFontFamilies();
}
/*
*-------------------------------------------------------------------------
*
- * FontMapInsert --
+ * FontFamilyEnumCallback --
*
- * Tell the font mapping cache that the given screen font should be
- * used to display the specified character. This is called when no
- * font on the system can be be found that can display that
- * character; we lie to the font and tell it that it can display
- * the character, otherwise we would end up re-searching the entire
- * fallback hierarchy every time that character was seen.
+ * Callback for ATSFontFamilyApplyFunction().
*
* Results:
- * None.
+ *
+ * noErr.
*
* Side effects:
- * New pages are added to the font mapping cache whenever the
- * character belongs to a page that hasn't been seen before.
- * When a page is loaded, information about all the characters on
- * that page is stored, not just for the single character in
- * question.
+ *
+ * None.
*
*-------------------------------------------------------------------------
*/
-static void
-FontMapInsert(
- SubFont *subFontPtr, /* Contains font mapping cache to be
- * updated. */
- int ch) /* Character to be added to cache. */
+static OSStatus
+FontFamilyEnumCallback(
+ ATSFontFamilyRef family,
+ void *refCon)
{
- int row, bitOffset;
+ OSStatus err;
+ char name[260] = "";
- row = ch >> FONTMAP_SHIFT;
- if (subFontPtr->fontMap[row] == NULL) {
- FontMapLoadPage(subFontPtr, row);
+ (void) refCon;
+
+ err = ChkErr(GetFontFamilyName, family, name, sizeof(name));
+ if (err == noErr) {
+ AddFontFamily(name, family);
}
- bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
- subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
+
+ return noErr;
}
/*
*-------------------------------------------------------------------------
*
- * FontMapLoadPage --
+ * GetFontFamilyName --
*
- * Load information about all the characters on a given page.
- * This information consists of one bit per character that indicates
- * whether the associated HFONT can (1) or cannot (0) display the
- * characters on the page.
+ * 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:
- * None.
+ * An OS error code, noErr on success. name is filled with the
+ * resulting name.
*
* Side effects:
- * Mempry allocated.
+ * None.
*
*-------------------------------------------------------------------------
*/
-static void
-FontMapLoadPage(
- SubFont *subFontPtr, /* Contains font mapping cache to be
- * updated. */
- int row) /* Index of the page to be loaded into
- * the cache. */
+
+static OSStatus
+GetFontFamilyName(
+ FMFontFamily fontFamily, /* The font family for which to find the
+ * name. */
+ char * name, int numBytes) /* Filled with the result. */
{
- FMInput fm;
- FMOutPtr fmOut;
- int i, end, bitOffset, isMultiByteFont;
- char src[TCL_UTF_MAX];
- unsigned char buf[16];
- int srcRead, dstWrote;
- Tcl_Encoding encoding;
- Handle fHandle = NULL;
-
- subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
- memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
-
- encoding = subFontPtr->familyPtr->encoding;
-
- fm.family = subFontPtr->familyPtr->faceNum;
- fm.size = 12;
- fm.face = 0;
- fm.needBits = 0;
- fm.device = 0;
- fm.numer.h = 1;
- fm.numer.v = 1;
- fm.denom.h = 1;
- fm.denom.v = 1;
+ 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;
+ }
-/*
- * For some reason, FMSwapFont alywas returns a structure where the returned font handle
- * is NULL. Until we figure this one out, assume all characters are allowed
- */
+ /*
+ * 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.
+ */
- fmOut = FMSwapFont(&fm);
- fHandle = fmOut->fontHandle;
- isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont;
+ encoding = kTextEncodingMacRoman;
+ ChkErr(FMGetFontFamilyTextEncoding, fontFamily, &encoding);
+ nameencoding = encoding;
+ ChkErr(RevertTextEncodingToScriptInfo, encoding, &nameencoding, NULL,
+ NULL);
- /*
- * Found an outline font which has very complex font record.
- * Let's just assume *ALL* the characters are allowed.
- */
+ /*
+ * 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.
+ */
- end = (row + 1) << FONTMAP_SHIFT;
- for (i = row << FONTMAP_SHIFT; i < end; i++) {
- if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i,
- src),
- TCL_ENCODING_STOPONERROR, NULL, (char *) buf,
- sizeof(buf),
- &srcRead, &dstWrote, NULL) == TCL_OK) {
- bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
- subFontPtr->fontMap[row][bitOffset >> 3] |= 1
- << (bitOffset & 7);
- }
- }
+ 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;
}
/*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*
- * CanUseFallbackWithAliases --
+ * FindFontFamily --
*
- * Helper function for FindSubFontForChar. Determine if the
- * specified face name (or an alias of the specified face name)
- * can be used to construct a screen font that can display the
- * given character.
+ * 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:
- * See CanUseFallback().
+ *
+ * MacFontFamily: A pair of family id and the actual name registered for
+ * the font.
*
* Side effects:
- * If the name and/or one of its aliases was rejected, the
- * rejected string is recorded in nameTriedPtr so that it won't
- * be tried again. The table of SubFonts might be extended, and if
- * a non-NULL reference to a subfont pointer is available, it is
- * updated if it previously pointed into the old subfont table.
*
- *---------------------------------------------------------------------------
+ * None.
+ *
+ * Assumption:
+ *
+ * Requires the familyList array to be sorted.
+ *
+ *-------------------------------------------------------------------------
*/
-static SubFont *
-CanUseFallbackWithAliases(
- MacFont *fontPtr, /* The font object that will own the new
- * screen font. */
- const char *faceName, /* Desired face name for new screen font. */
- int ch, /* The Unicode character that the new
- * screen font must be able to display. */
- Tcl_DString *nameTriedPtr, /* Records face names that have already
- * been tried. It is possible for the same
- * face name to be queried multiple times when
- * trying to find a suitable screen font. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
+static const MacFontFamily *
+FindFontFamily(
+ const char *name) /* The family name. Note: Names are compared
+ * non-case-sensitive. */
{
- SubFont *subFontPtr;
- char **aliases;
- int i;
+ const MacFontFamily key = {name,-1};
- if (SeenName(faceName, nameTriedPtr) == 0) {
- subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- return subFontPtr;
- }
- }
- aliases = TkFontGetAliasList(faceName);
- if (aliases != NULL) {
- for (i = 0; aliases[i] != NULL; i++) {
- if (SeenName(aliases[i], nameTriedPtr) == 0) {
- subFontPtr = CanUseFallback(fontPtr, aliases[i], ch,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- return subFontPtr;
- }
- }
- }
+ if(familyListMaxValid <= 0) {
+ return NULL;
}
- return NULL;
+
+ return bsearch(&key, familyList, familyListMaxValid, sizeof(*familyList),
+ CompareFontFamilies);
}
/*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*
- * SeenName --
+ * EnumFontFamilies --
*
- * Used to determine we have already tried and rejected the given
- * face name when looking for a screen font that can support some
- * Unicode character.
+ * Create a Tcl list with the registered names in the global familyList.
*
* Results:
- * The return value is 0 if this face name has not already been seen,
- * non-zero otherwise.
+ * A Tcl list of names.
*
* Side effects:
* None.
*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*/
-static int
-SeenName(
- const char *name, /* The name to check. */
- Tcl_DString *dsPtr) /* Contains names that have already been
- * seen. */
+static Tcl_Obj *
+EnumFontFamilies(void)
{
- const char *seen, *end;
+ int i;
+ Tcl_Obj * tclList;
- seen = Tcl_DStringValue(dsPtr);
- end = seen + Tcl_DStringLength(dsPtr);
- while (seen < end) {
- if (strcasecmp(seen, name) == 0) {
- return 1;
- }
- seen += strlen(seen) + 1;
+ tclList = Tcl_NewListObj(0, NULL);
+ for (i=0; i<familyListMaxValid; ++i) {
+ Tcl_ListObjAppendElement(NULL, tclList,
+ Tcl_NewStringObj(familyList[i].name, -1));
}
- Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));
- return 0;
+
+ return tclList;
}
/*
*-------------------------------------------------------------------------
*
- * CanUseFallback --
+ * AddFontFamily --
*
- * If the specified physical screen font has not already been loaded
- * into the font object, determine if the specified physical screen
- * font can display the given character.
+ * Register a font family in familyList. Until SortFontFamilies() is
+ * called, this is not actually available for FindFontFamily().
*
* Results:
- * The return value is a pointer to a newly allocated SubFont, owned
- * by the font object. This SubFont can be used to display the given
- * character. The SubFont represents the screen font with the base set
- * of font attributes from the font object, but using the specified
- * font name. NULL is returned if the font object already holds
- * a reference to the specified physical font or if the specified
- * physical font cannot display the given character.
+ *
+ * MacFontFamily: The new pair of family id and the actual name
+ * registered for the font.
*
* Side effects:
- * The font object's subFontArray is updated to contain a reference
- * to the newly allocated SubFont. The table of SubFonts might be
- * extended, and if a non-NULL reference to a subfont pointer is
- * available, it is updated if it previously pointed into the old
- * subfont table.
+ *
+ * New entry in familyList and familyListNextFree updated.
*
*-------------------------------------------------------------------------
*/
-static SubFont *
-CanUseFallback(
- MacFont *fontPtr, /* The font object that will own the new
- * screen font. */
- const char *faceName, /* Desired face name for new screen font. */
- int ch, /* The Unicode character that the new
- * screen font must be able to display. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
+static const MacFontFamily *
+AddFontFamily(
+ const char *name, /* Font family name to register. */
+ FMFontFamily familyId) /* Font family id to register. */
{
- int i;
- SubFont subFont;
- short faceNum;
-
- if (GetFamilyNum(faceName, &faceNum) == 0) {
- return NULL;
- }
-
- /*
- * Skip all fonts we've already used.
- */
+ MacFontFamily * familyPtr;
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- if (faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) {
- return NULL;
- }
+ if (familyListNextFree >= familyListSize) {
+ familyListSize += 100;
+ familyList = (MacFontFamily *) ckrealloc((void*) familyList,
+ familyListSize * sizeof(*familyList));
}
- /*
- * Load this font and see if it has the desired character.
- */
+ familyPtr = familyList + familyListNextFree;
+ ++familyListNextFree;
- InitSubFont(fontPtr, faceNum, &subFont);
- if (((ch < 256) && (subFont.familyPtr->isSymbolFont))
- || (FontMapLookup(&subFont, ch) == 0)) {
- ReleaseSubFont(&subFont);
- return NULL;
- }
+ familyPtr->name = AddString(name);
+ familyPtr->familyId = familyId;
- if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
- SubFont *newPtr = (SubFont *) ckalloc(sizeof(SubFont)
- * (fontPtr->numSubFonts + 1));
- memcpy((char *) newPtr, fontPtr->subFontArray,
- fontPtr->numSubFonts * sizeof(SubFont));
- if (fixSubFontPtrPtr != NULL) {
- /*
- * Fix up the variable pointed to by fixSubFontPtrPtr so it
- * still points into the live array. [Bug 618872]
- */
+ 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.
+ *
+ *-------------------------------------------------------------------------
+ */
- *fixSubFontPtrPtr =
- newPtr + (*fixSubFontPtrPtr - fontPtr->subFontArray);
- }
- if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
- ckfree((char *) fontPtr->subFontArray);
- }
- fontPtr->subFontArray = newPtr;
+static void
+SortFontFamilies(void)
+{
+ if (familyListNextFree > 0) {
+ qsort(familyList, familyListNextFree, sizeof(*familyList),
+ CompareFontFamilies);
}
- fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
- fontPtr->numSubFonts++;
- return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
+ familyListMaxValid = familyListNextFree;
}
/*
*-------------------------------------------------------------------------
*
- * GetFamilyNum --
+ * CompareFontFamilies --
*
- * Determines 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.
+ * Comparison function used by SortFontFamilies() and FindFontFamily().
*
* Results:
- * The return value is 0 if the specified font family does not exist,
- * non-zero otherwise. *faceNumPtr is filled with the unique face
- * number that identifies the screen font, or 0 if the font family
- * did not exist.
+ * 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.
@@ -1991,148 +2331,101 @@ CanUseFallback(
*/
static int
-GetFamilyNum(
- const char *faceName, /* UTF-8 name of font family to query. */
- short *faceNumPtr) /* Filled with font number for above family. */
+CompareFontFamilies(
+ const void * vp1,
+ const void * vp2)
{
- FontNameMap *mapPtr;
+ const char * name1;
+ const char * name2;
+ int len1, len2, diff;
- if (faceName != NULL) {
- for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
- if (strcasecmp(faceName, mapPtr->utfName) == 0) {
- *faceNumPtr = mapPtr->faceNum;
- return 1;
- }
- }
- }
- *faceNumPtr = 0;
- return 0;
-}
+ name1 = ((const MacFontFamily *) vp1)->name;
+ name2 = ((const MacFontFamily *) vp2)->name;
-static int
-GetFamilyOrAliasNum(
- const char *faceName, /* UTF-8 name of font family to query. */
- short *faceNumPtr) /* Filled with font number for above family. */
-{
- char **aliases;
- int i;
+ len1 = Tcl_NumUtfChars(name1, -1);
+ len2 = Tcl_NumUtfChars(name2, -1);
- if (GetFamilyNum(faceName, faceNumPtr) != 0) {
- return 1;
- }
- aliases = TkFontGetAliasList(faceName);
- if (aliases != NULL) {
- for (i = 0; aliases[i] != NULL; i++) {
- if (GetFamilyNum(aliases[i], faceNumPtr) != 0) {
- return 1;
- }
- }
- }
- return 0;
+ diff = Tcl_UtfNcasecmp(name1, name2, len1<len2 ? len1 : len2);
+
+ return diff == 0 ? len1-len2 : diff;
}
/*
*-------------------------------------------------------------------------
*
- * GetUtfFaceName --
+ * AddString --
*
- * Given the native name for a Macintosh font (in which the name of
- * the font is in the encoding of the font itself), return the UTF-8
- * name that corresponds to that font. The specified font name must
- * refer to a font that actually exists on the machine.
- *
- * This function is used to obtain the UTF-8 name when querying the
- * properties of a Macintosh font object.
+ * Helper for AddFontFamily(). Allocates a string in the one-shot
+ * allocator.
*
* Results:
- * The return value is a pointer to the UTF-8 of the specified font.
+ * A duplicated string in the one-shot allocator.
*
* Side effects:
- * None.
+ * May allocate a new memory block.
*
- *------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*/
-static Tk_Uid
-GetUtfFaceName(
- StringPtr nativeName) /* Pascal name for font in native encoding. */
+static const char *
+AddString(
+ const char *in) /* String to add, zero-terminated. */
{
- FontNameMap *mapPtr;
+ int len;
+ char *result;
- for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
- if (pstrcmp(nativeName, mapPtr->nativeName) == 0) {
- return mapPtr->utfName;
- }
+ 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;
}
- Tcl_Panic("GetUtfFaceName: unexpected nativeName");
- return NULL;
+
+ result = stringMemory->strings + stringMemory->nextFree;
+ stringMemory->nextFree += len;
+
+ memcpy(result, in, len);
+
+ return result;
}
/*
- *------------------------------------------------------------------------
- *
- * GetFontEncoding --
+ *---------------------------------------------------------------------------
*
- * Return a string that can be passed to Tcl_GetTextEncoding() and
- * used to convert bytes from UTF-8 into the encoding of the
- * specified font.
+ * TkMacOSXIsCharacterMissing --
*
- * The desired encoding to use to convert the name of a symbolic
- * font into UTF-8 is macRoman, while the desired encoding to use
- * to convert bytes in a symbolic font to UTF-8 is the corresponding
- * symbolic encoding. Due to this dual interpretatation of symbolic
- * fonts, the caller can specify what type of encoding to return
- * should the specified font be symbolic.
+ * Given a tkFont and a character determine whether the character has
+ * a glyph defined in the font or not.
*
* Results:
- * The return value is a string that specifies the font's encoding.
- * If the font's encoding could not be identified, NULL is returned.
+ * Returns a 1 if the character is missing, a 0 if it is not.
*
* Side effects:
* None.
*
- *------------------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
-static Tcl_Encoding
-GetFontEncoding(
- int faceNum, /* Macintosh font number. */
- int allowSymbol, /* If non-zero, then the encoding string
- * for symbol fonts will be the corresponding
- * symbol encoding. Otherwise, the encoding
- * string for symbol fonts will be
- * "macRoman". */
- int *isSymbolPtr) /* Filled with non-zero if this font is a
- * symbol font, 0 otherwise. */
+int
+TkMacOSXIsCharacterMissing(
+ Tk_Font tkfont, /* The font we are looking in. */
+ unsigned int searchChar) /* The character we are looking for. */
{
- Str255 faceName;
- int script, lang;
- char *name;
-
- if (allowSymbol != 0) {
- GetFontName(faceNum, faceName);
- if (pstrcasecmp(faceName, "\psymbol") == 0) {
- *isSymbolPtr = 1;
- return Tcl_GetEncoding(NULL, "symbol");
- }
- if (pstrcasecmp(faceName, "\pzapf dingbats") == 0) {
- *isSymbolPtr = 1;
- return Tcl_GetEncoding(NULL, "macDingbats");
- }
- }
- *isSymbolPtr = 0;
- script = FontToScript(faceNum);
- lang = GetScriptVariable(script, smScriptLang);
- name = NULL;
- if (script == smRoman) {
- name = TkFindStateString(romanMap, lang);
- } else if (script == smCyrillic) {
- name = TkFindStateString(cyrillicMap, lang);
- }
- if (name == NULL) {
- name = TkFindStateString(scriptMap, script);
- }
- return Tcl_GetEncoding(NULL, name);
+ /* 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;
}
/*
@@ -2154,17 +2447,16 @@ GetFontEncoding(
void
TkMacOSXInitControlFontStyle(
- Tk_Font tkfont,
- ControlFontStylePtr fsPtr)
+ Tk_Font tkfont, /* Tk font object to use for the control. */
+ ControlFontStylePtr fsPtr) /* The style object to configure. */
{
- MacFont *fontPtr = (MacFont *) tkfont;
- FontFamily *lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;
+ const MacFont * fontPtr = (MacFont *) tkfont;
fsPtr->flags = kControlUseFontMask | kControlUseSizeMask |
kControlUseFaceMask | kControlUseJustMask;
- fsPtr->font = lastFamilyPtr->faceNum;
- fsPtr->size = fontPtr->size;
- fsPtr->style = fontPtr->style;
+ fsPtr->font = fontPtr->qdFont;
+ fsPtr->size = fontPtr->qdSize;
+ fsPtr->style = fontPtr->qdStyle;
fsPtr->just = teCenter;
}
@@ -2173,72 +2465,55 @@ TkMacOSXInitControlFontStyle(
*
* TkMacOSXUseAntialiasedText --
*
- * Enables or disables application-wide use of quickdraw
- * antialiased text (where available).
- * Sets up a linked tcl global boolean variable with write trace
- * to allow disabling of antialiased text from tcl.
+ * Enables or disables application-wide use of antialiased text (where
+ * available). Sets up a linked Tcl global variable to allow
+ * disabling of antialiased text from tcl.
+ * The possible values for this variable are:
+ *
+ * -1 - Use system default as configurable in "System Prefs" -> "General".
+ * 0 - Unconditionally disable antialiasing.
+ * 1 - Unconditionally enable antialiasing.
*
* Results:
- * TCL_OK if facility was sucessfully enabled/disabled.
- * TCL_ERROR if an error occurred or if facility is not available.
+ *
+ * TCL_OK.
*
* Side effects:
+ *
* None.
*
*----------------------------------------------------------------------
*/
-static int TkMacOSXAntialiasedTextEnabled = FALSE;
-
-static char *
-TkMacOSXAntialiasedTextVariableProc(
- ClientData clientData,
- Tcl_Interp *interp,
- const char *name1,
- const char *name2,
- int flags)
-{
- TkMacOSXUseAntialiasedText(interp, TkMacOSXAntialiasedTextEnabled);
- return (char *) NULL;
-}
-
-int
+MODULE_SCOPE int
TkMacOSXUseAntialiasedText(
- Tcl_Interp *interp,
- int enable)
+ Tcl_Interp * interp, /* The Tcl interpreter to receive the
+ * variable.*/
+ int enable) /* Initial value. */
{
static Boolean initialized = FALSE;
- static UInt32 (*swaptextflags)(UInt32) = NULL;
- if(!initialized) {
- swaptextflags = TkMacOSXGetNamedSymbol("QD", "_QDSwapTextFlags");
- if (!swaptextflags) {
- swaptextflags = TkMacOSXGetNamedSymbol("QD", "_SwapQDTextFlags");
- }
+ if (!initialized) {
initialized = TRUE;
- TkMacOSXAntialiasedTextEnabled = (swaptextflags ? enable : FALSE);
if (Tcl_CreateNamespace(interp, "::tk::mac", NULL, NULL) == NULL) {
Tcl_ResetResult(interp);
}
- if (Tcl_TraceVar(interp, "::tk::mac::antialiasedtext",
- TCL_GLOBAL_ONLY | TCL_TRACE_WRITES,
- TkMacOSXAntialiasedTextVariableProc, NULL) != TCL_OK) {
- Tcl_ResetResult(interp);
- }
if (Tcl_LinkVar(interp, "::tk::mac::antialiasedtext",
- (char *) &TkMacOSXAntialiasedTextEnabled,
- TCL_LINK_BOOLEAN) != TCL_OK) {
+ (char *) &antialiasedTextEnabled,
+ TCL_LINK_INT) != TCL_OK) {
Tcl_ResetResult(interp);
}
}
- if (swaptextflags) {
- swaptextflags(enable ? kQDUseCGTextRendering | kQDUseCGTextMetrics
- : kQDUseTrueTypeScalerGlyphs);
- TkMacOSXAntialiasedTextEnabled = enable;
- return TCL_OK;
- } else {
- TkMacOSXAntialiasedTextEnabled = FALSE;
- return TCL_ERROR;
- }
+ antialiasedTextEnabled = enable;
+ return TCL_OK;
}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 79
+ * coding: utf-8
+ * End:
+ */