diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/macfont.m | 201 |
1 files changed, 166 insertions, 35 deletions
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, | |||
| 897 | return entity; | 897 | return entity; |
| 898 | } | 898 | } |
| 899 | 899 | ||
| 900 | /* Cache for font family name symbols vs CFStrings. A value of nil | ||
| 901 | means the cache has been invalidated. Otherwise the value is a Lisp | ||
| 902 | hash table whose keys are symbols and the value for a key is either | ||
| 903 | nil (no corresponding family name) or a Lisp save value wrapping the | ||
| 904 | corresponding family name in CFString. */ | ||
| 905 | |||
| 906 | static Lisp_Object macfont_family_cache; | ||
| 907 | |||
| 908 | static void | ||
| 909 | macfont_invalidate_family_cache (void) | ||
| 910 | { | ||
| 911 | if (HASH_TABLE_P (macfont_family_cache)) | ||
| 912 | { | ||
| 913 | struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache); | ||
| 914 | ptrdiff_t i, size = HASH_TABLE_SIZE (h); | ||
| 915 | |||
| 916 | for (i = 0; i < size; ++i) | ||
| 917 | if (!NILP (HASH_HASH (h, i))) | ||
| 918 | { | ||
| 919 | Lisp_Object value = HASH_VALUE (h, i); | ||
| 920 | |||
| 921 | if (SAVE_VALUEP (value)) | ||
| 922 | CFRelease (XSAVE_POINTER (value, 0)); | ||
| 923 | } | ||
| 924 | macfont_family_cache = Qnil; | ||
| 925 | } | ||
| 926 | } | ||
| 927 | |||
| 928 | static bool | ||
| 929 | macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string) | ||
| 930 | { | ||
| 931 | if (HASH_TABLE_P (macfont_family_cache)) | ||
| 932 | { | ||
| 933 | struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache); | ||
| 934 | ptrdiff_t i = hash_lookup (h, symbol, NULL); | ||
| 935 | |||
| 936 | if (i >= 0) | ||
| 937 | { | ||
| 938 | Lisp_Object value = HASH_VALUE (h, i); | ||
| 939 | |||
| 940 | *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL; | ||
| 941 | |||
| 942 | return true; | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | return false; | ||
| 947 | } | ||
| 948 | |||
| 949 | static void | ||
| 950 | macfont_set_family_cache (Lisp_Object symbol, CFStringRef string) | ||
| 951 | { | ||
| 952 | struct Lisp_Hash_Table *h; | ||
| 953 | ptrdiff_t i; | ||
| 954 | EMACS_UINT hash; | ||
| 955 | Lisp_Object value; | ||
| 956 | |||
| 957 | if (!HASH_TABLE_P (macfont_family_cache)) | ||
| 958 | { | ||
| 959 | Lisp_Object args[2]; | ||
| 960 | |||
| 961 | args[0] = QCtest; | ||
| 962 | args[1] = Qeq; | ||
| 963 | macfont_family_cache = Fmake_hash_table (2, args); | ||
| 964 | } | ||
| 965 | |||
| 966 | h = XHASH_TABLE (macfont_family_cache); | ||
| 967 | i = hash_lookup (h, symbol, &hash); | ||
| 968 | value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil; | ||
| 969 | if (i >= 0) | ||
| 970 | { | ||
| 971 | Lisp_Object old_value = HASH_VALUE (h, i); | ||
| 972 | |||
| 973 | if (SAVE_VALUEP (old_value)) | ||
| 974 | CFRelease (XSAVE_POINTER (old_value, 0)); | ||
| 975 | set_hash_value_slot (h, i, value); | ||
| 976 | } | ||
| 977 | else | ||
| 978 | hash_put (h, symbol, value, hash); | ||
| 979 | } | ||
| 980 | |||
| 981 | /* Cache of all the available font family names except "LastResort" | ||
| 982 | and those start with ".". NULL means the cache has been invalidated. | ||
| 983 | Otherwise, the value is CFArray of CFStrings and the elements are | ||
| 984 | sorted in the canonical order (CTFontManagerCompareFontFamilyNames on | ||
| 985 | OS X 10.6 and later). */ | ||
| 986 | |||
| 987 | static CFArrayRef macfont_available_families_cache = NULL; | ||
| 988 | |||
| 989 | static void | ||
| 990 | macfont_invalidate_available_families_cache (void) | ||
| 991 | { | ||
| 992 | if (macfont_available_families_cache) | ||
| 993 | { | ||
| 994 | CFRelease (macfont_available_families_cache); | ||
| 995 | macfont_available_families_cache = NULL; | ||
| 996 | } | ||
| 997 | } | ||
| 998 | |||
| 999 | static void | ||
| 1000 | macfont_handle_font_change_notification (CFNotificationCenterRef center, | ||
| 1001 | void *observer, | ||
| 1002 | CFStringRef name, const void *object, | ||
| 1003 | CFDictionaryRef userInfo) | ||
| 1004 | { | ||
| 1005 | macfont_invalidate_family_cache (); | ||
| 1006 | macfont_invalidate_available_families_cache (); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static void | ||
| 1010 | macfont_init_font_change_handler (void) | ||
| 1011 | { | ||
| 1012 | static bool initialized = false; | ||
| 1013 | |||
| 1014 | if (initialized) | ||
| 1015 | return; | ||
| 1016 | |||
| 1017 | initialized = true; | ||
| 1018 | CFNotificationCenterAddObserver | ||
| 1019 | (CFNotificationCenterGetLocalCenter (), NULL, | ||
| 1020 | macfont_handle_font_change_notification, | ||
| 1021 | kCTFontManagerRegisteredFontsChangedNotification, | ||
| 1022 | NULL, CFNotificationSuspensionBehaviorCoalesce); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static CFArrayRef | ||
| 1026 | macfont_copy_available_families_cache (void) | ||
| 1027 | { | ||
| 1028 | macfont_init_font_change_handler (); | ||
| 1029 | |||
| 1030 | if (macfont_available_families_cache == NULL) | ||
| 1031 | macfont_available_families_cache = mac_font_create_available_families (); | ||
| 1032 | |||
| 1033 | return (macfont_available_families_cache | ||
| 1034 | ? CFRetain (macfont_available_families_cache) : NULL); | ||
| 1035 | } | ||
| 1036 | |||
| 900 | static CFStringRef | 1037 | static CFStringRef |
| 901 | macfont_create_family_with_symbol (Lisp_Object symbol) | 1038 | macfont_create_family_with_symbol (Lisp_Object symbol) |
| 902 | { | 1039 | { |
| 903 | static CFArrayRef families = NULL; | ||
| 904 | CFStringRef result = NULL, family_name; | 1040 | CFStringRef result = NULL, family_name; |
| 905 | int using_cache_p = 1; | ||
| 906 | CFComparatorFunction family_name_comparator; | 1041 | CFComparatorFunction family_name_comparator; |
| 907 | 1042 | ||
| 1043 | if (macfont_get_family_cache_if_present (symbol, &result)) | ||
| 1044 | return result ? CFRetain (result) : NULL; | ||
| 1045 | |||
| 908 | family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol)); | 1046 | family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol)); |
| 909 | if (family_name == NULL) | 1047 | if (family_name == NULL) |
| 910 | return NULL; | 1048 | return NULL; |
| @@ -917,42 +1055,32 @@ macfont_create_family_with_symbol (Lisp_Object symbol) | |||
| 917 | == kCFCompareEqualTo) | 1055 | == kCFCompareEqualTo) |
| 918 | result = CFSTR ("LastResort"); | 1056 | result = CFSTR ("LastResort"); |
| 919 | else | 1057 | else |
| 920 | while (1) | 1058 | { |
| 921 | { | 1059 | CFIndex i, count; |
| 922 | CFIndex i, count; | 1060 | CFArrayRef families = macfont_copy_available_families_cache (); |
| 923 | |||
| 924 | if (families == NULL) | ||
| 925 | { | ||
| 926 | families = mac_font_create_available_families (); | ||
| 927 | using_cache_p = 0; | ||
| 928 | if (families == NULL) | ||
| 929 | break; | ||
| 930 | } | ||
| 931 | |||
| 932 | count = CFArrayGetCount (families); | ||
| 933 | i = CFArrayBSearchValues (families, CFRangeMake (0, count), | ||
| 934 | (const void *) family_name, | ||
| 935 | family_name_comparator, NULL); | ||
| 936 | if (i < count) | ||
| 937 | { | ||
| 938 | CFStringRef name = CFArrayGetValueAtIndex (families, i); | ||
| 939 | 1061 | ||
| 940 | if ((*family_name_comparator) (name, family_name, NULL) | 1062 | if (families) |
| 941 | == kCFCompareEqualTo) | 1063 | { |
| 942 | result = CFRetain (name); | 1064 | count = CFArrayGetCount (families); |
| 943 | } | 1065 | i = CFArrayBSearchValues (families, CFRangeMake (0, count), |
| 1066 | (const void *) family_name, | ||
| 1067 | family_name_comparator, NULL); | ||
| 1068 | if (i < count) | ||
| 1069 | { | ||
| 1070 | CFStringRef name = CFArrayGetValueAtIndex (families, i); | ||
| 944 | 1071 | ||
| 945 | if (result || !using_cache_p) | 1072 | if ((*family_name_comparator) (name, family_name, NULL) |
| 946 | break; | 1073 | == kCFCompareEqualTo) |
| 947 | else | 1074 | result = CFRetain (name); |
| 948 | { | 1075 | } |
| 949 | CFRelease (families); | 1076 | CFRelease (families); |
| 950 | families = NULL; | 1077 | } |
| 951 | } | 1078 | } |
| 952 | } | ||
| 953 | 1079 | ||
| 954 | CFRelease (family_name); | 1080 | CFRelease (family_name); |
| 955 | 1081 | ||
| 1082 | macfont_set_family_cache (symbol, result); | ||
| 1083 | |||
| 956 | return result; | 1084 | return result; |
| 957 | } | 1085 | } |
| 958 | 1086 | ||
| @@ -2091,7 +2219,7 @@ macfont_list (struct frame *f, Lisp_Object spec) | |||
| 2091 | CFStringRef pref_family; | 2219 | CFStringRef pref_family; |
| 2092 | CFIndex families_count, pref_family_index = -1; | 2220 | CFIndex families_count, pref_family_index = -1; |
| 2093 | 2221 | ||
| 2094 | families = mac_font_create_available_families (); | 2222 | families = macfont_copy_available_families_cache (); |
| 2095 | if (families == NULL) | 2223 | if (families == NULL) |
| 2096 | goto err; | 2224 | goto err; |
| 2097 | 2225 | ||
| @@ -2380,7 +2508,7 @@ macfont_list_family (struct frame *frame) | |||
| 2380 | 2508 | ||
| 2381 | block_input (); | 2509 | block_input (); |
| 2382 | 2510 | ||
| 2383 | families = mac_font_create_available_families (); | 2511 | families = macfont_copy_available_families_cache (); |
| 2384 | if (families) | 2512 | if (families) |
| 2385 | { | 2513 | { |
| 2386 | CFIndex i, count = CFArrayGetCount (families); | 2514 | CFIndex i, count = CFArrayGetCount (families); |
| @@ -3923,4 +4051,7 @@ syms_of_macfont (void) | |||
| 3923 | 4051 | ||
| 3924 | /* The boolean-valued font property key specifying the use of leading. */ | 4052 | /* The boolean-valued font property key specifying the use of leading. */ |
| 3925 | DEFSYM (QCminspace, ":minspace"); | 4053 | DEFSYM (QCminspace, ":minspace"); |
| 4054 | |||
| 4055 | macfont_family_cache = Qnil; | ||
| 4056 | staticpro (&macfont_family_cache); | ||
| 3926 | } | 4057 | } |