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