Remove subprocesses #ifdefs from term.c.
[bpt/emacs.git] / src / font.c
CommitLineData
c2f5bfd6 1/* font.c -- "Font" primitives.
114f9c96
GM
2 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010
c2f5bfd6
KH
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
c2f5bfd6 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
c2f5bfd6
KH
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c2f5bfd6
KH
21
22#include <config.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <ctype.h>
d7306fe6 26#include <setjmp.h>
c2f5bfd6
KH
27
28#include "lisp.h"
29#include "buffer.h"
30#include "frame.h"
10d16101 31#include "window.h"
c2f5bfd6
KH
32#include "dispextern.h"
33#include "charset.h"
34#include "character.h"
35#include "composite.h"
36#include "fontset.h"
37#include "font.h"
38
43c0454d
KH
39#ifdef HAVE_X_WINDOWS
40#include "xterm.h"
41#endif /* HAVE_X_WINDOWS */
42
43#ifdef HAVE_NTGUI
44#include "w32term.h"
45#endif /* HAVE_NTGUI */
46
edfda783
AR
47#ifdef HAVE_NS
48#include "nsterm.h"
49#endif /* HAVE_NS */
50
ed96cde8
AR
51#ifdef HAVE_NS
52extern Lisp_Object Qfontsize;
53#endif
c2f5bfd6 54
e0708580
KH
55Lisp_Object Qopentype;
56
35027d0c 57/* Important character set strings. */
9e1bb909 58Lisp_Object Qascii_0, Qiso8859_1, Qiso10646_1, Qunicode_bmp, Qunicode_sip;
1bb1d99b 59
edfda783 60#define DEFAULT_ENCODING Qiso8859_1
edfda783 61
071132a9
KH
62/* Unicode category `Cf'. */
63static Lisp_Object QCf;
64
c2f5bfd6
KH
65/* Special vector of zero length. This is repeatedly used by (struct
66 font_driver *)->list when a specified font is not found. */
35027d0c 67static Lisp_Object null_vector;
c2f5bfd6 68
d0ab1ebe
KH
69static Lisp_Object Vfont_weight_table, Vfont_slant_table, Vfont_width_table;
70
71/* Vector of Vfont_weight_table, Vfont_slant_table, and Vfont_width_table. */
c2f5bfd6
KH
72static Lisp_Object font_style_table;
73
d0ab1ebe
KH
74/* Structure used for tables mapping weight, slant, and width numeric
75 values and their names. */
76
77struct table_entry
78{
79 int numeric;
80 /* The first one is a valid name as a face attribute.
81 The second one (if any) is a typical name in XLFD field. */
5e2327cf 82 const char *names[5];
d0ab1ebe
KH
83};
84
85/* Table of weight numeric values and their names. This table must be
86 sorted by numeric values in ascending order. */
87
5e2327cf 88static const struct table_entry weight_table[] =
d0ab1ebe
KH
89{
90 { 0, { "thin" }},
91 { 20, { "ultra-light", "ultralight" }},
92 { 40, { "extra-light", "extralight" }},
93 { 50, { "light" }},
94 { 75, { "semi-light", "semilight", "demilight", "book" }},
c2694a06 95 { 100, { "normal", "medium", "regular", "unspecified" }},
d0ab1ebe
KH
96 { 180, { "semi-bold", "semibold", "demibold", "demi" }},
97 { 200, { "bold" }},
98 { 205, { "extra-bold", "extrabold" }},
99 { 210, { "ultra-bold", "ultrabold", "black" }}
100};
101
102/* Table of slant numeric values and their names. This table must be
103 sorted by numeric values in ascending order. */
104
5e2327cf 105static const struct table_entry slant_table[] =
d0ab1ebe
KH
106{
107 { 0, { "reverse-oblique", "ro" }},
108 { 10, { "reverse-italic", "ri" }},
c2694a06 109 { 100, { "normal", "r", "unspecified" }},
d0ab1ebe
KH
110 { 200, { "italic" ,"i", "ot" }},
111 { 210, { "oblique", "o" }}
112};
113
114/* Table of width numeric values and their names. This table must be
115 sorted by numeric values in ascending order. */
116
5e2327cf 117static const struct table_entry width_table[] =
d0ab1ebe
KH
118{
119 { 50, { "ultra-condensed", "ultracondensed" }},
120 { 63, { "extra-condensed", "extracondensed" }},
121 { 75, { "condensed", "compressed", "narrow" }},
122 { 87, { "semi-condensed", "semicondensed", "demicondensed" }},
c2694a06 123 { 100, { "normal", "medium", "regular", "unspecified" }},
d0ab1ebe
KH
124 { 113, { "semi-expanded", "semiexpanded", "demiexpanded" }},
125 { 125, { "expanded" }},
126 { 150, { "extra-expanded", "extraexpanded" }},
127 { 200, { "ultra-expanded", "ultraexpanded", "wide" }}
128};
129
35027d0c 130extern Lisp_Object Qnormal;
c2f5bfd6
KH
131
132/* Symbols representing keys of normal font properties. */
b1868a1a
CY
133extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth;
134extern Lisp_Object QCheight, QCsize, QCname;
135
35027d0c 136Lisp_Object QCfoundry, QCadstyle, QCregistry;
c2f5bfd6 137/* Symbols representing keys of font extra info. */
35027d0c
KH
138Lisp_Object QCspacing, QCdpi, QCscalable, QCotf, QClang, QCscript, QCavgwidth;
139Lisp_Object QCantialias, QCfont_entity, QCfc_unknown_spec;
ec6fe57c
KH
140/* Symbols representing values of font spacing property. */
141Lisp_Object Qc, Qm, Qp, Qd;
cf702558
CY
142/* Special ADSTYLE properties to avoid fonts used for Latin
143 characters; used in xfont.c and ftfont.c. */
144Lisp_Object Qja, Qko;
c2f5bfd6 145
42707278
JD
146Lisp_Object QCuser_spec;
147
819e81df
KH
148Lisp_Object Vfont_encoding_alist;
149
1701724c
KH
150/* Alist of font registry symbol and the corresponding charsets
151 information. The information is retrieved from
152 Vfont_encoding_alist on demand.
153
154 Eash element has the form:
155 (REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID))
156 or
157 (REGISTRY . nil)
158
159 In the former form, ENCODING-CHARSET-ID is an ID of a charset that
160 encodes a character code to a glyph code of a font, and
161 REPERTORY-CHARSET-ID is an ID of a charset that tells if a
162 character is supported by a font.
163
164 The latter form means that the information for REGISTRY couldn't be
165 retrieved. */
166static Lisp_Object font_charset_alist;
167
f697fff0
KH
168/* List of all font drivers. Each font-backend (XXXfont.c) calls
169 register_font_driver in syms_of_XXXfont to register its font-driver
c2f5bfd6
KH
170 here. */
171static struct font_driver_list *font_driver_list;
172
35027d0c
KH
173\f
174
175/* Creaters of font-related Lisp object. */
176
177Lisp_Object
971de7fb 178font_make_spec (void)
35027d0c
KH
179{
180 Lisp_Object font_spec;
181 struct font_spec *spec
182 = ((struct font_spec *)
183 allocate_pseudovector (VECSIZE (struct font_spec),
184 FONT_SPEC_MAX, PVEC_FONT));
185 XSETFONT (font_spec, spec);
186 return font_spec;
187}
188
189Lisp_Object
971de7fb 190font_make_entity (void)
35027d0c
KH
191{
192 Lisp_Object font_entity;
193 struct font_entity *entity
194 = ((struct font_entity *)
195 allocate_pseudovector (VECSIZE (struct font_entity),
196 FONT_ENTITY_MAX, PVEC_FONT));
197 XSETFONT (font_entity, entity);
198 return font_entity;
199}
200
51c13510
KH
201/* Create a font-object whose structure size is SIZE. If ENTITY is
202 not nil, copy properties from ENTITY to the font-object. If
203 PIXELSIZE is positive, set the `size' property to PIXELSIZE. */
35027d0c 204Lisp_Object
971de7fb 205font_make_object (int size, Lisp_Object entity, int pixelsize)
35027d0c
KH
206{
207 Lisp_Object font_object;
208 struct font *font
209 = (struct font *) allocate_pseudovector (size, FONT_OBJECT_MAX, PVEC_FONT);
51c13510
KH
210 int i;
211
35027d0c
KH
212 XSETFONT (font_object, font);
213
51c13510
KH
214 if (! NILP (entity))
215 {
216 for (i = 1; i < FONT_SPEC_MAX; i++)
217 font->props[i] = AREF (entity, i);
218 if (! NILP (AREF (entity, FONT_EXTRA_INDEX)))
219 font->props[FONT_EXTRA_INDEX]
581e51e8 220 = Fcopy_alist (AREF (entity, FONT_EXTRA_INDEX));
51c13510
KH
221 }
222 if (size > 0)
223 font->props[FONT_SIZE_INDEX] = make_number (pixelsize);
35027d0c
KH
224 return font_object;
225}
226
227\f
228
f57e2426
J
229static int font_pixel_size (FRAME_PTR f, Lisp_Object);
230static Lisp_Object font_open_entity (FRAME_PTR, Lisp_Object, int);
231static Lisp_Object font_matching_entity (FRAME_PTR, Lisp_Object *,
232 Lisp_Object);
c2f5bfd6
KH
233
234/* Number of registered font drivers. */
235static int num_font_drivers;
236
35027d0c
KH
237
238/* Return a Lispy value of a font property value at STR and LEN bytes.
239 If STR is "*", it returns nil.
2f286d4f
KH
240 If FORCE_SYMBOL is zero and all characters in STR are digits, it
241 returns an integer. Otherwise, it returns a symbol interned from
242 STR. */
35027d0c
KH
243
244Lisp_Object
971de7fb 245font_intern_prop (char *str, int len, int force_symbol)
35027d0c
KH
246{
247 int i;
d0ab1ebe 248 Lisp_Object tem;
35027d0c 249 Lisp_Object obarray;
545312c2 250 int nbytes, nchars;
35027d0c
KH
251
252 if (len == 1 && *str == '*')
253 return Qnil;
2f286d4f 254 if (!force_symbol && len >=1 && isdigit (*str))
35027d0c
KH
255 {
256 for (i = 1; i < len; i++)
257 if (! isdigit (str[i]))
258 break;
259 if (i == len)
260 return make_number (atoi (str));
261 }
262
545312c2
KH
263 /* The following code is copied from the function intern (in
264 lread.c), and modified to suite our purpose. */
35027d0c
KH
265 obarray = Vobarray;
266 if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
267 obarray = check_obarray (obarray);
72d36834 268 parse_str_as_multibyte ((unsigned char *) str, len, &nchars, &nbytes);
545312c2
KH
269 if (len == nchars || len != nbytes)
270 /* CONTENTS contains no multibyte sequences or contains an invalid
271 multibyte sequence. We'll make a unibyte string. */
272 tem = oblookup (obarray, str, len, len);
273 else
274 tem = oblookup (obarray, str, nchars, len);
35027d0c
KH
275 if (SYMBOLP (tem))
276 return tem;
545312c2
KH
277 if (len == nchars || len != nbytes)
278 tem = make_unibyte_string (str, len);
279 else
280 tem = make_multibyte_string (str, nchars, len);
281 return Fintern (tem, obarray);
35027d0c
KH
282}
283
9331887d 284/* Return a pixel size of font-spec SPEC on frame F. */
ec6fe57c 285
9331887d 286static int
971de7fb 287font_pixel_size (FRAME_PTR f, Lisp_Object spec)
9331887d 288{
819e81df 289#ifdef HAVE_WINDOW_SYSTEM
9331887d
KH
290 Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
291 double point_size;
35027d0c 292 int dpi, pixel_size;
d0ab1ebe 293 Lisp_Object val;
51c01100 294
9331887d
KH
295 if (INTEGERP (size))
296 return XINT (size);
297 if (NILP (size))
819e81df 298 return 0;
d0ab1ebe 299 font_assert (FLOATP (size));
9331887d 300 point_size = XFLOAT_DATA (size);
35027d0c
KH
301 val = AREF (spec, FONT_DPI_INDEX);
302 if (INTEGERP (val))
17e28f6d 303 dpi = XINT (val);
9331887d
KH
304 else
305 dpi = f->resy;
306 pixel_size = POINT_TO_PIXEL (point_size, dpi);
307 return pixel_size;
819e81df
KH
308#else
309 return 1;
310#endif
9331887d
KH
311}
312
c2f5bfd6 313
35027d0c
KH
314/* Return a value of PROP's VAL (symbol or integer) to be stored in a
315 font vector. If VAL is not valid (i.e. not registered in
316 font_style_table), return -1 if NOERROR is zero, and return a
317 proper index if NOERROR is nonzero. In that case, register VAL in
318 font_style_table if VAL is a symbol, and return a closest index if
319 VAL is an integer. */
c2f5bfd6 320
35027d0c 321int
971de7fb 322font_style_to_value (enum font_property_index prop, Lisp_Object val, int noerror)
c2f5bfd6 323{
35027d0c
KH
324 Lisp_Object table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
325 int len = ASIZE (table);
d0ab1ebe 326 int i, j;
c2f5bfd6 327
35027d0c 328 if (SYMBOLP (val))
c2f5bfd6 329 {
72606e45 330 unsigned char *s;
35027d0c
KH
331 Lisp_Object args[2], elt;
332
333 /* At first try exact match. */
334 for (i = 0; i < len; i++)
d0ab1ebe
KH
335 for (j = 1; j < ASIZE (AREF (table, i)); j++)
336 if (EQ (val, AREF (AREF (table, i), j)))
337 return ((XINT (AREF (AREF (table, i), 0)) << 8)
338 | (i << 4) | (j - 1));
35027d0c 339 /* Try also with case-folding match. */
72606e45 340 s = SDATA (SYMBOL_NAME (val));
35027d0c 341 for (i = 0; i < len; i++)
d0ab1ebe
KH
342 for (j = 1; j < ASIZE (AREF (table, i)); j++)
343 {
344 elt = AREF (AREF (table, i), j);
72606e45 345 if (xstrcasecmp (s, SDATA (SYMBOL_NAME (elt))) == 0)
d0ab1ebe
KH
346 return ((XINT (AREF (AREF (table, i), 0)) << 8)
347 | (i << 4) | (j - 1));
348 }
35027d0c
KH
349 if (! noerror)
350 return -1;
351 if (len == 255)
352 abort ();
c2694a06 353 elt = Fmake_vector (make_number (2), make_number (100));
d0ab1ebe 354 ASET (elt, 1, val);
35027d0c 355 args[0] = table;
d0ab1ebe 356 args[1] = Fmake_vector (make_number (1), elt);
35027d0c 357 ASET (font_style_table, prop - FONT_WEIGHT_INDEX, Fvconcat (2, args));
c2694a06 358 return (100 << 8) | (i << 4);
c2f5bfd6 359 }
35027d0c
KH
360 else
361 {
d0ab1ebe 362 int i, last_n;
35027d0c 363 int numeric = XINT (val);
c2f5bfd6 364
d0ab1ebe 365 for (i = 0, last_n = -1; i < len; i++)
35027d0c 366 {
d0ab1ebe 367 int n = XINT (AREF (AREF (table, i), 0));
c2f5bfd6 368
35027d0c 369 if (numeric == n)
d0ab1ebe 370 return (n << 8) | (i << 4);
35027d0c
KH
371 if (numeric < n)
372 {
373 if (! noerror)
374 return -1;
d0ab1ebe
KH
375 return ((i == 0 || n - numeric < numeric - last_n)
376 ? (n << 8) | (i << 4): (last_n << 8 | ((i - 1) << 4)));
35027d0c 377 }
35027d0c 378 last_n = n;
35027d0c
KH
379 }
380 if (! noerror)
381 return -1;
d0ab1ebe 382 return ((last_n << 8) | ((i - 1) << 4));
35027d0c
KH
383 }
384}
c2f5bfd6
KH
385
386Lisp_Object
971de7fb 387font_style_symbolic (Lisp_Object font, enum font_property_index prop, int for_face)
c2f5bfd6 388{
3ef8c1b4 389 Lisp_Object val = AREF (font, prop);
d0ab1ebe
KH
390 Lisp_Object table, elt;
391 int i;
c2f5bfd6 392
35027d0c
KH
393 if (NILP (val))
394 return Qnil;
395 table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
d0ab1ebe
KH
396 i = XINT (val) & 0xFF;
397 font_assert (((i >> 4) & 0xF) < ASIZE (table));
398 elt = AREF (table, ((i >> 4) & 0xF));
399 font_assert ((i & 0xF) + 1 < ASIZE (elt));
ba3de0e8 400 return (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));
6fe9826d
JR
401}
402
c2f5bfd6
KH
403extern Lisp_Object Vface_alternative_font_family_alist;
404
f57e2426 405extern Lisp_Object find_font_encoding (Lisp_Object);
1701724c 406
35027d0c 407
819e81df
KH
408/* Return ENCODING or a cons of ENCODING and REPERTORY of the font
409 FONTNAME. ENCODING is a charset symbol that specifies the encoding
410 of the font. REPERTORY is a charset symbol or nil. */
411
412Lisp_Object
971de7fb 413find_font_encoding (Lisp_Object fontname)
819e81df
KH
414{
415 Lisp_Object tail, elt;
416
417 for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
418 {
419 elt = XCAR (tail);
420 if (CONSP (elt)
421 && STRINGP (XCAR (elt))
422 && fast_string_match_ignore_case (XCAR (elt), fontname) >= 0
423 && (SYMBOLP (XCDR (elt))
424 ? CHARSETP (XCDR (elt))
425 : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
426 return (XCDR (elt));
427 }
182ba28c 428 return Qnil;
819e81df
KH
429}
430
1701724c
KH
431/* Return encoding charset and repertory charset for REGISTRY in
432 ENCODING and REPERTORY correspondingly. If correct information for
433 REGISTRY is available, return 0. Otherwise return -1. */
434
435int
971de7fb 436font_registry_charsets (Lisp_Object registry, struct charset **encoding, struct charset **repertory)
1701724c
KH
437{
438 Lisp_Object val;
439 int encoding_id, repertory_id;
440
35027d0c 441 val = Fassoc_string (registry, font_charset_alist, Qt);
1701724c
KH
442 if (! NILP (val))
443 {
444 val = XCDR (val);
445 if (NILP (val))
446 return -1;
447 encoding_id = XINT (XCAR (val));
448 repertory_id = XINT (XCDR (val));
449 }
450 else
451 {
452 val = find_font_encoding (SYMBOL_NAME (registry));
453 if (SYMBOLP (val) && CHARSETP (val))
454 {
455 encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val));
456 }
457 else if (CONSP (val))
458 {
459 if (! CHARSETP (XCAR (val)))
460 goto invalid_entry;
461 encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val)));
462 if (NILP (XCDR (val)))
463 repertory_id = -1;
464 else
465 {
466 if (! CHARSETP (XCDR (val)))
467 goto invalid_entry;
468 repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val)));
469 }
51c01100 470 }
1701724c
KH
471 else
472 goto invalid_entry;
473 val = Fcons (make_number (encoding_id), make_number (repertory_id));
474 font_charset_alist
475 = nconc2 (font_charset_alist, Fcons (Fcons (registry, val), Qnil));
476 }
477
478 if (encoding)
479 *encoding = CHARSET_FROM_ID (encoding_id);
480 if (repertory)
481 *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
482 return 0;
483
484 invalid_entry:
485 font_charset_alist
486 = nconc2 (font_charset_alist, Fcons (Fcons (registry, Qnil), Qnil));
487 return -1;
488}
489
c2f5bfd6 490\f
45eb10fb
KH
491/* Font property value validaters. See the comment of
492 font_property_table for the meaning of the arguments. */
493
f57e2426
J
494static Lisp_Object font_prop_validate (int, Lisp_Object, Lisp_Object);
495static Lisp_Object font_prop_validate_symbol (Lisp_Object, Lisp_Object);
496static Lisp_Object font_prop_validate_style (Lisp_Object, Lisp_Object);
497static Lisp_Object font_prop_validate_non_neg (Lisp_Object, Lisp_Object);
498static Lisp_Object font_prop_validate_spacing (Lisp_Object, Lisp_Object);
499static int get_font_prop_index (Lisp_Object);
c2f5bfd6
KH
500
501static Lisp_Object
971de7fb 502font_prop_validate_symbol (Lisp_Object prop, Lisp_Object val)
c2f5bfd6
KH
503{
504 if (STRINGP (val))
35027d0c
KH
505 val = Fintern (val, Qnil);
506 if (! SYMBOLP (val))
c2f5bfd6 507 val = Qerror;
35027d0c
KH
508 else if (EQ (prop, QCregistry))
509 val = Fintern (Fdowncase (SYMBOL_NAME (val)), Qnil);
c2f5bfd6
KH
510 return val;
511}
512
35027d0c 513
c2f5bfd6 514static Lisp_Object
971de7fb 515font_prop_validate_style (Lisp_Object style, Lisp_Object val)
c2f5bfd6 516{
35027d0c
KH
517 enum font_property_index prop = (EQ (style, QCweight) ? FONT_WEIGHT_INDEX
518 : EQ (style, QCslant) ? FONT_SLANT_INDEX
519 : FONT_WIDTH_INDEX);
520 int n;
521 if (INTEGERP (val))
c2f5bfd6 522 {
35027d0c 523 n = XINT (val);
64b900e3 524 if (((n >> 4) & 0xF)
35027d0c 525 >= ASIZE (AREF (font_style_table, prop - FONT_WEIGHT_INDEX)))
c2f5bfd6
KH
526 val = Qerror;
527 else
528 {
64b900e3
KH
529 Lisp_Object elt = AREF (AREF (font_style_table, prop - FONT_WEIGHT_INDEX), (n >> 4) & 0xF);
530
531 if ((n & 0xF) + 1 >= ASIZE (elt))
532 val = Qerror;
533 else if (XINT (AREF (elt, 0)) != (n >> 8))
c2f5bfd6
KH
534 val = Qerror;
535 }
536 }
35027d0c
KH
537 else if (SYMBOLP (val))
538 {
539 int n = font_style_to_value (prop, val, 0);
540
541 val = n >= 0 ? make_number (n) : Qerror;
542 }
543 else
544 val = Qerror;
c2f5bfd6
KH
545 return val;
546}
547
548static Lisp_Object
971de7fb 549font_prop_validate_non_neg (Lisp_Object prop, Lisp_Object val)
c2f5bfd6
KH
550{
551 return (NATNUMP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0)
552 ? val : Qerror);
553}
554
555static Lisp_Object
971de7fb 556font_prop_validate_spacing (Lisp_Object prop, Lisp_Object val)
ec6fe57c
KH
557{
558 if (NILP (val) || (NATNUMP (val) && XINT (val) <= FONT_SPACING_CHARCELL))
559 return val;
3692570f
KH
560 if (SYMBOLP (val) && SBYTES (SYMBOL_NAME (val)) == 1)
561 {
562 char spacing = SDATA (SYMBOL_NAME (val))[0];
563
564 if (spacing == 'c' || spacing == 'C')
565 return make_number (FONT_SPACING_CHARCELL);
566 if (spacing == 'm' || spacing == 'M')
567 return make_number (FONT_SPACING_MONO);
0615d903 568 if (spacing == 'p' || spacing == 'P')
3692570f
KH
569 return make_number (FONT_SPACING_PROPORTIONAL);
570 if (spacing == 'd' || spacing == 'D')
571 return make_number (FONT_SPACING_DUAL);
572 }
ec6fe57c
KH
573 return Qerror;
574}
575
1701724c 576static Lisp_Object
971de7fb 577font_prop_validate_otf (Lisp_Object prop, Lisp_Object val)
1701724c
KH
578{
579 Lisp_Object tail, tmp;
580 int i;
581
582 /* VAL = (SCRIPT [ LANGSYS [ GSUB-FEATURES [ GPOS-FEATURES ]]])
583 GSUB-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil
584 GPOS-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil */
585 if (! CONSP (val))
586 return Qerror;
587 if (! SYMBOLP (XCAR (val)))
588 return Qerror;
589 tail = XCDR (val);
590 if (NILP (tail))
591 return val;
592 if (! CONSP (tail) || ! SYMBOLP (XCAR (val)))
593 return Qerror;
594 for (i = 0; i < 2; i++)
595 {
596 tail = XCDR (tail);
597 if (NILP (tail))
598 return val;
599 if (! CONSP (tail))
600 return Qerror;
601 for (tmp = XCAR (tail); CONSP (tmp); tmp = XCDR (tmp))
602 if (! SYMBOLP (XCAR (tmp)))
603 return Qerror;
604 if (! NILP (tmp))
605 return Qerror;
606 }
607 return val;
608}
609
ec6fe57c
KH
610/* Structure of known font property keys and validater of the
611 values. */
c2f5bfd6
KH
612struct
613{
ec6fe57c 614 /* Pointer to the key symbol. */
c2f5bfd6 615 Lisp_Object *key;
45eb10fb
KH
616 /* Function to validate PROP's value VAL, or NULL if any value is
617 ok. The value is VAL or its regularized value if VAL is valid,
618 and Qerror if not. */
f57e2426 619 Lisp_Object (*validater) (Lisp_Object prop, Lisp_Object val);
ec6fe57c
KH
620} font_property_table[] =
621 { { &QCtype, font_prop_validate_symbol },
c2f5bfd6
KH
622 { &QCfoundry, font_prop_validate_symbol },
623 { &QCfamily, font_prop_validate_symbol },
624 { &QCadstyle, font_prop_validate_symbol },
625 { &QCregistry, font_prop_validate_symbol },
626 { &QCweight, font_prop_validate_style },
627 { &QCslant, font_prop_validate_style },
628 { &QCwidth, font_prop_validate_style },
ec6fe57c 629 { &QCsize, font_prop_validate_non_neg },
ec6fe57c
KH
630 { &QCdpi, font_prop_validate_non_neg },
631 { &QCspacing, font_prop_validate_spacing },
35027d0c
KH
632 { &QCavgwidth, font_prop_validate_non_neg },
633 /* The order of the above entries must match with enum
634 font_property_index. */
635 { &QClang, font_prop_validate_symbol },
636 { &QCscript, font_prop_validate_symbol },
637 { &QCotf, font_prop_validate_otf }
c2f5bfd6
KH
638 };
639
45eb10fb 640/* Size (number of elements) of the above table. */
ec6fe57c
KH
641#define FONT_PROPERTY_TABLE_SIZE \
642 ((sizeof font_property_table) / (sizeof *font_property_table))
643
45eb10fb 644/* Return an index number of font property KEY or -1 if KEY is not an
35027d0c 645 already known property. */
45eb10fb 646
ec6fe57c 647static int
971de7fb 648get_font_prop_index (Lisp_Object key)
c2f5bfd6 649{
35027d0c
KH
650 int i;
651
652 for (i = 0; i < FONT_PROPERTY_TABLE_SIZE; i++)
653 if (EQ (key, *font_property_table[i].key))
654 return i;
ec6fe57c 655 return -1;
c2f5bfd6
KH
656}
657
35027d0c
KH
658/* Validate the font property. The property key is specified by the
659 symbol PROP, or the index IDX (if PROP is nil). If VAL is invalid,
660 signal an error. The value is VAL or the regularized one. */
45eb10fb 661
c2f5bfd6 662static Lisp_Object
971de7fb 663font_prop_validate (int idx, Lisp_Object prop, Lisp_Object val)
c2f5bfd6 664{
35027d0c 665 Lisp_Object validated;
c2f5bfd6 666
1f09f444
KH
667 if (NILP (val))
668 return val;
35027d0c
KH
669 if (NILP (prop))
670 prop = *font_property_table[idx].key;
671 else
ec6fe57c 672 {
35027d0c
KH
673 idx = get_font_prop_index (prop);
674 if (idx < 0)
675 return val;
ec6fe57c 676 }
35027d0c
KH
677 validated = (font_property_table[idx].validater) (prop, val);
678 if (EQ (validated, Qerror))
679 signal_error ("invalid font property", Fcons (prop, val));
680 return validated;
c2f5bfd6 681}
51c01100 682
35027d0c
KH
683
684/* Store VAL as a value of extra font property PROP in FONT while
685 keeping the sorting order. Don't check the validity of VAL. */
45eb10fb 686
01dbeb0b 687Lisp_Object
971de7fb 688font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
9331887d
KH
689{
690 Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
ec6fe57c 691 Lisp_Object slot = (NILP (extra) ? Qnil : assq_no_quit (prop, extra));
9331887d
KH
692
693 if (NILP (slot))
694 {
35027d0c
KH
695 Lisp_Object prev = Qnil;
696
697 while (CONSP (extra)
698 && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
699 prev = extra, extra = XCDR (extra);
581e51e8 700
ce75f06e 701 if (NILP (prev))
581e51e8 702 ASET (font, FONT_EXTRA_INDEX, Fcons (Fcons (prop, val), extra));
ce75f06e 703 else
581e51e8 704 XSETCDR (prev, Fcons (Fcons (prop, val), extra));
ce75f06e 705
ec6fe57c 706 return val;
9331887d 707 }
9331887d 708 XSETCDR (slot, val);
483670b5
KH
709 if (NILP (val))
710 ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
ec6fe57c 711 return val;
9331887d
KH
712}
713
c2f5bfd6
KH
714\f
715/* Font name parser and unparser */
716
f57e2426
J
717static int parse_matrix (char *);
718static int font_expand_wildcards (Lisp_Object *, int);
719static int font_parse_name (char *, Lisp_Object);
c2f5bfd6 720
ec6fe57c 721/* An enumerator for each field of an XLFD font name. */
c2f5bfd6
KH
722enum xlfd_field_index
723{
724 XLFD_FOUNDRY_INDEX,
725 XLFD_FAMILY_INDEX,
726 XLFD_WEIGHT_INDEX,
727 XLFD_SLANT_INDEX,
728 XLFD_SWIDTH_INDEX,
729 XLFD_ADSTYLE_INDEX,
4485a28e
KH
730 XLFD_PIXEL_INDEX,
731 XLFD_POINT_INDEX,
c2f5bfd6
KH
732 XLFD_RESX_INDEX,
733 XLFD_RESY_INDEX,
734 XLFD_SPACING_INDEX,
735 XLFD_AVGWIDTH_INDEX,
736 XLFD_REGISTRY_INDEX,
737 XLFD_ENCODING_INDEX,
738 XLFD_LAST_INDEX
739};
740
ec6fe57c 741/* An enumerator for mask bit corresponding to each XLFD field. */
4485a28e
KH
742enum xlfd_field_mask
743{
744 XLFD_FOUNDRY_MASK = 0x0001,
745 XLFD_FAMILY_MASK = 0x0002,
746 XLFD_WEIGHT_MASK = 0x0004,
747 XLFD_SLANT_MASK = 0x0008,
748 XLFD_SWIDTH_MASK = 0x0010,
749 XLFD_ADSTYLE_MASK = 0x0020,
750 XLFD_PIXEL_MASK = 0x0040,
751 XLFD_POINT_MASK = 0x0080,
752 XLFD_RESX_MASK = 0x0100,
753 XLFD_RESY_MASK = 0x0200,
754 XLFD_SPACING_MASK = 0x0400,
755 XLFD_AVGWIDTH_MASK = 0x0800,
756 XLFD_REGISTRY_MASK = 0x1000,
757 XLFD_ENCODING_MASK = 0x2000
758};
759
760
c2f5bfd6
KH
761/* Parse P pointing the pixel/point size field of the form
762 `[A B C D]' which specifies a transformation matrix:
763
764 A B 0
765 C D 0
766 0 0 1
767
768 by which all glyphs of the font are transformed. The spec says
769 that scalar value N for the pixel/point size is equivalent to:
770 A = N * resx/resy, B = C = 0, D = N.
771
772 Return the scalar value N if the form is valid. Otherwise return
773 -1. */
774
775static int
971de7fb 776parse_matrix (char *p)
c2f5bfd6
KH
777{
778 double matrix[4];
779 char *end;
780 int i;
781
782 for (i = 0, p++; i < 4 && *p && *p != ']'; i++)
783 {
784 if (*p == '~')
785 matrix[i] = - strtod (p + 1, &end);
786 else
787 matrix[i] = strtod (p, &end);
788 p = end;
789 }
790 return (i == 4 ? (int) matrix[3] : -1);
791}
792
4485a28e
KH
793/* Expand a wildcard field in FIELD (the first N fields are filled) to
794 multiple fields to fill in all 14 XLFD fields while restring a
795 field position by its contents. */
796
ec6fe57c 797static int
971de7fb 798font_expand_wildcards (Lisp_Object *field, int n)
4485a28e
KH
799{
800 /* Copy of FIELD. */
801 Lisp_Object tmp[XLFD_LAST_INDEX];
802 /* Array of information about where this element can go. Nth
803 element is for Nth element of FIELD. */
804 struct {
805 /* Minimum possible field. */
806 int from;
807 /* Maxinum possible field. */
808 int to;
809 /* Bit mask of possible field. Nth bit corresponds to Nth field. */
810 int mask;
811 } range[XLFD_LAST_INDEX];
812 int i, j;
ec6fe57c 813 int range_from, range_to;
4485a28e
KH
814 unsigned range_mask;
815
816#define XLFD_SYMBOL_MASK (XLFD_FOUNDRY_MASK | XLFD_FAMILY_MASK \
817 | XLFD_ADSTYLE_MASK | XLFD_REGISTRY_MASK)
818#define XLFD_NULL_MASK (XLFD_FOUNDRY_MASK | XLFD_ADSTYLE_MASK)
4485a28e 819#define XLFD_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \
ef18374f 820 | XLFD_AVGWIDTH_MASK)
4485a28e
KH
821#define XLFD_REGENC_MASK (XLFD_REGISTRY_MASK | XLFD_ENCODING_MASK)
822
823 /* Initialize RANGE_MASK for FIELD[0] which can be 0th to (14 - N)th
824 field. The value is shifted to left one bit by one in the
825 following loop. */
826 for (i = 0, range_mask = 0; i <= 14 - n; i++)
827 range_mask = (range_mask << 1) | 1;
828
ec6fe57c
KH
829 /* The triplet RANGE_FROM, RANGE_TO, and RANGE_MASK is a
830 position-based retriction for FIELD[I]. */
831 for (i = 0, range_from = 0, range_to = 14 - n; i < n;
832 i++, range_from++, range_to++, range_mask <<= 1)
4485a28e 833 {
4485a28e
KH
834 Lisp_Object val = field[i];
835
836 tmp[i] = val;
837 if (NILP (val))
838 {
839 /* Wildcard. */
840 range[i].from = range_from;
841 range[i].to = range_to;
842 range[i].mask = range_mask;
843 }
844 else
845 {
846 /* The triplet FROM, TO, and MASK is a value-based
847 retriction for FIELD[I]. */
848 int from, to;
849 unsigned mask;
850
851 if (INTEGERP (val))
852 {
853 int numeric = XINT (val);
854
ef18374f
KH
855 if (i + 1 == n)
856 from = to = XLFD_ENCODING_INDEX,
857 mask = XLFD_ENCODING_MASK;
ec6fe57c
KH
858 else if (numeric == 0)
859 from = XLFD_PIXEL_INDEX, to = XLFD_AVGWIDTH_INDEX,
860 mask = XLFD_PIXEL_MASK | XLFD_LARGENUM_MASK;
ef18374f
KH
861 else if (numeric <= 48)
862 from = to = XLFD_PIXEL_INDEX,
863 mask = XLFD_PIXEL_MASK;
51c01100 864 else
ec6fe57c 865 from = XLFD_POINT_INDEX, to = XLFD_AVGWIDTH_INDEX,
4485a28e
KH
866 mask = XLFD_LARGENUM_MASK;
867 }
35027d0c 868 else if (SBYTES (SYMBOL_NAME (val)) == 0)
4485a28e
KH
869 from = XLFD_FOUNDRY_INDEX, to = XLFD_ADSTYLE_INDEX,
870 mask = XLFD_NULL_MASK;
871 else if (i == 0)
872 from = to = XLFD_FOUNDRY_INDEX, mask = XLFD_FOUNDRY_MASK;
873 else if (i + 1 == n)
874 {
875 Lisp_Object name = SYMBOL_NAME (val);
876
877 if (SDATA (name)[SBYTES (name) - 1] == '*')
878 from = XLFD_REGISTRY_INDEX, to = XLFD_ENCODING_INDEX,
879 mask = XLFD_REGENC_MASK;
880 else
881 from = to = XLFD_ENCODING_INDEX,
882 mask = XLFD_ENCODING_MASK;
883 }
ef18374f
KH
884 else if (range_from <= XLFD_WEIGHT_INDEX
885 && range_to >= XLFD_WEIGHT_INDEX
35027d0c 886 && FONT_WEIGHT_NAME_NUMERIC (val) >= 0)
4485a28e 887 from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK;
ef18374f
KH
888 else if (range_from <= XLFD_SLANT_INDEX
889 && range_to >= XLFD_SLANT_INDEX
35027d0c 890 && FONT_SLANT_NAME_NUMERIC (val) >= 0)
4485a28e 891 from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK;
ef18374f
KH
892 else if (range_from <= XLFD_SWIDTH_INDEX
893 && range_to >= XLFD_SWIDTH_INDEX
35027d0c 894 && FONT_WIDTH_NAME_NUMERIC (val) >= 0)
4485a28e
KH
895 from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK;
896 else
897 {
ec6fe57c 898 if (EQ (val, Qc) || EQ (val, Qm) || EQ (val, Qp) || EQ (val, Qd))
4485a28e
KH
899 from = to = XLFD_SPACING_INDEX, mask = XLFD_SPACING_MASK;
900 else
901 from = XLFD_FOUNDRY_INDEX, to = XLFD_ENCODING_INDEX,
902 mask = XLFD_SYMBOL_MASK;
903 }
904
905 /* Merge position-based and value-based restrictions. */
906 mask &= range_mask;
907 while (from < range_from)
908 mask &= ~(1 << from++);
909 while (from < 14 && ! (mask & (1 << from)))
910 from++;
911 while (to > range_to)
912 mask &= ~(1 << to--);
913 while (to >= 0 && ! (mask & (1 << to)))
914 to--;
915 if (from > to)
916 return -1;
917 range[i].from = from;
918 range[i].to = to;
919 range[i].mask = mask;
920
921 if (from > range_from || to < range_to)
ec6fe57c
KH
922 {
923 /* The range is narrowed by value-based restrictions.
924 Reflect it to the other fields. */
925
926 /* Following fields should be after FROM. */
927 range_from = from;
928 /* Preceding fields should be before TO. */
929 for (j = i - 1, from--, to--; j >= 0; j--, from--, to--)
930 {
931 /* Check FROM for non-wildcard field. */
932 if (! NILP (tmp[j]) && range[j].from < from)
933 {
934 while (range[j].from < from)
935 range[j].mask &= ~(1 << range[j].from++);
936 while (from < 14 && ! (range[j].mask & (1 << from)))
937 from++;
938 range[j].from = from;
939 }
940 else
941 from = range[j].from;
942 if (range[j].to > to)
943 {
944 while (range[j].to > to)
945 range[j].mask &= ~(1 << range[j].to--);
946 while (to >= 0 && ! (range[j].mask & (1 << to)))
947 to--;
948 range[j].to = to;
949 }
950 else
951 to = range[j].to;
952 if (from > to)
953 return -1;
954 }
955 }
4485a28e
KH
956 }
957 }
958
959 /* Decide all fileds from restrictions in RANGE. */
960 for (i = j = 0; i < n ; i++)
961 {
962 if (j < range[i].from)
963 {
964 if (i == 0 || ! NILP (tmp[i - 1]))
965 /* None of TMP[X] corresponds to Jth field. */
966 return -1;
967 for (; j < range[i].from; j++)
968 field[j] = Qnil;
969 }
970 field[j++] = tmp[i];
971 }
972 if (! NILP (tmp[n - 1]) && j < XLFD_REGISTRY_INDEX)
973 return -1;
974 for (; j < XLFD_LAST_INDEX; j++)
975 field[j] = Qnil;
976 if (INTEGERP (field[XLFD_ENCODING_INDEX]))
977 field[XLFD_ENCODING_INDEX]
978 = Fintern (Fnumber_to_string (field[XLFD_ENCODING_INDEX]), Qnil);
979 return 0;
980}
981
43a1d19b
SM
982
983#ifdef ENABLE_CHECKING
984/* Match a 14-field XLFD pattern against a full XLFD font name. */
985static int
986font_match_xlfd (char *pattern, char *name)
987{
988 while (*pattern && *name)
989 {
990 if (*pattern == *name)
991 pattern++;
992 else if (*pattern == '*')
993 if (*name == pattern[1])
994 pattern += 2;
995 else
996 ;
997 else
998 return 0;
999 name++;
1000 }
1001 return 1;
1002}
1003
1004/* Make sure the font object matches the XLFD font name. */
1005static int
1006font_check_xlfd_parse (Lisp_Object font, char *name)
1007{
1008 char name_check[256];
1009 font_unparse_xlfd (font, 0, name_check, 255);
1010 return font_match_xlfd (name_check, name);
1011}
1012
1013#endif
1014
35027d0c 1015
ef18374f 1016/* Parse NAME (null terminated) as XLFD and store information in FONT
9331887d
KH
1017 (font-spec or font-entity). Size property of FONT is set as
1018 follows:
1019 specified XLFD fields FONT property
1020 --------------------- -------------
1021 PIXEL_SIZE PIXEL_SIZE (Lisp integer)
1022 POINT_SIZE and RESY calculated pixel size (Lisp integer)
1023 POINT_SIZE POINT_SIZE/10 (Lisp float)
1024
ec6fe57c 1025 If NAME is successfully parsed, return 0. Otherwise return -1.
9331887d 1026
ec6fe57c
KH
1027 FONT is usually a font-spec, but when this function is called from
1028 X font backend driver, it is a font-entity. In that case, NAME is
35027d0c 1029 a fully specified XLFD. */
c2f5bfd6
KH
1030
1031int
971de7fb 1032font_parse_xlfd (char *name, Lisp_Object font)
c2f5bfd6
KH
1033{
1034 int len = strlen (name);
35027d0c 1035 int i, j, n;
cf23b845 1036 char *f[XLFD_LAST_INDEX + 1];
c2f5bfd6 1037 Lisp_Object val;
4485a28e 1038 char *p;
c2f5bfd6 1039
e3928081 1040 if (len > 255 || !len)
c2f5bfd6
KH
1041 /* Maximum XLFD name length is 255. */
1042 return -1;
ec6fe57c 1043 /* Accept "*-.." as a fully specified XLFD. */
e3928081 1044 if (name[0] == '*' && (len == 1 || name[1] == '-'))
ec6fe57c
KH
1045 i = 1, f[XLFD_FOUNDRY_INDEX] = name;
1046 else
1047 i = 0;
1048 for (p = name + i; *p; p++)
35027d0c
KH
1049 if (*p == '-')
1050 {
1051 f[i++] = p + 1;
1052 if (i == XLFD_LAST_INDEX)
1053 break;
1054 }
1055 f[i] = name + len;
c2f5bfd6 1056
2f286d4f
KH
1057#define INTERN_FIELD(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 0)
1058#define INTERN_FIELD_SYM(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 1)
4485a28e 1059
ec6fe57c 1060 if (i == XLFD_LAST_INDEX)
4485a28e 1061 {
35027d0c 1062 /* Fully specified XLFD. */
ec6fe57c
KH
1063 int pixel_size;
1064
2f286d4f
KH
1065 ASET (font, FONT_FOUNDRY_INDEX, INTERN_FIELD_SYM (XLFD_FOUNDRY_INDEX));
1066 ASET (font, FONT_FAMILY_INDEX, INTERN_FIELD_SYM (XLFD_FAMILY_INDEX));
35027d0c
KH
1067 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1068 i <= XLFD_SWIDTH_INDEX; i++, j++)
4485a28e 1069 {
2f286d4f 1070 val = INTERN_FIELD_SYM (i);
ec6fe57c 1071 if (! NILP (val))
4485a28e 1072 {
2f286d4f 1073 if ((n = font_style_to_value (j, INTERN_FIELD_SYM (i), 0)) < 0)
35027d0c
KH
1074 return -1;
1075 ASET (font, j, make_number (n));
ec6fe57c
KH
1076 }
1077 }
2f286d4f 1078 ASET (font, FONT_ADSTYLE_INDEX, INTERN_FIELD_SYM (XLFD_ADSTYLE_INDEX));
35027d0c
KH
1079 if (strcmp (f[XLFD_REGISTRY_INDEX], "*-*") == 0)
1080 ASET (font, FONT_REGISTRY_INDEX, Qnil);
1081 else
1082 ASET (font, FONT_REGISTRY_INDEX,
1083 font_intern_prop (f[XLFD_REGISTRY_INDEX],
2f286d4f
KH
1084 f[XLFD_LAST_INDEX] - f[XLFD_REGISTRY_INDEX],
1085 1));
ec6fe57c
KH
1086 p = f[XLFD_PIXEL_INDEX];
1087 if (*p == '[' && (pixel_size = parse_matrix (p)) >= 0)
51c01100 1088 ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
ec6fe57c
KH
1089 else
1090 {
35027d0c
KH
1091 val = INTERN_FIELD (XLFD_PIXEL_INDEX);
1092 if (INTEGERP (val))
ec6fe57c 1093 ASET (font, FONT_SIZE_INDEX, val);
b57d9029
KH
1094 else if (FONT_ENTITY_P (font))
1095 return -1;
ec6fe57c
KH
1096 else
1097 {
1098 double point_size = -1;
1099
d0ab1ebe 1100 font_assert (FONT_SPEC_P (font));
ec6fe57c
KH
1101 p = f[XLFD_POINT_INDEX];
1102 if (*p == '[')
1103 point_size = parse_matrix (p);
1104 else if (isdigit (*p))
1105 point_size = atoi (p), point_size /= 10;
1106 if (point_size >= 0)
1107 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
4485a28e
KH
1108 }
1109 }
ec6fe57c 1110
087048cd
KH
1111 val = INTERN_FIELD (XLFD_RESY_INDEX);
1112 if (! NILP (val) && ! INTEGERP (val))
1113 return -1;
1114 ASET (font, FONT_DPI_INDEX, val);
35027d0c
KH
1115 val = INTERN_FIELD (XLFD_SPACING_INDEX);
1116 if (! NILP (val))
ec6fe57c 1117 {
35027d0c
KH
1118 val = font_prop_validate_spacing (QCspacing, val);
1119 if (! INTEGERP (val))
1120 return -1;
1121 ASET (font, FONT_SPACING_INDEX, val);
ec6fe57c 1122 }
ec6fe57c
KH
1123 p = f[XLFD_AVGWIDTH_INDEX];
1124 if (*p == '~')
1125 p++;
087048cd
KH
1126 val = font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p, 0);
1127 if (! NILP (val) && ! INTEGERP (val))
1128 return -1;
1129 ASET (font, FONT_AVGWIDTH_INDEX, val);
4485a28e
KH
1130 }
1131 else
c2f5bfd6 1132 {
4485a28e 1133 int wild_card_found = 0;
ec6fe57c 1134 Lisp_Object prop[XLFD_LAST_INDEX];
4485a28e 1135
35027d0c
KH
1136 if (FONT_ENTITY_P (font))
1137 return -1;
ec6fe57c 1138 for (j = 0; j < i; j++)
4485a28e 1139 {
ec6fe57c 1140 if (*f[j] == '*')
4485a28e 1141 {
ec6fe57c
KH
1142 if (f[j][1] && f[j][1] != '-')
1143 return -1;
1144 prop[j] = Qnil;
1145 wild_card_found = 1;
1146 }
ec6fe57c 1147 else if (j + 1 < i)
35027d0c 1148 prop[j] = INTERN_FIELD (j);
ec6fe57c 1149 else
2f286d4f 1150 prop[j] = font_intern_prop (f[j], f[i] - f[j], 0);
4485a28e
KH
1151 }
1152 if (! wild_card_found)
c2f5bfd6 1153 return -1;
ec6fe57c 1154 if (font_expand_wildcards (prop, i) < 0)
4485a28e 1155 return -1;
ec6fe57c 1156
35027d0c
KH
1157 ASET (font, FONT_FOUNDRY_INDEX, prop[XLFD_FOUNDRY_INDEX]);
1158 ASET (font, FONT_FAMILY_INDEX, prop[XLFD_FAMILY_INDEX]);
1159 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1160 i <= XLFD_SWIDTH_INDEX; i++, j++)
ec6fe57c 1161 if (! NILP (prop[i]))
35027d0c
KH
1162 {
1163 if ((n = font_style_to_value (j, prop[i], 1)) < 0)
1164 return -1;
1165 ASET (font, j, make_number (n));
1166 }
1167 ASET (font, FONT_ADSTYLE_INDEX, prop[XLFD_ADSTYLE_INDEX]);
ec6fe57c
KH
1168 val = prop[XLFD_REGISTRY_INDEX];
1169 if (NILP (val))
c2f5bfd6 1170 {
ec6fe57c
KH
1171 val = prop[XLFD_ENCODING_INDEX];
1172 if (! NILP (val))
35027d0c 1173 val = concat2 (build_string ("*-"), SYMBOL_NAME (val));
4485a28e 1174 }
ec6fe57c 1175 else if (NILP (prop[XLFD_ENCODING_INDEX]))
35027d0c 1176 val = concat2 (SYMBOL_NAME (val), build_string ("-*"));
4485a28e 1177 else
35027d0c
KH
1178 val = concat3 (SYMBOL_NAME (val), build_string ("-"),
1179 SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
ec6fe57c 1180 if (! NILP (val))
35027d0c 1181 ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
ec6fe57c
KH
1182
1183 if (INTEGERP (prop[XLFD_PIXEL_INDEX]))
1184 ASET (font, FONT_SIZE_INDEX, prop[XLFD_PIXEL_INDEX]);
1185 else if (INTEGERP (prop[XLFD_POINT_INDEX]))
4485a28e 1186 {
ec6fe57c 1187 double point_size = XINT (prop[XLFD_POINT_INDEX]);
c2f5bfd6 1188
ec6fe57c
KH
1189 ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
1190 }
c2f5bfd6 1191
35027d0c
KH
1192 if (INTEGERP (prop[XLFD_RESX_INDEX]))
1193 ASET (font, FONT_DPI_INDEX, prop[XLFD_RESY_INDEX]);
1194 if (! NILP (prop[XLFD_SPACING_INDEX]))
1195 {
1196 val = font_prop_validate_spacing (QCspacing,
1197 prop[XLFD_SPACING_INDEX]);
1198 if (! INTEGERP (val))
1199 return -1;
1200 ASET (font, FONT_SPACING_INDEX, val);
1201 }
ec6fe57c 1202 if (INTEGERP (prop[XLFD_AVGWIDTH_INDEX]))
35027d0c 1203 ASET (font, FONT_AVGWIDTH_INDEX, prop[XLFD_AVGWIDTH_INDEX]);
c2f5bfd6
KH
1204 }
1205
ec6fe57c 1206 return 0;
c2f5bfd6
KH
1207}
1208
1209/* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES
1210 length), and return the name length. If FONT_SIZE_INDEX of FONT is
1211 0, use PIXEL_SIZE instead. */
1212
1213int
971de7fb 1214font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
c2f5bfd6 1215{
ec6fe57c 1216 char *f[XLFD_REGISTRY_INDEX + 1];
c2f5bfd6
KH
1217 Lisp_Object val;
1218 int i, j, len = 0;
1219
d0ab1ebe 1220 font_assert (FONTP (font));
c2f5bfd6
KH
1221
1222 for (i = FONT_FOUNDRY_INDEX, j = XLFD_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX;
1223 i++, j++)
1224 {
1225 if (i == FONT_ADSTYLE_INDEX)
1226 j = XLFD_ADSTYLE_INDEX;
1227 else if (i == FONT_REGISTRY_INDEX)
1228 j = XLFD_REGISTRY_INDEX;
1229 val = AREF (font, i);
1230 if (NILP (val))
1bb1d99b
KH
1231 {
1232 if (j == XLFD_REGISTRY_INDEX)
1233 f[j] = "*-*", len += 4;
1234 else
1235 f[j] = "*", len += 2;
1236 }
c2f5bfd6
KH
1237 else
1238 {
1239 if (SYMBOLP (val))
1240 val = SYMBOL_NAME (val);
1bb1d99b
KH
1241 if (j == XLFD_REGISTRY_INDEX
1242 && ! strchr ((char *) SDATA (val), '-'))
1243 {
1244 /* Change "jisx0208*" and "jisx0208" to "jisx0208*-*". */
1245 if (SDATA (val)[SBYTES (val) - 1] == '*')
1246 {
1247 f[j] = alloca (SBYTES (val) + 3);
1248 sprintf (f[j], "%s-*", SDATA (val));
1249 len += SBYTES (val) + 3;
1250 }
1251 else
1252 {
1253 f[j] = alloca (SBYTES (val) + 4);
1254 sprintf (f[j], "%s*-*", SDATA (val));
1255 len += SBYTES (val) + 4;
1256 }
1257 }
1258 else
1259 f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
c2f5bfd6
KH
1260 }
1261 }
1262
1263 for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX;
1264 i++, j++)
1265 {
35027d0c 1266 val = font_style_symbolic (font, i, 0);
c2f5bfd6
KH
1267 if (NILP (val))
1268 f[j] = "*", len += 2;
1269 else
1270 {
35027d0c 1271 val = SYMBOL_NAME (val);
c2f5bfd6
KH
1272 f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
1273 }
1274 }
1275
1276 val = AREF (font, FONT_SIZE_INDEX);
d0ab1ebe 1277 font_assert (NUMBERP (val) || NILP (val));
c2f5bfd6
KH
1278 if (INTEGERP (val))
1279 {
35027d0c 1280 i = XINT (val);
81aefea4
SM
1281 if (i <= 0)
1282 i = pixel_size;
c2f5bfd6 1283 if (i > 0)
81aefea4
SM
1284 {
1285 f[XLFD_PIXEL_INDEX] = alloca (22);
1286 len += sprintf (f[XLFD_PIXEL_INDEX], "%d-*", i) + 1;
1287 }
1288 else
1289 f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
c2f5bfd6
KH
1290 }
1291 else if (FLOATP (val))
1292 {
35027d0c 1293 i = XFLOAT_DATA (val) * 10;
ec6fe57c 1294 f[XLFD_PIXEL_INDEX] = alloca (12);
ec6fe57c 1295 len += sprintf (f[XLFD_PIXEL_INDEX], "*-%d", i) + 1;
c2f5bfd6
KH
1296 }
1297 else
ec6fe57c
KH
1298 f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
1299
35027d0c 1300 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
c2f5bfd6 1301 {
35027d0c
KH
1302 i = XINT (AREF (font, FONT_DPI_INDEX));
1303 f[XLFD_RESX_INDEX] = alloca (22);
1304 len += sprintf (f[XLFD_RESX_INDEX],
1305 "%d-%d", i, i) + 1;
c2f5bfd6
KH
1306 }
1307 else
35027d0c
KH
1308 f[XLFD_RESX_INDEX] = "*-*", len += 4;
1309 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
ec6fe57c 1310 {
35027d0c 1311 int spacing = XINT (AREF (font, FONT_SPACING_INDEX));
ec6fe57c 1312
35027d0c
KH
1313 f[XLFD_SPACING_INDEX] = (spacing <= FONT_SPACING_PROPORTIONAL ? "p"
1314 : spacing <= FONT_SPACING_DUAL ? "d"
1315 : spacing <= FONT_SPACING_MONO ? "m"
1316 : "c");
1317 len += 2;
ec6fe57c 1318 }
35027d0c
KH
1319 else
1320 f[XLFD_SPACING_INDEX] = "*", len += 2;
1321 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1322 {
1323 f[XLFD_AVGWIDTH_INDEX] = alloca (11);
c56c14a1
AR
1324 len += sprintf (f[XLFD_AVGWIDTH_INDEX], "%ld",
1325 (long) XINT (AREF (font, FONT_AVGWIDTH_INDEX))) + 1;
35027d0c
KH
1326 }
1327 else
1328 f[XLFD_AVGWIDTH_INDEX] = "*", len += 2;
ec6fe57c 1329 len++; /* for terminating '\0'. */
c2f5bfd6
KH
1330 if (len >= nbytes)
1331 return -1;
35027d0c 1332 return sprintf (name, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
c2f5bfd6
KH
1333 f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
1334 f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
35027d0c
KH
1335 f[XLFD_SWIDTH_INDEX], f[XLFD_ADSTYLE_INDEX],
1336 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
1337 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
1338 f[XLFD_REGISTRY_INDEX]);
c2f5bfd6
KH
1339}
1340
8c102d5b
CY
1341/* Parse NAME (null terminated) and store information in FONT
1342 (font-spec or font-entity). NAME is supplied in either the
1343 Fontconfig or GTK font name format. If NAME is successfully
1344 parsed, return 0. Otherwise return -1.
1345
1346 The fontconfig format is
1347
1348 FAMILY[-SIZE][:PROP1[=VAL1][:PROP2[=VAL2]...]]
1349
1350 The GTK format is
1351
1352 FAMILY [PROPS...] [SIZE]
1353
1354 This function tries to guess which format it is. */
ef18374f
KH
1355
1356int
971de7fb 1357font_parse_fcname (char *name, Lisp_Object font)
ef18374f 1358{
8c102d5b
CY
1359 char *p, *q;
1360 char *size_beg = NULL, *size_end = NULL;
1361 char *props_beg = NULL, *family_end = NULL;
9331887d 1362 int len = strlen (name);
ef18374f 1363
ec6fe57c
KH
1364 if (len == 0)
1365 return -1;
8c102d5b
CY
1366
1367 for (p = name; *p; p++)
ef18374f 1368 {
8c102d5b
CY
1369 if (*p == '\\' && p[1])
1370 p++;
1371 else if (*p == ':')
ef18374f 1372 {
59facb78 1373 props_beg = family_end = p;
8c102d5b
CY
1374 break;
1375 }
1376 else if (*p == '-')
1377 {
b1868a1a 1378 int decimal = 0, size_found = 1;
8c102d5b 1379 for (q = p + 1; *q && *q != ':'; q++)
b1868a1a 1380 if (! isdigit(*q))
8c102d5b 1381 {
b1868a1a
CY
1382 if (*q != '.' || decimal)
1383 {
1384 size_found = 0;
1385 break;
1386 }
1387 decimal = 1;
8c102d5b
CY
1388 }
1389 if (size_found)
1390 {
1391 family_end = p;
1392 size_beg = p + 1;
1393 size_end = q;
1394 break;
1395 }
ef18374f 1396 }
ef18374f 1397 }
9331887d 1398
8c102d5b
CY
1399 if (family_end)
1400 {
637fa988
JD
1401 Lisp_Object extra_props = Qnil;
1402
8c102d5b
CY
1403 /* A fontconfig name with size and/or property data. */
1404 if (family_end > name)
1405 {
1406 Lisp_Object family;
1407 family = font_intern_prop (name, family_end - name, 1);
1408 ASET (font, FONT_FAMILY_INDEX, family);
1409 }
1410 if (size_beg)
1411 {
1412 double point_size = strtod (size_beg, &size_end);
1413 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1414 if (*size_end == ':' && size_end[1])
59facb78 1415 props_beg = size_end;
8c102d5b
CY
1416 }
1417 if (props_beg)
1418 {
d26424c5 1419 /* Now parse ":KEY=VAL" patterns. */
59facb78 1420 Lisp_Object val;
8c102d5b 1421
59facb78 1422 for (p = props_beg; *p; p = q)
8c102d5b 1423 {
8c102d5b 1424 for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
8c102d5b
CY
1425 if (*q != '=')
1426 {
1427 /* Must be an enumerated value. */
59facb78
CY
1428 int word_len;
1429 p = p + 1;
1430 word_len = q - p;
8c102d5b 1431 val = font_intern_prop (p, q - p, 1);
9277a69d
CY
1432
1433#define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
1434
8c102d5b
CY
1435 if (PROP_MATCH ("light", 5)
1436 || PROP_MATCH ("medium", 6)
1437 || PROP_MATCH ("demibold", 8)
1438 || PROP_MATCH ("bold", 4)
1439 || PROP_MATCH ("black", 5))
1440 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
1441 else if (PROP_MATCH ("roman", 5)
1442 || PROP_MATCH ("italic", 6)
1443 || PROP_MATCH ("oblique", 7))
1444 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
1445 else if (PROP_MATCH ("charcell", 8))
1446 ASET (font, FONT_SPACING_INDEX,
1447 make_number (FONT_SPACING_CHARCELL));
1448 else if (PROP_MATCH ("mono", 4))
1449 ASET (font, FONT_SPACING_INDEX,
1450 make_number (FONT_SPACING_MONO));
1451 else if (PROP_MATCH ("proportional", 12))
1452 ASET (font, FONT_SPACING_INDEX,
1453 make_number (FONT_SPACING_PROPORTIONAL));
9277a69d 1454#undef PROP_MATCH
8c102d5b 1455 }
59facb78 1456 else
8c102d5b 1457 {
59facb78 1458 /* KEY=VAL pairs */
8c102d5b 1459 Lisp_Object key;
59facb78 1460 int prop;
51c01100 1461
59facb78 1462 if (q - p == 10 && memcmp (p + 1, "pixelsize", 9) == 0)
8c102d5b
CY
1463 prop = FONT_SIZE_INDEX;
1464 else
1465 {
1466 key = font_intern_prop (p, q - p, 1);
1467 prop = get_font_prop_index (key);
1468 }
77989187 1469
8c102d5b
CY
1470 p = q + 1;
1471 for (q = p; *q && *q != ':'; q++);
90c00b01 1472 val = font_intern_prop (p, q - p, 0);
77989187 1473
d26424c5
KH
1474 if (prop >= FONT_FOUNDRY_INDEX
1475 && prop < FONT_EXTRA_INDEX)
637fa988 1476 ASET (font, prop, font_prop_validate (prop, Qnil, val));
ce75f06e 1477 else
637fa988
JD
1478 {
1479 extra_props = nconc2 (extra_props,
1480 Fcons (Fcons (key, val), Qnil));
1481 }
8c102d5b 1482 }
d26424c5 1483 p = q;
8c102d5b 1484 }
8c102d5b 1485 }
637fa988
JD
1486
1487 if (! NILP (extra_props))
1488 {
1489 struct font_driver_list *driver_list = font_driver_list;
1490 for ( ; driver_list; driver_list = driver_list->next)
1491 if (driver_list->driver->filter_properties)
1492 (*driver_list->driver->filter_properties) (font, extra_props);
1493 }
ce75f06e 1494
8c102d5b
CY
1495 }
1496 else
ef18374f 1497 {
8c102d5b
CY
1498 /* Either a fontconfig-style name with no size and property
1499 data, or a GTK-style name. */
1500 Lisp_Object prop;
1501 int word_len, prop_found = 0;
ef18374f 1502
8c102d5b 1503 for (p = name; *p; p = *q ? q + 1 : q)
ef18374f 1504 {
8c102d5b 1505 if (isdigit (*p))
9331887d 1506 {
8c102d5b 1507 int size_found = 1;
7181ea6a 1508
8c102d5b 1509 for (q = p + 1; *q && *q != ' '; q++)
32a679fd 1510 if (! isdigit (*q) && *q != '.')
8c102d5b
CY
1511 {
1512 size_found = 0;
1513 break;
1514 }
1515 if (size_found)
1516 {
1517 double point_size = strtod (p, &q);
1518 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1519 continue;
1520 }
027a33c0 1521 }
8c102d5b
CY
1522
1523 for (q = p + 1; *q && *q != ' '; q++)
1524 if (*q == '\\' && q[1])
1525 q++;
1526 word_len = q - p;
1527
1528#define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
1529
1530 if (PROP_MATCH ("Ultra-Light", 11))
9331887d 1531 {
8c102d5b
CY
1532 prop_found = 1;
1533 prop = font_intern_prop ("ultra-light", 11, 1);
1534 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
9331887d 1535 }
8c102d5b 1536 else if (PROP_MATCH ("Light", 5))
9331887d 1537 {
8c102d5b
CY
1538 prop_found = 1;
1539 prop = font_intern_prop ("light", 5, 1);
1540 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
9331887d 1541 }
fe69a722
CY
1542 else if (PROP_MATCH ("Book", 4))
1543 {
1544 prop_found = 1;
1545 prop = font_intern_prop ("book", 4, 1);
1546 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1547 }
4ed28cf4
CY
1548 else if (PROP_MATCH ("Medium", 6))
1549 {
1550 prop_found = 1;
1551 prop = font_intern_prop ("medium", 6, 1);
1552 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1553 }
8c102d5b 1554 else if (PROP_MATCH ("Semi-Bold", 9))
9331887d 1555 {
8c102d5b
CY
1556 prop_found = 1;
1557 prop = font_intern_prop ("semi-bold", 9, 1);
1558 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1559 }
1560 else if (PROP_MATCH ("Bold", 4))
1561 {
1562 prop_found = 1;
1563 prop = font_intern_prop ("bold", 4, 1);
1564 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
ef18374f 1565 }
8c102d5b
CY
1566 else if (PROP_MATCH ("Italic", 6))
1567 {
1568 prop_found = 1;
1569 prop = font_intern_prop ("italic", 4, 1);
1570 FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop);
1571 }
1572 else if (PROP_MATCH ("Oblique", 7))
1573 {
1574 prop_found = 1;
1575 prop = font_intern_prop ("oblique", 7, 1);
1576 FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop);
1577 }
fe69a722
CY
1578 else if (PROP_MATCH ("Semi-Condensed", 14))
1579 {
1580 prop_found = 1;
1581 prop = font_intern_prop ("semi-condensed", 14, 1);
1582 FONT_SET_STYLE (font, FONT_WIDTH_INDEX, prop);
1583 }
1584 else if (PROP_MATCH ("Condensed", 9))
1585 {
1586 prop_found = 1;
1587 prop = font_intern_prop ("condensed", 9, 1);
1588 FONT_SET_STYLE (font, FONT_WIDTH_INDEX, prop);
1589 }
8c102d5b
CY
1590 else {
1591 if (prop_found)
1592 return -1; /* Unknown property in GTK-style font name. */
1593 family_end = q;
1594 }
ef18374f 1595 }
8c102d5b 1596#undef PROP_MATCH
9ba6fd41 1597
8c102d5b
CY
1598 if (family_end)
1599 {
1600 Lisp_Object family;
1601 family = font_intern_prop (name, family_end - name, 1);
1602 ASET (font, FONT_FAMILY_INDEX, family);
1603 }
1604 }
17ab8f5d 1605
9331887d 1606 return 0;
ef18374f
KH
1607}
1608
1609/* Store fontconfig's font name of FONT (font-spec or font-entity) in
1610 NAME (NBYTES length), and return the name length. If
1611 FONT_SIZE_INDEX of FONT is 0, use PIXEL_SIZE instead. */
1612
1613int
971de7fb 1614font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
ef18374f 1615{
b1868a1a 1616 Lisp_Object family, foundry;
35027d0c 1617 Lisp_Object tail, val;
ec6fe57c 1618 int point_size;
ec6fe57c 1619 int i, len = 1;
ef18374f 1620 char *p;
a9262bb8 1621 Lisp_Object styles[3];
417a1b10 1622 char *style_names[3] = { "weight", "slant", "width" };
35027d0c 1623 char work[256];
ef18374f 1624
b1868a1a
CY
1625 family = AREF (font, FONT_FAMILY_INDEX);
1626 if (! NILP (family))
1627 {
1628 if (SYMBOLP (family))
1629 {
1630 family = SYMBOL_NAME (family);
1631 len += SBYTES (family);
1632 }
1633 else
1634 family = Qnil;
1635 }
ec6fe57c
KH
1636
1637 val = AREF (font, FONT_SIZE_INDEX);
1638 if (INTEGERP (val))
ef18374f 1639 {
ec6fe57c
KH
1640 if (XINT (val) != 0)
1641 pixel_size = XINT (val);
1642 point_size = -1;
1643 len += 21; /* for ":pixelsize=NUM" */
ef18374f 1644 }
ec6fe57c 1645 else if (FLOATP (val))
ef18374f 1646 {
ec6fe57c
KH
1647 pixel_size = -1;
1648 point_size = (int) XFLOAT_DATA (val);
1649 len += 11; /* for "-NUM" */
ef18374f 1650 }
ec6fe57c 1651
b1868a1a
CY
1652 foundry = AREF (font, FONT_FOUNDRY_INDEX);
1653 if (! NILP (foundry))
1654 {
1655 if (SYMBOLP (foundry))
1656 {
1657 foundry = SYMBOL_NAME (foundry);
1658 len += 9 + SBYTES (foundry); /* ":foundry=NAME" */
1659 }
1660 else
1661 foundry = Qnil;
1662 }
ec6fe57c 1663
35027d0c 1664 for (i = 0; i < 3; i++)
a9262bb8 1665 {
35027d0c
KH
1666 styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
1667 if (! NILP (styles[i]))
1668 len += sprintf (work, ":%s=%s", style_names[i],
1669 SDATA (SYMBOL_NAME (styles[i])));
ec6fe57c 1670 }
35027d0c
KH
1671
1672 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
c56c14a1 1673 len += sprintf (work, ":dpi=%ld", (long)XINT (AREF (font, FONT_DPI_INDEX)));
35027d0c
KH
1674 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
1675 len += strlen (":spacing=100");
1676 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1677 len += strlen (":scalable=false"); /* or ":scalable=true" */
1678 for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
ec6fe57c 1679 {
35027d0c
KH
1680 Lisp_Object key = XCAR (XCAR (tail)), val = XCDR (XCAR (tail));
1681
1682 len += SBYTES (SYMBOL_NAME (key)) + 1; /* for :KEY= */
1683 if (STRINGP (val))
1684 len += SBYTES (val);
1685 else if (INTEGERP (val))
c56c14a1 1686 len += sprintf (work, "%ld", (long) XINT (val));
35027d0c
KH
1687 else if (SYMBOLP (val))
1688 len += (NILP (val) ? 5 : 4); /* for "false" or "true" */
ec6fe57c
KH
1689 }
1690
ef18374f
KH
1691 if (len > nbytes)
1692 return -1;
1693 p = name;
b1868a1a
CY
1694 if (! NILP (family))
1695 p += sprintf (p, "%s", SDATA (family));
ec6fe57c
KH
1696 if (point_size > 0)
1697 {
1698 if (p == name)
1699 p += sprintf (p, "%d", point_size);
1700 else
1701 p += sprintf (p, "-%d", point_size);
1702 }
ef18374f
KH
1703 else if (pixel_size > 0)
1704 p += sprintf (p, ":pixelsize=%d", pixel_size);
35027d0c 1705 if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
a9262bb8
KH
1706 p += sprintf (p, ":foundry=%s",
1707 SDATA (SYMBOL_NAME (AREF (font, FONT_FOUNDRY_INDEX))));
1708 for (i = 0; i < 3; i++)
35027d0c 1709 if (! NILP (styles[i]))
a9262bb8 1710 p += sprintf (p, ":%s=%s", style_names[i],
35027d0c
KH
1711 SDATA (SYMBOL_NAME (styles[i])));
1712 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
c56c14a1 1713 p += sprintf (p, ":dpi=%ld", (long) XINT (AREF (font, FONT_DPI_INDEX)));
35027d0c 1714 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
c56c14a1
AR
1715 p += sprintf (p, ":spacing=%ld",
1716 (long) XINT (AREF (font, FONT_SPACING_INDEX)));
35027d0c
KH
1717 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1718 {
1719 if (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0)
1720 p += sprintf (p, ":scalable=true");
1721 else
1722 p += sprintf (p, ":scalable=false");
1723 }
ef18374f
KH
1724 return (p - name);
1725}
1726
b1868a1a
CY
1727/* Store GTK-style font name of FONT (font-spec or font-entity) in
1728 NAME (NBYTES length), and return the name length. F is the frame
1729 on which the font is displayed; it is used to calculate the point
1730 size. */
1731
1732int
971de7fb 1733font_unparse_gtkname (Lisp_Object font, struct frame *f, char *name, int nbytes)
b1868a1a
CY
1734{
1735 char *p;
1736 int len = 1;
1737 Lisp_Object family, weight, slant, size;
1738 int point_size = -1;
1739
1740 family = AREF (font, FONT_FAMILY_INDEX);
1741 if (! NILP (family))
1742 {
1743 if (! SYMBOLP (family))
1744 return -1;
1745 family = SYMBOL_NAME (family);
1746 len += SBYTES (family);
1747 }
1748
1749 weight = font_style_symbolic (font, FONT_WEIGHT_INDEX, 0);
93eed26b 1750 if (EQ (weight, Qnormal))
b1868a1a
CY
1751 weight = Qnil;
1752 else if (! NILP (weight))
1753 {
1754 weight = SYMBOL_NAME (weight);
1755 len += SBYTES (weight);
1756 }
1757
1758 slant = font_style_symbolic (font, FONT_SLANT_INDEX, 0);
93eed26b 1759 if (EQ (slant, Qnormal))
b1868a1a
CY
1760 slant = Qnil;
1761 else if (! NILP (slant))
1762 {
1763 slant = SYMBOL_NAME (slant);
1764 len += SBYTES (slant);
1765 }
1766
1767 size = AREF (font, FONT_SIZE_INDEX);
1768 /* Convert pixel size to point size. */
1769 if (INTEGERP (size))
1770 {
1771 Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
1772 int dpi = 75;
1773 if (INTEGERP (font_dpi))
1774 dpi = XINT (font_dpi);
1775 else if (f)
1776 dpi = f->resy;
1777 point_size = PIXEL_TO_POINT (XINT (size), dpi);
1778 len += 11;
1779 }
1780 else if (FLOATP (size))
1781 {
1782 point_size = (int) XFLOAT_DATA (size);
1783 len += 11;
1784 }
1785
1786 if (len > nbytes)
1787 return -1;
1788
1789 p = name + sprintf (name, "%s", SDATA (family));
1790
1791 if (! NILP (weight))
1792 {
1793 char *q = p;
1794 p += sprintf (p, " %s", SDATA (weight));
1795 q[1] = toupper (q[1]);
1796 }
1797
1798 if (! NILP (slant))
1799 {
1800 char *q = p;
1801 p += sprintf (p, " %s", SDATA (slant));
1802 q[1] = toupper (q[1]);
1803 }
1804
1805 if (point_size > 0)
1806 p += sprintf (p, " %d", point_size);
1807
1808 return (p - name);
1809}
1810
ef18374f
KH
1811/* Parse NAME (null terminated) and store information in FONT
1812 (font-spec or font-entity). If NAME is successfully parsed, return
35027d0c 1813 0. Otherwise return -1. */
ef18374f
KH
1814
1815static int
971de7fb 1816font_parse_name (char *name, Lisp_Object font)
ef18374f 1817{
8966b757 1818 if (name[0] == '-' || strchr (name, '*') || strchr (name, '?'))
e950d6f1 1819 return font_parse_xlfd (name, font);
ec6fe57c 1820 return font_parse_fcname (name, font);
ef18374f
KH
1821}
1822
35027d0c
KH
1823
1824/* Merge FAMILY and REGISTRY into FONT_SPEC. FAMILY may have the form
1825 "FAMILY-FOUNDRY". REGISTRY may not contain charset-encoding
1826 part. */
45eb10fb 1827
c2f5bfd6 1828void
971de7fb 1829font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Object font_spec)
c2f5bfd6 1830{
35027d0c
KH
1831 int len;
1832 char *p0, *p1;
1833
d0ab1ebe
KH
1834 if (! NILP (family)
1835 && NILP (AREF (font_spec, FONT_FAMILY_INDEX)))
c2f5bfd6 1836 {
35027d0c
KH
1837 CHECK_STRING (family);
1838 len = SBYTES (family);
1839 p0 = (char *) SDATA (family);
8966b757 1840 p1 = strchr (p0, '-');
35027d0c 1841 if (p1)
c2f5bfd6 1842 {
9903d1e6 1843 if ((*p0 != '*' && p1 - p0 > 0)
d0ab1ebe 1844 && NILP (AREF (font_spec, FONT_FOUNDRY_INDEX)))
2f286d4f 1845 Ffont_put (font_spec, QCfoundry, font_intern_prop (p0, p1 - p0, 1));
35027d0c
KH
1846 p1++;
1847 len -= p1 - p0;
2f286d4f 1848 Ffont_put (font_spec, QCfamily, font_intern_prop (p1, len, 1));
c2f5bfd6 1849 }
35027d0c
KH
1850 else
1851 ASET (font_spec, FONT_FAMILY_INDEX, Fintern (family, Qnil));
c2f5bfd6 1852 }
35027d0c 1853 if (! NILP (registry))
c2f5bfd6 1854 {
35027d0c
KH
1855 /* Convert "XXX" and "XXX*" to "XXX*-*". */
1856 CHECK_STRING (registry);
1857 len = SBYTES (registry);
1858 p0 = (char *) SDATA (registry);
8966b757 1859 p1 = strchr (p0, '-');
35027d0c 1860 if (! p1)
c2f5bfd6 1861 {
35027d0c
KH
1862 if (SDATA (registry)[len - 1] == '*')
1863 registry = concat2 (registry, build_string ("-*"));
1864 else
1865 registry = concat2 (registry, build_string ("*-*"));
c2f5bfd6 1866 }
35027d0c
KH
1867 registry = Fdowncase (registry);
1868 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
c2f5bfd6
KH
1869 }
1870}
1871
45eb10fb 1872\f
35027d0c
KH
1873/* This part (through the next ^L) is still experimental and not
1874 tested much. We may drastically change codes. */
10d16101 1875
45eb10fb 1876/* OTF handler */
10d16101 1877
6a3dadd2
KH
1878#if 0
1879
e950d6f1
KH
1880#define LGSTRING_HEADER_SIZE 6
1881#define LGSTRING_GLYPH_SIZE 8
1882
1883static int
1884check_gstring (gstring)
1885 Lisp_Object gstring;
1886{
1887 Lisp_Object val;
1888 int i, j;
1889
1890 CHECK_VECTOR (gstring);
1891 val = AREF (gstring, 0);
1892 CHECK_VECTOR (val);
1893 if (ASIZE (val) < LGSTRING_HEADER_SIZE)
1894 goto err;
1895 CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
f9ffa1ea
SM
1896 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING)))
1897 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING));
1898 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING)))
1899 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING));
1900 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH)))
1901 CHECK_NATNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH));
1902 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1903 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
1904 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1905 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
e950d6f1 1906
071132a9 1907 for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
e950d6f1
KH
1908 {
1909 val = LGSTRING_GLYPH (gstring, i);
1910 CHECK_VECTOR (val);
1911 if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
1912 goto err;
f9ffa1ea 1913 if (NILP (AREF (val, LGLYPH_IX_CHAR)))
e950d6f1 1914 break;
f9ffa1ea
SM
1915 CHECK_NATNUM (AREF (val, LGLYPH_IX_FROM));
1916 CHECK_NATNUM (AREF (val, LGLYPH_IX_TO));
1917 CHECK_CHARACTER (AREF (val, LGLYPH_IX_CHAR));
1918 if (!NILP (AREF (val, LGLYPH_IX_CODE)))
1919 CHECK_NATNUM (AREF (val, LGLYPH_IX_CODE));
1920 if (!NILP (AREF (val, LGLYPH_IX_WIDTH)))
1921 CHECK_NATNUM (AREF (val, LGLYPH_IX_WIDTH));
1922 if (!NILP (AREF (val, LGLYPH_IX_ADJUSTMENT)))
e950d6f1 1923 {
f9ffa1ea 1924 val = AREF (val, LGLYPH_IX_ADJUSTMENT);
e950d6f1
KH
1925 CHECK_VECTOR (val);
1926 if (ASIZE (val) < 3)
1927 goto err;
1928 for (j = 0; j < 3; j++)
1929 CHECK_NUMBER (AREF (val, j));
1930 }
1931 }
1932 return i;
1933 err:
1934 error ("Invalid glyph-string format");
1935 return -1;
1936}
1937
cf385d93
KH
1938static void
1939check_otf_features (otf_features)
1940 Lisp_Object otf_features;
1941{
35027d0c 1942 Lisp_Object val;
cf385d93
KH
1943
1944 CHECK_CONS (otf_features);
1945 CHECK_SYMBOL (XCAR (otf_features));
1946 otf_features = XCDR (otf_features);
1947 CHECK_CONS (otf_features);
1948 CHECK_SYMBOL (XCAR (otf_features));
1949 otf_features = XCDR (otf_features);
1950 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
1951 {
1952 CHECK_SYMBOL (Fcar (val));
1953 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1954 error ("Invalid OTF GSUB feature: %s", SYMBOL_NAME (XCAR (val)));
1955 }
1956 otf_features = XCDR (otf_features);
1957 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
1958 {
1959 CHECK_SYMBOL (Fcar (val));
1960 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1961 error ("Invalid OTF GPOS feature: %s", SYMBOL_NAME (XCAR (val)));
1962 }
1963}
1964
c2f5bfd6
KH
1965#ifdef HAVE_LIBOTF
1966#include <otf.h>
1967
733fd013 1968Lisp_Object otf_list;
c2f5bfd6
KH
1969
1970static Lisp_Object
1971otf_tag_symbol (tag)
1972 OTF_Tag tag;
1973{
1974 char name[5];
1975
1976 OTF_tag_name (tag, name);
1977 return Fintern (make_unibyte_string (name, 4), Qnil);
1978}
1979
1980static OTF *
35027d0c
KH
1981otf_open (file)
1982 Lisp_Object file;
c2f5bfd6 1983{
35027d0c 1984 Lisp_Object val = Fassoc (file, otf_list);
733fd013
KH
1985 OTF *otf;
1986
1987 if (! NILP (val))
1988 otf = XSAVE_VALUE (XCDR (val))->pointer;
1989 else
c2f5bfd6 1990 {
35027d0c 1991 otf = STRINGP (file) ? OTF_open ((char *) SDATA (file)) : NULL;
733fd013 1992 val = make_save_value (otf, 0);
35027d0c 1993 otf_list = Fcons (Fcons (file, val), otf_list);
c2f5bfd6 1994 }
733fd013 1995 return otf;
c2f5bfd6
KH
1996}
1997
1998
1999/* Return a list describing which scripts/languages FONT supports by
2000 which GSUB/GPOS features of OpenType tables. See the comment of
51c01100 2001 (struct font_driver).otf_capability. */
c2f5bfd6
KH
2002
2003Lisp_Object
2004font_otf_capability (font)
2005 struct font *font;
2006{
2007 OTF *otf;
2008 Lisp_Object capability = Fcons (Qnil, Qnil);
2009 int i;
2010
35027d0c 2011 otf = otf_open (font->props[FONT_FILE_INDEX]);
c2f5bfd6
KH
2012 if (! otf)
2013 return Qnil;
2014 for (i = 0; i < 2; i++)
2015 {
2016 OTF_GSUB_GPOS *gsub_gpos;
2017 Lisp_Object script_list = Qnil;
2018 int j;
2019
2020 if (OTF_get_features (otf, i == 0) < 0)
2021 continue;
2022 gsub_gpos = i == 0 ? otf->gsub : otf->gpos;
2023 for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--)
2024 {
2025 OTF_Script *script = gsub_gpos->ScriptList.Script + j;
2026 Lisp_Object langsys_list = Qnil;
2027 Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag);
2028 int k;
2029
2030 for (k = script->LangSysCount; k >= 0; k--)
2031 {
2032 OTF_LangSys *langsys;
2033 Lisp_Object feature_list = Qnil;
2034 Lisp_Object langsys_tag;
2035 int l;
2036
e80e09b4 2037 if (k == script->LangSysCount)
c2f5bfd6
KH
2038 {
2039 langsys = &script->DefaultLangSys;
2040 langsys_tag = Qnil;
2041 }
2042 else
2043 {
2044 langsys = script->LangSys + k;
2045 langsys_tag
2046 = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
2047 }
e80e09b4 2048 for (l = langsys->FeatureCount - 1; l >= 0; l--)
c2f5bfd6
KH
2049 {
2050 OTF_Feature *feature
2051 = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
2052 Lisp_Object feature_tag
2053 = otf_tag_symbol (feature->FeatureTag);
2054
2055 feature_list = Fcons (feature_tag, feature_list);
2056 }
2057 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
2058 langsys_list);
2059 }
2060 script_list = Fcons (Fcons (script_tag, langsys_list),
2061 script_list);
2062 }
2063
2064 if (i == 0)
2065 XSETCAR (capability, script_list);
2066 else
2067 XSETCDR (capability, script_list);
2068 }
2069
2070 return capability;
2071}
2072
733fd013
KH
2073/* Parse OTF features in SPEC and write a proper features spec string
2074 in FEATURES for the call of OTF_drive_gsub/gpos (of libotf). It is
2075 assured that the sufficient memory has already allocated for
2076 FEATURES. */
2077
e80e09b4 2078static void
733fd013 2079generate_otf_features (spec, features)
c2f5bfd6 2080 Lisp_Object spec;
733fd013 2081 char *features;
c2f5bfd6
KH
2082{
2083 Lisp_Object val;
35027d0c 2084 char *p;
c2f5bfd6
KH
2085 int asterisk;
2086
733fd013 2087 p = features;
e80e09b4 2088 *p = '\0';
c2f5bfd6
KH
2089 for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
2090 {
2091 val = XCAR (spec);
e80e09b4
KH
2092 CHECK_SYMBOL (val);
2093 if (p > features)
733fd013 2094 *p++ = ',';
c2f5bfd6
KH
2095 if (SREF (SYMBOL_NAME (val), 0) == '*')
2096 {
2097 asterisk = 1;
e80e09b4 2098 *p++ = '*';
c2f5bfd6
KH
2099 }
2100 else if (! asterisk)
e80e09b4
KH
2101 {
2102 val = SYMBOL_NAME (val);
e80e09b4
KH
2103 p += sprintf (p, "%s", SDATA (val));
2104 }
c2f5bfd6 2105 else
e80e09b4
KH
2106 {
2107 val = SYMBOL_NAME (val);
e80e09b4
KH
2108 p += sprintf (p, "~%s", SDATA (val));
2109 }
c2f5bfd6 2110 }
e80e09b4
KH
2111 if (CONSP (spec))
2112 error ("OTF spec too long");
2113}
2114
733fd013
KH
2115Lisp_Object
2116font_otf_DeviceTable (device_table)
2117 OTF_DeviceTable *device_table;
2118{
2119 int len = device_table->StartSize - device_table->EndSize + 1;
2120
2121 return Fcons (make_number (len),
2122 make_unibyte_string (device_table->DeltaValue, len));
2123}
2124
2125Lisp_Object
2126font_otf_ValueRecord (value_format, value_record)
2127 int value_format;
2128 OTF_ValueRecord *value_record;
2129{
2130 Lisp_Object val = Fmake_vector (make_number (8), Qnil);
2131
2132 if (value_format & OTF_XPlacement)
43c0454d 2133 ASET (val, 0, make_number (value_record->XPlacement));
733fd013 2134 if (value_format & OTF_YPlacement)
43c0454d 2135 ASET (val, 1, make_number (value_record->YPlacement));
733fd013 2136 if (value_format & OTF_XAdvance)
43c0454d 2137 ASET (val, 2, make_number (value_record->XAdvance));
733fd013 2138 if (value_format & OTF_YAdvance)
43c0454d 2139 ASET (val, 3, make_number (value_record->YAdvance));
733fd013
KH
2140 if (value_format & OTF_XPlaDevice)
2141 ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
2142 if (value_format & OTF_YPlaDevice)
2143 ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
2144 if (value_format & OTF_XAdvDevice)
2145 ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
2146 if (value_format & OTF_YAdvDevice)
2147 ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
2148 return val;
2149}
2150
2151Lisp_Object
2152font_otf_Anchor (anchor)
2153 OTF_Anchor *anchor;
2154{
2155 Lisp_Object val;
2156
2157 val = Fmake_vector (make_number (anchor->AnchorFormat + 1), Qnil);
2158 ASET (val, 0, make_number (anchor->XCoordinate));
2159 ASET (val, 1, make_number (anchor->YCoordinate));
2160 if (anchor->AnchorFormat == 2)
2161 ASET (val, 2, make_number (anchor->f.f1.AnchorPoint));
2162 else
2163 {
2164 ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
2165 ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
2166 }
2167 return val;
2168}
c2f5bfd6 2169#endif /* HAVE_LIBOTF */
6a3dadd2 2170#endif /* 0 */
c2f5bfd6 2171
c2f5bfd6
KH
2172\f
2173/* Font sorting */
2174
f57e2426
J
2175static unsigned font_score (Lisp_Object, Lisp_Object *);
2176static int font_compare (const void *, const void *);
2177static Lisp_Object font_sort_entities (Lisp_Object, Lisp_Object,
2178 Lisp_Object, int);
c2f5bfd6 2179
55e41770
KH
2180/* Return a rescaling ratio of FONT_ENTITY. */
2181extern Lisp_Object Vface_font_rescale_alist;
2182
2183static double
971de7fb 2184font_rescale_ratio (Lisp_Object font_entity)
55e41770
KH
2185{
2186 Lisp_Object tail, elt;
2187 Lisp_Object name = Qnil;
2188
2189 for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail))
2190 {
2191 elt = XCAR (tail);
2192 if (FLOATP (XCDR (elt)))
2193 {
2194 if (STRINGP (XCAR (elt)))
2195 {
2196 if (NILP (name))
2197 name = Ffont_xlfd_name (font_entity, Qnil);
2198 if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
2199 return XFLOAT_DATA (XCDR (elt));
2200 }
2201 else if (FONT_SPEC_P (XCAR (elt)))
2202 {
2203 if (font_match_p (XCAR (elt), font_entity))
2204 return XFLOAT_DATA (XCDR (elt));
2205 }
2206 }
2207 }
2208 return 1.0;
2209}
2210
c2f5bfd6
KH
2211/* We sort fonts by scoring each of them against a specified
2212 font-spec. The score value is 32 bit (`unsigned'), and the smaller
2213 the value is, the closer the font is to the font-spec.
2214
4007dd1c
KH
2215 The lowest 2 bits of the score is used for driver type. The font
2216 available by the most preferred font driver is 0.
35027d0c 2217
4007dd1c 2218 Each 7-bit in the higher 28 bits are used for numeric properties
c2f5bfd6
KH
2219 WEIGHT, SLANT, WIDTH, and SIZE. */
2220
2221/* How many bits to shift to store the difference value of each font
35027d0c
KH
2222 property in a score. Note that flots for FONT_TYPE_INDEX and
2223 FONT_REGISTRY_INDEX are not used. */
c2f5bfd6
KH
2224static int sort_shift_bits[FONT_SIZE_INDEX + 1];
2225
9331887d
KH
2226/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
2227 The return value indicates how different ENTITY is compared with
51c13510 2228 SPEC_PROP. */
c2f5bfd6
KH
2229
2230static unsigned
971de7fb 2231font_score (Lisp_Object entity, Lisp_Object *spec_prop)
c2f5bfd6
KH
2232{
2233 unsigned score = 0;
2234 int i;
c2f5bfd6 2235
35027d0c
KH
2236 /* Score three style numeric fields. Maximum difference is 127. */
2237 for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
2238 if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
2239 {
2240 int diff = (XINT (AREF (entity, i)) >> 8) - (XINT (spec_prop[i]) >> 8);
2241
2242 if (diff < 0)
2243 diff = - diff;
f4cc0153
KH
2244 if (diff > 0)
2245 score |= min (diff, 127) << sort_shift_bits[i];
35027d0c
KH
2246 }
2247
2248 /* Score the size. Maximum difference is 127. */
2249 i = FONT_SIZE_INDEX;
55e41770
KH
2250 if (! NILP (spec_prop[FONT_SIZE_INDEX])
2251 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
35027d0c
KH
2252 {
2253 /* We use the higher 6-bit for the actual size difference. The
2254 lowest bit is set if the DPI is different. */
55e41770
KH
2255 int diff;
2256 int pixel_size = XINT (spec_prop[FONT_SIZE_INDEX]);
35027d0c 2257
55e41770
KH
2258 if (CONSP (Vface_font_rescale_alist))
2259 pixel_size *= font_rescale_ratio (entity);
2260 diff = pixel_size - XINT (AREF (entity, FONT_SIZE_INDEX));
35027d0c
KH
2261 if (diff < 0)
2262 diff = - diff;
d0ab1ebe 2263 diff <<= 1;
35027d0c
KH
2264 if (! NILP (spec_prop[FONT_DPI_INDEX])
2265 && ! EQ (spec_prop[FONT_DPI_INDEX], AREF (entity, FONT_DPI_INDEX)))
2266 diff |= 1;
c0a6070d
KH
2267 if (! NILP (spec_prop[FONT_AVGWIDTH_INDEX])
2268 && ! EQ (spec_prop[FONT_AVGWIDTH_INDEX], AREF (entity, FONT_AVGWIDTH_INDEX)))
2269 diff |= 1;
35027d0c 2270 score |= min (diff, 127) << sort_shift_bits[FONT_SIZE_INDEX];
c2f5bfd6
KH
2271 }
2272
2273 return score;
2274}
2275
2276
72d36834
KH
2277/* Concatenate all elements of LIST into one vector. LIST is a list
2278 of font-entity vectors. */
c2f5bfd6 2279
72d36834
KH
2280static Lisp_Object
2281font_vconcat_entity_vectors (Lisp_Object list)
c2f5bfd6 2282{
72d36834
KH
2283 int nargs = XINT (Flength (list));
2284 Lisp_Object *args = alloca (sizeof (Lisp_Object) * nargs);
2285 int i;
2286
2287 for (i = 0; i < nargs; i++, list = XCDR (list))
2288 args[i] = XCAR (list);
2289 return Fvconcat (nargs, args);
c2f5bfd6
KH
2290}
2291
2292
2293/* The structure for elements being sorted by qsort. */
2294struct font_sort_data
2295{
2296 unsigned score;
72d36834 2297 int font_driver_preference;
c2f5bfd6
KH
2298 Lisp_Object entity;
2299};
2300
2301
72d36834
KH
2302/* The comparison function for qsort. */
2303
2304static int
971de7fb 2305font_compare (const void *d1, const void *d2)
72d36834
KH
2306{
2307 const struct font_sort_data *data1 = d1;
2308 const struct font_sort_data *data2 = d2;
2309
2310 if (data1->score < data2->score)
2311 return -1;
2312 else if (data1->score > data2->score)
2313 return 1;
2314 return (data1->font_driver_preference - data2->font_driver_preference);
2315}
2316
2317
2318/* Sort each font-entity vector in LIST by closeness to font-spec PREFER.
c2f5bfd6 2319 If PREFER specifies a point-size, calculate the corresponding
9331887d 2320 pixel-size from QCdpi property of PREFER or from the Y-resolution
7181ea6a 2321 of FRAME before sorting.
35027d0c 2322
c9477f01
KH
2323 If BEST-ONLY is nonzero, return the best matching entity (that
2324 supports the character BEST-ONLY if BEST-ONLY is positive, or any
72d36834
KH
2325 if BEST-ONLY is negative). Otherwise, return the sorted result as
2326 a single vector of font-entities.
c9477f01 2327
72d36834
KH
2328 This function does no optimization for the case that the total
2329 number of elements is 1. The caller should avoid calling this in
2330 such a case. */
c2f5bfd6
KH
2331
2332static Lisp_Object
971de7fb 2333font_sort_entities (Lisp_Object list, Lisp_Object prefer, Lisp_Object frame, int best_only)
c2f5bfd6 2334{
9331887d 2335 Lisp_Object prefer_prop[FONT_SPEC_MAX];
72d36834 2336 int len, maxlen, i;
c2f5bfd6 2337 struct font_sort_data *data;
35027d0c 2338 unsigned best_score;
72d36834 2339 Lisp_Object best_entity;
4007dd1c 2340 struct frame *f = XFRAME (frame);
72d36834 2341 Lisp_Object tail, vec;
c2f5bfd6
KH
2342 USE_SAFE_ALLOCA;
2343
9903d1e6 2344 for (i = FONT_WEIGHT_INDEX; i <= FONT_AVGWIDTH_INDEX; i++)
9331887d 2345 prefer_prop[i] = AREF (prefer, i);
9331887d
KH
2346 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2347 prefer_prop[FONT_SIZE_INDEX]
2348 = make_number (font_pixel_size (XFRAME (frame), prefer));
2349
72d36834
KH
2350 if (NILP (XCDR (list)))
2351 {
2352 /* What we have to take care of is this single vector. */
2353 vec = XCAR (list);
2354 maxlen = ASIZE (vec);
2355 }
2356 else if (best_only)
2357 {
2358 /* We don't have to perform sort, so there's no need of creating
2359 a single vector. But, we must find the length of the longest
2360 vector. */
2361 maxlen = 0;
2362 for (tail = list; CONSP (tail); tail = XCDR (tail))
2363 if (maxlen < ASIZE (XCAR (tail)))
2364 maxlen = ASIZE (XCAR (tail));
2365 }
2366 else
2367 {
2368 /* We have to create a single vector to sort it. */
2369 vec = font_vconcat_entity_vectors (list);
2370 maxlen = ASIZE (vec);
2371 }
2372
2373 SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * maxlen);
c9477f01
KH
2374 best_score = 0xFFFFFFFF;
2375 best_entity = Qnil;
72d36834
KH
2376
2377 for (tail = list; CONSP (tail); tail = XCDR (tail))
c2f5bfd6 2378 {
72d36834
KH
2379 int font_driver_preference = 0;
2380 Lisp_Object current_font_driver;
ce75f06e 2381
72d36834
KH
2382 if (best_only)
2383 vec = XCAR (tail);
2384 len = ASIZE (vec);
2385
2386 /* We are sure that the length of VEC > 0. */
2387 current_font_driver = AREF (AREF (vec, 0), FONT_TYPE_INDEX);
2388 /* Score the elements. */
2389 for (i = 0; i < len; i++)
35027d0c 2390 {
72d36834
KH
2391 data[i].entity = AREF (vec, i);
2392 data[i].score
2393 = ((best_only <= 0 || font_has_char (f, data[i].entity, best_only)
2394 > 0)
2395 ? font_score (data[i].entity, prefer_prop)
2396 : 0xFFFFFFFF);
2397 if (best_only && best_score > data[i].score)
2398 {
2399 best_score = data[i].score;
2400 best_entity = data[i].entity;
2401 if (best_score == 0)
2402 break;
2403 }
2404 if (! EQ (current_font_driver, AREF (AREF (vec, i), FONT_TYPE_INDEX)))
2405 {
2406 current_font_driver = AREF (AREF (vec, i), FONT_TYPE_INDEX);
2407 font_driver_preference++;
2408 }
2409 data[i].font_driver_preference = font_driver_preference;
35027d0c 2410 }
72d36834
KH
2411
2412 /* Sort if necessary. */
2413 if (! best_only)
2414 {
2415 qsort (data, len, sizeof *data, font_compare);
2416 for (i = 0; i < len; i++)
2417 ASET (vec, i, data[i].entity);
2418 break;
2419 }
2420 else
2421 vec = best_entity;
c2f5bfd6 2422 }
72d36834 2423
c2f5bfd6
KH
2424 SAFE_FREE ();
2425
652b9560 2426 FONT_ADD_LOG ("sort-by", prefer, vec);
c2f5bfd6
KH
2427 return vec;
2428}
2429
2430\f
2431/* API of Font Service Layer. */
2432
45eb10fb
KH
2433/* Reflect ORDER (see the variable font_sort_order in xfaces.c) to
2434 sort_shift_bits. Finternal_set_font_selection_order calls this
2435 function with font_sort_order after setting up it. */
2436
c2f5bfd6 2437void
971de7fb 2438font_update_sort_order (int *order)
c2f5bfd6 2439{
35027d0c 2440 int i, shift_bits;
c2f5bfd6 2441
943b7eea 2442 for (i = 0, shift_bits = 23; i < 4; i++, shift_bits -= 7)
c2f5bfd6
KH
2443 {
2444 int xlfd_idx = order[i];
2445
2446 if (xlfd_idx == XLFD_WEIGHT_INDEX)
2447 sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits;
2448 else if (xlfd_idx == XLFD_SLANT_INDEX)
2449 sort_shift_bits[FONT_SLANT_INDEX] = shift_bits;
2450 else if (xlfd_idx == XLFD_SWIDTH_INDEX)
2451 sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits;
2452 else
2453 sort_shift_bits[FONT_SIZE_INDEX] = shift_bits;
2454 }
2455}
2456
51c13510 2457static int
971de7fb 2458font_check_otf_features (Lisp_Object script, Lisp_Object langsys, Lisp_Object features, Lisp_Object table)
51c13510
KH
2459{
2460 Lisp_Object val;
2461 int negative;
2462
2463 table = assq_no_quit (script, table);
2464 if (NILP (table))
2465 return 0;
2466 table = XCDR (table);
2467 if (! NILP (langsys))
2468 {
2469 table = assq_no_quit (langsys, table);
2470 if (NILP (table))
2471 return 0;
2472 }
2473 else
2474 {
2475 val = assq_no_quit (Qnil, table);
2476 if (NILP (val))
2477 table = XCAR (table);
2478 else
2479 table = val;
2480 }
2481 table = XCDR (table);
2482 for (negative = 0; CONSP (features); features = XCDR (features))
2483 {
2484 if (NILP (XCAR (features)))
c423ecca
KH
2485 {
2486 negative = 1;
2487 continue;
2488 }
51c13510
KH
2489 if (NILP (Fmemq (XCAR (features), table)) != negative)
2490 return 0;
2491 }
2492 return 1;
2493}
2494
2495/* Check if OTF_CAPABILITY satisfies SPEC (otf-spec). */
2496
2497static int
3cba9369 2498font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
51c13510
KH
2499{
2500 Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
2501
2502 script = XCAR (spec);
2503 spec = XCDR (spec);
2504 if (! NILP (spec))
2505 {
2506 langsys = XCAR (spec);
2507 spec = XCDR (spec);
2508 if (! NILP (spec))
2509 {
2510 gsub = XCAR (spec);
2511 spec = XCDR (spec);
2512 if (! NILP (spec))
2513 gpos = XCAR (spec);
2514 }
2515 }
2516
2517 if (! NILP (gsub) && ! font_check_otf_features (script, langsys, gsub,
2518 XCAR (otf_capability)))
2519 return 0;
2520 if (! NILP (gpos) && ! font_check_otf_features (script, langsys, gpos,
2521 XCDR (otf_capability)))
2522 return 0;
2523 return 1;
2524}
2525
45eb10fb 2526
51c13510
KH
2527
2528/* Check if FONT (font-entity or font-object) matches with the font
2529 specification SPEC. */
45eb10fb 2530
ef18374f 2531int
971de7fb 2532font_match_p (Lisp_Object spec, Lisp_Object font)
ef18374f 2533{
51c13510
KH
2534 Lisp_Object prop[FONT_SPEC_MAX], *props;
2535 Lisp_Object extra, font_extra;
ef18374f
KH
2536 int i;
2537
51c13510
KH
2538 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
2539 if (! NILP (AREF (spec, i))
2540 && ! NILP (AREF (font, i))
2541 && ! EQ (AREF (spec, i), AREF (font, i)))
2542 return 0;
2543 props = XFONT_SPEC (spec)->props;
2544 if (FLOATP (props[FONT_SIZE_INDEX]))
2545 {
2546 for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
2547 prop[i] = AREF (spec, i);
2548 prop[FONT_SIZE_INDEX]
2549 = make_number (font_pixel_size (XFRAME (selected_frame), spec));
2550 props = prop;
2551 }
2552
2553 if (font_score (font, props) > 0)
2554 return 0;
2555 extra = AREF (spec, FONT_EXTRA_INDEX);
2556 font_extra = AREF (font, FONT_EXTRA_INDEX);
2557 for (; CONSP (extra); extra = XCDR (extra))
35027d0c 2558 {
51c13510
KH
2559 Lisp_Object key = XCAR (XCAR (extra));
2560 Lisp_Object val = XCDR (XCAR (extra)), val2;
2561
2562 if (EQ (key, QClang))
2563 {
2564 val2 = assq_no_quit (key, font_extra);
2565 if (NILP (val2))
2566 return 0;
2567 val2 = XCDR (val2);
2568 if (CONSP (val))
2569 {
2570 if (! CONSP (val2))
2571 return 0;
2572 while (CONSP (val))
2573 if (NILP (Fmemq (val, val2)))
2574 return 0;
2575 }
2576 else
2577 if (CONSP (val2)
2578 ? NILP (Fmemq (val, XCDR (val2)))
2579 : ! EQ (val, val2))
2580 return 0;
2581 }
2582 else if (EQ (key, QCscript))
2583 {
2584 val2 = assq_no_quit (val, Vscript_representative_chars);
5bdd4dd2
KH
2585 if (CONSP (val2))
2586 {
2587 val2 = XCDR (val2);
2588 if (CONSP (val2))
2589 {
2590 /* All characters in the list must be supported. */
2591 for (; CONSP (val2); val2 = XCDR (val2))
2592 {
2593 if (! NATNUMP (XCAR (val2)))
2594 continue;
2595 if (font_encode_char (font, XFASTINT (XCAR (val2)))
2596 == FONT_INVALID_CODE)
2597 return 0;
2598 }
2599 }
2600 else if (VECTORP (val2))
2601 {
2602 /* At most one character in the vector must be supported. */
2603 for (i = 0; i < ASIZE (val2); i++)
2604 {
2605 if (! NATNUMP (AREF (val2, i)))
2606 continue;
2607 if (font_encode_char (font, XFASTINT (AREF (val2, i)))
2608 != FONT_INVALID_CODE)
f5485732 2609 break;
5bdd4dd2
KH
2610 }
2611 if (i == ASIZE (val2))
2612 return 0;
2613 }
2614 }
51c13510
KH
2615 }
2616 else if (EQ (key, QCotf))
2617 {
2618 struct font *fontp;
2619
2620 if (! FONT_OBJECT_P (font))
2621 return 0;
2622 fontp = XFONT_OBJECT (font);
2623 if (! fontp->driver->otf_capability)
2624 return 0;
2625 val2 = fontp->driver->otf_capability (fontp);
2626 if (NILP (val2) || ! font_check_otf (val, val2))
2627 return 0;
2628 }
35027d0c
KH
2629 }
2630
51c13510 2631 return 1;
ef18374f 2632}
ca4da08a 2633\f
819e81df 2634
ca4da08a
KH
2635/* Font cache
2636
2637 Each font backend has the callback function get_cache, and it
2638 returns a cons cell of which cdr part can be freely used for
2639 caching fonts. The cons cell may be shared by multiple frames
2640 and/or multiple font drivers. So, we arrange the cdr part as this:
2641
2642 ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...)
2643
2644 where DRIVER-TYPE is a symbol such as `x', `xft', etc., NUM-FRAMES
2645 is a number frames sharing this cache, and FONT-CACHE-DATA is a
2646 cons (FONT-SPEC FONT-ENTITY ...). */
2647
f57e2426
J
2648static void font_prepare_cache (FRAME_PTR, struct font_driver *);
2649static void font_finish_cache (FRAME_PTR, struct font_driver *);
2650static Lisp_Object font_get_cache (FRAME_PTR, struct font_driver *);
2651static void font_clear_cache (FRAME_PTR, Lisp_Object,
2652 struct font_driver *);
ca4da08a
KH
2653
2654static void
971de7fb 2655font_prepare_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2656{
2657 Lisp_Object cache, val;
2658
2659 cache = driver->get_cache (f);
2660 val = XCDR (cache);
2661 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2662 val = XCDR (val);
2663 if (NILP (val))
2664 {
2665 val = Fcons (driver->type, Fcons (make_number (1), Qnil));
2666 XSETCDR (cache, Fcons (val, XCDR (cache)));
2667 }
2668 else
2669 {
2670 val = XCDR (XCAR (val));
2671 XSETCAR (val, make_number (XINT (XCAR (val)) + 1));
2672 }
2673}
2674
43c0454d 2675
ca4da08a 2676static void
971de7fb 2677font_finish_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2678{
2679 Lisp_Object cache, val, tmp;
2680
2681
2682 cache = driver->get_cache (f);
2683 val = XCDR (cache);
2684 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2685 cache = val, val = XCDR (val);
d0ab1ebe 2686 font_assert (! NILP (val));
ca4da08a 2687 tmp = XCDR (XCAR (val));
43c0454d 2688 XSETCAR (tmp, make_number (XINT (XCAR (tmp)) - 1));
ca4da08a
KH
2689 if (XINT (XCAR (tmp)) == 0)
2690 {
2691 font_clear_cache (f, XCAR (val), driver);
2692 XSETCDR (cache, XCDR (val));
2693 }
ca4da08a
KH
2694}
2695
43c0454d 2696
ca4da08a 2697static Lisp_Object
971de7fb 2698font_get_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2699{
2700 Lisp_Object val = driver->get_cache (f);
2701 Lisp_Object type = driver->type;
2702
d0ab1ebe 2703 font_assert (CONSP (val));
ca4da08a 2704 for (val = XCDR (val); ! EQ (XCAR (XCAR (val)), type); val = XCDR (val));
d0ab1ebe 2705 font_assert (CONSP (val));
ca4da08a
KH
2706 /* VAL = ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...) */
2707 val = XCDR (XCAR (val));
2708 return val;
2709}
2710
43c0454d
KH
2711static int num_fonts;
2712
ca4da08a 2713static void
971de7fb 2714font_clear_cache (FRAME_PTR f, Lisp_Object cache, struct font_driver *driver)
ca4da08a
KH
2715{
2716 Lisp_Object tail, elt;
6136b72f 2717 Lisp_Object tail2, entity;
51c01100 2718
ca4da08a
KH
2719 /* CACHE = (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) */
2720 for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
2721 {
2722 elt = XCAR (tail);
6136b72f
CY
2723 /* elt should have the form (FONT-SPEC FONT-ENTITY ...) */
2724 if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
ca4da08a 2725 {
6136b72f 2726 for (tail2 = XCDR (elt); CONSP (tail2); tail2 = XCDR (tail2))
ca4da08a 2727 {
6136b72f 2728 entity = XCAR (tail2);
ca4da08a 2729
6136b72f
CY
2730 if (FONT_ENTITY_P (entity)
2731 && EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
ca4da08a
KH
2732 {
2733 Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
2734
2735 for (; CONSP (objlist); objlist = XCDR (objlist))
2736 {
2737 Lisp_Object val = XCAR (objlist);
35027d0c 2738 struct font *font = XFONT_OBJECT (val);
ca4da08a 2739
5e634ec9
KH
2740 if (! NILP (AREF (val, FONT_TYPE_INDEX)))
2741 {
2742 font_assert (font && driver == font->driver);
2743 driver->close (f, font);
2744 num_fonts--;
2745 }
ca4da08a
KH
2746 }
2747 if (driver->free_entity)
2748 driver->free_entity (entity);
2749 }
2750 }
2751 }
2752 }
2753 XSETCDR (cache, Qnil);
2754}
2755\f
2756
c2f5bfd6
KH
2757static Lisp_Object scratch_font_spec, scratch_font_prefer;
2758
7d56b2dd
KH
2759/* Check each font-entity in VEC, and return a list of font-entities
2760 that satisfy this condition:
2761 (1) matches with SPEC and SIZE if SPEC is not nil, and
2762 (2) doesn't match with any regexps in Vface_ignored_fonts (if non-nil).
2763*/
2764
2765extern Lisp_Object Vface_ignored_fonts;
2766
35027d0c 2767Lisp_Object
971de7fb 2768font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
35027d0c 2769{
d0ab1ebe 2770 Lisp_Object entity, val;
35027d0c 2771 enum font_property_index prop;
72d36834 2772 int i;
45eb10fb 2773
72d36834 2774 for (val = Qnil, i = ASIZE (vec) - 1; i >= 0; i--)
35027d0c 2775 {
72d36834 2776 entity = AREF (vec, i);
7d56b2dd
KH
2777 if (! NILP (Vface_ignored_fonts))
2778 {
2779 char name[256];
2780 Lisp_Object tail, regexp;
2781
2782 if (font_unparse_xlfd (entity, 0, name, 256) >= 0)
2783 {
2784 for (tail = Vface_ignored_fonts; CONSP (tail); tail = XCDR (tail))
2785 {
2786 regexp = XCAR (tail);
2787 if (STRINGP (regexp)
2788 && fast_c_string_match_ignore_case (regexp, name) >= 0)
2789 break;
2790 }
2791 if (CONSP (tail))
2792 continue;
2793 }
2794 }
2795 if (NILP (spec))
2796 {
2797 val = Fcons (entity, val);
2798 continue;
2799 }
35027d0c
KH
2800 for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
2801 if (INTEGERP (AREF (spec, prop))
2802 && ((XINT (AREF (spec, prop)) >> 8)
2803 != (XINT (AREF (entity, prop)) >> 8)))
2804 prop = FONT_SPEC_MAX;
7181ea6a 2805 if (prop < FONT_SPEC_MAX
35027d0c
KH
2806 && size
2807 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
2808 {
2809 int diff = XINT (AREF (entity, FONT_SIZE_INDEX)) - size;
c2f5bfd6 2810
35027d0c
KH
2811 if (diff != 0
2812 && (diff < 0 ? -diff > FONT_PIXEL_SIZE_QUANTUM
2813 : diff > FONT_PIXEL_SIZE_QUANTUM))
2814 prop = FONT_SPEC_MAX;
2815 }
7181ea6a
KH
2816 if (prop < FONT_SPEC_MAX
2817 && INTEGERP (AREF (spec, FONT_DPI_INDEX))
2818 && INTEGERP (AREF (entity, FONT_DPI_INDEX))
c576d6dc 2819 && XINT (AREF (entity, FONT_DPI_INDEX)) != 0
7181ea6a
KH
2820 && ! EQ (AREF (spec, FONT_DPI_INDEX), AREF (entity, FONT_DPI_INDEX)))
2821 prop = FONT_SPEC_MAX;
2822 if (prop < FONT_SPEC_MAX
2823 && INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
2824 && INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
c576d6dc 2825 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) != 0
7181ea6a
KH
2826 && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
2827 AREF (entity, FONT_AVGWIDTH_INDEX)))
2828 prop = FONT_SPEC_MAX;
35027d0c 2829 if (prop < FONT_SPEC_MAX)
d0ab1ebe 2830 val = Fcons (entity, val);
35027d0c 2831 }
72d36834 2832 return (Fvconcat (1, &val));
35027d0c
KH
2833}
2834
2835
72d36834 2836/* Return a list of vectors of font-entities matching with SPEC on
ce75f06e
CY
2837 FRAME. Each elements in the list is a vector of entities from the
2838 same font-driver. */
35027d0c
KH
2839
2840Lisp_Object
971de7fb 2841font_list_entities (Lisp_Object frame, Lisp_Object spec)
c2f5bfd6
KH
2842{
2843 FRAME_PTR f = XFRAME (frame);
2844 struct font_driver_list *driver_list = f->font_driver_list;
4007dd1c 2845 Lisp_Object ftype, val;
72d36834 2846 Lisp_Object list = Qnil;
35027d0c
KH
2847 int size;
2848 int need_filtering = 0;
c2f5bfd6
KH
2849 int i;
2850
d0ab1ebe 2851 font_assert (FONT_SPEC_P (spec));
c2f5bfd6 2852
35027d0c
KH
2853 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
2854 size = XINT (AREF (spec, FONT_SIZE_INDEX));
2855 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2856 size = font_pixel_size (f, spec);
2857 else
2858 size = 0;
2859
c2f5bfd6 2860 ftype = AREF (spec, FONT_TYPE_INDEX);
4007dd1c 2861 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
35027d0c 2862 ASET (scratch_font_spec, i, AREF (spec, i));
4007dd1c 2863 for (i = FONT_WEIGHT_INDEX; i < FONT_EXTRA_INDEX; i++)
35027d0c
KH
2864 {
2865 ASET (scratch_font_spec, i, Qnil);
2866 if (! NILP (AREF (spec, i)))
2867 need_filtering = 1;
4007dd1c
KH
2868 if (i == FONT_DPI_INDEX)
2869 /* Skip FONT_SPACING_INDEX */
2870 i++;
35027d0c 2871 }
aa50ca2f 2872 ASET (scratch_font_spec, FONT_SPACING_INDEX, AREF (spec, FONT_SPACING_INDEX));
35027d0c
KH
2873 ASET (scratch_font_spec, FONT_EXTRA_INDEX, AREF (spec, FONT_EXTRA_INDEX));
2874
c2f5bfd6 2875 for (i = 0; driver_list; driver_list = driver_list->next)
417a1b10
KH
2876 if (driver_list->on
2877 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
c2f5bfd6 2878 {
ca4da08a 2879 Lisp_Object cache = font_get_cache (f, driver_list->driver);
c2f5bfd6 2880
e4c93315 2881 ASET (scratch_font_spec, FONT_TYPE_INDEX, driver_list->driver->type);
4007dd1c
KH
2882 val = assoc_no_quit (scratch_font_spec, XCDR (cache));
2883 if (CONSP (val))
2884 val = XCDR (val);
2885 else
c2f5bfd6 2886 {
4007dd1c 2887 Lisp_Object copy;
35027d0c 2888
4007dd1c 2889 val = driver_list->driver->list (frame, scratch_font_spec);
72d36834
KH
2890 if (NILP (val))
2891 val = null_vector;
2892 else
2893 val = Fvconcat (1, &val);
4007dd1c
KH
2894 copy = Fcopy_font_spec (scratch_font_spec);
2895 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2896 XSETCDR (cache, Fcons (Fcons (copy, val), XCDR (cache)));
c2f5bfd6 2897 }
7d56b2dd
KH
2898 if (ASIZE (val) > 0
2899 && (need_filtering
2900 || ! NILP (Vface_ignored_fonts)))
2901 val = font_delete_unmatched (val, need_filtering ? spec : Qnil, size);
72d36834
KH
2902 if (ASIZE (val) > 0)
2903 list = Fcons (val, list);
c2f5bfd6 2904 }
35027d0c 2905
72d36834
KH
2906 list = Fnreverse (list);
2907 FONT_ADD_LOG ("list", spec, list);
2908 return list;
c2f5bfd6
KH
2909}
2910
45eb10fb 2911
35027d0c
KH
2912/* Return a font entity matching with SPEC on FRAME. ATTRS, if non
2913 nil, is an array of face's attributes, which specifies preferred
2914 font-related attributes. */
45eb10fb 2915
e950d6f1 2916static Lisp_Object
971de7fb 2917font_matching_entity (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec)
e950d6f1 2918{
e950d6f1
KH
2919 struct font_driver_list *driver_list = f->font_driver_list;
2920 Lisp_Object ftype, size, entity;
35027d0c 2921 Lisp_Object frame;
819ab95f 2922 Lisp_Object work = Fcopy_font_spec (spec);
e950d6f1 2923
35027d0c 2924 XSETFRAME (frame, f);
e950d6f1
KH
2925 ftype = AREF (spec, FONT_TYPE_INDEX);
2926 size = AREF (spec, FONT_SIZE_INDEX);
819ab95f 2927
8d0e382e
AR
2928 if (FLOATP (size))
2929 ASET (work, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
819ab95f
KH
2930 FONT_SET_STYLE (work, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2931 FONT_SET_STYLE (work, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2932 FONT_SET_STYLE (work, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
2933
e950d6f1
KH
2934 entity = Qnil;
2935 for (; driver_list; driver_list = driver_list->next)
2936 if (driver_list->on
2937 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2938 {
ca4da08a 2939 Lisp_Object cache = font_get_cache (f, driver_list->driver);
7cee5d63 2940 Lisp_Object copy;
e950d6f1 2941
819ab95f
KH
2942 ASET (work, FONT_TYPE_INDEX, driver_list->driver->type);
2943 entity = assoc_no_quit (work, XCDR (cache));
7cee5d63 2944 if (CONSP (entity))
e950d6f1
KH
2945 entity = XCDR (entity);
2946 else
2947 {
819ab95f
KH
2948 entity = driver_list->driver->match (frame, work);
2949 copy = Fcopy_font_spec (work);
7cee5d63
KH
2950 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2951 XSETCDR (cache, Fcons (Fcons (copy, entity), XCDR (cache)));
e950d6f1
KH
2952 }
2953 if (! NILP (entity))
2954 break;
2955 }
652b9560 2956 FONT_ADD_LOG ("match", work, entity);
e950d6f1
KH
2957 return entity;
2958}
2959
45eb10fb
KH
2960
2961/* Open a font of ENTITY and PIXEL_SIZE on frame F, and return the
2962 opened font object. */
2963
c2f5bfd6 2964static Lisp_Object
971de7fb 2965font_open_entity (FRAME_PTR f, Lisp_Object entity, int pixel_size)
c2f5bfd6
KH
2966{
2967 struct font_driver_list *driver_list;
43c0454d 2968 Lisp_Object objlist, size, val, font_object;
c2f5bfd6 2969 struct font *font;
d26424c5 2970 int min_width, height;
a35dd56b 2971 int scaled_pixel_size;
c2f5bfd6 2972
d0ab1ebe 2973 font_assert (FONT_ENTITY_P (entity));
c2f5bfd6 2974 size = AREF (entity, FONT_SIZE_INDEX);
c2f5bfd6 2975 if (XINT (size) != 0)
a35dd56b 2976 scaled_pixel_size = pixel_size = XINT (size);
55e41770 2977 else if (CONSP (Vface_font_rescale_alist))
a35dd56b 2978 scaled_pixel_size = pixel_size * font_rescale_ratio (entity);
c2f5bfd6 2979
35027d0c
KH
2980 val = AREF (entity, FONT_TYPE_INDEX);
2981 for (driver_list = f->font_driver_list;
2982 driver_list && ! EQ (driver_list->driver->type, val);
2983 driver_list = driver_list->next);
2984 if (! driver_list)
2985 return Qnil;
c2f5bfd6 2986
d0cf45b7
JD
2987 for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
2988 objlist = XCDR (objlist))
2989 {
2990 Lisp_Object fn = XCAR (objlist);
2991 if (! NILP (AREF (fn, FONT_TYPE_INDEX))
2992 && XFONT_OBJECT (fn)->pixel_size == pixel_size)
2993 {
2994 if (driver_list->driver->cached_font_ok == NULL
2995 || driver_list->driver->cached_font_ok (f, fn, entity))
2996 return fn;
2997 }
2998 }
2999
a35dd56b 3000 font_object = driver_list->driver->open (f, entity, scaled_pixel_size);
66f5ced0
YM
3001 if (!NILP (font_object))
3002 ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
652b9560 3003 FONT_ADD_LOG ("open", entity, font_object);
43c0454d 3004 if (NILP (font_object))
35027d0c
KH
3005 return Qnil;
3006 ASET (entity, FONT_OBJLIST_INDEX,
3007 Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
a7840ffb 3008 ASET (font_object, FONT_ENTITY_INDEX, entity);
35027d0c
KH
3009 num_fonts++;
3010
3011 font = XFONT_OBJECT (font_object);
3012 min_width = (font->min_width ? font->min_width
3013 : font->average_width ? font->average_width
3014 : font->space_width ? font->space_width
3015 : 1);
d26424c5 3016 height = (font->height ? font->height : 1);
819e81df 3017#ifdef HAVE_WINDOW_SYSTEM
35027d0c
KH
3018 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
3019 if (FRAME_X_DISPLAY_INFO (f)->n_fonts == 1)
43c0454d 3020 {
35027d0c 3021 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
d26424c5 3022 FRAME_SMALLEST_FONT_HEIGHT (f) = height;
35027d0c
KH
3023 fonts_changed_p = 1;
3024 }
3025 else
3026 {
3027 if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
3028 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, fonts_changed_p = 1;
d26424c5
KH
3029 if (FRAME_SMALLEST_FONT_HEIGHT (f) > height)
3030 FRAME_SMALLEST_FONT_HEIGHT (f) = height, fonts_changed_p = 1;
43c0454d 3031 }
819e81df 3032#endif
43c0454d
KH
3033
3034 return font_object;
c2f5bfd6
KH
3035}
3036
45eb10fb
KH
3037
3038/* Close FONT_OBJECT that is opened on frame F. */
3039
c2f5bfd6 3040void
971de7fb 3041font_close_object (FRAME_PTR f, Lisp_Object font_object)
c2f5bfd6 3042{
35027d0c 3043 struct font *font = XFONT_OBJECT (font_object);
c2f5bfd6 3044
5e634ec9
KH
3045 if (NILP (AREF (font_object, FONT_TYPE_INDEX)))
3046 /* Already closed. */
3047 return;
652b9560 3048 FONT_ADD_LOG ("close", font_object, Qnil);
5e634ec9 3049 font->driver->close (f, font);
819e81df 3050#ifdef HAVE_WINDOW_SYSTEM
5e634ec9
KH
3051 font_assert (FRAME_X_DISPLAY_INFO (f)->n_fonts);
3052 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
819e81df 3053#endif
5e634ec9 3054 num_fonts--;
c2f5bfd6
KH
3055}
3056
45eb10fb 3057
1701724c
KH
3058/* Return 1 if FONT on F has a glyph for character C, 0 if not, -1 if
3059 FONT is a font-entity and it must be opened to check. */
45eb10fb 3060
c2f5bfd6 3061int
971de7fb 3062font_has_char (FRAME_PTR f, Lisp_Object font, int c)
c2f5bfd6 3063{
1b834a8d 3064 struct font *fontp;
c2f5bfd6 3065
1b834a8d
KH
3066 if (FONT_ENTITY_P (font))
3067 {
3068 Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
3069 struct font_driver_list *driver_list;
3070
3071 for (driver_list = f->font_driver_list;
3072 driver_list && ! EQ (driver_list->driver->type, type);
3073 driver_list = driver_list->next);
3074 if (! driver_list)
3075 return 0;
3076 if (! driver_list->driver->has_char)
3077 return -1;
3078 return driver_list->driver->has_char (font, c);
3079 }
3080
d0ab1ebe 3081 font_assert (FONT_OBJECT_P (font));
35027d0c 3082 fontp = XFONT_OBJECT (font);
1b834a8d
KH
3083 if (fontp->driver->has_char)
3084 {
35027d0c 3085 int result = fontp->driver->has_char (font, c);
1b834a8d
KH
3086
3087 if (result >= 0)
3088 return result;
3089 }
3090 return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
c2f5bfd6
KH
3091}
3092
45eb10fb
KH
3093
3094/* Return the glyph ID of FONT_OBJECT for character C. */
3095
c2f5bfd6 3096unsigned
971de7fb 3097font_encode_char (Lisp_Object font_object, int c)
c2f5bfd6 3098{
35027d0c 3099 struct font *font;
c2f5bfd6 3100
d0ab1ebe 3101 font_assert (FONT_OBJECT_P (font_object));
35027d0c 3102 font = XFONT_OBJECT (font_object);
c2f5bfd6
KH
3103 return font->driver->encode_char (font, c);
3104}
3105
45eb10fb
KH
3106
3107/* Return the name of FONT_OBJECT. */
3108
ef18374f 3109Lisp_Object
971de7fb 3110font_get_name (Lisp_Object font_object)
c2f5bfd6 3111{
d0ab1ebe 3112 font_assert (FONT_OBJECT_P (font_object));
35027d0c 3113 return AREF (font_object, FONT_NAME_INDEX);
ef18374f
KH
3114}
3115
45eb10fb
KH
3116
3117/* Return the specification of FONT_OBJECT. */
3118
ef18374f 3119Lisp_Object
971de7fb 3120font_get_spec (Lisp_Object font_object)
ef18374f 3121{
35027d0c 3122 Lisp_Object spec = font_make_spec ();
ef18374f
KH
3123 int i;
3124
3125 for (i = 0; i < FONT_SIZE_INDEX; i++)
35027d0c
KH
3126 ASET (spec, i, AREF (font_object, i));
3127 ASET (spec, FONT_SIZE_INDEX,
3128 make_number (XFONT_OBJECT (font_object)->pixel_size));
ef18374f 3129 return spec;
c2f5bfd6
KH
3130}
3131
05802645
CY
3132
3133/* Create a new font spec from FONT_NAME, and return it. If FONT_NAME
3134 could not be parsed by font_parse_name, return Qnil. */
3135
35027d0c 3136Lisp_Object
971de7fb 3137font_spec_from_name (Lisp_Object font_name)
35027d0c 3138{
05802645 3139 Lisp_Object spec = Ffont_spec (0, NULL);
35027d0c 3140
05802645
CY
3141 CHECK_STRING (font_name);
3142 if (font_parse_name ((char *) SDATA (font_name), spec) == -1)
3143 return Qnil;
3144 font_put_extra (spec, QCname, font_name);
42707278 3145 font_put_extra (spec, QCuser_spec, font_name);
05802645 3146 return spec;
35027d0c
KH
3147}
3148
45eb10fb 3149
35027d0c 3150void
971de7fb 3151font_clear_prop (Lisp_Object *attrs, enum font_property_index prop)
35027d0c
KH
3152{
3153 Lisp_Object font = attrs[LFACE_FONT_INDEX];
45eb10fb 3154
35027d0c
KH
3155 if (! FONTP (font))
3156 return;
42707278 3157
483670b5
KH
3158 if (! NILP (Ffont_get (font, QCname)))
3159 {
3160 font = Fcopy_font_spec (font);
3161 font_put_extra (font, QCname, Qnil);
3162 }
3163
35027d0c 3164 if (NILP (AREF (font, prop))
e234927a
CY
3165 && prop != FONT_FAMILY_INDEX
3166 && prop != FONT_FOUNDRY_INDEX
3167 && prop != FONT_WIDTH_INDEX
4007dd1c 3168 && prop != FONT_SIZE_INDEX)
35027d0c 3169 return;
483670b5
KH
3170 if (EQ (font, attrs[LFACE_FONT_INDEX]))
3171 font = Fcopy_font_spec (font);
35027d0c 3172 ASET (font, prop, Qnil);
4007dd1c 3173 if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
35027d0c 3174 {
4007dd1c 3175 if (prop == FONT_FAMILY_INDEX)
962e8aa9
CY
3176 {
3177 ASET (font, FONT_FOUNDRY_INDEX, Qnil);
3178 /* If we are setting the font family, we must also clear
3179 FONT_WIDTH_INDEX to avoid rejecting families that lack
3180 support for some widths. */
3181 ASET (font, FONT_WIDTH_INDEX, Qnil);
3182 }
35027d0c 3183 ASET (font, FONT_ADSTYLE_INDEX, Qnil);
4007dd1c 3184 ASET (font, FONT_REGISTRY_INDEX, Qnil);
35027d0c
KH
3185 ASET (font, FONT_SIZE_INDEX, Qnil);
3186 ASET (font, FONT_DPI_INDEX, Qnil);
3187 ASET (font, FONT_SPACING_INDEX, Qnil);
3188 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3189 }
3190 else if (prop == FONT_SIZE_INDEX)
3191 {
3192 ASET (font, FONT_DPI_INDEX, Qnil);
3193 ASET (font, FONT_SPACING_INDEX, Qnil);
3194 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3195 }
e234927a
CY
3196 else if (prop == FONT_WIDTH_INDEX)
3197 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
35027d0c
KH
3198 attrs[LFACE_FONT_INDEX] = font;
3199}
3200
3201void
971de7fb 3202font_update_lface (FRAME_PTR f, Lisp_Object *attrs)
c2f5bfd6 3203{
d0ab1ebe 3204 Lisp_Object spec;
35027d0c
KH
3205
3206 spec = attrs[LFACE_FONT_INDEX];
3207 if (! FONT_SPEC_P (spec))
3208 return;
3209
4007dd1c
KH
3210 if (! NILP (AREF (spec, FONT_FOUNDRY_INDEX)))
3211 attrs[LFACE_FOUNDRY_INDEX] = SYMBOL_NAME (AREF (spec, FONT_FOUNDRY_INDEX));
3212 if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
3213 attrs[LFACE_FAMILY_INDEX] = SYMBOL_NAME (AREF (spec, FONT_FAMILY_INDEX));
35027d0c
KH
3214 if (! NILP (AREF (spec, FONT_WEIGHT_INDEX)))
3215 attrs[LFACE_WEIGHT_INDEX] = FONT_WEIGHT_FOR_FACE (spec);
3216 if (! NILP (AREF (spec, FONT_SLANT_INDEX)))
8510724d 3217 attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);
35027d0c
KH
3218 if (! NILP (AREF (spec, FONT_WIDTH_INDEX)))
3219 attrs[LFACE_SWIDTH_INDEX] = FONT_WIDTH_FOR_FACE (spec);
3220 if (! NILP (AREF (spec, FONT_SIZE_INDEX)))
3221 {
3222 int point;
3223
3224 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
3225 {
3226 Lisp_Object val;
3227 int dpi = f->resy;
3228
3229 val = Ffont_get (spec, QCdpi);
3230 if (! NILP (val))
3231 dpi = XINT (val);
3232 point = PIXEL_TO_POINT (XINT (AREF (spec, FONT_SIZE_INDEX)) * 10,
3233 dpi);
2cf4d521 3234 attrs[LFACE_HEIGHT_INDEX] = make_number (point);
35027d0c
KH
3235 }
3236 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2cf4d521
CY
3237 {
3238 point = XFLOAT_DATA (AREF (spec, FONT_SIZE_INDEX)) * 10;
3239 attrs[LFACE_HEIGHT_INDEX] = make_number (point);
3240 }
35027d0c 3241 }
c2f5bfd6
KH
3242}
3243
45eb10fb 3244
72d36834
KH
3245/* Selecte a font from ENTITIES (list of font-entity vectors) that
3246 supports C and matches best with ATTRS and PIXEL_SIZE. */
988a7ddb
KH
3247
3248static Lisp_Object
971de7fb 3249font_select_entity (Lisp_Object frame, Lisp_Object entities, Lisp_Object *attrs, int pixel_size, int c)
988a7ddb
KH
3250{
3251 Lisp_Object font_entity;
3252 Lisp_Object prefer;
988a7ddb
KH
3253 int result, i;
3254 FRAME_PTR f = XFRAME (frame);
3255
72d36834
KH
3256 if (NILP (XCDR (entities))
3257 && ASIZE (XCAR (entities)) == 1)
988a7ddb 3258 {
72d36834 3259 font_entity = AREF (XCAR (entities), 0);
988a7ddb
KH
3260 if (c < 0
3261 || (result = font_has_char (f, font_entity, c)) > 0)
3262 return font_entity;
3263 return Qnil;
3264 }
3265
3266 /* Sort fonts by properties specified in ATTRS. */
3267 prefer = scratch_font_prefer;
3268
3269 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3270 ASET (prefer, i, Qnil);
3271 if (FONTP (attrs[LFACE_FONT_INDEX]))
3272 {
3273 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3274
3275 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3276 ASET (prefer, i, AREF (face_font, i));
3277 }
3278 if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
3279 FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
3280 if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
3281 FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
3282 if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
3283 FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
3284 ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
988a7ddb 3285
2645d15b 3286 return font_sort_entities (entities, prefer, frame, c);
988a7ddb
KH
3287}
3288
35027d0c
KH
3289/* Return a font-entity satisfying SPEC and best matching with face's
3290 font related attributes in ATTRS. C, if not negative, is a
1701724c 3291 character that the entity must support. */
c2f5bfd6
KH
3292
3293Lisp_Object
971de7fb 3294font_find_for_lface (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec, int c)
c2f5bfd6 3295{
4007dd1c 3296 Lisp_Object work;
72d36834 3297 Lisp_Object frame, entities, val;
22459668 3298 Lisp_Object size, foundry[3], *family, registry[3], adstyle[3];
1d1e1245 3299 int pixel_size;
72d36834 3300 int i, j, k, l;
d0a47776
KH
3301
3302 registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
3303 if (NILP (registry[0]))
3304 {
edfda783 3305 registry[0] = DEFAULT_ENCODING;
d0a47776
KH
3306 registry[1] = Qascii_0;
3307 registry[2] = null_vector;
3308 }
3309 else
3310 registry[1] = null_vector;
c2f5bfd6 3311
4007dd1c 3312 if (c >= 0 && ! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
fe5ddfbc 3313 {
35027d0c 3314 struct charset *encoding, *repertory;
1701724c 3315
4007dd1c
KH
3316 if (font_registry_charsets (AREF (spec, FONT_REGISTRY_INDEX),
3317 &encoding, &repertory) < 0)
35027d0c 3318 return Qnil;
72d36834
KH
3319 if (repertory
3320 && ENCODE_CHAR (repertory, c) == CHARSET_INVALID_CODE (repertory))
3321 return Qnil;
35027d0c
KH
3322 else if (c > encoding->max_char)
3323 return Qnil;
c2f5bfd6
KH
3324 }
3325
4007dd1c 3326 work = Fcopy_font_spec (spec);
227f12fa 3327 ASET (work, FONT_TYPE_INDEX, AREF (spec, FONT_TYPE_INDEX));
35027d0c
KH
3328 XSETFRAME (frame, f);
3329 size = AREF (spec, FONT_SIZE_INDEX);
1d1e1245
KH
3330 pixel_size = font_pixel_size (f, spec);
3331 if (pixel_size == 0)
3332 {
3333 double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3334
3335 pixel_size = POINT_TO_PIXEL (pt / 10, f->resy);
3336 }
4007dd1c
KH
3337 ASET (work, FONT_SIZE_INDEX, Qnil);
3338 foundry[0] = AREF (work, FONT_FOUNDRY_INDEX);
3339 if (! NILP (foundry[0]))
3340 foundry[1] = null_vector;
3341 else if (STRINGP (attrs[LFACE_FOUNDRY_INDEX]))
3342 {
071132a9
KH
3343 val = attrs[LFACE_FOUNDRY_INDEX];
3344 foundry[0] = font_intern_prop ((char *) SDATA (val), SBYTES (val), 1);
4007dd1c
KH
3345 foundry[1] = Qnil;
3346 foundry[2] = null_vector;
3347 }
3348 else
3349 foundry[0] = Qnil, foundry[1] = null_vector;
3350
22459668
KH
3351 adstyle[0] = AREF (work, FONT_ADSTYLE_INDEX);
3352 if (! NILP (adstyle[0]))
3353 adstyle[1] = null_vector;
3354 else if (FONTP (attrs[LFACE_FONT_INDEX]))
3355 {
3356 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3357
3358 if (! NILP (AREF (face_font, FONT_ADSTYLE_INDEX)))
3359 {
3360 adstyle[0] = AREF (face_font, FONT_ADSTYLE_INDEX);
3361 adstyle[1] = Qnil;
3362 adstyle[2] = null_vector;
3363 }
3364 else
3365 adstyle[0] = Qnil, adstyle[1] = null_vector;
3366 }
3367 else
3368 adstyle[0] = Qnil, adstyle[1] = null_vector;
3369
3370
4007dd1c
KH
3371 val = AREF (work, FONT_FAMILY_INDEX);
3372 if (NILP (val) && STRINGP (attrs[LFACE_FAMILY_INDEX]))
071132a9
KH
3373 {
3374 val = attrs[LFACE_FAMILY_INDEX];
3375 val = font_intern_prop ((char *) SDATA (val), SBYTES (val), 1);
3376 }
4007dd1c
KH
3377 if (NILP (val))
3378 {
3379 family = alloca ((sizeof family[0]) * 2);
3380 family[0] = Qnil;
3381 family[1] = null_vector; /* terminator. */
3382 }
3383 else
3384 {
3385 Lisp_Object alters
819ab95f 3386 = Fassoc_string (val, Vface_alternative_font_family_alist,
7107c29e 3387 /* Font family names are case-sensitive under NS. */
819ab95f
KH
3388#ifndef HAVE_NS
3389 Qt
3390#else
3391 Qnil
3392#endif
3393 );
4007dd1c
KH
3394
3395 if (! NILP (alters))
3396 {
3397 family = alloca ((sizeof family[0]) * (XINT (Flength (alters)) + 2));
3398 for (i = 0; CONSP (alters); i++, alters = XCDR (alters))
3399 family[i] = XCAR (alters);
3400 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3401 family[i++] = Qnil;
3402 family[i] = null_vector;
3403 }
3404 else
3405 {
3406 family = alloca ((sizeof family[0]) * 3);
3407 i = 0;
3408 family[i++] = val;
3409 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3410 family[i++] = Qnil;
3411 family[i] = null_vector;
3412 }
3413 }
3414
d0a47776 3415 for (i = 0; SYMBOLP (family[i]); i++)
4007dd1c 3416 {
d0a47776
KH
3417 ASET (work, FONT_FAMILY_INDEX, family[i]);
3418 for (j = 0; SYMBOLP (foundry[j]); j++)
4007dd1c 3419 {
d0a47776
KH
3420 ASET (work, FONT_FOUNDRY_INDEX, foundry[j]);
3421 for (k = 0; SYMBOLP (registry[k]); k++)
3422 {
904a2e0e 3423 ASET (work, FONT_REGISTRY_INDEX, registry[k]);
22459668
KH
3424 for (l = 0; SYMBOLP (adstyle[l]); l++)
3425 {
3426 ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
3427 entities = font_list_entities (frame, work);
72d36834 3428 if (! NILP (entities))
988a7ddb
KH
3429 {
3430 val = font_select_entity (frame, entities,
3431 attrs, pixel_size, c);
3432 if (! NILP (val))
637fa988 3433 return val;
988a7ddb 3434 }
22459668 3435 }
d0a47776 3436 }
4007dd1c 3437 }
4007dd1c 3438 }
d0a47776 3439 return Qnil;
1701724c 3440}
45eb10fb
KH
3441
3442
c2f5bfd6 3443Lisp_Object
971de7fb 3444font_open_for_lface (FRAME_PTR f, Lisp_Object entity, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3445{
9331887d 3446 int size;
c2f5bfd6 3447
4007dd1c
KH
3448 if (INTEGERP (AREF (entity, FONT_SIZE_INDEX))
3449 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
3450 size = XINT (AREF (entity, FONT_SIZE_INDEX));
3451 else if (FONT_SPEC_P (spec) && ! NILP (AREF (spec, FONT_SIZE_INDEX)))
1d1e1245 3452 size = font_pixel_size (f, spec);
733fd013
KH
3453 else
3454 {
50b0cd29
CY
3455 double pt;
3456 if (INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
3457 pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3458 else
3459 {
3460 struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
3461 Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
3462 if (INTEGERP (height))
3463 pt = XINT (height);
3464 else
3465 abort(); /* We should never end up here. */
3466 }
733fd013
KH
3467
3468 pt /= 10;
3469 size = POINT_TO_PIXEL (pt, f->resy);
ed96cde8
AR
3470#ifdef HAVE_NS
3471 if (size == 0)
3472 {
3473 Lisp_Object ffsize = get_frame_param(f, Qfontsize);
3474 size = NUMBERP (ffsize) ? POINT_TO_PIXEL (XINT (ffsize), f->resy) : 0;
3475 }
3476#endif
733fd013 3477 }
c2f5bfd6
KH
3478 return font_open_entity (f, entity, size);
3479}
3480
45eb10fb 3481
35027d0c
KH
3482/* Find a font satisfying SPEC and best matching with face's
3483 attributes in ATTRS on FRAME, and return the opened
3484 font-object. */
45eb10fb 3485
35027d0c 3486Lisp_Object
971de7fb 3487font_load_for_lface (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3488{
637fa988 3489 Lisp_Object entity, name;
ef18374f 3490
908567ef 3491 entity = font_find_for_lface (f, attrs, spec, -1);
35027d0c 3492 if (NILP (entity))
ef18374f 3493 {
35027d0c
KH
3494 /* No font is listed for SPEC, but each font-backend may have
3495 the different criteria about "font matching". So, try
3496 it. */
3497 entity = font_matching_entity (f, attrs, spec);
3498 if (NILP (entity))
3499 return Qnil;
c2f5bfd6 3500 }
637fa988
JD
3501 /* Don't loose the original name that was put in initially. We need
3502 it to re-apply the font when font parameters (like hinting or dpi) have
3503 changed. */
3504 entity = font_open_for_lface (f, entity, attrs, spec);
8096a0ff
YM
3505 if (!NILP (entity))
3506 {
42707278
JD
3507 name = Ffont_get (spec, QCuser_spec);
3508 if (STRINGP (name)) font_put_extra (entity, QCuser_spec, name);
8096a0ff 3509 }
637fa988 3510 return entity;
c2f5bfd6
KH
3511}
3512
45eb10fb
KH
3513
3514/* Make FACE on frame F ready to use the font opened for FACE. */
3515
c2f5bfd6 3516void
971de7fb 3517font_prepare_for_face (FRAME_PTR f, struct face *face)
c2f5bfd6 3518{
35027d0c
KH
3519 if (face->font->driver->prepare_face)
3520 face->font->driver->prepare_face (f, face);
c2f5bfd6
KH
3521}
3522
45eb10fb
KH
3523
3524/* Make FACE on frame F stop using the font opened for FACE. */
3525
c2f5bfd6 3526void
971de7fb 3527font_done_for_face (FRAME_PTR f, struct face *face)
c2f5bfd6 3528{
35027d0c
KH
3529 if (face->font->driver->done_face)
3530 face->font->driver->done_face (f, face);
c2f5bfd6
KH
3531 face->extra = NULL;
3532}
3533
45eb10fb 3534
c50b7e98
KH
3535/* Open a font matching with font-spec SPEC on frame F. If no proper
3536 font is found, return Qnil. */
45eb10fb 3537
c2f5bfd6 3538Lisp_Object
971de7fb 3539font_open_by_spec (FRAME_PTR f, Lisp_Object spec)
c2f5bfd6 3540{
c50b7e98 3541 Lisp_Object attrs[LFACE_VECTOR_SIZE];
a9262bb8 3542
4007dd1c
KH
3543 /* We set up the default font-related attributes of a face to prefer
3544 a moderate font. */
3545 attrs[LFACE_FAMILY_INDEX] = attrs[LFACE_FOUNDRY_INDEX] = Qnil;
3546 attrs[LFACE_SWIDTH_INDEX] = attrs[LFACE_WEIGHT_INDEX]
3547 = attrs[LFACE_SLANT_INDEX] = Qnormal;
ed96cde8 3548#ifndef HAVE_NS
4007dd1c 3549 attrs[LFACE_HEIGHT_INDEX] = make_number (120);
ed96cde8
AR
3550#else
3551 attrs[LFACE_HEIGHT_INDEX] = make_number (0);
3552#endif
4007dd1c
KH
3553 attrs[LFACE_FONT_INDEX] = Qnil;
3554
3555 return font_load_for_lface (f, attrs, spec);
c2f5bfd6
KH
3556}
3557
3558
c50b7e98
KH
3559/* Open a font matching with NAME on frame F. If no proper font is
3560 found, return Qnil. */
3561
3562Lisp_Object
971de7fb 3563font_open_by_name (FRAME_PTR f, char *name)
c50b7e98
KH
3564{
3565 Lisp_Object args[2];
581e51e8 3566 Lisp_Object spec, ret;
c50b7e98
KH
3567
3568 args[0] = QCname;
3569 args[1] = make_unibyte_string (name, strlen (name));
3570 spec = Ffont_spec (2, args);
581e51e8
JD
3571 ret = font_open_by_spec (f, spec);
3572 /* Do not loose name originally put in. */
8096a0ff 3573 if (!NILP (ret))
42707278 3574 font_put_extra (ret, QCuser_spec, args[1]);
581e51e8
JD
3575
3576 return ret;
c50b7e98
KH
3577}
3578
3579
c2f5bfd6
KH
3580/* Register font-driver DRIVER. This function is used in two ways.
3581
417a1b10
KH
3582 The first is with frame F non-NULL. In this case, make DRIVER
3583 available (but not yet activated) on F. All frame creaters
3584 (e.g. Fx_create_frame) must call this function at least once with
3585 an available font-driver.
c2f5bfd6
KH
3586
3587 The second is with frame F NULL. In this case, DRIVER is globally
3588 registered in the variable `font_driver_list'. All font-driver
3589 implementations must call this function in its syms_of_XXXX
3590 (e.g. syms_of_xfont). */
3591
3592void
971de7fb 3593register_font_driver (struct font_driver *driver, FRAME_PTR f)
c2f5bfd6
KH
3594{
3595 struct font_driver_list *root = f ? f->font_driver_list : font_driver_list;
3596 struct font_driver_list *prev, *list;
3597
3598 if (f && ! driver->draw)
43a1d19b 3599 error ("Unusable font driver for a frame: %s",
c2f5bfd6
KH
3600 SDATA (SYMBOL_NAME (driver->type)));
3601
3602 for (prev = NULL, list = root; list; prev = list, list = list->next)
cf23b845 3603 if (EQ (list->driver->type, driver->type))
c2f5bfd6
KH
3604 error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type)));
3605
c115043b 3606 list = xmalloc (sizeof (struct font_driver_list));
417a1b10 3607 list->on = 0;
c2f5bfd6
KH
3608 list->driver = driver;
3609 list->next = NULL;
3610 if (prev)
3611 prev->next = list;
3612 else if (f)
3613 f->font_driver_list = list;
3614 else
3615 font_driver_list = list;
72606e45
KH
3616 if (! f)
3617 num_font_drivers++;
c2f5bfd6
KH
3618}
3619
2ed98482 3620void
971de7fb 3621free_font_driver_list (FRAME_PTR f)
2ed98482
CY
3622{
3623 struct font_driver_list *list, *next;
3624
3625 for (list = f->font_driver_list; list; list = next)
3626 {
3627 next = list->next;
3628 xfree (list);
3629 }
3630 f->font_driver_list = NULL;
3631}
3632
45eb10fb 3633
f697fff0 3634/* Make the frame F use font backends listed in NEW_DRIVERS (list of
ca4da08a
KH
3635 symbols, e.g. xft, x). If NEW_DRIVERS is t, make F use all
3636 available font drivers. If NEW_DRIVERS is nil, finalize all drivers.
417a1b10 3637
ca4da08a
KH
3638 A caller must free all realized faces if any in advance. The
3639 return value is a list of font backends actually made used on
3640 F. */
e950d6f1
KH
3641
3642Lisp_Object
971de7fb 3643font_update_drivers (FRAME_PTR f, Lisp_Object new_drivers)
417a1b10
KH
3644{
3645 Lisp_Object active_drivers = Qnil;
4007dd1c 3646 struct font_driver *driver;
417a1b10
KH
3647 struct font_driver_list *list;
3648
4007dd1c
KH
3649 /* At first, turn off non-requested drivers, and turn on requested
3650 drivers. */
f697fff0 3651 for (list = f->font_driver_list; list; list = list->next)
4007dd1c
KH
3652 {
3653 driver = list->driver;
3654 if ((EQ (new_drivers, Qt) || ! NILP (Fmemq (driver->type, new_drivers)))
3655 != list->on)
3656 {
3657 if (list->on)
3658 {
3659 if (driver->end_for_frame)
3660 driver->end_for_frame (f);
3661 font_finish_cache (f, driver);
3662 list->on = 0;
3663 }
3664 else
3665 {
3666 if (! driver->start_for_frame
3667 || driver->start_for_frame (f) == 0)
3668 {
3669 font_prepare_cache (f, driver);
3670 list->on = 1;
3671 }
3672 }
3673 }
3674 }
3675
3676 if (NILP (new_drivers))
3677 return Qnil;
3678
3679 if (! EQ (new_drivers, Qt))
3680 {
3681 /* Re-order the driver list according to new_drivers. */
3306c6dc 3682 struct font_driver_list **list_table, **next;
4007dd1c
KH
3683 Lisp_Object tail;
3684 int i;
3685
3686 list_table = alloca (sizeof list_table[0] * (num_font_drivers + 1));
3687 for (i = 0, tail = new_drivers; ! NILP (tail); tail = XCDR (tail))
3688 {
3689 for (list = f->font_driver_list; list; list = list->next)
3690 if (list->on && EQ (list->driver->type, XCAR (tail)))
3691 break;
3692 if (list)
3693 list_table[i++] = list;
3694 }
3695 for (list = f->font_driver_list; list; list = list->next)
3696 if (! list->on)
6136b72f 3697 list_table[i++] = list;
4007dd1c
KH
3698 list_table[i] = NULL;
3699
3306c6dc 3700 next = &f->font_driver_list;
4007dd1c
KH
3701 for (i = 0; list_table[i]; i++)
3702 {
3306c6dc
AS
3703 *next = list_table[i];
3704 next = &(*next)->next;
4007dd1c 3705 }
3306c6dc 3706 *next = NULL;
ba98e3a0
SM
3707
3708 if (! f->font_driver_list->on)
3709 { /* None of the drivers is enabled: enable them all.
3710 Happens if you set the list of drivers to (xft x) in your .emacs
3711 and then use it under w32 or ns. */
3712 for (list = f->font_driver_list; list; list = list->next)
3713 {
3714 struct font_driver *driver = list->driver;
3715 eassert (! list->on);
3716 if (! driver->start_for_frame
3717 || driver->start_for_frame (f) == 0)
3718 {
3719 font_prepare_cache (f, driver);
3720 list->on = 1;
3721 }
3722 }
3723 }
4007dd1c 3724 }
417a1b10 3725
4007dd1c
KH
3726 for (list = f->font_driver_list; list; list = list->next)
3727 if (list->on)
3728 active_drivers = nconc2 (active_drivers,
3729 Fcons (list->driver->type, Qnil));
e950d6f1 3730 return active_drivers;
417a1b10
KH
3731}
3732
f697fff0 3733int
971de7fb 3734font_put_frame_data (FRAME_PTR f, struct font_driver *driver, void *data)
f697fff0
KH
3735{
3736 struct font_data_list *list, *prev;
3737
3738 for (prev = NULL, list = f->font_data_list; list;
3739 prev = list, list = list->next)
3740 if (list->driver == driver)
3741 break;
3742 if (! data)
3743 {
3744 if (list)
3745 {
3746 if (prev)
3747 prev->next = list->next;
3748 else
3749 f->font_data_list = list->next;
973e7849 3750 xfree (list);
f697fff0
KH
3751 }
3752 return 0;
3753 }
3754
3755 if (! list)
3756 {
c115043b 3757 list = xmalloc (sizeof (struct font_data_list));
f697fff0
KH
3758 list->driver = driver;
3759 list->next = f->font_data_list;
3760 f->font_data_list = list;
3761 }
3762 list->data = data;
3763 return 0;
3764}
3765
3766
3767void *
971de7fb 3768font_get_frame_data (FRAME_PTR f, struct font_driver *driver)
f697fff0
KH
3769{
3770 struct font_data_list *list;
3771
3772 for (list = f->font_data_list; list; list = list->next)
3773 if (list->driver == driver)
3774 break;
3775 if (! list)
3776 return NULL;
3777 return list->data;
3778}
3779
417a1b10 3780
45eb10fb 3781/* Return the font used to draw character C by FACE at buffer position
e3ee0340
KH
3782 POS in window W. If STRING is non-nil, it is a string containing C
3783 at index POS. If C is negative, get C from the current buffer or
3784 STRING. */
45eb10fb 3785
10d16101 3786Lisp_Object
971de7fb 3787font_at (int c, EMACS_INT pos, struct face *face, struct window *w, Lisp_Object string)
10d16101
KH
3788{
3789 FRAME_PTR f;
e3ee0340 3790 int multibyte;
35027d0c 3791 Lisp_Object font_object;
e3ee0340 3792
e500c47d
KH
3793 multibyte = (NILP (string)
3794 ? ! NILP (current_buffer->enable_multibyte_characters)
3795 : STRING_MULTIBYTE (string));
e3ee0340
KH
3796 if (c < 0)
3797 {
3798 if (NILP (string))
3799 {
e3ee0340
KH
3800 if (multibyte)
3801 {
3802 EMACS_INT pos_byte = CHAR_TO_BYTE (pos);
3803
3804 c = FETCH_CHAR (pos_byte);
3805 }
3806 else
3807 c = FETCH_BYTE (pos);
3808 }
3809 else
3810 {
3811 unsigned char *str;
3812
3813 multibyte = STRING_MULTIBYTE (string);
3814 if (multibyte)
3815 {
3816 EMACS_INT pos_byte = string_char_to_byte (string, pos);
3817
3818 str = SDATA (string) + pos_byte;
62a6e103 3819 c = STRING_CHAR (str);
e3ee0340
KH
3820 }
3821 else
3822 c = SDATA (string)[pos];
3823 }
3824 }
10d16101
KH
3825
3826 f = XFRAME (w->frame);
1385a806
KH
3827 if (! FRAME_WINDOW_P (f))
3828 return Qnil;
10d16101
KH
3829 if (! face)
3830 {
e3ee0340 3831 int face_id;
0f8b27ea 3832 EMACS_INT endptr;
e3ee0340
KH
3833
3834 if (STRINGP (string))
3835 face_id = face_at_string_position (w, string, pos, 0, -1, -1, &endptr,
10d16101
KH
3836 DEFAULT_FACE_ID, 0);
3837 else
e3ee0340 3838 face_id = face_at_buffer_position (w, pos, -1, -1, &endptr,
6970f632 3839 pos + 100, 0, -1);
10d16101
KH
3840 face = FACE_FROM_ID (f, face_id);
3841 }
e3ee0340
KH
3842 if (multibyte)
3843 {
3844 int face_id = FACE_FOR_CHAR (f, face, c, pos, string);
3845 face = FACE_FROM_ID (f, face_id);
3846 }
35027d0c 3847 if (! face->font)
10d16101 3848 return Qnil;
35027d0c 3849
35027d0c
KH
3850 XSETFONT (font_object, face->font);
3851 return font_object;
3852}
3853
3854
071132a9
KH
3855#ifdef HAVE_WINDOW_SYSTEM
3856
3857/* Check how many characters after POS (at most to *LIMIT) can be
3858 displayed by the same font on the window W. FACE, if non-NULL, is
3859 the face selected for the character at POS. If STRING is not nil,
3860 it is the string to check instead of the current buffer. In that
3861 case, FACE must be not NULL.
027a33c0 3862
071132a9
KH
3863 The return value is the font-object for the character at POS.
3864 *LIMIT is set to the position where that font can't be used.
35027d0c 3865
071132a9
KH
3866 It is assured that the current buffer (or STRING) is multibyte. */
3867
3868Lisp_Object
971de7fb 3869font_range (EMACS_INT pos, EMACS_INT *limit, struct window *w, struct face *face, Lisp_Object string)
35027d0c 3870{
0e5d7800 3871 EMACS_INT pos_byte, ignore;
35027d0c 3872 int c;
071132a9 3873 Lisp_Object font_object = Qnil;
35027d0c
KH
3874
3875 if (NILP (string))
3876 {
35027d0c 3877 pos_byte = CHAR_TO_BYTE (pos);
071132a9
KH
3878 if (! face)
3879 {
3880 int face_id;
3881
6970f632
CY
3882 face_id = face_at_buffer_position (w, pos, 0, 0, &ignore,
3883 *limit, 0, -1);
071132a9
KH
3884 face = FACE_FROM_ID (XFRAME (w->frame), face_id);
3885 }
35027d0c
KH
3886 }
3887 else
3888 {
071132a9 3889 font_assert (face);
35027d0c
KH
3890 pos_byte = string_char_to_byte (string, pos);
3891 }
3892
071132a9 3893 while (pos < *limit)
35027d0c 3894 {
071132a9 3895 Lisp_Object category;
35027d0c
KH
3896
3897 if (NILP (string))
3898 FETCH_CHAR_ADVANCE_NO_CHECK (c, pos, pos_byte);
3899 else
3900 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, pos, pos_byte);
0e5d7800
KH
3901 category = CHAR_TABLE_REF (Vunicode_category_table, c);
3902 if (EQ (category, QCf)
3903 || CHAR_VARIATION_SELECTOR_P (c))
3904 continue;
071132a9 3905 if (NILP (font_object))
35027d0c 3906 {
071132a9
KH
3907 font_object = font_for_char (face, c, pos - 1, string);
3908 if (NILP (font_object))
3909 return Qnil;
35027d0c
KH
3910 continue;
3911 }
0e5d7800
KH
3912 if (font_encode_char (font_object, c) == FONT_INVALID_CODE)
3913 *limit = pos - 1;
35027d0c 3914 }
071132a9 3915 return font_object;
10d16101 3916}
071132a9 3917#endif
10d16101 3918
c2f5bfd6
KH
3919\f
3920/* Lisp API */
3921
35027d0c 3922DEFUN ("fontp", Ffontp, Sfontp, 1, 2, 0,
6c8ec042 3923 doc: /* Return t if OBJECT is a font-spec, font-entity, or font-object.
35027d0c
KH
3924Return nil otherwise.
3925Optional 2nd argument EXTRA-TYPE, if non-nil, specifies to check
027a33c0 3926which kind of font it is. It must be one of `font-spec', `font-entity',
35027d0c 3927`font-object'. */)
5842a27b 3928 (Lisp_Object object, Lisp_Object extra_type)
c2f5bfd6 3929{
35027d0c
KH
3930 if (NILP (extra_type))
3931 return (FONTP (object) ? Qt : Qnil);
3932 if (EQ (extra_type, Qfont_spec))
3933 return (FONT_SPEC_P (object) ? Qt : Qnil);
3934 if (EQ (extra_type, Qfont_entity))
3935 return (FONT_ENTITY_P (object) ? Qt : Qnil);
3936 if (EQ (extra_type, Qfont_object))
3937 return (FONT_OBJECT_P (object) ? Qt : Qnil);
3938 wrong_type_argument (intern ("font-extra-type"), extra_type);
c2f5bfd6
KH
3939}
3940
3941DEFUN ("font-spec", Ffont_spec, Sfont_spec, 0, MANY, 0,
45eb10fb
KH
3942 doc: /* Return a newly created font-spec with arguments as properties.
3943
3944ARGS must come in pairs KEY VALUE of font properties. KEY must be a
3945valid font property name listed below:
3946
3947`:family', `:weight', `:slant', `:width'
3948
3949They are the same as face attributes of the same name. See
51c01100 3950`set-face-attribute'.
45eb10fb
KH
3951
3952`:foundry'
3953
3954VALUE must be a string or a symbol specifying the font foundry, e.g. ``misc''.
3955
3956`:adstyle'
3957
3958VALUE must be a string or a symbol specifying the additional
35027d0c 3959typographic style information of a font, e.g. ``sans''.
45eb10fb
KH
3960
3961`:registry'
3962
3963VALUE must be a string or a symbol specifying the charset registry and
3964encoding of a font, e.g. ``iso8859-1''.
3965
3966`:size'
3967
3968VALUE must be a non-negative integer or a floating point number
c423ecca
KH
3969specifying the font size. It specifies the font size in pixels (if
3970VALUE is an integer), or in points (if VALUE is a float).
2babb359
KH
3971
3972`:name'
3973
7a18a178 3974VALUE must be a string of XLFD-style or fontconfig-style font name.
5bdd4dd2
KH
3975
3976`:script'
3977
3978VALUE must be a symbol representing a script that the font must
209f39ac
KH
3979support. It may be a symbol representing a subgroup of a script
3980listed in the variable `script-representative-chars'.
c423ecca
KH
3981
3982`:lang'
3983
3984VALUE must be a symbol of two-letter ISO-639 language names,
3985e.g. `ja'.
3986
3987`:otf'
3988
3989VALUE must be a list (SCRIPT-TAG LANGSYS-TAG GSUB [ GPOS ]) to specify
3990required OpenType features.
3991
3992 SCRIPT-TAG: OpenType script tag symbol (e.g. `deva').
3993 LANGSYS-TAG: OpenType language system tag symbol,
3994 or nil for the default language system.
3995 GSUB: List of OpenType GSUB feature tag symbols, or nil if none required.
3996 GPOS: List of OpenType GPOS feature tag symbols, or nil if none required.
3997
3998GSUB and GPOS may contain `nil' element. In such a case, the font
3999must not have any of the remaining elements.
4000
4001For instance, if the VALUE is `(thai nil nil (mark))', the font must
22f79966 4002be an OpenType font, and whose GPOS table of `thai' script's default
c423ecca
KH
4003language system must contain `mark' feature.
4004
ba3de0e8 4005usage: (font-spec ARGS...) */)
5842a27b 4006 (int nargs, Lisp_Object *args)
c2f5bfd6 4007{
35027d0c 4008 Lisp_Object spec = font_make_spec ();
c2f5bfd6
KH
4009 int i;
4010
4011 for (i = 0; i < nargs; i += 2)
4012 {
cccd42d5
KH
4013 Lisp_Object key = args[i], val;
4014
4015 CHECK_SYMBOL (key);
4016 if (i + 1 >= nargs)
4017 error ("No value for key `%s'", SDATA (SYMBOL_NAME (key)));
4018 val = args[i + 1];
c2f5bfd6 4019
35027d0c
KH
4020 if (EQ (key, QCname))
4021 {
4022 CHECK_STRING (val);
4023 font_parse_name ((char *) SDATA (val), spec);
4024 font_put_extra (spec, key, val);
4025 }
c2f5bfd6 4026 else
4485a28e 4027 {
35027d0c
KH
4028 int idx = get_font_prop_index (key);
4029
4030 if (idx >= 0)
ec6fe57c 4031 {
35027d0c
KH
4032 val = font_prop_validate (idx, Qnil, val);
4033 if (idx < FONT_EXTRA_INDEX)
4034 ASET (spec, idx, val);
4035 else
4036 font_put_extra (spec, key, val);
ec6fe57c 4037 }
35027d0c
KH
4038 else
4039 font_put_extra (spec, key, font_prop_validate (0, key, val));
4485a28e 4040 }
e950d6f1 4041 }
c2f5bfd6
KH
4042 return spec;
4043}
4044
35027d0c
KH
4045DEFUN ("copy-font-spec", Fcopy_font_spec, Scopy_font_spec, 1, 1, 0,
4046 doc: /* Return a copy of FONT as a font-spec. */)
5842a27b 4047 (Lisp_Object font)
35027d0c 4048{
d26424c5 4049 Lisp_Object new_spec, tail, prev, extra;
35027d0c
KH
4050 int i;
4051
4052 CHECK_FONT (font);
4053 new_spec = font_make_spec ();
4054 for (i = 1; i < FONT_EXTRA_INDEX; i++)
4055 ASET (new_spec, i, AREF (font, i));
581e51e8 4056 extra = Fcopy_alist (AREF (font, FONT_EXTRA_INDEX));
d26424c5
KH
4057 /* We must remove :font-entity property. */
4058 for (prev = Qnil, tail = extra; CONSP (tail); prev = tail, tail = XCDR (tail))
4059 if (EQ (XCAR (XCAR (tail)), QCfont_entity))
4060 {
4061 if (NILP (prev))
4062 extra = XCDR (extra);
4063 else
4064 XSETCDR (prev, XCDR (tail));
4065 break;
4066 }
35027d0c
KH
4067 ASET (new_spec, FONT_EXTRA_INDEX, extra);
4068 return new_spec;
4069}
4070
4071DEFUN ("merge-font-spec", Fmerge_font_spec, Smerge_font_spec, 2, 2, 0,
4072 doc: /* Merge font-specs FROM and TO, and return a new font-spec.
4073Every specified properties in FROM override the corresponding
4074properties in TO. */)
5842a27b 4075 (Lisp_Object from, Lisp_Object to)
35027d0c
KH
4076{
4077 Lisp_Object extra, tail;
4078 int i;
4079
4080 CHECK_FONT (from);
4081 CHECK_FONT (to);
4082 to = Fcopy_font_spec (to);
4083 for (i = 0; i < FONT_EXTRA_INDEX; i++)
4084 ASET (to, i, AREF (from, i));
4085 extra = AREF (to, FONT_EXTRA_INDEX);
4086 for (tail = AREF (from, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
4087 if (! EQ (XCAR (XCAR (tail)), Qfont_entity))
4088 {
4089 Lisp_Object slot = assq_no_quit (XCAR (XCAR (tail)), extra);
4090
4091 if (! NILP (slot))
4092 XSETCDR (slot, XCDR (XCAR (tail)));
4093 else
4094 extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
4095 }
4096 ASET (to, FONT_EXTRA_INDEX, extra);
4097 return to;
4098}
c2f5bfd6
KH
4099
4100DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
45eb10fb 4101 doc: /* Return the value of FONT's property KEY.
5bdd4dd2 4102FONT is a font-spec, a font-entity, or a font-object.
a7840ffb 4103KEY is any symbol, but these are reserved for specific meanings:
5bdd4dd2 4104 :family, :weight, :slant, :width, :foundry, :adstyle, :registry,
a7840ffb 4105 :size, :name, :script, :otf
5bdd4dd2 4106See the documentation of `font-spec' for their meanings.
a7840ffb
KH
4107In addition, if FONT is a font-entity or a font-object, values of
4108:script and :otf are different from those of a font-spec as below:
4109
4110The value of :script may be a list of scripts that are supported by the font.
4111
4112The value of :otf is a cons (GSUB . GPOS) where GSUB and GPOS are lists
4113representing the OpenType features supported by the font by this form:
4114 ((SCRIPT (LANGSYS FEATURE ...) ...) ...)
4115SCRIPT, LANGSYS, and FEATURE are all symbols representing OpenType
4116Layout tags. */)
5842a27b 4117 (Lisp_Object font, Lisp_Object key)
c2f5bfd6 4118{
35027d0c 4119 int idx;
a7840ffb 4120 Lisp_Object val;
c2f5bfd6 4121
35027d0c
KH
4122 CHECK_FONT (font);
4123 CHECK_SYMBOL (key);
e80e09b4 4124
35027d0c 4125 idx = get_font_prop_index (key);
2babb359
KH
4126 if (idx >= FONT_WEIGHT_INDEX && idx <= FONT_WIDTH_INDEX)
4127 return font_style_symbolic (font, idx, 0);
35027d0c 4128 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
c2f5bfd6 4129 return AREF (font, idx);
a7840ffb
KH
4130 val = Fassq (key, AREF (font, FONT_EXTRA_INDEX));
4131 if (NILP (val) && EQ (key, QCotf) && FONT_OBJECT_P (font))
4132 {
4133 struct font *fontp = XFONT_OBJECT (font);
4134 Lisp_Object entity = AREF (font, FONT_ENTITY_INDEX);
4135
4136 val = Fassq (key, AREF (entity, FONT_EXTRA_INDEX));
4137 if (NILP (val))
4138 {
4139 if (fontp->driver->otf_capability)
4140 val = fontp->driver->otf_capability (fontp);
4141 else
4142 val = Fcons (Qnil, Qnil);
4143 font_put_extra (font, QCotf, val);
4144 font_put_extra (entity, QCotf, val);
4145 }
4146 else
4147 val = Fcdr (val);
4148 }
4149 else
4150 val = Fcdr (val);
4151 return val;
c2f5bfd6
KH
4152}
4153
51cf11be
AS
4154#ifdef HAVE_WINDOW_SYSTEM
4155
b1868a1a
CY
4156DEFUN ("font-face-attributes", Ffont_face_attributes, Sfont_face_attributes, 1, 2, 0,
4157 doc: /* Return a plist of face attributes generated by FONT.
4158FONT is a font name, a font-spec, a font-entity, or a font-object.
4159The return value is a list of the form
4160
6f568955 4161\(:family FAMILY :height HEIGHT :weight WEIGHT :slant SLANT :width WIDTH)
b1868a1a 4162
48105a6a 4163where FAMILY, HEIGHT, WEIGHT, SLANT, and WIDTH are face attribute values
5989ba2f
CY
4164compatible with `set-face-attribute'. Some of these key-attribute pairs
4165may be omitted from the list if they are not specified by FONT.
b1868a1a 4166
48105a6a
JB
4167The optional argument FRAME specifies the frame that the face attributes
4168are to be displayed on. If omitted, the selected frame is used. */)
5842a27b 4169 (Lisp_Object font, Lisp_Object frame)
b1868a1a
CY
4170{
4171 struct frame *f;
4172 Lisp_Object plist[10];
4173 Lisp_Object val;
5989ba2f 4174 int n = 0;
b1868a1a
CY
4175
4176 if (NILP (frame))
4177 frame = selected_frame;
4178 CHECK_LIVE_FRAME (frame);
4179 f = XFRAME (frame);
4180
4181 if (STRINGP (font))
4182 {
4183 int fontset = fs_query_fontset (font, 0);
4184 Lisp_Object name = font;
4185 if (fontset >= 0)
4186 font = fontset_ascii (fontset);
4187 font = font_spec_from_name (name);
4188 if (! FONTP (font))
4189 signal_error ("Invalid font name", name);
4190 }
4191 else if (! FONTP (font))
4192 signal_error ("Invalid font object", font);
4193
b1868a1a 4194 val = AREF (font, FONT_FAMILY_INDEX);
5989ba2f
CY
4195 if (! NILP (val))
4196 {
4197 plist[n++] = QCfamily;
4198 plist[n++] = SYMBOL_NAME (val);
4199 }
b1868a1a 4200
b1868a1a
CY
4201 val = AREF (font, FONT_SIZE_INDEX);
4202 if (INTEGERP (val))
4203 {
4204 Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
4205 int dpi = INTEGERP (font_dpi) ? XINT (font_dpi) : f->resy;
5989ba2f 4206 plist[n++] = QCheight;
c3bb5465 4207 plist[n++] = make_number (PIXEL_TO_POINT (XINT (val) * 10, dpi));
b1868a1a
CY
4208 }
4209 else if (FLOATP (val))
5989ba2f
CY
4210 {
4211 plist[n++] = QCheight;
4212 plist[n++] = make_number (10 * (int) XFLOAT_DATA (val));
4213 }
b1868a1a 4214
b1868a1a 4215 val = FONT_WEIGHT_FOR_FACE (font);
5989ba2f
CY
4216 if (! NILP (val))
4217 {
4218 plist[n++] = QCweight;
4219 plist[n++] = val;
4220 }
b1868a1a 4221
b1868a1a 4222 val = FONT_SLANT_FOR_FACE (font);
5989ba2f
CY
4223 if (! NILP (val))
4224 {
4225 plist[n++] = QCslant;
4226 plist[n++] = val;
4227 }
b1868a1a 4228
b1868a1a 4229 val = FONT_WIDTH_FOR_FACE (font);
5989ba2f
CY
4230 if (! NILP (val))
4231 {
4232 plist[n++] = QCwidth;
4233 plist[n++] = val;
4234 }
b1868a1a 4235
5989ba2f 4236 return Flist (n, plist);
b1868a1a 4237}
c2f5bfd6 4238
51cf11be
AS
4239#endif
4240
c2f5bfd6 4241DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
a7840ffb
KH
4242 doc: /* Set one property of FONT: give property KEY value VAL.
4243FONT is a font-spec, a font-entity, or a font-object.
4244
4245If FONT is a font-spec, KEY can be any symbol. But if KEY is the one
4246accepted by the function `font-spec' (which see), VAL must be what
4247allowed in `font-spec'.
4248
4249If FONT is a font-entity or a font-object, KEY must not be the one
4250accepted by `font-spec'. */)
e1ffae3b 4251 (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
c2f5bfd6 4252{
35027d0c 4253 int idx;
c2f5bfd6 4254
35027d0c
KH
4255 idx = get_font_prop_index (prop);
4256 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
a7840ffb
KH
4257 {
4258 CHECK_FONT_SPEC (font);
4259 ASET (font, idx, font_prop_validate (idx, Qnil, val));
4260 }
c2f5bfd6 4261 else
a7840ffb
KH
4262 {
4263 if (EQ (prop, QCname)
4264 || EQ (prop, QCscript)
4265 || EQ (prop, QClang)
4266 || EQ (prop, QCotf))
4267 CHECK_FONT_SPEC (font);
4268 else
4269 CHECK_FONT (font);
4270 font_put_extra (font, prop, font_prop_validate (0, prop, val));
4271 }
c2f5bfd6
KH
4272 return val;
4273}
4274
4275DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0,
4276 doc: /* List available fonts matching FONT-SPEC on the current frame.
4277Optional 2nd argument FRAME specifies the target frame.
4278Optional 3rd argument NUM, if non-nil, limits the number of returned fonts.
45eb10fb
KH
4279Optional 4th argument PREFER, if non-nil, is a font-spec to
4280control the order of the returned list. Fonts are sorted by
027a33c0 4281how close they are to PREFER. */)
5842a27b 4282 (Lisp_Object font_spec, Lisp_Object frame, Lisp_Object num, Lisp_Object prefer)
c2f5bfd6 4283{
72d36834
KH
4284 Lisp_Object vec, list;
4285 int n = 0;
c2f5bfd6
KH
4286
4287 if (NILP (frame))
4288 frame = selected_frame;
4289 CHECK_LIVE_FRAME (frame);
35027d0c 4290 CHECK_FONT_SPEC (font_spec);
c2f5bfd6
KH
4291 if (! NILP (num))
4292 {
4293 CHECK_NUMBER (num);
4294 n = XINT (num);
4295 if (n <= 0)
4296 return Qnil;
4297 }
4298 if (! NILP (prefer))
35027d0c 4299 CHECK_FONT_SPEC (prefer);
c2f5bfd6 4300
72d36834
KH
4301 list = font_list_entities (frame, font_spec);
4302 if (NILP (list))
c2f5bfd6 4303 return Qnil;
72d36834
KH
4304 if (NILP (XCDR (list))
4305 && ASIZE (XCAR (list)) == 1)
4306 return Fcons (AREF (XCAR (list), 0), Qnil);
c2f5bfd6
KH
4307
4308 if (! NILP (prefer))
72d36834
KH
4309 vec = font_sort_entities (list, prefer, frame, 0);
4310 else
4311 vec = font_vconcat_entity_vectors (list);
4312 if (n == 0 || n >= ASIZE (vec))
c2f5bfd6 4313 {
72d36834 4314 Lisp_Object args[2];
c2f5bfd6 4315
72d36834
KH
4316 args[0] = vec;
4317 args[1] = Qnil;
4318 list = Fappend (2, args);
4319 }
4320 else
4321 {
4322 for (list = Qnil, n--; n >= 0; n--)
4323 list = Fcons (AREF (vec, n), list);
c2f5bfd6
KH
4324 }
4325 return list;
4326}
4327
35027d0c 4328DEFUN ("font-family-list", Ffont_family_list, Sfont_family_list, 0, 1, 0,
c2f5bfd6 4329 doc: /* List available font families on the current frame.
027a33c0 4330Optional argument FRAME, if non-nil, specifies the target frame. */)
5842a27b 4331 (Lisp_Object frame)
c2f5bfd6
KH
4332{
4333 FRAME_PTR f;
4334 struct font_driver_list *driver_list;
4335 Lisp_Object list;
4336
4337 if (NILP (frame))
4338 frame = selected_frame;
4339 CHECK_LIVE_FRAME (frame);
4340 f = XFRAME (frame);
4341 list = Qnil;
4342 for (driver_list = f->font_driver_list; driver_list;
4343 driver_list = driver_list->next)
4344 if (driver_list->driver->list_family)
4345 {
4346 Lisp_Object val = driver_list->driver->list_family (frame);
13bf758b 4347 Lisp_Object tail = list;
c2f5bfd6 4348
13bf758b
CY
4349 for (; CONSP (val); val = XCDR (val))
4350 if (NILP (Fmemq (XCAR (val), tail))
4351 && SYMBOLP (XCAR (val)))
4352 list = Fcons (SYMBOL_NAME (XCAR (val)), list);
c2f5bfd6
KH
4353 }
4354 return list;
4355}
4356
4357DEFUN ("find-font", Ffind_font, Sfind_font, 1, 2, 0,
4358 doc: /* Return a font-entity matching with FONT-SPEC on the current frame.
4359Optional 2nd argument FRAME, if non-nil, specifies the target frame. */)
5842a27b 4360 (Lisp_Object font_spec, Lisp_Object frame)
c2f5bfd6
KH
4361{
4362 Lisp_Object val = Flist_fonts (font_spec, frame, make_number (1), Qnil);
4363
4364 if (CONSP (val))
4365 val = XCAR (val);
4366 return val;
4367}
4368
d0ab1ebe 4369DEFUN ("font-xlfd-name", Ffont_xlfd_name, Sfont_xlfd_name, 1, 2, 0,
c2f5bfd6
KH
4370 doc: /* Return XLFD name of FONT.
4371FONT is a font-spec, font-entity, or font-object.
d0ab1ebe
KH
4372If the name is too long for XLFD (maximum 255 chars), return nil.
4373If the 2nd optional arg FOLD-WILDCARDS is non-nil,
4374the consecutive wildcards are folded to one. */)
5842a27b 4375 (Lisp_Object font, Lisp_Object fold_wildcards)
c2f5bfd6
KH
4376{
4377 char name[256];
4378 int pixel_size = 0;
4379
35027d0c
KH
4380 CHECK_FONT (font);
4381
4382 if (FONT_OBJECT_P (font))
c2f5bfd6 4383 {
35027d0c 4384 Lisp_Object font_name = AREF (font, FONT_NAME_INDEX);
c2f5bfd6 4385
35027d0c
KH
4386 if (STRINGP (font_name)
4387 && SDATA (font_name)[0] == '-')
d0ab1ebe
KH
4388 {
4389 if (NILP (fold_wildcards))
4390 return font_name;
4391 strcpy (name, (char *) SDATA (font_name));
4392 goto done;
4393 }
35027d0c 4394 pixel_size = XFONT_OBJECT (font)->pixel_size;
c2f5bfd6 4395 }
c2f5bfd6
KH
4396 if (font_unparse_xlfd (font, pixel_size, name, 256) < 0)
4397 return Qnil;
d0ab1ebe
KH
4398 done:
4399 if (! NILP (fold_wildcards))
4400 {
4401 char *p0 = name, *p1;
4402
4403 while ((p1 = strstr (p0, "-*-*")))
4404 {
4405 strcpy (p1, p1 + 2);
4406 p0 = p1;
4407 }
4408 }
4409
c2f5bfd6
KH
4410 return build_string (name);
4411}
4412
4413DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
4414 doc: /* Clear font cache. */)
5842a27b 4415 (void)
c2f5bfd6
KH
4416{
4417 Lisp_Object list, frame;
4418
4419 FOR_EACH_FRAME (list, frame)
4420 {
4421 FRAME_PTR f = XFRAME (frame);
4422 struct font_driver_list *driver_list = f->font_driver_list;
4423
4424 for (; driver_list; driver_list = driver_list->next)
417a1b10
KH
4425 if (driver_list->on)
4426 {
ca4da08a 4427 Lisp_Object cache = driver_list->driver->get_cache (f);
7a6f7fea 4428 Lisp_Object val, tmp;
51c01100 4429
ca4da08a 4430 val = XCDR (cache);
43c0454d
KH
4431 while (! NILP (val)
4432 && ! EQ (XCAR (XCAR (val)), driver_list->driver->type))
ca4da08a 4433 val = XCDR (val);
d0ab1ebe 4434 font_assert (! NILP (val));
7a6f7fea
AS
4435 tmp = XCDR (XCAR (val));
4436 if (XINT (XCAR (tmp)) == 0)
417a1b10 4437 {
ca4da08a
KH
4438 font_clear_cache (f, XCAR (val), driver_list->driver);
4439 XSETCDR (cache, XCDR (val));
417a1b10 4440 }
417a1b10 4441 }
c2f5bfd6
KH
4442 }
4443
4444 return Qnil;
4445}
4446
071132a9
KH
4447\f
4448void
971de7fb 4449font_fill_lglyph_metrics (Lisp_Object glyph, Lisp_Object font_object)
c2f5bfd6 4450{
071132a9 4451 struct font *font = XFONT_OBJECT (font_object);
f62ab7c5
EZ
4452 unsigned code;
4453 /* ecode used in LGLYPH_SET_CODE to avoid compiler warnings. */
4454 EMACS_INT ecode = font->driver->encode_char (font, LGLYPH_CHAR (glyph));
071132a9 4455 struct font_metrics metrics;
c2f5bfd6 4456
f62ab7c5
EZ
4457 LGLYPH_SET_CODE (glyph, ecode);
4458 code = ecode;
071132a9
KH
4459 font->driver->text_extents (font, &code, 1, &metrics);
4460 LGLYPH_SET_LBEARING (glyph, metrics.lbearing);
4461 LGLYPH_SET_RBEARING (glyph, metrics.rbearing);
4462 LGLYPH_SET_WIDTH (glyph, metrics.width);
4463 LGLYPH_SET_ASCENT (glyph, metrics.ascent);
4464 LGLYPH_SET_DESCENT (glyph, metrics.descent);
c2f5bfd6
KH
4465}
4466
c2f5bfd6 4467
071132a9
KH
4468DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 1, 1, 0,
4469 doc: /* Shape the glyph-string GSTRING.
4470Shaping means substituting glyphs and/or adjusting positions of glyphs
4471to get the correct visual image of character sequences set in the
4472header of the glyph-string.
1701724c 4473
071132a9
KH
4474If the shaping was successful, the value is GSTRING itself or a newly
4475created glyph-string. Otherwise, the value is nil. */)
5842a27b 4476 (Lisp_Object gstring)
1701724c
KH
4477{
4478 struct font *font;
071132a9 4479 Lisp_Object font_object, n, glyph;
fc3a285e 4480 int i, j, from, to;
ba3de0e8 4481
071132a9
KH
4482 if (! composition_gstring_p (gstring))
4483 signal_error ("Invalid glyph-string: ", gstring);
4484 if (! NILP (LGSTRING_ID (gstring)))
4485 return gstring;
4486 font_object = LGSTRING_FONT (gstring);
4487 CHECK_FONT_OBJECT (font_object);
35027d0c 4488 font = XFONT_OBJECT (font_object);
b876ea91
KH
4489 if (! font->driver->shape)
4490 return Qnil;
4491
40fb53d6
KH
4492 /* Try at most three times with larger gstring each time. */
4493 for (i = 0; i < 3; i++)
4494 {
40fb53d6
KH
4495 n = font->driver->shape (gstring);
4496 if (INTEGERP (n))
4497 break;
071132a9
KH
4498 gstring = larger_vector (gstring,
4499 ASIZE (gstring) + LGSTRING_GLYPH_LEN (gstring),
4500 Qnil);
40fb53d6 4501 }
071132a9 4502 if (i == 3 || XINT (n) == 0)
1701724c 4503 return Qnil;
ba3de0e8 4504
071132a9 4505 glyph = LGSTRING_GLYPH (gstring, 0);
fc3a285e
KH
4506 from = LGLYPH_FROM (glyph);
4507 to = LGLYPH_TO (glyph);
4508 for (i = 1, j = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
071132a9
KH
4509 {
4510 Lisp_Object this = LGSTRING_GLYPH (gstring, i);
10d16101 4511
071132a9
KH
4512 if (NILP (this))
4513 break;
4514 if (NILP (LGLYPH_ADJUSTMENT (this)))
fc3a285e
KH
4515 {
4516 if (j < i - 1)
4517 for (; j < i; j++)
4518 {
4519 glyph = LGSTRING_GLYPH (gstring, j);
4520 LGLYPH_SET_FROM (glyph, from);
4521 LGLYPH_SET_TO (glyph, to);
4522 }
4523 from = LGLYPH_FROM (this);
4524 to = LGLYPH_TO (this);
4525 j = i;
4526 }
071132a9 4527 else
b2937119 4528 {
fc3a285e
KH
4529 if (from > LGLYPH_FROM (this))
4530 from = LGLYPH_FROM (this);
4531 if (to < LGLYPH_TO (this))
4532 to = LGLYPH_TO (this);
b2937119 4533 }
10d16101 4534 }
fc3a285e
KH
4535 if (j < i - 1)
4536 for (; j < i; j++)
4537 {
4538 glyph = LGSTRING_GLYPH (gstring, j);
4539 LGLYPH_SET_FROM (glyph, from);
4540 LGLYPH_SET_TO (glyph, to);
4541 }
071132a9 4542 return composition_gstring_put_cache (gstring, XINT (n));
c2f5bfd6
KH
4543}
4544
78a2f9cd
KH
4545DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
4546 2, 2, 0,
4547 doc: /* Return a list of variation glyphs for CHAR in FONT-OBJECT.
4548Each element of the value is a cons (VARIATION-SELECTOR . GLYPH-ID),
4549where
4550 VARIATION-SELECTOR is a chracter code of variation selection
4551 (#xFE00..#xFE0F or #xE0100..#xE01EF)
4552 GLYPH-ID is a glyph code of the corresponding variation glyph. */)
5842a27b 4553 (Lisp_Object font_object, Lisp_Object character)
78a2f9cd
KH
4554{
4555 unsigned variations[256];
4556 struct font *font;
4557 int i, n;
4558 Lisp_Object val;
4559
4560 CHECK_FONT_OBJECT (font_object);
4561 CHECK_CHARACTER (character);
4562 font = XFONT_OBJECT (font_object);
4563 if (! font->driver->get_variation_glyphs)
4564 return Qnil;
4565 n = font->driver->get_variation_glyphs (font, XINT (character), variations);
4566 if (! n)
4567 return Qnil;
4568 val = Qnil;
4569 for (i = 0; i < 255; i++)
4570 if (variations[i])
4571 {
4572 Lisp_Object code;
4573 int vs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
b60861e6
GM
4574 /* Stops GCC whining about limited range of data type. */
4575 EMACS_INT var = variations[i];
78a2f9cd 4576
b60861e6 4577 if (var > MOST_POSITIVE_FIXNUM)
78a2f9cd
KH
4578 code = Fcons (make_number ((variations[i]) >> 16),
4579 make_number ((variations[i]) & 0xFFFF));
4580 else
4581 code = make_number (variations[i]);
4582 val = Fcons (Fcons (make_number (vs), code), val);
4583 }
4584 return val;
4585}
4586
6a3dadd2
KH
4587#if 0
4588
733fd013
KH
4589DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
4590 doc: /* Apply OpenType features on glyph-string GSTRING-IN.
51c01100 4591OTF-FEATURES specifies which features to apply in this format:
733fd013 4592 (SCRIPT LANGSYS GSUB GPOS)
e80e09b4
KH
4593where
4594 SCRIPT is a symbol specifying a script tag of OpenType,
4595 LANGSYS is a symbol specifying a langsys tag of OpenType,
733fd013 4596 GSUB and GPOS, if non-nil, are lists of symbols specifying feature tags.
e80e09b4
KH
4597
4598If LANGYS is nil, the default langsys is selected.
4599
51c01100
JB
4600The features are applied in the order they appear in the list. The
4601symbol `*' means to apply all available features not present in this
733fd013
KH
4602list, and the remaining features are ignored. For instance, (vatu
4603pstf * haln) is to apply vatu and pstf in this order, then to apply
4604all available features other than vatu, pstf, and haln.
e80e09b4
KH
4605
4606The features are applied to the glyphs in the range FROM and TO of
733fd013 4607the glyph-string GSTRING-IN.
e80e09b4 4608
51c01100 4609If some feature is actually applicable, the resulting glyphs are
e80e09b4
KH
4610produced in the glyph-string GSTRING-OUT from the index INDEX. In
4611this case, the value is the number of produced glyphs.
4612
4613If no feature is applicable, no glyph is produced in GSTRING-OUT, and
4614the value is 0.
4615
51c01100 4616If GSTRING-OUT is too short to hold produced glyphs, no glyphs are
e80e09b4
KH
4617produced in GSTRING-OUT, and the value is nil.
4618
4619See the documentation of `font-make-gstring' for the format of
4620glyph-string. */)
5842a27b 4621 (Lisp_Object otf_features, Lisp_Object gstring_in, Lisp_Object from, Lisp_Object to, Lisp_Object gstring_out, Lisp_Object index)
e80e09b4
KH
4622{
4623 Lisp_Object font_object = LGSTRING_FONT (gstring_in);
733fd013
KH
4624 Lisp_Object val;
4625 struct font *font;
e80e09b4
KH
4626 int len, num;
4627
733fd013 4628 check_otf_features (otf_features);
35027d0c
KH
4629 CHECK_FONT_OBJECT (font_object);
4630 font = XFONT_OBJECT (font_object);
733fd013 4631 if (! font->driver->otf_drive)
e80e09b4
KH
4632 error ("Font backend %s can't drive OpenType GSUB table",
4633 SDATA (SYMBOL_NAME (font->driver->type)));
733fd013
KH
4634 CHECK_CONS (otf_features);
4635 CHECK_SYMBOL (XCAR (otf_features));
4636 val = XCDR (otf_features);
4637 CHECK_SYMBOL (XCAR (val));
4638 val = XCDR (otf_features);
4639 if (! NILP (val))
4640 CHECK_CONS (val);
e80e09b4
KH
4641 len = check_gstring (gstring_in);
4642 CHECK_VECTOR (gstring_out);
4643 CHECK_NATNUM (from);
4644 CHECK_NATNUM (to);
4645 CHECK_NATNUM (index);
4646
4647 if (XINT (from) >= XINT (to) || XINT (to) > len)
4648 args_out_of_range_3 (from, to, make_number (len));
4649 if (XINT (index) >= ASIZE (gstring_out))
4650 args_out_of_range (index, make_number (ASIZE (gstring_out)));
733fd013
KH
4651 num = font->driver->otf_drive (font, otf_features,
4652 gstring_in, XINT (from), XINT (to),
4653 gstring_out, XINT (index), 0);
e80e09b4
KH
4654 if (num < 0)
4655 return Qnil;
4656 return make_number (num);
4657}
4658
e80e09b4
KH
4659DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
4660 3, 3, 0,
4661 doc: /* Return a list of alternate glyphs of CHARACTER in FONT-OBJECT.
51c01100 4662OTF-FEATURES specifies which features of the font FONT-OBJECT to apply
e80e09b4
KH
4663in this format:
4664 (SCRIPT LANGSYS FEATURE ...)
027a33c0 4665See the documentation of `font-drive-otf' for more detail.
e80e09b4
KH
4666
4667The value is a list of cons cells of the format (GLYPH-ID . CHARACTER),
4668where GLYPH-ID is a glyph index of the font, and CHARACTER is a
4669character code corresponding to the glyph or nil if there's no
4670corresponding character. */)
5842a27b 4671 (Lisp_Object font_object, Lisp_Object character, Lisp_Object otf_features)
e80e09b4
KH
4672{
4673 struct font *font;
4674 Lisp_Object gstring_in, gstring_out, g;
4675 Lisp_Object alternates;
4676 int i, num;
4677
4678 CHECK_FONT_GET_OBJECT (font_object, font);
733fd013 4679 if (! font->driver->otf_drive)
e950d6f1
KH
4680 error ("Font backend %s can't drive OpenType GSUB table",
4681 SDATA (SYMBOL_NAME (font->driver->type)));
e80e09b4 4682 CHECK_CHARACTER (character);
733fd013 4683 CHECK_CONS (otf_features);
e80e09b4
KH
4684
4685 gstring_in = Ffont_make_gstring (font_object, make_number (1));
4686 g = LGSTRING_GLYPH (gstring_in, 0);
f9ffa1ea 4687 LGLYPH_SET_CHAR (g, XINT (character));
e80e09b4 4688 gstring_out = Ffont_make_gstring (font_object, make_number (10));
733fd013
KH
4689 while ((num = font->driver->otf_drive (font, otf_features, gstring_in, 0, 1,
4690 gstring_out, 0, 1)) < 0)
e80e09b4
KH
4691 gstring_out = Ffont_make_gstring (font_object,
4692 make_number (ASIZE (gstring_out) * 2));
4693 alternates = Qnil;
4694 for (i = 0; i < num; i++)
4695 {
4696 Lisp_Object g = LGSTRING_GLYPH (gstring_out, i);
f9ffa1ea
SM
4697 int c = LGLYPH_CHAR (g);
4698 unsigned code = LGLYPH_CODE (g);
e80e09b4
KH
4699
4700 alternates = Fcons (Fcons (make_number (code),
4701 c > 0 ? make_number (c) : Qnil),
4702 alternates);
4703 }
4704 return Fnreverse (alternates);
4705}
6a3dadd2 4706#endif /* 0 */
c2f5bfd6
KH
4707
4708#ifdef FONT_DEBUG
4709
4710DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0,
4711 doc: /* Open FONT-ENTITY. */)
5842a27b 4712 (Lisp_Object font_entity, Lisp_Object size, Lisp_Object frame)
c2f5bfd6
KH
4713{
4714 int isize;
4715
4716 CHECK_FONT_ENTITY (font_entity);
c2f5bfd6
KH
4717 if (NILP (frame))
4718 frame = selected_frame;
4719 CHECK_LIVE_FRAME (frame);
51c01100 4720
35027d0c
KH
4721 if (NILP (size))
4722 isize = XINT (AREF (font_entity, FONT_SIZE_INDEX));
4723 else
4724 {
4725 CHECK_NUMBER_OR_FLOAT (size);
4726 if (FLOATP (size))
d03b5cdb 4727 isize = POINT_TO_PIXEL (XFLOAT_DATA (size), XFRAME (frame)->resy);
35027d0c
KH
4728 else
4729 isize = XINT (size);
4730 if (isize == 0)
4731 isize = 120;
4732 }
c2f5bfd6
KH
4733 return font_open_entity (XFRAME (frame), font_entity, isize);
4734}
4735
4736DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0,
4737 doc: /* Close FONT-OBJECT. */)
5842a27b 4738 (Lisp_Object font_object, Lisp_Object frame)
c2f5bfd6
KH
4739{
4740 CHECK_FONT_OBJECT (font_object);
4741 if (NILP (frame))
4742 frame = selected_frame;
4743 CHECK_LIVE_FRAME (frame);
4744 font_close_object (XFRAME (frame), font_object);
4745 return Qnil;
4746}
4747
4748DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
e80e09b4
KH
4749 doc: /* Return information about FONT-OBJECT.
4750The value is a vector:
4751 [ NAME FILENAME PIXEL-SIZE SIZE ASCENT DESCENT SPACE-WIDTH AVERAGE-WIDTH
e0708580 4752 CAPABILITY ]
e80e09b4
KH
4753
4754NAME is a string of the font name (or nil if the font backend doesn't
4755provide a name).
4756
4757FILENAME is a string of the font file (or nil if the font backend
4758doesn't provide a file name).
4759
4760PIXEL-SIZE is a pixel size by which the font is opened.
4761
027a33c0 4762SIZE is a maximum advance width of the font in pixels.
e80e09b4
KH
4763
4764ASCENT, DESCENT, SPACE-WIDTH, AVERAGE-WIDTH are metrics of the font in
027a33c0 4765pixels.
e80e09b4 4766
e0708580
KH
4767CAPABILITY is a list whose first element is a symbol representing the
4768font format \(x, opentype, truetype, type1, pcf, or bdf) and the
027a33c0 4769remaining elements describe the details of the font capability.
e0708580
KH
4770
4771If the font is OpenType font, the form of the list is
4772 \(opentype GSUB GPOS)
4773where GSUB shows which "GSUB" features the font supports, and GPOS
4774shows which "GPOS" features the font supports. Both GSUB and GPOS are
4775lists of the format:
4776 \((SCRIPT (LANGSYS FEATURE ...) ...) ...)
4777
4778If the font is not OpenType font, currently the length of the form is
4779one.
e80e09b4
KH
4780
4781SCRIPT is a symbol representing OpenType script tag.
4782
4783LANGSYS is a symbol representing OpenType langsys tag, or nil
4784representing the default langsys.
4785
51c01100 4786FEATURE is a symbol representing OpenType feature tag.
e80e09b4 4787
51c01100 4788If the font is not OpenType font, CAPABILITY is nil. */)
5842a27b 4789 (Lisp_Object font_object)
c2f5bfd6
KH
4790{
4791 struct font *font;
4792 Lisp_Object val;
4793
4794 CHECK_FONT_GET_OBJECT (font_object, font);
4795
4796 val = Fmake_vector (make_number (9), Qnil);
35027d0c
KH
4797 ASET (val, 0, AREF (font_object, FONT_NAME_INDEX));
4798 ASET (val, 1, AREF (font_object, FONT_FILE_INDEX));
c2f5bfd6 4799 ASET (val, 2, make_number (font->pixel_size));
35027d0c 4800 ASET (val, 3, make_number (font->max_width));
c2f5bfd6
KH
4801 ASET (val, 4, make_number (font->ascent));
4802 ASET (val, 5, make_number (font->descent));
35027d0c
KH
4803 ASET (val, 6, make_number (font->space_width));
4804 ASET (val, 7, make_number (font->average_width));
c2f5bfd6 4805 if (font->driver->otf_capability)
e0708580 4806 ASET (val, 8, Fcons (Qopentype, font->driver->otf_capability (font)));
c2f5bfd6
KH
4807 return val;
4808}
4809
a7840ffb
KH
4810DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
4811 doc:
4812 /* Return a vector of FONT-OBJECT's glyphs for the specified characters.
4813FROM and TO are positions (integers or markers) specifying a region
4814of the current buffer.
4815If the optional fourth arg OBJECT is not nil, it is a string or a
4816vector containing the target characters.
4817
4818Each element is a vector containing information of a glyph in this format:
4819 [FROM-IDX TO-IDX C CODE WIDTH LBEARING RBEARING ASCENT DESCENT ADJUSTMENT]
4820where
4821 FROM is an index numbers of a character the glyph corresponds to.
4822 TO is the same as FROM.
4823 C is the character of the glyph.
4824 CODE is the glyph-code of C in FONT-OBJECT.
4825 WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
4826 ADJUSTMENT is always nil.
4827If FONT-OBJECT doesn't have a glyph for a character,
4828the corresponding element is nil. */)
e1ffae3b
KH
4829 (Lisp_Object font_object, Lisp_Object from, Lisp_Object to,
4830 Lisp_Object object)
c2f5bfd6
KH
4831{
4832 struct font *font;
a7840ffb
KH
4833 int i, len, c;
4834 Lisp_Object *chars, vec;
4835 USE_SAFE_ALLOCA;
c2f5bfd6
KH
4836
4837 CHECK_FONT_GET_OBJECT (font_object, font);
a7840ffb
KH
4838 if (NILP (object))
4839 {
4840 EMACS_INT charpos, bytepos;
4841
4842 validate_region (&from, &to);
4843 if (EQ (from, to))
4844 return Qnil;
4845 len = XFASTINT (to) - XFASTINT (from);
4846 SAFE_ALLOCA_LISP (chars, len);
4847 charpos = XFASTINT (from);
4848 bytepos = CHAR_TO_BYTE (charpos);
4849 for (i = 0; charpos < XFASTINT (to); i++)
4850 {
4851 FETCH_CHAR_ADVANCE (c, charpos, bytepos);
4852 chars[i] = make_number (c);
4853 }
4854 }
4855 else if (STRINGP (object))
4856 {
4857 const unsigned char *p;
4858
4859 CHECK_NUMBER (from);
4860 CHECK_NUMBER (to);
4861 if (XINT (from) < 0 || XINT (from) > XINT (to)
4862 || XINT (to) > SCHARS (object))
4863 args_out_of_range_3 (object, from, to);
4864 if (EQ (from, to))
4865 return Qnil;
4866 len = XFASTINT (to) - XFASTINT (from);
4867 SAFE_ALLOCA_LISP (chars, len);
4868 p = SDATA (object);
4869 if (STRING_MULTIBYTE (object))
4870 for (i = 0; i < len; i++)
4871 {
4872 c = STRING_CHAR_ADVANCE (p);
4873 chars[i] = make_number (c);
4874 }
4875 else
4876 for (i = 0; i < len; i++)
4877 chars[i] = make_number (p[i]);
4878 }
4879 else
4880 {
4881 CHECK_VECTOR (object);
4882 CHECK_NUMBER (from);
4883 CHECK_NUMBER (to);
4884 if (XINT (from) < 0 || XINT (from) > XINT (to)
4885 || XINT (to) > ASIZE (object))
4886 args_out_of_range_3 (object, from, to);
4887 if (EQ (from, to))
4888 return Qnil;
4889 len = XFASTINT (to) - XFASTINT (from);
4890 for (i = 0; i < len; i++)
4891 {
4892 Lisp_Object elt = AREF (object, XFASTINT (from) + i);
4893 CHECK_CHARACTER (elt);
4894 }
4895 chars = &(AREF (object, XFASTINT (from)));
4896 }
4897
c2f5bfd6
KH
4898 vec = Fmake_vector (make_number (len), Qnil);
4899 for (i = 0; i < len; i++)
4900 {
a7840ffb
KH
4901 Lisp_Object g;
4902 int c = XFASTINT (chars[i]);
c2f5bfd6 4903 unsigned code;
2930d117 4904 EMACS_INT cod;
c2f5bfd6
KH
4905 struct font_metrics metrics;
4906
2930d117 4907 cod = code = font->driver->encode_char (font, c);
c2f5bfd6
KH
4908 if (code == FONT_INVALID_CODE)
4909 continue;
a7840ffb
KH
4910 g = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
4911 LGLYPH_SET_FROM (g, i);
4912 LGLYPH_SET_TO (g, i);
4913 LGLYPH_SET_CHAR (g, c);
4914 LGLYPH_SET_CODE (g, code);
51c01100 4915 font->driver->text_extents (font, &code, 1, &metrics);
a7840ffb
KH
4916 LGLYPH_SET_WIDTH (g, metrics.width);
4917 LGLYPH_SET_LBEARING (g, metrics.lbearing);
4918 LGLYPH_SET_RBEARING (g, metrics.rbearing);
4919 LGLYPH_SET_ASCENT (g, metrics.ascent);
4920 LGLYPH_SET_DESCENT (g, metrics.descent);
4921 ASET (vec, i, g);
4922 }
4923 if (! VECTORP (object))
4924 SAFE_FREE ();
c2f5bfd6
KH
4925 return vec;
4926}
4927
ec6fe57c 4928DEFUN ("font-match-p", Ffont_match_p, Sfont_match_p, 2, 2, 0,
67b5d7de 4929 doc: /* Return t if and only if font-spec SPEC matches with FONT.
ec6fe57c 4930FONT is a font-spec, font-entity, or font-object. */)
5842a27b 4931 (Lisp_Object spec, Lisp_Object font)
ec6fe57c
KH
4932{
4933 CHECK_FONT_SPEC (spec);
35027d0c 4934 CHECK_FONT (font);
ec6fe57c
KH
4935
4936 return (font_match_p (spec, font) ? Qt : Qnil);
4937}
4938
1701724c 4939DEFUN ("font-at", Ffont_at, Sfont_at, 1, 3, 0,
51c01100 4940 doc: /* Return a font-object for displaying a character at POSITION.
10d16101
KH
4941Optional second arg WINDOW, if non-nil, is a window displaying
4942the current buffer. It defaults to the currently selected window. */)
5842a27b 4943 (Lisp_Object position, Lisp_Object window, Lisp_Object string)
10d16101
KH
4944{
4945 struct window *w;
e3ee0340 4946 EMACS_INT pos;
10d16101 4947
1701724c
KH
4948 if (NILP (string))
4949 {
4950 CHECK_NUMBER_COERCE_MARKER (position);
4951 pos = XINT (position);
4952 if (pos < BEGV || pos >= ZV)
4953 args_out_of_range_3 (position, make_number (BEGV), make_number (ZV));
1701724c
KH
4954 }
4955 else
4956 {
1701724c
KH
4957 CHECK_NUMBER (position);
4958 CHECK_STRING (string);
4959 pos = XINT (position);
4960 if (pos < 0 || pos >= SCHARS (string))
4961 args_out_of_range (string, position);
1701724c 4962 }
10d16101
KH
4963 if (NILP (window))
4964 window = selected_window;
4965 CHECK_LIVE_WINDOW (window);
40fb53d6 4966 w = XWINDOW (window);
10d16101 4967
40fb53d6 4968 return font_at (-1, pos, NULL, w, string);
10d16101
KH
4969}
4970
c2f5bfd6
KH
4971#if 0
4972DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
4973 doc: /* Draw STRING by FONT-OBJECT on the top left corner of the current frame.
4974The value is a number of glyphs drawn.
4975Type C-l to recover what previously shown. */)
5842a27b 4976 (Lisp_Object font_object, Lisp_Object string)
c2f5bfd6
KH
4977{
4978 Lisp_Object frame = selected_frame;
4979 FRAME_PTR f = XFRAME (frame);
4980 struct font *font;
4981 struct face *face;
4982 int i, len, width;
4983 unsigned *code;
4984
4985 CHECK_FONT_GET_OBJECT (font_object, font);
4986 CHECK_STRING (string);
4987 len = SCHARS (string);
4988 code = alloca (sizeof (unsigned) * len);
4989 for (i = 0; i < len; i++)
4990 {
4991 Lisp_Object ch = Faref (string, make_number (i));
4992 Lisp_Object val;
4993 int c = XINT (ch);
4994
4995 code[i] = font->driver->encode_char (font, c);
4996 if (code[i] == FONT_INVALID_CODE)
4997 break;
4998 }
4999 face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
5000 face->fontp = font;
5001 if (font->driver->prepare_face)
5002 font->driver->prepare_face (f, face);
5003 width = font->driver->text_extents (font, code, i, NULL);
5004 len = font->driver->draw_text (f, face, 0, font->ascent, code, i, width);
5005 if (font->driver->done_face)
5006 font->driver->done_face (f, face);
5007 face->fontp = NULL;
5008 return make_number (len);
5009}
5010#endif
5011
5012#endif /* FONT_DEBUG */
5013
a266686a
KH
5014#ifdef HAVE_WINDOW_SYSTEM
5015
72606e45
KH
5016DEFUN ("font-info", Ffont_info, Sfont_info, 1, 2, 0,
5017 doc: /* Return information about a font named NAME on frame FRAME.
5018If FRAME is omitted or nil, use the selected frame.
06f19b91 5019The returned value is a vector of OPENED-NAME, FULL-NAME, SIZE,
72606e45
KH
5020 HEIGHT, BASELINE-OFFSET, RELATIVE-COMPOSE, and DEFAULT-ASCENT,
5021where
5022 OPENED-NAME is the name used for opening the font,
5023 FULL-NAME is the full name of the font,
06f19b91
KH
5024 SIZE is the pixelsize of the font,
5025 HEIGHT is the pixel-height of the font (i.e ascent + descent),
72606e45
KH
5026 BASELINE-OFFSET is the upward offset pixels from ASCII baseline,
5027 RELATIVE-COMPOSE and DEFAULT-ASCENT are the numbers controlling
5028 how to compose characters.
5029If the named font is not yet loaded, return nil. */)
5842a27b 5030 (Lisp_Object name, Lisp_Object frame)
72606e45
KH
5031{
5032 FRAME_PTR f;
5033 struct font *font;
5034 Lisp_Object info;
5035 Lisp_Object font_object;
5036
5037 (*check_window_system_func) ();
5038
5039 if (! FONTP (name))
5040 CHECK_STRING (name);
5041 if (NILP (frame))
5042 frame = selected_frame;
5043 CHECK_LIVE_FRAME (frame);
5044 f = XFRAME (frame);
5045
5046 if (STRINGP (name))
5047 {
5048 int fontset = fs_query_fontset (name, 0);
5049
5050 if (fontset >= 0)
5051 name = fontset_ascii (fontset);
5052 font_object = font_open_by_name (f, (char *) SDATA (name));
5053 }
5054 else if (FONT_OBJECT_P (name))
5055 font_object = name;
5056 else if (FONT_ENTITY_P (name))
5057 font_object = font_open_entity (f, name, 0);
5058 else
5059 {
5060 struct face *face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
5061 Lisp_Object entity = font_matching_entity (f, face->lface, name);
5062
5063 font_object = ! NILP (entity) ? font_open_entity (f, entity, 0) : Qnil;
5064 }
5065 if (NILP (font_object))
5066 return Qnil;
5067 font = XFONT_OBJECT (font_object);
5068
5069 info = Fmake_vector (make_number (7), Qnil);
5070 XVECTOR (info)->contents[0] = AREF (font_object, FONT_NAME_INDEX);
06f19b91 5071 XVECTOR (info)->contents[1] = AREF (font_object, FONT_FULLNAME_INDEX);
72606e45
KH
5072 XVECTOR (info)->contents[2] = make_number (font->pixel_size);
5073 XVECTOR (info)->contents[3] = make_number (font->height);
5074 XVECTOR (info)->contents[4] = make_number (font->baseline_offset);
5075 XVECTOR (info)->contents[5] = make_number (font->relative_compose);
5076 XVECTOR (info)->contents[6] = make_number (font->default_ascent);
5077
5078#if 0
5079 /* As font_object is still in FONT_OBJLIST of the entity, we can't
5080 close it now. Perhaps, we should manage font-objects
5081 by `reference-count'. */
5082 font_close_object (f, font_object);
5083#endif
5084 return info;
5085}
a266686a 5086#endif
72606e45 5087
c2f5bfd6 5088\f
d0ab1ebe
KH
5089#define BUILD_STYLE_TABLE(TBL) \
5090 build_style_table ((TBL), sizeof TBL / sizeof (struct table_entry))
5091
5092static Lisp_Object
971de7fb 5093build_style_table (const struct table_entry *entry, int nelement)
d0ab1ebe
KH
5094{
5095 int i, j;
5096 Lisp_Object table, elt;
17ab8f5d 5097
d0ab1ebe
KH
5098 table = Fmake_vector (make_number (nelement), Qnil);
5099 for (i = 0; i < nelement; i++)
5100 {
5101 for (j = 0; entry[i].names[j]; j++);
5102 elt = Fmake_vector (make_number (j + 1), Qnil);
5103 ASET (elt, 0, make_number (entry[i].numeric));
5104 for (j = 0; entry[i].names[j]; j++)
d67b4f80 5105 ASET (elt, j + 1, intern_c_string (entry[i].names[j]));
d0ab1ebe
KH
5106 ASET (table, i, elt);
5107 }
5108 return table;
5109}
5110
652b9560 5111Lisp_Object Vfont_log;
d0ab1ebe 5112
d0818984
KH
5113/* The deferred font-log data of the form [ACTION ARG RESULT].
5114 If ACTION is not nil, that is added to the log when font_add_log is
5115 called next time. At that time, ACTION is set back to nil. */
5116static Lisp_Object Vfont_log_deferred;
5117
5118/* Prepend the font-related logging data in Vfont_log if it is not
5119 `t'. ACTION describes a kind of font-related action (e.g. listing,
5120 opening), ARG is the argument for the action, and RESULT is the
5121 result of the action. */
d0ab1ebe 5122void
971de7fb 5123font_add_log (char *action, Lisp_Object arg, Lisp_Object result)
d0ab1ebe
KH
5124{
5125 Lisp_Object tail, val;
5126 int i;
5127
d0ab1ebe
KH
5128 if (EQ (Vfont_log, Qt))
5129 return;
d0818984
KH
5130 if (STRINGP (AREF (Vfont_log_deferred, 0)))
5131 {
071132a9 5132 char *str = (char *) SDATA (AREF (Vfont_log_deferred, 0));
d0818984
KH
5133
5134 ASET (Vfont_log_deferred, 0, Qnil);
5135 font_add_log (str, AREF (Vfont_log_deferred, 1),
5136 AREF (Vfont_log_deferred, 2));
5137 }
5138
d0ab1ebe 5139 if (FONTP (arg))
db716644
KH
5140 {
5141 Lisp_Object tail, elt;
5142 Lisp_Object equalstr = build_string ("=");
5143
5144 val = Ffont_xlfd_name (arg, Qt);
5145 for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
5146 tail = XCDR (tail))
5147 {
5148 elt = XCAR (tail);
49f9c344
KH
5149 if (EQ (XCAR (elt), QCscript)
5150 && SYMBOLP (XCDR (elt)))
db716644
KH
5151 val = concat3 (val, SYMBOL_NAME (QCscript),
5152 concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
49f9c344
KH
5153 else if (EQ (XCAR (elt), QClang)
5154 && SYMBOLP (XCDR (elt)))
db716644
KH
5155 val = concat3 (val, SYMBOL_NAME (QClang),
5156 concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
49f9c344
KH
5157 else if (EQ (XCAR (elt), QCotf)
5158 && CONSP (XCDR (elt)) && SYMBOLP (XCAR (XCDR (elt))))
db716644
KH
5159 val = concat3 (val, SYMBOL_NAME (QCotf),
5160 concat2 (equalstr,
5161 SYMBOL_NAME (XCAR (XCDR (elt)))));
5162 }
5163 arg = val;
5164 }
72d36834
KH
5165
5166 if (CONSP (result)
5167 && VECTORP (XCAR (result))
5168 && ASIZE (XCAR (result)) > 0
5169 && FONTP (AREF (XCAR (result), 0)))
5170 result = font_vconcat_entity_vectors (result);
d0ab1ebe 5171 if (FONTP (result))
d26424c5
KH
5172 {
5173 val = Ffont_xlfd_name (result, Qt);
5174 if (! FONT_SPEC_P (result))
5175 val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
5176 build_string (":"), val);
5177 result = val;
5178 }
d0ab1ebe
KH
5179 else if (CONSP (result))
5180 {
5181 result = Fcopy_sequence (result);
5182 for (tail = result; CONSP (tail); tail = XCDR (tail))
5183 {
5184 val = XCAR (tail);
5185 if (FONTP (val))
5186 val = Ffont_xlfd_name (val, Qt);
5187 XSETCAR (tail, val);
5188 }
5189 }
5190 else if (VECTORP (result))
5191 {
5192 result = Fcopy_sequence (result);
5193 for (i = 0; i < ASIZE (result); i++)
5194 {
5195 val = AREF (result, i);
5196 if (FONTP (val))
5197 val = Ffont_xlfd_name (val, Qt);
5198 ASET (result, i, val);
5199 }
5200 }
5201 Vfont_log = Fcons (list3 (intern (action), arg, result), Vfont_log);
5202}
5203
d0818984
KH
5204/* Record a font-related logging data to be added to Vfont_log when
5205 font_add_log is called next time. ACTION, ARG, RESULT are the same
5206 as font_add_log. */
5207
5208void
971de7fb 5209font_deferred_log (char *action, Lisp_Object arg, Lisp_Object result)
d0818984 5210{
652b9560
KH
5211 if (EQ (Vfont_log, Qt))
5212 return;
d0818984
KH
5213 ASET (Vfont_log_deferred, 0, build_string (action));
5214 ASET (Vfont_log_deferred, 1, arg);
5215 ASET (Vfont_log_deferred, 2, result);
ba3de0e8 5216}
d0818984 5217
971de7fb
DN
5218extern void syms_of_ftfont (void);
5219extern void syms_of_xfont (void);
5220extern void syms_of_xftfont (void);
5221extern void syms_of_ftxfont (void);
5222extern void syms_of_bdffont (void);
5223extern void syms_of_w32font (void);
5224extern void syms_of_atmfont (void);
5225extern void syms_of_nsfont (void);
c2f5bfd6
KH
5226
5227void
971de7fb 5228syms_of_font (void)
c2f5bfd6 5229{
4007dd1c
KH
5230 sort_shift_bits[FONT_TYPE_INDEX] = 0;
5231 sort_shift_bits[FONT_SLANT_INDEX] = 2;
5232 sort_shift_bits[FONT_WEIGHT_INDEX] = 9;
5233 sort_shift_bits[FONT_SIZE_INDEX] = 16;
5234 sort_shift_bits[FONT_WIDTH_INDEX] = 23;
5235 /* Note that the other elements in sort_shift_bits are not used. */
c2f5bfd6 5236
1701724c
KH
5237 staticpro (&font_charset_alist);
5238 font_charset_alist = Qnil;
5239
e0708580 5240 DEFSYM (Qopentype, "opentype");
c2f5bfd6 5241
9e1bb909 5242 DEFSYM (Qascii_0, "ascii-0");
1bb1d99b
KH
5243 DEFSYM (Qiso8859_1, "iso8859-1");
5244 DEFSYM (Qiso10646_1, "iso10646-1");
5245 DEFSYM (Qunicode_bmp, "unicode-bmp");
cf96c5c2 5246 DEFSYM (Qunicode_sip, "unicode-sip");
1bb1d99b 5247
071132a9
KH
5248 DEFSYM (QCf, "Cf");
5249
c2f5bfd6 5250 DEFSYM (QCotf, ":otf");
35027d0c 5251 DEFSYM (QClang, ":lang");
c2f5bfd6 5252 DEFSYM (QCscript, ":script");
4c496d0d 5253 DEFSYM (QCantialias, ":antialias");
c2f5bfd6
KH
5254
5255 DEFSYM (QCfoundry, ":foundry");
5256 DEFSYM (QCadstyle, ":adstyle");
5257 DEFSYM (QCregistry, ":registry");
9331887d
KH
5258 DEFSYM (QCspacing, ":spacing");
5259 DEFSYM (QCdpi, ":dpi");
ec6fe57c 5260 DEFSYM (QCscalable, ":scalable");
35027d0c
KH
5261 DEFSYM (QCavgwidth, ":avgwidth");
5262 DEFSYM (QCfont_entity, ":font-entity");
5263 DEFSYM (QCfc_unknown_spec, ":fc-unknown-spec");
c2f5bfd6 5264
ec6fe57c
KH
5265 DEFSYM (Qc, "c");
5266 DEFSYM (Qm, "m");
5267 DEFSYM (Qp, "p");
5268 DEFSYM (Qd, "d");
5269
cf702558
CY
5270 DEFSYM (Qja, "ja");
5271 DEFSYM (Qko, "ko");
5272
42707278
JD
5273 DEFSYM (QCuser_spec, "user-spec");
5274
c2f5bfd6
KH
5275 staticpro (&null_vector);
5276 null_vector = Fmake_vector (make_number (0), Qnil);
5277
5278 staticpro (&scratch_font_spec);
5279 scratch_font_spec = Ffont_spec (0, NULL);
5280 staticpro (&scratch_font_prefer);
5281 scratch_font_prefer = Ffont_spec (0, NULL);
5282
d0818984
KH
5283 staticpro (&Vfont_log_deferred);
5284 Vfont_log_deferred = Fmake_vector (make_number (3), Qnil);
5285
6a3dadd2 5286#if 0
733fd013
KH
5287#ifdef HAVE_LIBOTF
5288 staticpro (&otf_list);
5289 otf_list = Qnil;
6a3dadd2
KH
5290#endif /* HAVE_LIBOTF */
5291#endif /* 0 */
733fd013 5292
c2f5bfd6
KH
5293 defsubr (&Sfontp);
5294 defsubr (&Sfont_spec);
5295 defsubr (&Sfont_get);
51cf11be 5296#ifdef HAVE_WINDOW_SYSTEM
b1868a1a 5297 defsubr (&Sfont_face_attributes);
51cf11be 5298#endif
c2f5bfd6
KH
5299 defsubr (&Sfont_put);
5300 defsubr (&Slist_fonts);
35027d0c 5301 defsubr (&Sfont_family_list);
c2f5bfd6
KH
5302 defsubr (&Sfind_font);
5303 defsubr (&Sfont_xlfd_name);
5304 defsubr (&Sclear_font_cache);
071132a9 5305 defsubr (&Sfont_shape_gstring);
78a2f9cd 5306 defsubr (&Sfont_variation_glyphs);
6a3dadd2 5307#if 0
733fd013 5308 defsubr (&Sfont_drive_otf);
e80e09b4 5309 defsubr (&Sfont_otf_alternates);
6a3dadd2 5310#endif /* 0 */
c2f5bfd6
KH
5311
5312#ifdef FONT_DEBUG
5313 defsubr (&Sopen_font);
5314 defsubr (&Sclose_font);
5315 defsubr (&Squery_font);
a7840ffb 5316 defsubr (&Sfont_get_glyphs);
ec6fe57c 5317 defsubr (&Sfont_match_p);
10d16101 5318 defsubr (&Sfont_at);
c2f5bfd6
KH
5319#if 0
5320 defsubr (&Sdraw_string);
5321#endif
5322#endif /* FONT_DEBUG */
a266686a 5323#ifdef HAVE_WINDOW_SYSTEM
72606e45 5324 defsubr (&Sfont_info);
a266686a 5325#endif
c2f5bfd6 5326
819e81df
KH
5327 DEFVAR_LISP ("font-encoding-alist", &Vfont_encoding_alist,
5328 doc: /*
5329Alist of fontname patterns vs the corresponding encoding and repertory info.
5330Each element looks like (REGEXP . (ENCODING . REPERTORY)),
5331where ENCODING is a charset or a char-table,
5332and REPERTORY is a charset, a char-table, or nil.
5333
027a33c0 5334If ENCODING and REPERTORY are the same, the element can have the form
819e81df
KH
5335\(REGEXP . ENCODING).
5336
5337ENCODING is for converting a character to a glyph code of the font.
5338If ENCODING is a charset, encoding a character by the charset gives
5339the corresponding glyph code. If ENCODING is a char-table, looking up
5340the table by a character gives the corresponding glyph code.
5341
5342REPERTORY specifies a repertory of characters supported by the font.
5343If REPERTORY is a charset, all characters beloging to the charset are
5344supported. If REPERTORY is a char-table, all characters who have a
027a33c0 5345non-nil value in the table are supported. If REPERTORY is nil, Emacs
819e81df
KH
5346gets the repertory information by an opened font and ENCODING. */);
5347 Vfont_encoding_alist = Qnil;
5348
933ac235
SM
5349 /* FIXME: These 3 vars are not quite what they appear: setq on them
5350 won't have any effect other than disconnect them from the style
5351 table used by the font display code. So we make them read-only,
5352 to avoid this confusing situation. */
5353
d0ab1ebe
KH
5354 DEFVAR_LISP_NOPRO ("font-weight-table", &Vfont_weight_table,
5355 doc: /* Vector of valid font weight values.
5356Each element has the form:
5357 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
17ab8f5d 5358NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */);
d0ab1ebe 5359 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
933ac235 5360 XSYMBOL (intern_c_string ("font-weight-table"))->constant = 1;
d0ab1ebe
KH
5361
5362 DEFVAR_LISP_NOPRO ("font-slant-table", &Vfont_slant_table,
5363 doc: /* Vector of font slant symbols vs the corresponding numeric values.
17ab8f5d 5364See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5365 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
933ac235 5366 XSYMBOL (intern_c_string ("font-slant-table"))->constant = 1;
d0ab1ebe
KH
5367
5368 DEFVAR_LISP_NOPRO ("font-width-table", &Vfont_width_table,
5369 doc: /* Alist of font width symbols vs the corresponding numeric values.
17ab8f5d 5370See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5371 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
933ac235 5372 XSYMBOL (intern_c_string ("font-width-table"))->constant = 1;
d0ab1ebe
KH
5373
5374 staticpro (&font_style_table);
5375 font_style_table = Fmake_vector (make_number (3), Qnil);
5376 ASET (font_style_table, 0, Vfont_weight_table);
5377 ASET (font_style_table, 1, Vfont_slant_table);
5378 ASET (font_style_table, 2, Vfont_width_table);
5379
5380 DEFVAR_LISP ("font-log", &Vfont_log, doc: /*
5381*Logging list of font related actions and results.
5382The value t means to suppress the logging.
5383The initial value is set to nil if the environment variable
5384EMACS_FONT_LOG is set. Otherwise, it is set to t. */);
5385 Vfont_log = Qnil;
5386
819e81df 5387#ifdef HAVE_WINDOW_SYSTEM
c2f5bfd6 5388#ifdef HAVE_FREETYPE
35027d0c 5389 syms_of_ftfont ();
c2f5bfd6 5390#ifdef HAVE_X_WINDOWS
35027d0c
KH
5391 syms_of_xfont ();
5392 syms_of_ftxfont ();
c2f5bfd6 5393#ifdef HAVE_XFT
35027d0c 5394 syms_of_xftfont ();
c2f5bfd6
KH
5395#endif /* HAVE_XFT */
5396#endif /* HAVE_X_WINDOWS */
5397#else /* not HAVE_FREETYPE */
5398#ifdef HAVE_X_WINDOWS
35027d0c 5399 syms_of_xfont ();
c2f5bfd6
KH
5400#endif /* HAVE_X_WINDOWS */
5401#endif /* not HAVE_FREETYPE */
5402#ifdef HAVE_BDFFONT
35027d0c 5403 syms_of_bdffont ();
c2f5bfd6
KH
5404#endif /* HAVE_BDFFONT */
5405#ifdef WINDOWSNT
35027d0c 5406 syms_of_w32font ();
c2f5bfd6 5407#endif /* WINDOWSNT */
edfda783
AR
5408#ifdef HAVE_NS
5409 syms_of_nsfont ();
5410#endif /* HAVE_NS */
819e81df 5411#endif /* HAVE_WINDOW_SYSTEM */
c2f5bfd6 5412}
885b7d09 5413
652b9560 5414void
971de7fb 5415init_font (void)
652b9560
KH
5416{
5417 Vfont_log = egetenv ("EMACS_FONT_LOG") ? Qnil : Qt;
5418}
5419
885b7d09
MB
5420/* arch-tag: 74c9475d-5976-4c93-a327-942ae3072846
5421 (do not change this comment) */