comparison src/xft-fonts.c @ 3094:ad2f4ae9895b

[xemacs-hg @ 2005-11-26 11:45:47 by stephent] Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author stephent
date Sat, 26 Nov 2005 11:46:25 +0000
parents
children 859a2346db99
comparison
equal deleted inserted replaced
3093:769dc945b085 3094:ad2f4ae9895b
1 /* Lisp font handling implementation for X with Xft.
2
3 Copyright (C) 2003 Eric Knauel and Matthias Neubauer
4 Copyright (C) 2005 Eric Knauel
5 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
6
7 Authors: Eric Knauel <knauel@informatik.uni-tuebingen.de>
8 Matthias Neubauer <neubauer@informatik.uni-freiburg.de>
9 Stephen J. Turnbull <stephen@xemacs.org>
10 Created: 27 Oct 2003
11 Updated: 05 Mar 2005 by Stephen J. Turnbull
12
13 This file is part of XEmacs.
14
15 XEmacs is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License as published by the
17 Free Software Foundation; either version 2, or (at your option) any
18 later version.
19
20 XEmacs is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with XEmacs; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. */
29
30 /* Synched up with: Not in GNU Emacs. */
31
32 /* This module provides the Lisp interface to fonts in X11, including Xft,
33 but (at least at first) not GTK+ or Qt.
34
35 It should be renamed to fonts-x.h.
36
37 Sealevel code should be in ../lwlib/lwlib-fonts.c or
38 ../lwlib/lwlib-colors.c.
39 */
40
41 #include <config.h>
42 #include "lisp.h"
43 #include "device.h"
44 #include "device-impl.h"
45 #include "console-x-impl.h"
46 #include "objects-x.h"
47 #include "objects-x-impl.h"
48 #include "hash.h"
49 #include "xft-fonts.h"
50
51 /* #### TO DO ####
52 . The "x-xft-*" and "x_xft_*" nomenclature is mostly redundant, especially
53 if we separate X fonts from Xft fonts, and use fontconfig more generally.
54 . We should support the most recent Xft first, old Xft libraries later.
55 . We may (think about it) wish to use fontconfig generally, even if we're
56 not using Xft. Either way, names that are really from fontconfig should
57 use the Fc* namespace.
58 . Mule-ize this file.
59 . Separate X Font Struct ops from Xft Font ops; give precedence to Xft but
60 allow fallback to X.
61 . Push decisions about font choice, defaults, fallbacks to Lisp; if we
62 really need efficiency, can reimplement in C later.
63 . Implement symbols interned in this file in the Q* namespace.
64 . Implement FcMatrix (Lisp vector).
65 . Implement FcCharSets (Lisp chartable? For implementation hints, see
66 FcCharSetFirstPage and FcCharSetNextPage).
67 . Implement FcConfigs.
68 DONE
69 . Fontconfig fontnames are encoded in UTF-8.
70 */
71
72 Lisp_Object Qxft_font;
73 Lisp_Object Qfc_patternp;
74 Lisp_Object Qfc_fontsetp;
75 /* Lisp_Object Qfc_result_match; */ /* FcResultMatch */
76 Lisp_Object Qfc_result_type_mismatch; /* FcResultTypeMismatch */
77 Lisp_Object Qfc_result_no_match; /* FcResultNoMatch */
78 Lisp_Object Qfc_result_no_id; /* FcResultNoId */
79 Lisp_Object Qfc_internal_error;
80 Lisp_Object Vxlfd_font_name_regexp; /* #### Really needed? */
81 Lisp_Object Vxft_version;
82 /* Lisp_Object Vfc_version; */ /* #### Should have this, too! */
83 Fixnum debug_xft; /* Set to 1 enables lots of obnoxious messages.
84 Setting it to 2 or 3 enables even more. */
85
86 /****************************************************************
87 * FcPattern objects *
88 ****************************************************************/
89
90 static void
91 finalize_fc_pattern (void *header, int UNUSED (for_disksave))
92 {
93 struct fc_pattern *p = (struct fc_pattern *) header;
94 if (p->fcpatPtr)
95 {
96 FcPatternDestroy (p->fcpatPtr);
97 p->fcpatPtr = 0;
98 }
99 }
100
101 static const struct memory_description fcpattern_description [] = {
102 /* #### nothing here, is this right?? */
103 { XD_END }
104 };
105
106 DEFINE_LRECORD_IMPLEMENTATION("fc-pattern", fc_pattern,
107 0, 0, 0, finalize_fc_pattern, 0, 0,
108 fcpattern_description,
109 struct fc_pattern);
110
111 /*
112 * Helper Functions
113 */
114 static Lisp_Object make_xlfd_font_regexp (void);
115 static void string_list_to_fcobjectset (Lisp_Object list, FcObjectSet *os);
116
117 /*
118 extract the C representation of the Lisp string STR and convert it
119 to the encoding used by the Fontconfig API for property and font
120 names. I suppose that Qnative is the right encoding, the manual
121 doesn't say much about this topic. This functions assumes that STR
122 is a Lisp string.
123 */
124 #define extract_fcapi_string(str) \
125 ((FcChar8 *) NEW_LISP_STRING_TO_EXTERNAL ((str), Qnative))
126
127 /* fontconfig assumes that objects (property names) are statically allocated,
128 and you will get bizarre results if you pass Lisp string data or strings
129 allocated on the stack as objects. fontconfig _does_ copy values, so we
130 (I hope) don't have to worry about that member.
131
132 Probably these functions don't get called so often that the memory leak
133 due to strdup'ing every time we add a property would matter, but XEmacs
134 _is_ a long-running process. So we hash them.
135
136 I suspect that using symbol names or even keywords does not provide
137 assurance that the string won't move in memory. So we hash them
138 ourselves; hash.c hashtables do not interpret the value pointers. */
139 static FcChar8 *fc_standard_properties[] = {
140 "antialias", "aspect", "autohint", "charset", "dpi", "family", "file",
141 "foundry", "ftface", "globaladvance", "hinting", "index", "lang",
142 "minspace", "outline", "pixelsize", "rasterizer", "rgba", "scalable",
143 "scale", "size", "slant", "spacing", "style", "verticallayout", "weight",
144 /* obsolete after Xft v. 1 */
145 "charwidth", "charheight", "core", "encoding", "render"
146 };
147
148 static struct hash_table *fc_property_name_hash_table;
149
150 /* #### Maybe fc_intern should be exposed to LISP? The idea is that
151 fc-pattern-add could warn or error if the property isn't interned. */
152
153 static FcChar8 *
154 fc_intern (Lisp_Object property)
155 {
156 const void *dummy;
157 FcChar8 *prop = extract_fcapi_string (property);
158 const void *val = gethash (prop, fc_property_name_hash_table, &dummy);
159
160 /* extract_fcapi_string returns something alloca'd
161 so we can just drop the old value of prop on the floor */
162 if (val)
163 prop = (FcChar8 *) val;
164 else
165 {
166 prop = FcStrCopy (prop);
167 puthash (prop, NULL, fc_property_name_hash_table);
168 }
169 return prop;
170 }
171
172 DEFUN("fc-pattern-p", Ffc_pattern_p, 1, 1, 0, /*
173 Returns t if OBJECT is of type fc-pattern, nil otherwise.
174 */
175 (object))
176 {
177 return FCPATTERNP(object) ? Qt : Qnil;
178 }
179
180 DEFUN("fc-pattern-create", Ffc_pattern_create, 0, 0, 0, /*
181 Return a new, empty fc-pattern object.
182 */
183 ())
184 {
185 fc_pattern *fcpat =
186 ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
187
188 fcpat->fcpatPtr = FcPatternCreate();
189 return wrap_fcpattern(fcpat);
190 }
191
192 DEFUN("fc-name-parse", Ffc_name_parse, 1, 1, 0, /*
193 Parse an Fc font name and return its representation as a fc pattern object.
194 */
195 (name))
196 {
197 struct fc_pattern *fcpat =
198 ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
199
200 CHECK_STRING(name); /* #### MEMORY LEAK!! maybe not ... */
201
202 fcpat->fcpatPtr = FcNameParse (extract_fcapi_string (name));
203 return wrap_fcpattern(fcpat);
204 }
205
206 /* #### Ga-a-ack! Xft's similar function is actually a different API.
207 We provide both. */
208 DEFUN("fc-name-unparse", Ffc_name_unparse, 1, 1, 0, /*
209 Unparse an fc pattern object to a string.
210 */
211 (pattern))
212 {
213 CHECK_FCPATTERN(pattern);
214 {
215 FcChar8 *temp = FcNameUnparse(XFCPATTERN_PTR(pattern));
216 Lisp_Object res = build_ext_string (temp, Qxft_font_name_encoding);
217 free (temp);
218 return res;
219 }
220 }
221
222 #if 0
223 /* #### This seems to not work? */
224 DEFUN("xft-name-unparse", Fxft_name_unparse, 1, 1, 0, /*
225 Unparse an fc pattern object to a string (using the Xft API).
226 */
227 (pattern))
228 {
229 char temp[FCSTRLEN];
230 Bool res;
231
232 CHECK_FCPATTERN(pattern);
233 res = XftNameUnparse(XFCPATTERN_PTR(pattern), temp, FCSTRLEN-1);
234 return res ? build_ext_string (temp, Qxft_font_name_encoding) : Qnil;
235 }
236 #endif
237
238 DEFUN("fc-pattern-duplicate", Ffc_pattern_duplicate, 1, 1, 0, /*
239 Make a copy of the fc pattern object PATTERN and return it.
240 */
241 (pattern))
242 {
243 struct fc_pattern *copy = NULL;
244 CHECK_FCPATTERN(pattern);
245
246 copy = ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
247 copy->fcpatPtr = FcPatternDuplicate(XFCPATTERN_PTR(pattern));
248 return wrap_fcpattern(copy);
249 }
250
251 DEFUN("fc-pattern-add", Ffc_pattern_add, 3, 3, 0, /*
252 Add attributes to the pattern object PATTERN. PROPERTY is a string naming
253 the attribute to add, VALUE the value for this attribute.
254
255 VALUE may be a string, integer, float, or symbol, in which case the value
256 will be added as an FcChar8[], int, double, or FcBool respectively.
257 */
258 (pattern, property, value))
259 {
260 Bool res = 0;
261 Extbyte *obj;
262 FcPattern *fcpat;
263
264 CHECK_FCPATTERN(pattern);
265 CHECK_STRING(property);
266
267 obj = fc_intern (property);
268 fcpat = XFCPATTERN_PTR (pattern);
269
270 if (STRINGP(value))
271 {
272 FcChar8 *str = (FcChar8 *) extract_fcapi_string (value);
273 res = FcPatternAddString (fcpat, obj, str);
274 }
275 else if (INTP(value))
276 {
277 res = FcPatternAddInteger (fcpat, obj, XINT(value));
278 }
279 else if (FLOATP(value))
280 {
281 res = FcPatternAddDouble (fcpat, obj, (double) XFLOAT_DATA(value));
282 }
283 else if (SYMBOLP(value))
284 {
285 res = FcPatternAddBool (fcpat, obj, !NILP(value));
286 }
287 /* else ... maybe we should wta here? */
288
289 return res ? Qt : Qnil;
290 }
291
292 DEFUN("fc-pattern-del", Ffc_pattern_del, 2, 2, 0, /*
293 Remove attribute PROPERTY from fc pattern object OBJECT.
294 */
295 (pattern, property))
296 {
297 Bool res;
298
299 CHECK_FCPATTERN(pattern);
300 CHECK_STRING(property);
301
302 res = FcPatternDel(XFCPATTERN_PTR(pattern),
303 extract_fcapi_string (property));
304 return res ? Qt : Qnil;
305 }
306
307 /* Generic interface to FcPatternGet()
308 * Don't support the losing symbol-for-property interface.
309 */
310 DEFUN("fc-pattern-get", Ffc_pattern_get, 2, 4, 0, /*
311 From PATTERN, extract PROPERTY for the ID'th member, of type TYPE.
312
313 PATTERN is an Xft (fontconfig) pattern object.
314 PROPERTY is a string naming an fontconfig font property.
315 Optional ID is a nonnegative integer indexing the list of values for PROPERTY
316 stored in PATTERN, defaulting to 0 (the first value).
317 Optional TYPE is a symbol, one of 'string, 'boolean, 'integer, 'float,
318 'double, 'matrix, 'charset, or 'void, corresponding to the FcValue types.
319 ('float is an alias for 'double).
320
321 The Lisp types returned will conform to TYPE:
322 string string
323 boolean `t' or `nil'
324 integer integer
325 double (float) float
326 matrix not implemented
327 charset not implemented
328 void not implemented
329
330 Symbols with names of the form "fc-result-DESCRIPTION" are returned when
331 the desired value is not available. These are
332
333 fc-result-type-mismatch the value found has an unexpected type
334 fc-result-no-match there is no such attribute
335 fc-result-no-id there is no value for the requested ID
336
337 The types of the following standard properties are predefined by fontconfig.
338 The symbol 'fc-result-type-mismatch will be returned if the object exists but
339 TYPE does not match the predefined type. It is best not to specify a type
340 for predefined properties, as a mistake here ensures error returns on the
341 correct type.
342
343 Each standard property has a convenience accessor defined in fontconfig.el,
344 named in the form "fc-pattern-get-PROPERTY". The convenience functions are
345 preferred to `fc-pattern-get' since a typo in the string naming a property
346 will result in a silent null return, while a typo in a function name will
347 usually result in a compiler or runtime \"not fboundp\" error. You may use
348 `defsubst' to define convenience functions for non-standard properties.
349
350 family String Font family name
351 style String Font style. Overrides weight and slant
352 slant Int Italic, oblique or roman
353 weight Int Light, medium, demibold, bold or black
354 size Double Point size
355 aspect Double Stretches glyphs horizontally before hinting
356 pixelsize Double Pixel size
357 spacing Int Proportional, monospace or charcell
358 foundry String Font foundry name
359 antialias Bool Whether glyphs can be antialiased
360 hinting Bool Whether the rasterizer should use hinting
361 verticallayout Bool Use vertical layout
362 autohint Bool Use autohinter instead of normal hinter
363 globaladvance Bool Use font global advance data
364 file String The filename holding the font
365 index Int The index of the font within the file
366 ftface FT_Face Use the specified FreeType face object
367 rasterizer String Which rasterizer is in use
368 outline Bool Whether the glyphs are outlines
369 scalable Bool Whether glyphs can be scaled
370 scale Double Scale factor for point->pixel conversions
371 dpi Double Target dots per inch
372 rgba Int unknown, rgb, bgr, vrgb, vbgr, none - subpixel geometry
373 minspace Bool Eliminate leading from line spacing
374 charset CharSet Unicode chars encoded by the font
375 lang String List of RFC-3066-style languages this font supports
376
377 The FT_Face, Matrix, CharSet types are unimplemented, so the corresponding
378 properties are not accessible from Lisp at this time. If the value of a
379 property returned has type FT_Face, FcCharSet, or FcMatrix,
380 `fc-result-type-mismatch' is returned.
381
382 The following properties which were standard in Xft v.1 are obsolete in
383 Xft v.2: encoding, charwidth, charheight, core, and render. */
384 (pattern, property, id, type))
385 {
386 FcChar8 *fc_property; /* UExtbyte * */
387 FcResult fc_result;
388 FcValue fc_value;
389
390 /*
391 process arguments
392 */
393 CHECK_FCPATTERN (pattern);
394
395 #if 0
396 /* Don't support the losing symbol-for-property interface. */
397 property = SYMBOLP (property) ? symbol_name (XSYMBOL (property)) : property;
398 #endif
399 if (STRINGP (property))
400 {
401 fc_property = (FcChar8 *) extract_fcapi_string (property);
402 }
403 else
404 {
405 /* if we allow symbols, this would need to be
406 list3 (Qlambda, list1 (Qobject),
407 list3 (Qor, list2 (Qstringp, Qobject),
408 list2 (Qsymbolp, Qobject)))
409 or something like that? */
410 dead_wrong_type_argument (Qstringp, property);
411 }
412
413 if (!NILP (id)) CHECK_NATNUM (id);
414 if (!NILP (type)) CHECK_SYMBOL (type);
415
416 /* get property */
417 fc_result = FcPatternGet (XFCPATTERN_PTR (pattern),
418 fc_property,
419 NILP (id) ? 0 : XINT(id),
420 &fc_value);
421
422 switch (fc_result)
423 {
424 case FcResultMatch:
425 /* wrap it and return */
426 switch (fc_value.type)
427 {
428 case FcTypeInteger:
429 return ((!NILP (type) && !EQ (type, Qinteger))
430 ? Qfc_result_type_mismatch : make_int (fc_value.u.i));
431 case FcTypeDouble:
432 return ((!NILP (type) && !EQ (type, intern ("double"))
433 && !EQ (type, Qfloat))
434 ? Qfc_result_type_mismatch : make_float (fc_value.u.d));
435 case FcTypeString:
436 return ((!NILP (type) && !EQ (type, Qstring))
437 ? Qfc_result_type_mismatch
438 : build_ext_string (fc_value.u.s, Qxft_font_name_encoding));
439 case FcTypeBool:
440 return ((!NILP (type) && !EQ (type, Qboolean))
441 ? Qfc_result_type_mismatch : fc_value.u.b ? Qt : Qnil);
442 case FcTypeMatrix:
443 return Qfc_result_type_mismatch;
444 /* #### unimplemented
445 return ((!NILP (type) && !EQ (type, intern ("matrix")))
446 ? Qfc_result_type_mismatch : make_int (fc_value.u.m));
447 */
448 case FcTypeCharSet:
449 return Qfc_result_type_mismatch;
450 /* #### unimplemented
451 return ((!NILP (type) && !EQ (type, intern ("charset")))
452 ? Qfc_result_type_mismatch : make_int (fc_value.u.c));
453 */
454 }
455 case FcResultTypeMismatch:
456 return Qfc_result_type_mismatch;
457 case FcResultNoMatch:
458 return Qfc_result_no_match;
459 case FcResultNoId:
460 return Qfc_result_no_id;
461 default:
462 return Qfc_internal_error;
463 }
464 }
465
466 #if 0
467 /* #### delete this after some testing!! don't forget the DEFSUBR */
468 /* #### This is a big mistake, no? --- crap, there's no implicit finalizer */
469 DEFUN("fc-pattern-destroy", Ffc_pattern_destroy, 1, 1, 0, /*
470 Explicitly deallocate a fc pattern object PATTERN. */
471 (pattern))
472 {
473 CHECK_FCPATTERN(pattern);
474
475 /* paranoia strikes deep */
476 if (XFCPATTERN_PTR(pattern))
477 {
478 FcPatternDestroy(XFCPATTERN_PTR(pattern));
479 XFCPATTERN_PTR(pattern) = 0;
480 }
481 return Qnil;
482 }
483 #endif
484
485 DEFUN("fc-font-match", Ffc_font_match, 2, 2, 0, /*
486 Return the font on DEVICE that most closely matches PATTERN.
487
488 DEVICE is an X11 device.
489 PATTERN is a fontconfig pattern object.
490 Returns a fontconfig pattern object representing the closest match to the
491 given pattern, or an error code. Possible error codes are
492 `fc-result-no-match' and `fc-result-no-id'. */
493 (device, pattern))
494 {
495 Display *dpy;
496 FcResult res;
497
498 struct fc_pattern *res_fcpat =
499 ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
500 CHECK_FCPATTERN(pattern); /* #### MEMORY LEAKS!!! */
501 if (NILP(device))
502 return Qnil;
503 CHECK_X_DEVICE(device);
504 if (!DEVICE_LIVE_P(XDEVICE(device)))
505 return Qnil;
506
507 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
508 /* More Xft vs fontconfig brain damage? */
509 res_fcpat->fcpatPtr = XftFontMatch(dpy, DefaultScreen (dpy),
510 XFCPATTERN_PTR(pattern), &res);
511
512 if (res_fcpat->fcpatPtr == NULL)
513 switch (res) {
514 case FcResultNoMatch:
515 return Qfc_result_no_match;
516 case FcResultNoId:
517 return Qfc_result_no_id;
518 default:
519 return Qfc_internal_error;
520 }
521 else
522 return wrap_fcpattern(res_fcpat);
523 }
524
525 /* NOTE NOTE NOTE This function destroys the FcFontSet passed to it. */
526 static Lisp_Object
527 fontset_to_list (FcFontSet *fontset)
528 {
529 int idx;
530 Lisp_Object fontlist = Qnil;
531 fc_pattern *fcpat;
532
533 /* #### improve this error message */
534 if (!fontset)
535 Fsignal (Qinvalid_state,
536 list1 (build_string ("failed to create FcFontSet")));
537 for (idx = 0; idx < fontset->nfont; ++idx)
538 {
539 fcpat =
540 ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
541 fcpat->fcpatPtr = FcPatternDuplicate (fontset->fonts[idx]);
542 fontlist = Fcons (wrap_fcpattern(fcpat), fontlist);
543 }
544 FcFontSetDestroy (fontset);
545 return fontlist;
546 }
547
548 /* #### fix this name to correspond to Ben's new nomenclature */
549 DEFUN("fc-list-fonts-pattern-objects", Ffc_list_fonts_pattern_objects,
550 3, 3, 0, /*
551 Return a list of fonts on DEVICE that match PATTERN for PROPERTIES.
552 Each font is represented by a fontconfig pattern object.
553
554 DEVICE is an X11 device.
555 PATTERN is a fontconfig pattern to be matched.
556 PROPERTIES is a list of property names (strings) that should match.
557
558 #### DEVICE is unused, ignored, and may be removed if it's not needed to
559 match other font-listing APIs. */
560 (UNUSED (device), pattern, properties))
561 {
562 FcObjectSet *os;
563 FcFontSet *fontset;
564
565 CHECK_FCPATTERN (pattern);
566 CHECK_LIST (properties);
567
568 os = FcObjectSetCreate ();
569 string_list_to_fcobjectset (properties, os);
570 /* #### why don't we need to do the "usual substitutions"? */
571 fontset = FcFontList (NULL, XFCPATTERN_PTR (pattern), os);
572 FcObjectSetDestroy (os);
573
574 return fontset_to_list (fontset);
575
576 }
577
578 /* #### maybe this can/should be folded into fc-list-fonts-pattern-objects? */
579 DEFUN("fc-font-sort", Ffc_font_sort, 2, 4, 0, /*
580 Return a list of all fonts sorted by proximity to PATTERN.
581 Each font is represented by a fontconfig pattern object.
582
583 DEVICE is an X11 device.
584 PATTERN is a fontconfig pattern to be matched.
585 Optional argument TRIM, if non-nil, means to trim trailing fonts that do not
586 contribute new characters to the union repertoire.
587
588 #### Optional argument NOSUB, if non-nil, suppresses some of the usual
589 property substitutions. DON'T USE THIS in production code, it is intended
590 for exploring behavior of fontconfig and will be removed when this code is
591 stable.
592
593 #### DEVICE is unused, ignored, and may be removed if it's not needed to
594 match other font-listing APIs. */
595 (UNUSED (device), pattern, trim, nosub))
596 {
597 CHECK_FCPATTERN (pattern);
598
599 {
600 FcConfig *fcc = FcConfigGetCurrent();
601 FcFontSet *fontset;
602 FcPattern *p = XFCPATTERN_PTR (pattern);
603 FcResult fcresult;
604
605 if (NILP(nosub)) /* #### temporary debug hack */
606 FcDefaultSubstitute (p);
607 FcConfigSubstitute (fcc, p, FcMatchPattern);
608 fontset = FcFontSort (fcc, p, !NILP(trim), NULL, &fcresult);
609
610 return fontset_to_list (fontset);
611 }
612 }
613
614 /* #### this actually is an Xft function, should split those out
615 or get rid of them entirely? */
616 /* #### be consistent about argument order. */
617 DEFUN("fc-font-real-pattern", Ffc_font_real_pattern, 2, 2, 0, /*
618 Temporarily open FONTNAME (a string) and return the actual
619 fc pattern matched by the Fc library. */
620 (fontname, xdevice))
621 {
622 FcPattern *copy;
623 Display *dpy;
624 XftFont *font;
625 struct fc_pattern *fcpat =
626 ALLOC_LCRECORD_TYPE (struct fc_pattern, &lrecord_fc_pattern);
627
628 CHECK_STRING (fontname); /* #### MEMORY LEAK?! maybe not ... */
629 if (NILP(xdevice))
630 return Qnil;
631 CHECK_X_DEVICE (xdevice);
632 if (!DEVICE_LIVE_P(XDEVICE(xdevice)))
633 return Qnil;
634
635 /* #### these gymnastics should be unnecessary, just use FcFontMatch */
636 dpy = DEVICE_X_DISPLAY (XDEVICE (xdevice));
637 font = XftFontOpenName (dpy, DefaultScreen(dpy),
638 extract_fcapi_string (fontname));
639 if (font == NULL)
640 return Qnil;
641 copy = FcPatternDuplicate(font->pattern);
642 XftFontClose(dpy, font);
643 if (copy == NULL)
644 return Qnil;
645 fcpat->fcpatPtr = copy;
646 return wrap_fcpattern(fcpat);
647 }
648
649 DEFUN("xlfd-font-name-p", Fxlfd_font_name_p, 1, 1, 0, /*
650 Check whether the string FONTNAME is a XLFD font name. */
651 (fontname))
652 {
653 CHECK_STRING(fontname);
654 /* #### should bind `case-fold-search' here? */
655 return Fstring_match(Vxlfd_font_name_regexp, fontname, Qnil, Qnil);
656 }
657
658 /* FcPatternPrint: there is no point in having wrappers fc-pattern-print,
659 Ffc_pattern_print since this function prints to stdout. */
660
661 /* Initialization of xft-fonts */
662
663 #define XE_XLFD_SEPARATOR "-"
664 /* XLFD specifies ISO 8859-1 encoding, but we can't handle non-ASCII
665 in Mule when this function is called. So use HPC. */
666 #if 0
667 #define XE_XLFD_PREFIX "\\(\\+[\040-\176\240-\377]*\\)?-"
668 #define XE_XLFD_OPT_TEXT "\\([\040-\044\046-\176\240-\377]*\\)"
669 #define XE_XLFD_TEXT "\\([\040-\044\046-\176\240-\377]+\\)"
670 #else
671 #define XE_XLFD_PREFIX "\\(\\+[\040-\176]*\\)?-"
672 #define XE_XLFD_OPT_TEXT "\\([^-]*\\)"
673 #define XE_XLFD_TEXT "\\([^-]+\\)"
674 #endif
675
676 #define XE_XLFD_SLANT "\\([0-9ior?*][iot]?\\)"
677 #define XE_XLFD_SPACING "\\([cmp?*]\\)"
678 /* Hyphen as minus conflicts with use as separator. */
679 #define XE_XLFD_OPT_NEGATE "~?"
680 #define XE_XLFD_NUMBER "\\([0-9?*]+\\)"
681 #define XE_XLFD_PSIZE "\\([0-9?*]+\\|\\[[ 0-9+~.e?*]+\\]\\)"
682
683 /* Call this only from the init code
684 #### This is really horrible, let's get rid of it, please. */
685 static Lisp_Object
686 make_xlfd_font_regexp (void)
687 {
688 struct gcpro gcpro1;
689 unsigned i;
690 Lisp_Object reg = Qnil;
691 const Extbyte *re[] = /* #### This could just be catenated by
692 cpp and passed to build_ext_string. */
693 {
694 /* Regular expression matching XLFDs as defined by XLFD v. 1.5.
695 Matches must be case-insensitive.
696 PSIZE is a pixel or point size, which may be a "matrix". The
697 syntax of a matrix is not checked, just some lexical properties.
698 AFAICT none of the TEXT fields except adstyle is optional.
699
700 NB. It should not be a problem if this matches "too much", since
701 an "old" server will simply not be able to find a matching font. */
702 "\\`",
703 XE_XLFD_PREFIX, /* prefix */
704 XE_XLFD_TEXT, /* foundry */
705 XE_XLFD_SEPARATOR,
706 XE_XLFD_TEXT, /* family */
707 XE_XLFD_SEPARATOR,
708 XE_XLFD_TEXT, /* weight */
709 XE_XLFD_SEPARATOR,
710 XE_XLFD_SLANT, /* slant */
711 XE_XLFD_SEPARATOR,
712 XE_XLFD_TEXT, /* swidth */
713 XE_XLFD_SEPARATOR,
714 XE_XLFD_OPT_TEXT, /* adstyle */
715 XE_XLFD_SEPARATOR,
716 XE_XLFD_PSIZE, /* pixelsize */
717 XE_XLFD_SEPARATOR,
718 XE_XLFD_PSIZE, /* pointsize */
719 XE_XLFD_SEPARATOR,
720 XE_XLFD_NUMBER, /* resx */
721 XE_XLFD_SEPARATOR,
722 XE_XLFD_NUMBER, /* resy */
723 XE_XLFD_SEPARATOR,
724 XE_XLFD_SPACING, /* spacing */
725 XE_XLFD_SEPARATOR,
726 XE_XLFD_OPT_NEGATE, /* avgwidth */
727 XE_XLFD_NUMBER,
728 XE_XLFD_SEPARATOR,
729 XE_XLFD_TEXT, /* registry */
730 XE_XLFD_SEPARATOR,
731 XE_XLFD_TEXT, /* encoding */
732 "\\'"
733 };
734
735 GCPRO1 (reg);
736 for (i = 0; i < sizeof(re)/sizeof(Extbyte *); i++)
737 {
738 /* #### Currently this is Host Portable Coding, not ISO 8859-1. */
739 reg = concat2(reg, build_ext_string (re[i], Qx_font_name_encoding));
740 }
741
742 RETURN_UNGCPRO (reg);
743 }
744 #undef XE_XLFD_SEPARATOR
745 #undef XE_XLFD_PREFIX
746 #undef XE_XLFD_OPT_TEXT
747 #undef XE_XLFD_TEXT
748 #undef XE_XLFD_OPT_SLANT
749 #undef XE_XLFD_OPT_SPACING
750 #undef XE_XLFD_OPT_NEGATE
751 #undef XE_XLFD_NUMBER
752 #undef XE_XLFD_PSIZE
753
754 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
755 ? ((unsigned long) (x)) : ((unsigned long) (y)))
756
757 static void
758 string_list_to_fcobjectset (Lisp_Object list, FcObjectSet *os)
759 {
760 EXTERNAL_LIST_LOOP_2 (elt, list)
761 {
762 FcChar8 *s;
763
764 CHECK_STRING (elt);
765 s = fc_intern (elt);
766 fprintf (stderr, "%s\n", s);
767 FcObjectSetAdd (os, s);
768 }
769 }
770
771 void
772 syms_of_xft_fonts (void)
773 {
774 INIT_LRECORD_IMPLEMENTATION(fc_pattern);
775
776 DEFSYMBOL_MULTIWORD_PREDICATE(Qfc_patternp);
777
778 DEFSYMBOL(Qfc_result_type_mismatch);
779 DEFSYMBOL(Qfc_result_no_match);
780 DEFSYMBOL(Qfc_result_no_id);
781 DEFSYMBOL(Qfc_internal_error);
782 DEFSYMBOL(Qxft_font);
783
784 DEFSUBR(Ffc_pattern_p);
785 DEFSUBR(Ffc_pattern_create);
786 DEFSUBR(Ffc_name_parse);
787 DEFSUBR(Ffc_name_unparse);
788 DEFSUBR(Fxft_name_unparse); /* URK! */
789 DEFSUBR(Ffc_pattern_duplicate);
790 DEFSUBR(Ffc_pattern_add);
791 DEFSUBR(Ffc_pattern_del);
792 DEFSUBR(Ffc_pattern_get);
793 #if 0
794 DEFSUBR(Ffc_pattern_destroy);
795 #endif
796 DEFSUBR(Ffc_list_fonts_pattern_objects);
797 DEFSUBR(Ffc_font_sort);
798 DEFSUBR(Ffc_font_match);
799 DEFSUBR(Ffc_font_real_pattern);
800 DEFSUBR(Fxlfd_font_name_p);
801 }
802
803 void
804 vars_of_xft_fonts (void)
805 {
806 /* #### I know, but the right fix is use the generic debug facility. */
807 DEFVAR_INT ("xft-debug-level", &debug_xft /*
808 Level of debugging messages to issue to stderr for Xft.
809 A nonnegative integer. Set to 0 to suppress all warnings.
810 Default is 1 to ensure a minimum of debugging output at initialization.
811 Higher levels give even more information.
812 */ );
813 debug_xft = 1;
814
815 DEFVAR_LISP("xft-version", &Vxft_version /*
816 The major version number of the Xft library being used.
817 */ );
818 Vxft_version = make_int(XFT_VERSION);
819
820 Fprovide (intern ("xft"));
821 }
822
823 void
824 complex_vars_of_xft_fonts (void)
825 {
826 DEFVAR_LISP("xft-xlfd-font-regexp", &Vxlfd_font_name_regexp /*
827 The regular expression used to match XLFD font names. */
828 );
829 Vxlfd_font_name_regexp = make_xlfd_font_regexp();
830 }
831
832 void
833 reinit_vars_of_xft_fonts (void)
834 {
835 int i, size = (int) countof (fc_standard_properties);
836
837 FcInit ();
838
839 fc_property_name_hash_table = make_string_hash_table (size);
840 for (i = 0; i < size; ++i)
841 puthash (fc_standard_properties[i], NULL, fc_property_name_hash_table);
842 }
843