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