comparison src/specifier.c @ 4426:515b91f904c1

Fix specifier inheritance behavior This patch ensures that no fallback is used if so requested, when the specifier instantiation process involves inheritance (for instance, a face [property] inheriting from another face [property]).
author Didier Verna <didier@xemacs.org>
date Tue, 26 Feb 2008 18:02:34 +0100
parents edaaf9a96d40
children 11357f7846bf
comparison
equal deleted inserted replaced
4425:bfb8a26de3cb 4426:515b91f904c1
245 { 245 {
246 if (! marked_p (rest)) 246 if (! marked_p (rest))
247 { 247 {
248 Lisp_Specifier* sp = XSPECIFIER (rest); 248 Lisp_Specifier* sp = XSPECIFIER (rest);
249 /* A bit of assertion that we're removing both parts of the 249 /* A bit of assertion that we're removing both parts of the
250 magic one altogether */ 250 magic one altogether */
251 assert (!MAGIC_SPECIFIER_P(sp) 251 assert (!MAGIC_SPECIFIER_P(sp)
252 || (BODILY_SPECIFIER_P(sp) && marked_p (sp->fallback)) 252 || (BODILY_SPECIFIER_P(sp) && marked_p (sp->fallback))
253 || (GHOST_SPECIFIER_P(sp) && marked_p (sp->magic_parent))); 253 || (GHOST_SPECIFIER_P(sp) && marked_p (sp->magic_parent)));
254 /* This specifier is garbage. Remove it from the list. */ 254 /* This specifier is garbage. Remove it from the list. */
255 if (NILP (prev)) 255 if (NILP (prev))
384 static const struct memory_description specifier_caching_description_1[] = { 384 static const struct memory_description specifier_caching_description_1[] = {
385 { XD_END } 385 { XD_END }
386 }; 386 };
387 387
388 #ifdef NEW_GC 388 #ifdef NEW_GC
389 DEFINE_LRECORD_IMPLEMENTATION ("specifier-caching", 389 DEFINE_LRECORD_IMPLEMENTATION ("specifier-caching",
390 specifier_caching, 390 specifier_caching,
391 1, /*dumpable-flag*/ 391 1, /*dumpable-flag*/
392 0, 0, 0, 0, 0, 392 0, 0, 0, 0, 0,
393 specifier_caching_description_1, 393 specifier_caching_description_1,
394 struct specifier_caching); 394 struct specifier_caching);
395 #else /* not NEW_GC */ 395 #else /* not NEW_GC */
396 static const struct sized_memory_description specifier_caching_description = { 396 static const struct sized_memory_description specifier_caching_description = {
397 sizeof (struct specifier_caching), 397 sizeof (struct specifier_caching),
693 /* #### get image instances out of domains! */ 693 /* #### get image instances out of domains! */
694 IMAGE_INSTANCEP (domain)) 694 IMAGE_INSTANCEP (domain))
695 ? Qt : Qnil; 695 ? Qt : Qnil;
696 } 696 }
697 697
698 DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1, 698 DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1,
699 1, 0, /* 699 1, 0, /*
700 Given a specifier LOCALE-TYPE, return non-nil if it is valid. 700 Given a specifier LOCALE-TYPE, return non-nil if it is valid.
701 Valid locale types are `global', `device', `frame', `window', and `buffer'. 701 Valid locale types are `global', `device', `frame', `window', and `buffer'.
702 \(Note, however, that in functions that accept either a locale or a locale 702 \(Note, however, that in functions that accept either a locale or a locale
703 type, `global' is considered an individual locale.) 703 type, `global' is considered an individual locale.)
981 return 1; 981 return 1;
982 } 982 }
983 983
984 static int 984 static int
985 charset_matches_specifier_tag_set_p (Lisp_Object charset, 985 charset_matches_specifier_tag_set_p (Lisp_Object charset,
986 Lisp_Object tag_set, 986 Lisp_Object tag_set,
987 enum font_specifier_matchspec_stages 987 enum font_specifier_matchspec_stages
988 stage) 988 stage)
989 { 989 {
990 Lisp_Object rest; 990 Lisp_Object rest;
991 int res = 0; 991 int res = 0;
992 992
996 { 996 {
997 Lisp_Object tag = XCAR (rest); 997 Lisp_Object tag = XCAR (rest);
998 Lisp_Object assoc; 998 Lisp_Object assoc;
999 999
1000 /* In the event that, during the creation of a charset, no specifier 1000 /* In the event that, during the creation of a charset, no specifier
1001 tags exist for which CHARSET-PREDICATE has been specified, then 1001 tags exist for which CHARSET-PREDICATE has been specified, then
1002 that charset's entry in Vcharset_tag_lists will be nil, and this 1002 that charset's entry in Vcharset_tag_lists will be nil, and this
1003 charset shouldn't match. */ 1003 charset shouldn't match. */
1004 1004
1005 if (NILP (XVECTOR_DATA(Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset) 1005 if (NILP (XVECTOR_DATA(Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset)
1006 - MIN_LEADING_BYTE])) 1006 - MIN_LEADING_BYTE]))
1007 { 1007 {
1008 return 0; 1008 return 0;
1009 } 1009 }
1010 1010
1011 /* Now, find out what the pre-calculated value is. */ 1011 /* Now, find out what the pre-calculated value is. */
1012 assoc = assq_no_quit(tag, 1012 assoc = assq_no_quit(tag,
1013 XVECTOR_DATA(Vcharset_tag_lists) 1013 XVECTOR_DATA(Vcharset_tag_lists)
1014 [XCHARSET_LEADING_BYTE(charset) 1014 [XCHARSET_LEADING_BYTE(charset)
1015 - MIN_LEADING_BYTE]); 1015 - MIN_LEADING_BYTE]);
1016 1016
1017 if (!(NILP(assoc)) && !(NILP(XCDR(assoc)))) 1017 if (!(NILP(assoc)) && !(NILP(XCDR(assoc))))
1018 { 1018 {
1019 assert(VECTORP(XCDR(assoc))); 1019 assert(VECTORP(XCDR(assoc)));
1058 1058
1059 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil; 1059 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil;
1060 } 1060 }
1061 1061
1062 Lisp_Object 1062 Lisp_Object
1063 define_specifier_tag(Lisp_Object tag, Lisp_Object device_predicate, 1063 define_specifier_tag(Lisp_Object tag, Lisp_Object device_predicate,
1064 Lisp_Object charset_predicate) 1064 Lisp_Object charset_predicate)
1065 { 1065 {
1066 Lisp_Object assoc = assq_no_quit (tag, Vuser_defined_tags), 1066 Lisp_Object assoc = assq_no_quit (tag, Vuser_defined_tags),
1067 concons, devcons, charpres = Qnil; 1067 concons, devcons, charpres = Qnil;
1068 int recompute_devices = 0, recompute_charsets = 0, i, max_args = -1; 1068 int recompute_devices = 0, recompute_charsets = 0, i, max_args = -1;
1069 1069
1070 if (NILP (assoc)) 1070 if (NILP (assoc))
1071 { 1071 {
1072 recompute_devices = recompute_charsets = 1; 1072 recompute_devices = recompute_charsets = 1;
1073 Vuser_defined_tags = Fcons (list3 (tag, device_predicate, 1073 Vuser_defined_tags = Fcons (list3 (tag, device_predicate,
1074 charset_predicate), 1074 charset_predicate),
1075 Vuser_defined_tags); 1075 Vuser_defined_tags);
1076 DEVICE_LOOP_NO_BREAK (devcons, concons) 1076 DEVICE_LOOP_NO_BREAK (devcons, concons)
1077 { 1077 {
1078 struct device *d = XDEVICE (XCAR (devcons)); 1078 struct device *d = XDEVICE (XCAR (devcons));
1079 /* Initially set the value to t in case of error 1079 /* Initially set the value to t in case of error
1103 if (max_args < 1) 1103 if (max_args < 1)
1104 { 1104 {
1105 invalid_argument 1105 invalid_argument
1106 ("Charset predicate must be able to take an argument", tag); 1106 ("Charset predicate must be able to take an argument", tag);
1107 } 1107 }
1108 1108
1109 /* If there exists a charset_predicate for the tag currently (even if 1109 /* If there exists a charset_predicate for the tag currently (even if
1110 the new charset_predicate is nil), or if we're adding one, we need 1110 the new charset_predicate is nil), or if we're adding one, we need
1111 to recompute. This contrasts with the device predicates, where we 1111 to recompute. This contrasts with the device predicates, where we
1112 don't need to recompute if the old and new device predicates are 1112 don't need to recompute if the old and new device predicates are
1113 both nil. */ 1113 both nil. */
1137 XCDR (assoc) = !NILP (call1 (device_predicate, device)) ? Qt 1137 XCDR (assoc) = !NILP (call1 (device_predicate, device)) ? Qt
1138 : Qnil; 1138 : Qnil;
1139 } 1139 }
1140 } 1140 }
1141 1141
1142 if (recompute_charsets) 1142 if (recompute_charsets)
1143 { 1143 {
1144 if (NILP(charset_predicate)) 1144 if (NILP(charset_predicate))
1145 { 1145 {
1146 charpres = Qnil; 1146 charpres = Qnil;
1147 } 1147 }
1156 assoc = assq_no_quit (tag, 1156 assoc = assq_no_quit (tag,
1157 XVECTOR_DATA(Vcharset_tag_lists)[i]); 1157 XVECTOR_DATA(Vcharset_tag_lists)[i]);
1158 1158
1159 if (!NILP(charset_predicate)) 1159 if (!NILP(charset_predicate))
1160 { 1160 {
1161 struct gcpro gcpro1; 1161 struct gcpro gcpro1;
1162 charpres = make_vector(impossible, Qnil); 1162 charpres = make_vector(impossible, Qnil);
1163 GCPRO1 (charpres); 1163 GCPRO1 (charpres);
1164 1164
1165 /* If you want to extend the number of stages available, here 1165 /* If you want to extend the number of stages available, here
1166 in setup_charset_initial_specifier_tags, and in specifier.h 1166 in setup_charset_initial_specifier_tags, and in specifier.h
1167 is where you want to go. */ 1167 is where you want to go. */
1210 assert(CONSP(assoc)); 1210 assert(CONSP(assoc));
1211 XCDR (assoc) = charpres; 1211 XCDR (assoc) = charpres;
1212 } 1212 }
1213 else 1213 else
1214 { 1214 {
1215 XVECTOR_DATA(Vcharset_tag_lists)[i] 1215 XVECTOR_DATA(Vcharset_tag_lists)[i]
1216 = Fcons(Fcons(tag, charpres), 1216 = Fcons(Fcons(tag, charpres),
1217 XVECTOR_DATA (Vcharset_tag_lists)[i]); 1217 XVECTOR_DATA (Vcharset_tag_lists)[i]);
1218 } 1218 }
1219 } 1219 }
1220 } 1220 }
1221 return Qt; 1221 return Qt;
1308 GET_LIST_LENGTH(XCAR(rest), list_len); 1308 GET_LIST_LENGTH(XCAR(rest), list_len);
1309 1309
1310 assert(3 == list_len); 1310 assert(3 == list_len);
1311 1311
1312 device_predicate = XCADR(XCAR (rest)); 1312 device_predicate = XCADR(XCAR (rest));
1313 1313
1314 if (NILP (device_predicate)) 1314 if (NILP (device_predicate))
1315 { 1315 {
1316 XCDR (XCAR (rest2)) = Qt; 1316 XCDR (XCAR (rest2)) = Qt;
1317 } 1317 }
1318 else 1318 else
1319 { 1319 {
1320 device_predicate = !NILP (call_critical_lisp_code 1320 device_predicate = !NILP (call_critical_lisp_code
1321 (d, device_predicate, device)) 1321 (d, device_predicate, device))
1322 ? Qt : Qnil; 1322 ? Qt : Qnil;
1323 XCDR (XCAR (rest2)) = device_predicate; 1323 XCDR (XCAR (rest2)) = device_predicate;
1324 } 1324 }
1325 } 1325 }
1326 } 1326 }
1327 1327
1328 void 1328 void
1329 setup_charset_initial_specifier_tags (Lisp_Object charset) 1329 setup_charset_initial_specifier_tags (Lisp_Object charset)
1330 { 1330 {
1331 Lisp_Object rest, charset_predicate, tag, new_value; 1331 Lisp_Object rest, charset_predicate, tag, new_value;
1332 Lisp_Object charset_tag_list = Qnil; 1332 Lisp_Object charset_tag_list = Qnil;
1333 1333
1334 LIST_LOOP (rest, Vuser_defined_tags) 1334 LIST_LOOP (rest, Vuser_defined_tags)
1335 { 1335 {
1336 tag = XCAR(XCAR(rest)); 1336 tag = XCAR(XCAR(rest));
1337 charset_predicate = XCADDR(XCAR (rest)); 1337 charset_predicate = XCADDR(XCAR (rest));
1360 XVECTOR_DATA(new_value)[stage] = Qt; \ 1360 XVECTOR_DATA(new_value)[stage] = Qt; \
1361 } \ 1361 } \
1362 \ 1362 \
1363 } while (0) 1363 } while (0)
1364 1364
1365 SETUP_CHARSET_TAGS_FROB (initial); 1365 SETUP_CHARSET_TAGS_FROB (initial);
1366 SETUP_CHARSET_TAGS_FROB (final); 1366 SETUP_CHARSET_TAGS_FROB (final);
1367 /* More later? */ 1367 /* More later? */
1368 1368
1369 #undef SETUP_CHARSET_TAGS_FROB 1369 #undef SETUP_CHARSET_TAGS_FROB
1370 1370
2323 ((LOCALE (TAG-SET . INSTANTIATOR) ...) ...) 2323 ((LOCALE (TAG-SET . INSTANTIATOR) ...) ...)
2324 2324
2325 where 2325 where
2326 LOCALE := a window, a buffer, a frame, a device, or `global' 2326 LOCALE := a window, a buffer, a frame, a device, or `global'
2327 TAG-SET := an unordered list of zero or more TAGS, each of which 2327 TAG-SET := an unordered list of zero or more TAGS, each of which
2328 is a symbol 2328 is a symbol
2329 TAG := a device class (see `valid-device-class-p'), a device type 2329 TAG := a device class (see `valid-device-class-p'), a device type
2330 (see `valid-console-type-p'), or a tag defined with 2330 (see `valid-console-type-p'), or a tag defined with
2331 `define-specifier-tag' 2331 `define-specifier-tag'
2332 INSTANTIATOR := format determined by the type of specifier 2332 INSTANTIATOR := format determined by the type of specifier
2333 2333
2334 The pair (TAG-SET . INSTANTIATOR) is called an `inst-pair'. 2334 The pair (TAG-SET . INSTANTIATOR) is called an `inst-pair'.
2335 A list of inst-pairs is called an `inst-list'. 2335 A list of inst-pairs is called an `inst-list'.
2336 The pair (LOCALE . INST-LIST) is called a `specification' or `spec'. 2336 The pair (LOCALE . INST-LIST) is called a `specification' or `spec'.
2802 Lisp_Object matchspec, 2802 Lisp_Object matchspec,
2803 Lisp_Object domain, 2803 Lisp_Object domain,
2804 Lisp_Object inst_list, 2804 Lisp_Object inst_list,
2805 Error_Behavior errb, int no_quit, 2805 Error_Behavior errb, int no_quit,
2806 Lisp_Object depth, 2806 Lisp_Object depth,
2807 Lisp_Object *instantiator) 2807 Lisp_Object *instantiator,
2808 int no_fallback)
2808 { 2809 {
2809 /* This function can GC */ 2810 /* This function can GC */
2810 Lisp_Specifier *sp; 2811 Lisp_Specifier *sp;
2811 Lisp_Object device, charset = Qnil, rest; 2812 Lisp_Object device, charset = Qnil, rest;
2812 int count = specpdl_depth (), respected_charsets = 0; 2813 int count = specpdl_depth (), respected_charsets = 0;
2864 Lisp_Object tag_set = XCAR (tagged_inst); 2865 Lisp_Object tag_set = XCAR (tagged_inst);
2865 Lisp_Object val, the_instantiator; 2866 Lisp_Object val, the_instantiator;
2866 2867
2867 if (!device_matches_specifier_tag_set_p (device, tag_set)) 2868 if (!device_matches_specifier_tag_set_p (device, tag_set))
2868 { 2869 {
2869 continue; 2870 continue;
2870 } 2871 }
2871 2872
2872 val = XCDR (tagged_inst); 2873 val = XCDR (tagged_inst);
2873 the_instantiator = val; 2874 the_instantiator = val;
2874 2875
2881 2882
2882 if (HAS_SPECMETH_P (sp, instantiate)) 2883 if (HAS_SPECMETH_P (sp, instantiate))
2883 val = call_with_suspended_errors 2884 val = call_with_suspended_errors
2884 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), 2885 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate),
2885 Qunbound, Qspecifier, errb, 5, specifier, 2886 Qunbound, Qspecifier, errb, 5, specifier,
2886 matchspec, domain, val, depth); 2887 matchspec, domain, val, depth, no_fallback);
2887 2888
2888 if (!UNBOUNDP (val)) 2889 if (!UNBOUNDP (val))
2889 { 2890 {
2890 unbind_to (count); 2891 unbind_to (count);
2891 UNGCPRO; 2892 UNGCPRO;
2920 Lisp_Object tag_set = XCAR (tagged_inst); 2921 Lisp_Object tag_set = XCAR (tagged_inst);
2921 Lisp_Object val, the_instantiator; 2922 Lisp_Object val, the_instantiator;
2922 2923
2923 if (!device_matches_specifier_tag_set_p (device, tag_set)) 2924 if (!device_matches_specifier_tag_set_p (device, tag_set))
2924 { 2925 {
2925 continue; 2926 continue;
2926 } 2927 }
2927 2928
2928 val = XCDR (tagged_inst); 2929 val = XCDR (tagged_inst);
2929 the_instantiator = val; 2930 the_instantiator = val;
2930 2931
2931 if (HAS_SPECMETH_P (sp, instantiate)) 2932 if (HAS_SPECMETH_P (sp, instantiate))
2932 val = call_with_suspended_errors 2933 val = call_with_suspended_errors
2933 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), 2934 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate),
2934 Qunbound, Qspecifier, errb, 5, specifier, 2935 Qunbound, Qspecifier, errb, 5, specifier,
2935 matchspec, domain, val, depth); 2936 matchspec, domain, val, depth, no_fallback);
2936 2937
2937 if (!UNBOUNDP (val)) 2938 if (!UNBOUNDP (val))
2938 { 2939 {
2939 unbind_to (count); 2940 unbind_to (count);
2940 UNGCPRO; 2941 UNGCPRO;
2961 { \ 2962 { \
2962 Lisp_Object CIE_val = \ 2963 Lisp_Object CIE_val = \
2963 specifier_instance_from_inst_list (specifier, matchspec, \ 2964 specifier_instance_from_inst_list (specifier, matchspec, \
2964 domain, *CIE_inst_list, \ 2965 domain, *CIE_inst_list, \
2965 errb, no_quit, depth, \ 2966 errb, no_quit, depth, \
2966 instantiator); \ 2967 instantiator, no_fallback); \
2967 if (!UNBOUNDP (CIE_val)) \ 2968 if (!UNBOUNDP (CIE_val)) \
2968 return CIE_val; \ 2969 return CIE_val; \
2969 } \ 2970 } \
2970 } while (0) 2971 } while (0)
2971 2972
3073 } 3074 }
3074 3075
3075 assert (CONSP (sp->fallback)); 3076 assert (CONSP (sp->fallback));
3076 return specifier_instance_from_inst_list (specifier, matchspec, domain, 3077 return specifier_instance_from_inst_list (specifier, matchspec, domain,
3077 sp->fallback, errb, no_quit, 3078 sp->fallback, errb, no_quit,
3078 depth, instantiator); 3079 depth, instantiator,
3080 no_fallback);
3079 } 3081 }
3080 #undef CHECK_INSTANCE_ENTRY 3082 #undef CHECK_INSTANCE_ENTRY
3081 3083
3082 Lisp_Object 3084 Lisp_Object
3083 specifier_instance (Lisp_Object specifier, Lisp_Object matchspec, 3085 specifier_instance (Lisp_Object specifier, Lisp_Object matchspec,
3243 e.g., a buffer-local display table that only gives values for particular 3245 e.g., a buffer-local display table that only gives values for particular
3244 characters. All other characters are handled as if the buffer-local 3246 characters. All other characters are handled as if the buffer-local
3245 display table is not there. (Chartable specifiers are not yet 3247 display table is not there. (Chartable specifiers are not yet
3246 implemented.) 3248 implemented.)
3247 3249
3248 -- For font specifiers, MATCHSPEC should be a cons (CHARSET . STAGE). 3250 -- For font specifiers, MATCHSPEC should be a cons (CHARSET . STAGE).
3249 The defined stages are currently `initial' and `final'. On X11, 'initial 3251 The defined stages are currently `initial' and `final'. On X11, 'initial
3250 is used when the font matching process is looking for fonts that match 3252 is used when the font matching process is looking for fonts that match
3251 the desired registries of the charset--see the `charset-registries' 3253 the desired registries of the charset--see the `charset-registries'
3252 function. If that match process fails, then the 'final stage comes into 3254 function. If that match process fails, then the 'final stage comes into
3253 play; this means that a more general lookup is desired, and that a font 3255 play; this means that a more general lookup is desired, and that a font
3306 GCPRO1 (built_up_list); 3308 GCPRO1 (built_up_list);
3307 built_up_list = build_up_processed_list (specifier, domain, inst_list); 3309 built_up_list = build_up_processed_list (specifier, domain, inst_list);
3308 if (!NILP (built_up_list)) 3310 if (!NILP (built_up_list))
3309 val = specifier_instance_from_inst_list (specifier, matchspec, domain, 3311 val = specifier_instance_from_inst_list (specifier, matchspec, domain,
3310 built_up_list, ERROR_ME, 3312 built_up_list, ERROR_ME,
3311 0, Qzero, &instantiator); 3313 0, Qzero, &instantiator, 0);
3312 UNGCPRO; 3314 UNGCPRO;
3313 return UNBOUNDP (val) ? default_ : want_instantiator ? instantiator : val; 3315 return UNBOUNDP (val) ? default_ : want_instantiator ? instantiator : val;
3314 3316
3315 } 3317 }
3316 3318
3327 return specifier_matching_foo_from_inst_list (specifier, Qunbound, 3329 return specifier_matching_foo_from_inst_list (specifier, Qunbound,
3328 domain, inst_list, default_, 3330 domain, inst_list, default_,
3329 0); 3331 0);
3330 } 3332 }
3331 3333
3332 DEFUN ("specifier-instantiator-from-inst-list", 3334 DEFUN ("specifier-instantiator-from-inst-list",
3333 Fspecifier_instantiator_from_inst_list, 3, 4, 0, /* 3335 Fspecifier_instantiator_from_inst_list, 3, 4, 0, /*
3334 Attempt to convert an inst-list into an instance; return instantiator. 3336 Attempt to convert an inst-list into an instance; return instantiator.
3335 This is identical to `specifier-instance-from-inst-list' but returns 3337 This is identical to `specifier-instance-from-inst-list' but returns
3336 the instantiator used to generate the instance, rather than the instance 3338 the instantiator used to generate the instance, rather than the instance
3337 itself. 3339 itself.
3921 3923
3922 Vunlock_ghost_specifiers = Qnil; 3924 Vunlock_ghost_specifiers = Qnil;
3923 staticpro (&Vunlock_ghost_specifiers); 3925 staticpro (&Vunlock_ghost_specifiers);
3924 3926
3925 Vcharset_tag_lists = make_vector(NUM_LEADING_BYTES, Qnil); 3927 Vcharset_tag_lists = make_vector(NUM_LEADING_BYTES, Qnil);
3926 staticpro (&Vcharset_tag_lists); 3928 staticpro (&Vcharset_tag_lists);
3927 } 3929 }