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