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.
This commit is contained in:
YAMAMOTO Mitsuharu 2015-07-13 18:55:47 +09:00
parent 64d09655cf
commit 455fe1a7f1

View file

@ -897,14 +897,152 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
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 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
== kCFCompareEqualTo)
result = CFSTR ("LastResort");
else
while (1)
{
CFIndex i, count;
{
CFIndex i, count;
CFArrayRef families = macfont_copy_available_families_cache ();
if (families == NULL)
{
families = mac_font_create_available_families ();
using_cache_p = 0;
if (families == NULL)
break;
}
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);
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 ((*family_name_comparator) (name, family_name, NULL)
== kCFCompareEqualTo)
result = CFRetain (name);
}
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 @@ static int macfont_variation_glyphs (struct font *, int c,
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 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
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 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
/* The boolean-valued font property key specifying the use of leading. */
DEFSYM (QCminspace, ":minspace");
macfont_family_cache = Qnil;
staticpro (&macfont_family_cache);
}