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. */
|
|
128 if (UNBOUNDP (charset))
|
|
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 */
|