/* Font driver on Mac OSX Core text.
- Copyright (C) 2009-2014 Free Software Foundation, Inc.
+ Copyright (C) 2009-2015 Free Software Foundation, Inc.
This file is part of GNU Emacs.
static struct font_driver macfont_driver;
-/* Core Text, for Mac OS X. */
-static Lisp_Object Qmac_ct;
-
static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
static CFArrayRef mac_ctfont_create_available_families (void);
CGFontIndex);
#endif
-/* The font property key specifying the font design destination. The
- value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
- text. (See the documentation of X Logical Font Description
- Conventions.) In the Mac font driver, 1 means the screen font is
- used for calculating some glyph metrics. You can see the
- difference with Monaco 8pt or 9pt, for example. */
-static Lisp_Object QCdestination;
-
-/* The boolean-valued font property key specifying the use of
- leading. */
-static Lisp_Object QCminspace;
-
struct macfont_metrics;
/* The actual structure for Mac font that can be cast to struct font. */
return entity;
}
+/* Cache for font family name symbols vs CFStrings. A value of nil
+means the cache has been invalidated. Otherwise the value is a Lisp
+hash table whose keys are symbols and the value for a key is either
+nil (no corresponding family name) or a Lisp save value wrapping the
+corresponding family name in CFString. */
+
+static Lisp_Object macfont_family_cache;
+
+static void
+macfont_invalidate_family_cache (void)
+{
+ if (HASH_TABLE_P (macfont_family_cache))
+ {
+ struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
+ ptrdiff_t i, size = HASH_TABLE_SIZE (h);
+
+ for (i = 0; i < size; ++i)
+ if (!NILP (HASH_HASH (h, i)))
+ {
+ Lisp_Object value = HASH_VALUE (h, i);
+
+ if (SAVE_VALUEP (value))
+ CFRelease (XSAVE_POINTER (value, 0));
+ }
+ macfont_family_cache = Qnil;
+ }
+}
+
+static bool
+macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
+{
+ if (HASH_TABLE_P (macfont_family_cache))
+ {
+ struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
+ ptrdiff_t i = hash_lookup (h, symbol, NULL);
+
+ if (i >= 0)
+ {
+ Lisp_Object value = HASH_VALUE (h, i);
+
+ *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void
+macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
+{
+ struct Lisp_Hash_Table *h;
+ ptrdiff_t i;
+ EMACS_UINT hash;
+ Lisp_Object value;
+
+ if (!HASH_TABLE_P (macfont_family_cache))
+ {
+ Lisp_Object args[2];
+
+ args[0] = QCtest;
+ args[1] = Qeq;
+ macfont_family_cache = Fmake_hash_table (2, args);
+ }
+
+ h = XHASH_TABLE (macfont_family_cache);
+ i = hash_lookup (h, symbol, &hash);
+ value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
+ if (i >= 0)
+ {
+ Lisp_Object old_value = HASH_VALUE (h, i);
+
+ if (SAVE_VALUEP (old_value))
+ CFRelease (XSAVE_POINTER (old_value, 0));
+ set_hash_value_slot (h, i, value);
+ }
+ else
+ hash_put (h, symbol, value, hash);
+}
+
+/* Cache of all the available font family names except "LastResort"
+and those start with ".". NULL means the cache has been invalidated.
+Otherwise, the value is CFArray of CFStrings and the elements are
+sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
+OS X 10.6 and later). */
+
+static CFArrayRef macfont_available_families_cache = NULL;
+
+static void
+macfont_invalidate_available_families_cache (void)
+{
+ if (macfont_available_families_cache)
+ {
+ CFRelease (macfont_available_families_cache);
+ macfont_available_families_cache = NULL;
+ }
+}
+
+static void
+macfont_handle_font_change_notification (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name, const void *object,
+ CFDictionaryRef userInfo)
+{
+ macfont_invalidate_family_cache ();
+ macfont_invalidate_available_families_cache ();
+}
+
+static void
+macfont_init_font_change_handler (void)
+{
+ static bool initialized = false;
+
+ if (initialized)
+ return;
+
+ initialized = true;
+ CFNotificationCenterAddObserver
+ (CFNotificationCenterGetLocalCenter (), NULL,
+ macfont_handle_font_change_notification,
+ kCTFontManagerRegisteredFontsChangedNotification,
+ NULL, CFNotificationSuspensionBehaviorCoalesce);
+}
+
+static CFArrayRef
+macfont_copy_available_families_cache (void)
+{
+ macfont_init_font_change_handler ();
+
+ if (macfont_available_families_cache == NULL)
+ macfont_available_families_cache = mac_font_create_available_families ();
+
+ return (macfont_available_families_cache
+ ? CFRetain (macfont_available_families_cache) : NULL);
+}
+
static CFStringRef
macfont_create_family_with_symbol (Lisp_Object symbol)
{
- static CFArrayRef families = NULL;
CFStringRef result = NULL, family_name;
- int using_cache_p = 1;
CFComparatorFunction family_name_comparator;
+ if (macfont_get_family_cache_if_present (symbol, &result))
+ return result ? CFRetain (result) : NULL;
+
family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
if (family_name == NULL)
return NULL;
== kCFCompareEqualTo)
result = CFSTR ("LastResort");
else
- while (1)
- {
- CFIndex i, count;
-
- if (families == NULL)
- {
- families = mac_font_create_available_families ();
- using_cache_p = 0;
- if (families == NULL)
- break;
- }
-
- count = CFArrayGetCount (families);
- i = CFArrayBSearchValues (families, CFRangeMake (0, count),
- (const void *) family_name,
- family_name_comparator, NULL);
- if (i < count)
- {
- CFStringRef name = CFArrayGetValueAtIndex (families, i);
+ {
+ CFIndex i, count;
+ CFArrayRef families = macfont_copy_available_families_cache ();
- if ((*family_name_comparator) (name, family_name, NULL)
- == kCFCompareEqualTo)
- result = CFRetain (name);
- }
+ if (families)
+ {
+ count = CFArrayGetCount (families);
+ i = CFArrayBSearchValues (families, CFRangeMake (0, count),
+ (const void *) family_name,
+ family_name_comparator, NULL);
+ if (i < count)
+ {
+ CFStringRef name = CFArrayGetValueAtIndex (families, i);
- if (result || !using_cache_p)
- break;
- else
- {
- CFRelease (families);
- families = NULL;
- }
- }
+ if ((*family_name_comparator) (name, family_name, NULL)
+ == kCFCompareEqualTo)
+ result = CFRetain (name);
+ }
+ CFRelease (families);
+ }
+ }
CFRelease (family_name);
+ macfont_set_family_cache (symbol, result);
+
return result;
}
CFStringRef pref_family;
CFIndex families_count, pref_family_index = -1;
- families = mac_font_create_available_families ();
+ families = macfont_copy_available_families_cache ();
if (families == NULL)
goto err;
}
CFRelease (pat_desc);
if (! descs)
- goto err;
+ continue;
descs_count = CFArrayGetCount (descs);
if (descs_count == 0
block_input ();
- families = mac_font_create_available_families ();
+ families = macfont_copy_available_families_cache ();
if (families)
{
CFIndex i, count = CFArrayGetCount (families);
static Lisp_Object
macfont_shape (Lisp_Object lgstring)
{
- struct font *font;
- struct macfont_info *macfont_info;
- FontRef macfont;
+ struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+ struct macfont_info *macfont_info = (struct macfont_info *) font;
+ FontRef macfont = macfont_info->macfont;
ptrdiff_t glyph_len, len, i, j;
CFIndex nonbmp_len;
UniChar *unichars;
CFIndex used = 0;
struct mac_glyph_layout *glyph_layouts;
- CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
- macfont_info = (struct macfont_info *) font;
- macfont = macfont_info->macfont;
-
glyph_len = LGSTRING_GLYPH_LEN (lgstring);
nonbmp_len = 0;
for (i = 0; i < glyph_len; i++)
static inline double
mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
{
- return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
- &glyph, NULL, 1);
+ return CTFontGetAdvancesForGlyphs (font,
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+ kCTFontOrientationDefault,
+#else
+ kCTFontDefaultOrientation,
+#endif
+ &glyph, NULL, 1);
}
static inline CGRect
mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
{
- return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
- &glyph, NULL, 1);
+ return CTFontGetBoundingRectsForGlyphs (font,
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+ kCTFontOrientationDefault,
+#else
+ kCTFontDefaultOrientation,
+#endif
+ &glyph, NULL, 1);
}
static CFArrayRef
#endif
{
CTFontRef user_font =
- CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
+ CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
if (user_font)
{
{
static struct font_driver mac_font_driver;
+ /* Core Text, for Mac OS X. */
DEFSYM (Qmac_ct, "mac-ct");
macfont_driver.type = Qmac_ct;
register_font_driver (&macfont_driver, NULL);
+ /* The font property key specifying the font design destination. The
+ value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
+ text. (See the documentation of X Logical Font Description
+ Conventions.) In the Mac font driver, 1 means the screen font is
+ used for calculating some glyph metrics. You can see the
+ difference with Monaco 8pt or 9pt, for example. */
DEFSYM (QCdestination, ":destination");
+
+ /* The boolean-valued font property key specifying the use of leading. */
DEFSYM (QCminspace, ":minspace");
+
+ macfont_family_cache = Qnil;
+ staticpro (&macfont_family_cache);
}