From: YAMAMOTO Mitsuharu Date: Mon, 13 Jul 2015 09:55:47 +0000 (+0900) Subject: Cache font family in mac-ct font backend driver X-Git-Tag: emacs-25.0.90~1495 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=455fe1a7f1cf5cf6b7f1fc99bb8b05c633503c1d;p=emacs.git Cache font family in mac-ct font backend driver * src/macfont.m (macfont_family_cache): New variable. (syms_of_macfont): Initialize it. (macfont_available_families_cache): New variable. (macfont_invalidate_family_cache, macfont_get_family_cache_if_present) (macfont_set_family_cache, macfont_invalidate_available_families_cache) (macfont_handle_font_change_notification) (macfont_init_font_change_handler) (macfont_copy_available_families_cache): New functions. (macfont_create_family_with_symbol): Use font family caches. (macfont_list, macfont_list_family): Use macfont_copy_available_families_cache instead of mac_font_create_available_families. --- diff --git a/src/macfont.m b/src/macfont.m index cbf1ab8e55d..b25640e0cb8 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -897,14 +897,152 @@ macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra, 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; @@ -917,42 +1055,32 @@ macfont_create_family_with_symbol (Lisp_Object symbol) == 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; } @@ -2091,7 +2219,7 @@ macfont_list (struct frame *f, Lisp_Object spec) 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; @@ -2380,7 +2508,7 @@ macfont_list_family (struct frame *frame) block_input (); - families = mac_font_create_available_families (); + families = macfont_copy_available_families_cache (); if (families) { CFIndex i, count = CFArrayGetCount (families); @@ -3923,4 +4051,7 @@ syms_of_macfont (void) /* The boolean-valued font property key specifying the use of leading. */ DEFSYM (QCminspace, ":minspace"); + + macfont_family_cache = Qnil; + staticpro (&macfont_family_cache); }