comparison src/objects-xlike-inc.c @ 3659:98af8a976fc3

[xemacs-hg @ 2006-11-05 22:31:31 by aidan] Support specifying fonts for particular character sets in Mule; support translation to ISO 10646-1 for Mule character sets without an otherwise matching font; move to a vector of X11-charset-X11-registry instead of a regex for the charset-registry property.
author aidan
date Sun, 05 Nov 2006 22:31:46 +0000
parents
children 3ef0aaf3dc34
comparison
equal deleted inserted replaced
3658:0db1aaedbbef 3659:98af8a976fc3
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;
64 NULL != (new_hyphening = memchr((const void *)hyphening, '-', length));
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);
468 FcPatternDel (p, FC_WIDTH);
469 FcPatternDel (p, FC_SPACING);
470 FcPatternDel (p, FC_HINTING);
471 FcPatternDel (p, FC_VERTICAL_LAYOUT);
472 FcPatternDel (p, FC_AUTOHINT);
473 FcPatternDel (p, FC_GLOBAL_ADVANCE);
474 FcPatternDel (p, FC_INDEX);
475 FcPatternDel (p, FC_SCALE);
476 FcPatternDel (p, FC_FONTVERSION);
477 name = FcNameUnparse (p);
478 eicpy_ext (eistr_longname, (Extbyte *) name, Qfc_font_name_encoding);
479 free (name);
480
481 /* nickname, just family and size, but
482 "family" names usually have style, slant, and weight */
483 FcPatternDel (p, FC_FOUNDRY);
484 FcPatternDel (p, FC_STYLE);
485 FcPatternDel (p, FC_SLANT);
486 FcPatternDel (p, FC_WEIGHT);
487 FcPatternDel (p, FC_PIXEL_SIZE);
488 FcPatternDel (p, FC_OUTLINE);
489 FcPatternDel (p, FC_SCALABLE);
490 FcPatternDel (p, FC_DPI);
491 name = FcNameUnparse (p);
492 eicpy_ext (eistr_shortname, (Extbyte *) name, Qfc_font_name_encoding);
493 free (name);
494
495 FcPatternDestroy (p);
496 }
497
498 /* The language approach may better in the long run, but we can't use
499 it based on Mule charsets; fontconfig doesn't provide a way to test
500 for unions of languages, etc. That will require support from the
501 text module.
502
503 Optimization: cache the generated FcCharSet in the Mule charset.
504 Don't forget to destroy it if the Mule charset gets deallocated. */
505
506 {
507 /* This block possibly should be a function, but it generates
508 multiple values. I find the "pass an address to return the
509 value in" idiom opaque, so prefer a block. */
510 struct charset_reporter *cr;
511 for (cr = charset_table;
512 cr->charset && !EQ (*(cr->charset), charset);
513 cr++)
514 ;
515
516 if (cr->rfc3066)
517 {
518 DECLARE_DEBUG_FONTNAME (name);
519 CHECKING_LANG (0, eidata(name), cr->language);
520 lang = (FcChar8 *) cr->rfc3066;
521 }
522 else if (cr->charset)
523 {
524 /* what the hey, build 'em on the fly */
525 /* #### in the case of error this could return NULL! */
526 fccs = mule_to_fc_charset (charset);
527 lang = (FcChar8 *) XSTRING_DATA (XSYMBOL
528 (XCHARSET_NAME (charset))-> name);
529 }
530 else
531 {
532 /* OK, we fell off the end of the table */
533 warn_when_safe_lispobj (intern ("xft"), intern ("alert"),
534 list2 (build_string ("unchecked charset"),
535 charset));
536 /* default to "en"
537 #### THIS IS WRONG, WRONG, WRONG!!
538 It is why we never fall through to XLFD-checking. */
539 }
540
541 ASSERT_ASCTEXT_ASCII((Extbyte *) lang);
542
543 if (fccs)
544 {
545 /* check for character set coverage */
546 int i = 0;
547 FcCharSet *v;
548 FcResult r = FcPatternGetCharSet (fontxft, FC_CHARSET, i, &v);
549
550 if (r == FcResultTypeMismatch)
551 {
552 DEBUG_XFT0 (0, "Unexpected type return in charset value\n");
553 result = Qnil;
554 }
555 else if (r == FcResultMatch && FcCharSetIsSubset (fccs, v))
556 {
557 /* The full pattern with the bitmap coverage is massively
558 unwieldy, but the shorter names are just *wrong*. We
559 should have the full thing internally as truename, and
560 filter stuff the client doesn't want to see on output.
561 Should we just store it into the truename right here? */
562 DECLARE_DEBUG_FONTNAME (name);
563 DEBUG_XFT2 (0, "Xft font %s supports %s\n",
564 eidata(name), lang);
565 #ifdef RETURN_LONG_FONTCONFIG_NAMES
566 result = eimake_string(eistr_fullname);
567 #else
568 result = eimake_string(eistr_longname);
569 #endif
570 }
571 else
572 {
573 DECLARE_DEBUG_FONTNAME (name);
574 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n",
575 eidata(name), lang);
576 result = Qnil;
577 }
578
579 /* clean up */
580 FcCharSetDestroy (fccs);
581 }
582 else
583 {
584 /* check for language coverage */
585 int i = 0;
586 FcValue v;
587 /* the main event */
588 FcResult r = FcPatternGet (fontxft, FC_LANG, i, &v);
589
590 if (r == FcResultMatch)
591 {
592 if (v.type != FcTypeLangSet) /* excessive paranoia */
593 {
594 ASSERT_ASCTEXT_ASCII(FcTypeOfValueToString(v));
595 /* Urk! Fall back and punt to core font. */
596 DEBUG_XFT1 (0, "Unexpected type of lang value (%s)\n",
597 FcTypeOfValueToString (v));
598 result = Qnil;
599 }
600 else if (FcLangSetHasLang (v.u.l, lang) != FcLangDifferentLang)
601 {
602 DECLARE_DEBUG_FONTNAME (name);
603 DEBUG_XFT2 (0, "Xft font %s supports %s\n",
604 eidata(name), lang);
605 #ifdef RETURN_LONG_FONTCONFIG_NAMES
606 result = eimake_string(eistr_fullname);
607 #else
608 result = eimake_string(eistr_longname);
609 #endif
610 }
611 else
612 {
613 DECLARE_DEBUG_FONTNAME (name);
614 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n",
615 eidata(name), lang);
616 result = Qnil;
617 }
618 }
619 else
620 {
621 ASSERT_ASCTEXT_ASCII(FcResultToString(r));
622 DEBUG_XFT1 (0, "Getting lang: unexpected result=%s\n",
623 FcResultToString (r));
624 result = Qnil;
625 }
626 }
627
628 /* clean up and maybe return */
629 FcPatternDestroy (fontxft);
630 if (!UNBOUNDP (result))
631 return result;
632 }
633 }
634 return Qnil;
635 }
636 #undef DECLARE_DEBUG_FONTNAME
637
638 #endif /* USE_XFT */
639
640 /* find a font spec that matches font spec FONT and also matches
641 (the registry of) CHARSET. */
642 static Lisp_Object
643 #ifdef THIS_IS_GTK
644 gtk_find_charset_font (Lisp_Object device, Lisp_Object font,
645 Lisp_Object charset,
646 enum font_specifier_matchspec_stages stage)
647 #else
648 x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset,
649 enum font_specifier_matchspec_stages stage)
650 #endif
651 {
652 Lisp_Object result = Qnil, registries = Qnil;
653 int j, hyphen_count, registries_len = 0;
654 Ibyte *hyphening, *new_hyphening;
655 Bytecount xlfd_length;
656
657 DECLARE_EISTRING(ei_xlfd_without_registry);
658 DECLARE_EISTRING(ei_xlfd);
659
660 #ifdef USE_XFT
661 result = xft_find_charset_font(font, charset, stage);
662 if (!NILP(result))
663 {
664 return result;
665 }
666 #endif
667
668 switch (stage)
669 {
670 case initial:
671 {
672 if (!(NILP(XCHARSET_REGISTRIES(charset)))
673 && VECTORP(XCHARSET_REGISTRIES(charset)))
674 {
675 registries_len = XVECTOR_LENGTH(XCHARSET_REGISTRIES(charset));
676 registries = XCHARSET_REGISTRIES(charset);
677 }
678 break;
679 }
680 case final:
681 {
682 registries_len = 1;
683 registries = Qunicode_registries;
684 break;
685 }
686 default:
687 {
688 assert(0);
689 break;
690 }
691 }
692
693 eicpy_lstr(ei_xlfd, font);
694 hyphening = eidata(ei_xlfd);
695 xlfd_length = eilen(ei_xlfd);
696
697 /* Count the hyphens in the string, moving new_hyphening to just after the
698 last one. */
699 hyphen_count = count_hyphens(hyphening, xlfd_length, &new_hyphening);
700
701 if (0 == registries_len || (5 > hyphen_count &&
702 !(1 == xlfd_length && '*' == *hyphening)))
703 {
704 /* No proper XLFD specified, or we can't modify the pattern to change
705 the registry and encoding to match what we want, or we have no
706 information on the registry needed. */
707 eito_external(ei_xlfd, Qx_font_name_encoding);
708 DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n",
709 eidata(ei_xlfd));
710 result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd),
711 charset, stage);
712 /* No need to loop through the available registries; return
713 immediately. */
714 return result;
715 }
716 else if (1 == xlfd_length && '*' == *hyphening)
717 {
718 /* It's a single asterisk. We can add the registry directly to the
719 end. */
720 eicpy_ch(ei_xlfd_without_registry, '*');
721 }
722 else
723 {
724 /* It's a fully-specified XLFD. Work out where the registry and
725 encoding are, and initialise ei_xlfd_without_registry to the string
726 without them. */
727
728 /* count_hyphens has set new_hyphening to just after the last
729 hyphen. Move back to just after the hyphen before it. */
730
731 for (new_hyphening -= 2; new_hyphening > hyphening
732 && '-' != *new_hyphening; --new_hyphening)
733 ;
734 ++new_hyphening;
735
736 eicpy_ei(ei_xlfd_without_registry, ei_xlfd);
737
738 /* Manipulate ei_xlfd_without_registry, using the information about
739 ei_xlfd, to which it's identical. */
740 eidel(ei_xlfd_without_registry, new_hyphening - hyphening, -1,
741 eilen(ei_xlfd) - (new_hyphening - hyphening), -1);
742
743 }
744
745 /* Now, loop through the registries and encodings defined for this
746 charset, doing an XListFonts each time with the pattern modified to
747 specify the regisry and encoding. This avoids huge amounts of IPC and
748 duplicated searching; now we use the searching the X server was doing
749 anyway, where before the X server did its search, transferred huge
750 amounts of data, and then we proceeded to do a regexp search on that
751 data. */
752 for (j = 0; j < registries_len && NILP(result); ++j)
753 {
754 eireset(ei_xlfd);
755 eicpy_ei(ei_xlfd, ei_xlfd_without_registry);
756
757 eicat_lstr(ei_xlfd, XVECTOR_DATA(registries)[j]);
758
759 eito_external(ei_xlfd, Qx_font_name_encoding);
760
761 DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n",
762 eidata(ei_xlfd));
763 result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd),
764 charset, stage);
765 }
766
767 /* This function used to return the font spec, in the case where a font
768 didn't exist on the X server but it did match the charset. We're not
769 doing that any more, because none of the other platform code does, and
770 the old behaviour was badly-judged in other respects, so I don't trust
771 the original author to have had a good reason for it. */
772
773 return result;
774 }
775
776 #endif /* MULE */