Mercurial > hg > xemacs-beta
annotate src/objects-xlike-inc.c @ 4407:4ee73bbe4f8e
Always use boyer_moore in ASCII or Latin-1 buffers with ASCII search strings.
2007-12-26 Aidan Kehoe <kehoea@parhasard.net>
* casetab.c:
Extend and correct some case table documentation.
* search.c (search_buffer):
Correct a bug where only the first entry for a character in the
case equivalence table was examined in determining if the
Boyer-Moore search algorithm is appropriate.
If there are case mappings outside of the charset and row of the
characters specified in the search string, those case mappings can
be safely ignored (and Boyer-Moore search can be used) if we know
from the buffer statistics that the corresponding characters cannot
occur.
* search.c (boyer_moore):
Assert that we haven't been passed a string with varying
characters sets or rows within character sets. That's what
simple_search is for.
In the very rare event that a character in the search string has a
canonical case mapping that is not in the same character set and
row, don't try to search for the canonical character, search for
some other character that is in the the desired character set and
row. Assert that the case table isn't corrupt.
Do not search for any character case mappings that cannot possibly
occur in the buffer, given the buffer metadata about its
contents.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 26 Dec 2007 17:30:16 +0100 |
parents | 4143b78d0df0 |
children | ea66743ff201 |
rev | line source |
---|---|
3659 | 1 /* Shared object code between X and GTK -- include file. |
2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
4 Copyright (C) 1996, 2001, 2002, 2003 Ben Wing. | |
5 | |
6 This file is part of XEmacs. | |
7 | |
8 XEmacs is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with XEmacs; see the file COPYING. If not, write to | |
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 Boston, MA 02111-1307, USA. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
25 /* Pango is ready for prime-time now, as far as I understand it. The GTK | |
26 people should be using that. Oh well. (Aidan Kehoe, Sat Nov 4 12:41:12 | |
27 CET 2006) */ | |
28 | |
29 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) | |
30 | |
31 #ifdef DEBUG_XEMACS | |
32 # define DEBUG_OBJECTS(FORMAT, ...) \ | |
33 do { if (debug_x_objects) stderr_out(FORMAT, __VA_ARGS__); } while (0) | |
34 #else /* DEBUG_XEMACS */ | |
35 # define DEBUG_OBJECTS(format, ...) | |
36 #endif /* DEBUG_XEMACS */ | |
37 | |
38 #elif defined(__GNUC__) | |
39 | |
40 #ifdef DEBUG_XEMACS | |
41 # define DEBUG_OBJECTS(format, args...) \ | |
42 do { if (debug_x_objects) stderr_out(format, args ); } while (0) | |
43 #else /* DEBUG_XEMACS */ | |
44 # define DEBUG_OBJECTS(format, args...) | |
45 #endif /* DEBUG_XEMACS */ | |
46 | |
47 #else /* defined(__STDC_VERSION__) [...] */ | |
48 # define DEBUG_OBJECTS (void) | |
49 #endif | |
50 | |
51 #ifdef MULE | |
52 | |
53 /* For some code it's reasonable to have only one copy and conditionalize | |
54 at run-time. For other code it isn't. */ | |
55 | |
56 static int | |
57 count_hyphens(const Ibyte *str, Bytecount length, Ibyte **last_hyphen) | |
58 { | |
59 int hyphen_count = 0; | |
60 const Ibyte *hyphening = str; | |
61 const Ibyte *new_hyphening; | |
62 | |
63 for (hyphen_count = 0; | |
4124 | 64 NULL != (new_hyphening = (Ibyte *) memchr((const void *)hyphening, '-', length)); |
3659 | 65 hyphen_count++) |
66 { | |
67 ++new_hyphening; | |
68 length -= new_hyphening - hyphening; | |
69 hyphening = new_hyphening; | |
70 } | |
71 | |
72 if (NULL != last_hyphen) | |
73 { | |
74 *last_hyphen = (Ibyte *)hyphening; | |
75 } | |
76 | |
77 return hyphen_count; | |
78 } | |
79 | |
80 static int | |
81 #ifdef THIS_IS_GTK | |
82 gtk_font_spec_matches_charset (struct device * USED_IF_XFT (d), | |
83 Lisp_Object charset, | |
84 const Ibyte *nonreloc, Lisp_Object reloc, | |
85 Bytecount offset, Bytecount length, | |
86 enum font_specifier_matchspec_stages stage) | |
87 #else | |
88 x_font_spec_matches_charset (struct device * USED_IF_XFT (d), | |
89 Lisp_Object charset, | |
90 const Ibyte *nonreloc, Lisp_Object reloc, | |
91 Bytecount offset, Bytecount length, | |
92 enum font_specifier_matchspec_stages stage) | |
93 #endif | |
94 { | |
95 Lisp_Object registries = Qnil; | |
96 long i, registries_len; | |
97 const Ibyte *the_nonreloc; | |
98 Bytecount the_length; | |
99 | |
100 the_nonreloc = nonreloc; | |
101 the_length = length; | |
102 | |
103 if (!the_nonreloc) | |
104 the_nonreloc = XSTRING_DATA (reloc); | |
105 fixup_internal_substring (nonreloc, reloc, offset, &the_length); | |
106 the_nonreloc += offset; | |
107 | |
108 #ifdef USE_XFT | |
109 if (stage) | |
110 { | |
111 Display *dpy = DEVICE_X_DISPLAY (d); | |
112 Extbyte *extname; | |
113 XftFont *rf; | |
114 const Ibyte *the_nonreloc; | |
115 | |
116 if (!NILP(reloc)) | |
117 { | |
118 the_nonreloc = XSTRING_DATA (reloc); | |
119 LISP_STRING_TO_EXTERNAL (reloc, extname, Qx_font_name_encoding); | |
120 rf = xft_open_font_by_name (dpy, extname); | |
121 return 0; /* #### maybe this will compile and run ;) */ | |
122 /* Jesus, Stephen, what the fuck? */ | |
123 } | |
124 } | |
125 #endif | |
126 | |
127 /* Hmm, this smells bad. */ | |
4353
4143b78d0df0
Merge an old patch of Ben's, involving font instantiation and charsets.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4124
diff
changeset
|
128 if (NILP (charset)) |
3659 | 129 return 1; |
130 | |
131 /* Hack! Short font names don't have the registry in them, | |
132 so we just assume the user knows what they're doing in the | |
133 case of ASCII. For other charsets, you gotta give the | |
134 long form; sorry buster. | |
135 #### FMH: this screws fontconfig/Xft? | |
136 STRATEGY: use fontconfig's ability to hack languages and character | |
137 sets (lang and charset properties). | |
138 #### Maybe we can use the fontconfig model to eliminate the difference | |
139 between faces and fonts? No - it looks like that would be an abuse | |
140 (fontconfig doesn't know about colors, although Xft does). | |
141 */ | |
142 if (EQ (charset, Vcharset_ascii) && | |
143 (!memchr (the_nonreloc, '*', the_length)) | |
144 && (5 > (count_hyphens(the_nonreloc, the_length, NULL)))) | |
145 { | |
146 return 1; | |
147 } | |
148 | |
149 if (final == stage) | |
150 { | |
151 registries = Qunicode_registries; | |
152 } | |
153 else if (initial == stage) | |
154 { | |
155 registries = XCHARSET_REGISTRIES (charset); | |
156 if (NILP(registries)) | |
157 { | |
158 return 0; | |
159 } | |
160 } | |
161 else assert(0); | |
162 | |
163 CHECK_VECTOR (registries); | |
164 registries_len = XVECTOR_LENGTH(registries); | |
165 | |
166 for (i = 0; i < registries_len; ++i) | |
167 { | |
168 if (!(STRINGP(XVECTOR_DATA(registries)[i])) | |
169 || (XSTRING_LENGTH(XVECTOR_DATA(registries)[i]) > the_length)) | |
170 { | |
171 continue; | |
172 } | |
173 | |
174 /* Check if the font spec ends in the registry specified. X11 says | |
175 this comparison is case insensitive: XLFD, section 3.11: | |
176 | |
177 "Alphabetic case distinctions are allowed but are for human | |
178 readability concerns only. Conforming X servers will perform | |
179 matching on font name query or open requests independent of case." */ | |
180 if (0 == qxestrcasecmp(XSTRING_DATA(XVECTOR_DATA(registries)[i]), | |
181 the_nonreloc + (the_length - | |
182 XSTRING_LENGTH | |
183 (XVECTOR_DATA(registries)[i])))) | |
184 { | |
185 return 1; | |
186 } | |
187 } | |
188 return 0; | |
189 } | |
190 | |
191 static Lisp_Object | |
192 xlistfonts_checking_charset (Lisp_Object device, const Extbyte *xlfd, | |
193 Lisp_Object charset, | |
194 enum font_specifier_matchspec_stages stage) | |
195 { | |
196 Extbyte **names; | |
197 Lisp_Object result = Qnil; | |
198 int count = 0, i; | |
199 DECLARE_EISTRING(ei_single_result); | |
200 | |
201 names = XListFonts ( | |
202 #ifdef THIS_IS_GTK | |
203 GDK_DISPLAY (), | |
204 #else | |
205 DEVICE_X_DISPLAY (XDEVICE (device)), | |
206 #endif | |
207 xlfd, MAX_FONT_COUNT, &count); | |
208 | |
209 for (i = 0; i < count; ++i) | |
210 { | |
211 eireset(ei_single_result); | |
212 eicpy_ext(ei_single_result, names[i], Qx_font_name_encoding); | |
213 | |
214 if (DEVMETH_OR_GIVEN(XDEVICE (device), font_spec_matches_charset, | |
215 (XDEVICE (device), charset, | |
216 eidata(ei_single_result), Qnil, 0, | |
217 -1, stage), 0)) | |
218 { | |
219 result = eimake_string(ei_single_result); | |
220 DEBUG_OBJECTS ("in xlistfonts_checking_charset, returning %s\n", | |
221 eidata(ei_single_result)); | |
222 break; | |
223 } | |
224 } | |
225 | |
226 if (names) | |
227 { | |
228 XFreeFontNames (names); | |
229 } | |
230 | |
231 return result; | |
232 } | |
233 | |
234 #ifdef USE_XFT | |
235 /* #### debug functions: find a better place for us */ | |
236 const char *FcResultToString (FcResult r); | |
237 const char * | |
238 FcResultToString (FcResult r) | |
239 { | |
240 static char buffer[256]; | |
241 switch (r) | |
242 { | |
243 case FcResultMatch: | |
244 return "FcResultMatch"; | |
245 case FcResultNoMatch: | |
246 return "FcResultNoMatch"; | |
247 case FcResultTypeMismatch: | |
248 return "FcResultTypeMismatch"; | |
249 case FcResultNoId: | |
250 return "FcResultNoId"; | |
251 default: | |
252 snprintf (buffer, 255, "FcResultUndocumentedValue (%d)", r); | |
253 return buffer; | |
254 } | |
255 } | |
256 | |
257 const char *FcTypeOfValueToString (FcValue v); | |
258 const char * | |
259 FcTypeOfValueToString (FcValue v) | |
260 { | |
261 static char buffer[256]; | |
262 switch (v.type) | |
263 { | |
264 case FcTypeMatrix: | |
265 return "FcTypeMatrix"; | |
266 case FcTypeString: | |
267 return "FcTypeString"; | |
268 case FcTypeVoid: | |
269 return "FcTypeVoid"; | |
270 case FcTypeDouble: | |
271 return "FcTypeDouble"; | |
272 case FcTypeInteger: | |
273 return "FcTypeInteger"; | |
274 case FcTypeBool: | |
275 return "FcTypeBool"; | |
276 case FcTypeCharSet: | |
277 return "FcTypeCharSet"; | |
278 case FcTypeLangSet: | |
279 return "FcTypeLangSet"; | |
280 /* #### There is no union member of this type, but there are void* and | |
281 FcPattern* members, as of fontconfig.h FC_VERSION 10002 */ | |
282 case FcTypeFTFace: | |
283 return "FcTypeFTFace"; | |
284 default: | |
285 snprintf (buffer, 255, "FcTypeUndocumentedType (%d)", v.type); | |
286 return buffer; | |
287 } | |
288 } | |
289 | |
290 static FcCharSet * | |
291 mule_to_fc_charset (Lisp_Object cs) | |
292 { | |
293 int ucode, i, j; | |
294 FcCharSet *fccs; | |
295 | |
296 CHECK_CHARSET (cs); | |
297 fccs = FcCharSetCreate (); | |
298 /* #### do we also need to deal with 94 vs. 96 charsets? | |
299 ie, how are SP and DEL treated in ASCII? non-graphic should return -1 */ | |
300 if (1 == XCHARSET_DIMENSION (cs)) | |
301 /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ | |
302 for (i = 0; i < 96; i++) | |
303 { | |
304 ucode = ((int *) XCHARSET_TO_UNICODE_TABLE (cs))[i]; | |
305 if (ucode >= 0) | |
306 /* #### should check for allocation failure */ | |
307 FcCharSetAddChar (fccs, (FcChar32) ucode); | |
308 } | |
309 else if (2 == XCHARSET_DIMENSION (cs)) | |
310 /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ | |
311 for (i = 0; i < 96; i++) | |
312 for (j = 0; j < 96; j++) | |
313 { | |
314 ucode = ((int **) XCHARSET_TO_UNICODE_TABLE (cs))[i][j]; | |
315 if (ucode >= 0) | |
316 /* #### should check for allocation failure */ | |
317 FcCharSetAddChar (fccs, (FcChar32) ucode); | |
318 } | |
319 else | |
320 { | |
321 FcCharSetDestroy (fccs); | |
322 fccs = NULL; | |
323 } | |
324 return fccs; | |
325 } | |
326 | |
327 struct charset_reporter { | |
328 Lisp_Object *charset; | |
329 /* This is a debug facility, require ASCII. */ | |
330 Extbyte *language; /* ASCII, please */ | |
331 /* Technically this is FcChar8, but fsckin' GCC 4 bitches. */ | |
332 Extbyte *rfc3066; /* ASCII, please */ | |
333 }; | |
334 | |
335 static struct charset_reporter charset_table[] = | |
336 { | |
337 /* #### It's my branch, my favorite charsets get checked first! | |
338 That's a joke, Son. | |
339 Ie, I don't know what I'm doing, so my charsets first is as good as | |
340 any other arbitrary order. If you have a better idea, speak up! */ | |
341 { &Vcharset_ascii, "English", "en" }, | |
342 { &Vcharset_japanese_jisx0208, "Japanese", "ja" }, | |
343 { &Vcharset_japanese_jisx0212, "Japanese", "ja" }, | |
344 { &Vcharset_katakana_jisx0201, "Japanese", "ja" }, | |
345 { &Vcharset_latin_jisx0201, "Japanese", "ja" }, | |
346 { &Vcharset_japanese_jisx0208_1978, "Japanese", "ja" }, | |
347 { &Vcharset_greek_iso8859_7, "Greek", "el" }, | |
348 /* #### all the Chinese need checking | |
349 Damn the blood-sucking ISO anyway. */ | |
350 { &Vcharset_chinese_gb2312, "simplified Chinese", "zh-CN" }, | |
351 { &Vcharset_korean_ksc5601, "Korean", "ko" }, | |
352 { &Vcharset_chinese_cns11643_1, "traditional Chinese", "zh-TW" }, | |
353 { &Vcharset_chinese_cns11643_2, "traditional Chinese", "zh-TW" }, | |
354 { &Vcharset_latin_iso8859_1, NULL, NULL }, | |
355 { &Vcharset_latin_iso8859_2, NULL, NULL }, | |
356 { &Vcharset_latin_iso8859_3, NULL, NULL }, | |
357 { &Vcharset_latin_iso8859_4, NULL, NULL }, | |
358 { &Vcharset_latin_iso8859_9, NULL, NULL }, | |
359 { &Vcharset_latin_iso8859_15, NULL, NULL }, | |
360 { &Vcharset_thai_tis620, NULL, NULL }, | |
361 { &Vcharset_arabic_iso8859_6, NULL, NULL }, | |
362 { &Vcharset_hebrew_iso8859_8, "Hebrew", "he" }, | |
363 { &Vcharset_cyrillic_iso8859_5, NULL, NULL }, | |
364 /* #### these probably are not quite right */ | |
365 { &Vcharset_chinese_big5_1, "traditional Chinese", "zh-TW" }, | |
366 { &Vcharset_chinese_big5_2, "traditional Chinese", "zh-TW" }, | |
367 { NULL, NULL, NULL } | |
368 }; | |
369 | |
370 /* Choose appropriate font name for debug messages. | |
371 Use only in the top half of next function (enforced with #undef). */ | |
372 #define DECLARE_DEBUG_FONTNAME(__xemacs_name) \ | |
373 Eistring *__xemacs_name; \ | |
374 do \ | |
375 { \ | |
376 __xemacs_name = debug_xft > 2 ? eistr_fullname \ | |
377 : debug_xft > 1 ? eistr_longname \ | |
378 : eistr_shortname; \ | |
379 } while (0) | |
380 | |
381 static Lisp_Object | |
382 xft_find_charset_font (Lisp_Object font, Lisp_Object charset, | |
383 enum font_specifier_matchspec_stages stage) | |
384 { | |
385 const Extbyte *patternext; | |
386 Lisp_Object result = Qnil; | |
387 | |
388 /* #### with Xft need to handle second stage here -- sjt | |
389 Hm. Or maybe not. That would be cool. :-) */ | |
390 if (stage) | |
391 return Qnil; | |
392 | |
393 /* Fontconfig converts all FreeType names to UTF-8 before passing them | |
394 back to callers---see fcfreetype.c (FcFreeTypeQuery). | |
395 I don't believe this is documented. */ | |
396 | |
397 DEBUG_XFT1 (1, "confirming charset for font instance %s\n", | |
398 XSTRING_DATA(font)); | |
399 | |
400 /* #### this looks like a fair amount of work, but the basic design | |
401 has never been rethought, and it should be | |
402 | |
403 what really should happen here is that we use FcFontSort (FcFontList?) | |
404 to get a list of matching fonts, then pick the first (best) one that | |
405 gives language or repertoire coverage. | |
406 */ | |
407 | |
408 FcInit (); /* No-op if already initialized. | |
409 In fontconfig 2.3.2, this cannot return | |
410 failure, but that looks like a bug. We | |
411 check for it with FcGetCurrentConfig(), | |
412 which *can* fail. */ | |
413 if (!FcConfigGetCurrent()) /* #### We should expose FcInit* interfaces | |
414 to LISP and decide when to reinitialize | |
415 intelligently. */ | |
416 stderr_out ("Failed fontconfig initialization\n"); | |
417 else | |
418 { | |
419 FcPattern *fontxft; /* long-lived, freed at end of this block */ | |
420 FcResult fcresult; | |
421 FcConfig *fcc; | |
422 FcChar8 *lang = (FcChar8 *) "en"; /* #### fix this bogus hack! */ | |
423 FcCharSet *fccs = NULL; | |
424 DECLARE_EISTRING (eistr_shortname); /* user-friendly nickname */ | |
425 DECLARE_EISTRING (eistr_longname); /* omit FC_LANG and FC_CHARSET */ | |
426 DECLARE_EISTRING (eistr_fullname); /* everything */ | |
427 | |
428 LISP_STRING_TO_EXTERNAL (font, patternext, Qfc_font_name_encoding); | |
429 fcc = FcConfigGetCurrent (); | |
430 | |
431 /* parse the name, do the substitutions, and match the font */ | |
432 | |
433 { | |
434 FcPattern *p = FcNameParse ((FcChar8 *) patternext); | |
435 PRINT_XFT_PATTERN (3, "FcNameParse'ed name is %s\n", p); | |
436 /* #### Next two return FcBool, but what does the return mean? */ | |
437 /* The order is correct according the fontconfig docs. */ | |
438 FcConfigSubstitute (fcc, p, FcMatchPattern); | |
439 PRINT_XFT_PATTERN (2, "FcConfigSubstitute'ed name is %s\n", p); | |
440 FcDefaultSubstitute (p); | |
441 PRINT_XFT_PATTERN (3, "FcDefaultSubstitute'ed name is %s\n", p); | |
442 /* #### check fcresult of following match? */ | |
443 fontxft = FcFontMatch (fcc, p, &fcresult); | |
444 /* this prints the long fontconfig name */ | |
445 PRINT_XFT_PATTERN (1, "FcFontMatch'ed name is %s\n", fontxft); | |
446 FcPatternDestroy (p); | |
447 } | |
448 | |
449 /* heuristic to give reasonable-length names for debug reports | |
450 | |
451 I considered #ifdef SUPPORT_FULL_FONTCONFIG_NAME etc but that's | |
452 pointless. We're just going to remove this code once the font/ | |
453 face refactoring is done, but until then it could be very useful. | |
454 */ | |
455 { | |
456 FcPattern *p = FcFontRenderPrepare (fcc, fontxft, fontxft); | |
457 FcChar8 *name; | |
458 | |
459 /* full name, including language coverage and repertoire */ | |
460 name = FcNameUnparse (p); | |
461 eicpy_ext (eistr_fullname, (Extbyte *) name, Qfc_font_name_encoding); | |
462 free (name); | |
463 | |
464 /* long name, omitting coverage and repertoire, plus a number | |
465 of rarely useful properties */ | |
466 FcPatternDel (p, FC_CHARSET); | |
467 FcPatternDel (p, FC_LANG); | |
3841 | 468 #ifdef FC_WIDTH |
3659 | 469 FcPatternDel (p, FC_WIDTH); |
3841 | 470 #endif |
3659 | 471 FcPatternDel (p, FC_SPACING); |
472 FcPatternDel (p, FC_HINTING); | |
473 FcPatternDel (p, FC_VERTICAL_LAYOUT); | |
474 FcPatternDel (p, FC_AUTOHINT); | |
475 FcPatternDel (p, FC_GLOBAL_ADVANCE); | |
476 FcPatternDel (p, FC_INDEX); | |
477 FcPatternDel (p, FC_SCALE); | |
478 FcPatternDel (p, FC_FONTVERSION); | |
479 name = FcNameUnparse (p); | |
480 eicpy_ext (eistr_longname, (Extbyte *) name, Qfc_font_name_encoding); | |
481 free (name); | |
482 | |
483 /* nickname, just family and size, but | |
484 "family" names usually have style, slant, and weight */ | |
485 FcPatternDel (p, FC_FOUNDRY); | |
486 FcPatternDel (p, FC_STYLE); | |
487 FcPatternDel (p, FC_SLANT); | |
488 FcPatternDel (p, FC_WEIGHT); | |
489 FcPatternDel (p, FC_PIXEL_SIZE); | |
490 FcPatternDel (p, FC_OUTLINE); | |
491 FcPatternDel (p, FC_SCALABLE); | |
492 FcPatternDel (p, FC_DPI); | |
493 name = FcNameUnparse (p); | |
494 eicpy_ext (eistr_shortname, (Extbyte *) name, Qfc_font_name_encoding); | |
495 free (name); | |
496 | |
497 FcPatternDestroy (p); | |
498 } | |
499 | |
500 /* The language approach may better in the long run, but we can't use | |
501 it based on Mule charsets; fontconfig doesn't provide a way to test | |
502 for unions of languages, etc. That will require support from the | |
503 text module. | |
504 | |
505 Optimization: cache the generated FcCharSet in the Mule charset. | |
506 Don't forget to destroy it if the Mule charset gets deallocated. */ | |
507 | |
508 { | |
509 /* This block possibly should be a function, but it generates | |
510 multiple values. I find the "pass an address to return the | |
511 value in" idiom opaque, so prefer a block. */ | |
512 struct charset_reporter *cr; | |
513 for (cr = charset_table; | |
514 cr->charset && !EQ (*(cr->charset), charset); | |
515 cr++) | |
516 ; | |
517 | |
518 if (cr->rfc3066) | |
519 { | |
520 DECLARE_DEBUG_FONTNAME (name); | |
521 CHECKING_LANG (0, eidata(name), cr->language); | |
522 lang = (FcChar8 *) cr->rfc3066; | |
523 } | |
524 else if (cr->charset) | |
525 { | |
526 /* what the hey, build 'em on the fly */ | |
527 /* #### in the case of error this could return NULL! */ | |
528 fccs = mule_to_fc_charset (charset); | |
529 lang = (FcChar8 *) XSTRING_DATA (XSYMBOL | |
530 (XCHARSET_NAME (charset))-> name); | |
531 } | |
532 else | |
533 { | |
534 /* OK, we fell off the end of the table */ | |
535 warn_when_safe_lispobj (intern ("xft"), intern ("alert"), | |
536 list2 (build_string ("unchecked charset"), | |
537 charset)); | |
538 /* default to "en" | |
539 #### THIS IS WRONG, WRONG, WRONG!! | |
540 It is why we never fall through to XLFD-checking. */ | |
541 } | |
542 | |
543 ASSERT_ASCTEXT_ASCII((Extbyte *) lang); | |
544 | |
545 if (fccs) | |
546 { | |
547 /* check for character set coverage */ | |
548 int i = 0; | |
549 FcCharSet *v; | |
550 FcResult r = FcPatternGetCharSet (fontxft, FC_CHARSET, i, &v); | |
551 | |
552 if (r == FcResultTypeMismatch) | |
553 { | |
554 DEBUG_XFT0 (0, "Unexpected type return in charset value\n"); | |
555 result = Qnil; | |
556 } | |
557 else if (r == FcResultMatch && FcCharSetIsSubset (fccs, v)) | |
558 { | |
559 /* The full pattern with the bitmap coverage is massively | |
560 unwieldy, but the shorter names are just *wrong*. We | |
561 should have the full thing internally as truename, and | |
562 filter stuff the client doesn't want to see on output. | |
563 Should we just store it into the truename right here? */ | |
564 DECLARE_DEBUG_FONTNAME (name); | |
565 DEBUG_XFT2 (0, "Xft font %s supports %s\n", | |
566 eidata(name), lang); | |
567 #ifdef RETURN_LONG_FONTCONFIG_NAMES | |
568 result = eimake_string(eistr_fullname); | |
569 #else | |
570 result = eimake_string(eistr_longname); | |
571 #endif | |
572 } | |
573 else | |
574 { | |
575 DECLARE_DEBUG_FONTNAME (name); | |
576 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", | |
577 eidata(name), lang); | |
578 result = Qnil; | |
579 } | |
580 | |
581 /* clean up */ | |
582 FcCharSetDestroy (fccs); | |
583 } | |
584 else | |
585 { | |
586 /* check for language coverage */ | |
587 int i = 0; | |
588 FcValue v; | |
589 /* the main event */ | |
590 FcResult r = FcPatternGet (fontxft, FC_LANG, i, &v); | |
591 | |
592 if (r == FcResultMatch) | |
593 { | |
594 if (v.type != FcTypeLangSet) /* excessive paranoia */ | |
595 { | |
596 ASSERT_ASCTEXT_ASCII(FcTypeOfValueToString(v)); | |
597 /* Urk! Fall back and punt to core font. */ | |
598 DEBUG_XFT1 (0, "Unexpected type of lang value (%s)\n", | |
599 FcTypeOfValueToString (v)); | |
600 result = Qnil; | |
601 } | |
602 else if (FcLangSetHasLang (v.u.l, lang) != FcLangDifferentLang) | |
603 { | |
604 DECLARE_DEBUG_FONTNAME (name); | |
605 DEBUG_XFT2 (0, "Xft font %s supports %s\n", | |
606 eidata(name), lang); | |
607 #ifdef RETURN_LONG_FONTCONFIG_NAMES | |
608 result = eimake_string(eistr_fullname); | |
609 #else | |
610 result = eimake_string(eistr_longname); | |
611 #endif | |
612 } | |
613 else | |
614 { | |
615 DECLARE_DEBUG_FONTNAME (name); | |
616 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", | |
617 eidata(name), lang); | |
618 result = Qnil; | |
619 } | |
620 } | |
621 else | |
622 { | |
623 ASSERT_ASCTEXT_ASCII(FcResultToString(r)); | |
624 DEBUG_XFT1 (0, "Getting lang: unexpected result=%s\n", | |
625 FcResultToString (r)); | |
626 result = Qnil; | |
627 } | |
628 } | |
629 | |
630 /* clean up and maybe return */ | |
631 FcPatternDestroy (fontxft); | |
632 if (!UNBOUNDP (result)) | |
633 return result; | |
634 } | |
635 } | |
636 return Qnil; | |
637 } | |
638 #undef DECLARE_DEBUG_FONTNAME | |
639 | |
640 #endif /* USE_XFT */ | |
641 | |
642 /* find a font spec that matches font spec FONT and also matches | |
643 (the registry of) CHARSET. */ | |
644 static Lisp_Object | |
645 #ifdef THIS_IS_GTK | |
646 gtk_find_charset_font (Lisp_Object device, Lisp_Object font, | |
647 Lisp_Object charset, | |
648 enum font_specifier_matchspec_stages stage) | |
649 #else | |
650 x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, | |
651 enum font_specifier_matchspec_stages stage) | |
652 #endif | |
653 { | |
654 Lisp_Object result = Qnil, registries = Qnil; | |
655 int j, hyphen_count, registries_len = 0; | |
656 Ibyte *hyphening, *new_hyphening; | |
657 Bytecount xlfd_length; | |
658 | |
659 DECLARE_EISTRING(ei_xlfd_without_registry); | |
660 DECLARE_EISTRING(ei_xlfd); | |
661 | |
662 #ifdef USE_XFT | |
663 result = xft_find_charset_font(font, charset, stage); | |
664 if (!NILP(result)) | |
665 { | |
666 return result; | |
667 } | |
668 #endif | |
669 | |
670 switch (stage) | |
671 { | |
672 case initial: | |
673 { | |
674 if (!(NILP(XCHARSET_REGISTRIES(charset))) | |
675 && VECTORP(XCHARSET_REGISTRIES(charset))) | |
676 { | |
677 registries_len = XVECTOR_LENGTH(XCHARSET_REGISTRIES(charset)); | |
678 registries = XCHARSET_REGISTRIES(charset); | |
679 } | |
680 break; | |
681 } | |
682 case final: | |
683 { | |
684 registries_len = 1; | |
685 registries = Qunicode_registries; | |
686 break; | |
687 } | |
688 default: | |
689 { | |
690 assert(0); | |
691 break; | |
692 } | |
693 } | |
694 | |
695 eicpy_lstr(ei_xlfd, font); | |
696 hyphening = eidata(ei_xlfd); | |
697 xlfd_length = eilen(ei_xlfd); | |
698 | |
699 /* Count the hyphens in the string, moving new_hyphening to just after the | |
700 last one. */ | |
701 hyphen_count = count_hyphens(hyphening, xlfd_length, &new_hyphening); | |
702 | |
703 if (0 == registries_len || (5 > hyphen_count && | |
704 !(1 == xlfd_length && '*' == *hyphening))) | |
705 { | |
706 /* No proper XLFD specified, or we can't modify the pattern to change | |
707 the registry and encoding to match what we want, or we have no | |
708 information on the registry needed. */ | |
709 eito_external(ei_xlfd, Qx_font_name_encoding); | |
710 DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n", | |
711 eidata(ei_xlfd)); | |
712 result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd), | |
713 charset, stage); | |
714 /* No need to loop through the available registries; return | |
715 immediately. */ | |
716 return result; | |
717 } | |
718 else if (1 == xlfd_length && '*' == *hyphening) | |
719 { | |
720 /* It's a single asterisk. We can add the registry directly to the | |
721 end. */ | |
722 eicpy_ch(ei_xlfd_without_registry, '*'); | |
723 } | |
724 else | |
725 { | |
726 /* It's a fully-specified XLFD. Work out where the registry and | |
727 encoding are, and initialise ei_xlfd_without_registry to the string | |
728 without them. */ | |
729 | |
730 /* count_hyphens has set new_hyphening to just after the last | |
731 hyphen. Move back to just after the hyphen before it. */ | |
732 | |
733 for (new_hyphening -= 2; new_hyphening > hyphening | |
734 && '-' != *new_hyphening; --new_hyphening) | |
735 ; | |
736 ++new_hyphening; | |
737 | |
738 eicpy_ei(ei_xlfd_without_registry, ei_xlfd); | |
739 | |
740 /* Manipulate ei_xlfd_without_registry, using the information about | |
741 ei_xlfd, to which it's identical. */ | |
742 eidel(ei_xlfd_without_registry, new_hyphening - hyphening, -1, | |
743 eilen(ei_xlfd) - (new_hyphening - hyphening), -1); | |
744 | |
745 } | |
746 | |
747 /* Now, loop through the registries and encodings defined for this | |
748 charset, doing an XListFonts each time with the pattern modified to | |
749 specify the regisry and encoding. This avoids huge amounts of IPC and | |
750 duplicated searching; now we use the searching the X server was doing | |
751 anyway, where before the X server did its search, transferred huge | |
752 amounts of data, and then we proceeded to do a regexp search on that | |
753 data. */ | |
754 for (j = 0; j < registries_len && NILP(result); ++j) | |
755 { | |
756 eireset(ei_xlfd); | |
757 eicpy_ei(ei_xlfd, ei_xlfd_without_registry); | |
758 | |
759 eicat_lstr(ei_xlfd, XVECTOR_DATA(registries)[j]); | |
760 | |
761 eito_external(ei_xlfd, Qx_font_name_encoding); | |
762 | |
763 DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n", | |
764 eidata(ei_xlfd)); | |
765 result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd), | |
766 charset, stage); | |
767 } | |
768 | |
3676 | 769 /* In the event that the charset is ASCII and we haven't matched |
770 anything up to now, even with a pattern of "*", add "iso8859-1" | |
771 to the charset's registry and try again. Not returning a result | |
772 for ASCII means our frame geometry calculations are | |
773 inconsistent, and that we may crash. */ | |
774 | |
775 if (1 == xlfd_length && EQ(charset, Vcharset_ascii) && NILP(result) | |
776 && ('*' == eigetch(ei_xlfd_without_registry, 0))) | |
777 | |
778 { | |
779 int have_latin1 = 0; | |
780 | |
781 /* Set this to, for example, is08859-1 if you want to see the | |
782 error behaviour. */ | |
783 | |
784 #define FALLBACK_ASCII_REGISTRY "iso8859-1" | |
785 | |
786 for (j = 0; j < registries_len; ++j) | |
787 { | |
788 if (0 == qxestrcasecmp(XSTRING_DATA(XVECTOR_DATA(registries)[j]), | |
4124 | 789 (Ibyte *) FALLBACK_ASCII_REGISTRY)) |
3676 | 790 { |
791 have_latin1 = 1; | |
792 break; | |
793 } | |
794 } | |
795 | |
796 if (!have_latin1) | |
797 { | |
798 Lisp_Object new_registries = make_vector(registries_len + 1, Qnil); | |
799 | |
800 XVECTOR_DATA(new_registries)[0] | |
801 = build_string(FALLBACK_ASCII_REGISTRY); | |
802 | |
803 memcpy(XVECTOR_DATA(new_registries) + 1, | |
804 XVECTOR_DATA(registries), | |
805 sizeof XVECTOR_DATA(registries)[0] * | |
806 XVECTOR_LENGTH(registries)); | |
807 | |
808 /* Calling set_charset_registries instead of overwriting the | |
809 value directly, to allow the charset font caches to be | |
810 invalidated and a change to the default face to be | |
811 noted. */ | |
812 set_charset_registries(charset, new_registries); | |
813 | |
3680 | 814 warn_when_safe (Qface, Qwarning, |
815 "Your ASCII charset registries contain nothing " | |
816 "sensible. Adding `" FALLBACK_ASCII_REGISTRY "'."); | |
817 | |
3676 | 818 /* And recurse. */ |
819 result = | |
820 DEVMETH_OR_GIVEN (XDEVICE (device), find_charset_font, | |
821 (device, font, charset, stage), | |
822 result); | |
823 } | |
824 else | |
825 { | |
826 DECLARE_EISTRING (ei_connection_name); | |
827 | |
828 /* We preserve a copy of the connection name for the error message | |
829 after the device is deleted. */ | |
830 eicpy_lstr (ei_connection_name, | |
831 DEVICE_CONNECTION (XDEVICE(device))); | |
832 | |
833 stderr_out ("Cannot find a font for ASCII, deleting device on %s\n", | |
834 eidata (ei_connection_name)); | |
835 | |
836 io_error_delete_device (device); | |
837 | |
838 /* Do a normal warning in the event that we have other, non-X | |
839 frames available. (If we don't, io_error_delete_device will | |
840 have exited.) */ | |
841 warn_when_safe | |
842 (Qface, Qerror, | |
843 "Cannot find a font for ASCII, deleting device on %s.\n" | |
844 "\n" | |
845 "Your X server fonts appear to be inconsistent; fix them, or\n" | |
846 "the next frame you create on that DISPLAY will crash this\n" | |
847 "XEmacs. At a minimum, provide one font with an XLFD ending\n" | |
848 "in `" FALLBACK_ASCII_REGISTRY "', so we can work out what size\n" | |
849 "a frame should be. ", | |
850 eidata (ei_connection_name)); | |
851 } | |
852 | |
853 } | |
854 | |
3659 | 855 /* This function used to return the font spec, in the case where a font |
856 didn't exist on the X server but it did match the charset. We're not | |
857 doing that any more, because none of the other platform code does, and | |
858 the old behaviour was badly-judged in other respects, so I don't trust | |
859 the original author to have had a good reason for it. */ | |
860 | |
861 return result; | |
862 } | |
863 | |
864 #endif /* MULE */ |