Auto-commit of generated files.
[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
PE
1187 char *p;
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 {
35027d0c 1237 val = SYMBOL_NAME (val);
c21721cc 1238 f[j] = SSDATA (val);
c2f5bfd6
KH
1239 }
1240 }
1241
1242 val = AREF (font, FONT_SIZE_INDEX);
4e6a86c6 1243 eassert (NUMBERP (val) || NILP (val));
c2f5bfd6
KH
1244 if (INTEGERP (val))
1245 {
c21721cc
PE
1246 EMACS_INT v = XINT (val);
1247 if (v <= 0)
1248 v = pixel_size;
1249 if (v > 0)
81aefea4 1250 {
c21721cc
PE
1251 f[XLFD_PIXEL_INDEX] = p =
1252 alloca (sizeof "-*" + INT_STRLEN_BOUND (EMACS_INT));
1253 sprintf (p, "%"pI"d-*", v);
81aefea4
SM
1254 }
1255 else
c21721cc 1256 f[XLFD_PIXEL_INDEX] = "*-*";
c2f5bfd6
KH
1257 }
1258 else if (FLOATP (val))
1259 {
c21721cc
PE
1260 double v = XFLOAT_DATA (val) * 10;
1261 f[XLFD_PIXEL_INDEX] = p = alloca (sizeof "*-" + 1 + DBL_MAX_10_EXP + 1);
1262 sprintf (p, "*-%.0f", v);
c2f5bfd6
KH
1263 }
1264 else
c21721cc 1265 f[XLFD_PIXEL_INDEX] = "*-*";
ec6fe57c 1266
35027d0c 1267 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
c2f5bfd6 1268 {
c21721cc
PE
1269 EMACS_INT v = XINT (AREF (font, FONT_DPI_INDEX));
1270 f[XLFD_RESX_INDEX] = p =
1271 alloca (sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT));
1272 sprintf (p, "%"pI"d-%"pI"d", v, v);
c2f5bfd6
KH
1273 }
1274 else
c21721cc 1275 f[XLFD_RESX_INDEX] = "*-*";
35027d0c 1276 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
ec6fe57c 1277 {
c21721cc 1278 EMACS_INT spacing = XINT (AREF (font, FONT_SPACING_INDEX));
ec6fe57c 1279
35027d0c
KH
1280 f[XLFD_SPACING_INDEX] = (spacing <= FONT_SPACING_PROPORTIONAL ? "p"
1281 : spacing <= FONT_SPACING_DUAL ? "d"
1282 : spacing <= FONT_SPACING_MONO ? "m"
1283 : "c");
ec6fe57c 1284 }
35027d0c 1285 else
c21721cc 1286 f[XLFD_SPACING_INDEX] = "*";
35027d0c
KH
1287 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1288 {
c21721cc
PE
1289 f[XLFD_AVGWIDTH_INDEX] = p = alloca (INT_BUFSIZE_BOUND (EMACS_INT));
1290 sprintf (p, "%"pI"d", XINT (AREF (font, FONT_AVGWIDTH_INDEX)));
35027d0c
KH
1291 }
1292 else
c21721cc 1293 f[XLFD_AVGWIDTH_INDEX] = "*";
8666506e
PE
1294 len = snprintf (name, nbytes, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
1295 f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
1296 f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
1297 f[XLFD_SWIDTH_INDEX], f[XLFD_ADSTYLE_INDEX],
1298 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
1299 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
1300 f[XLFD_REGISTRY_INDEX]);
1301 return len < nbytes ? len : -1;
c2f5bfd6
KH
1302}
1303
8c102d5b
CY
1304/* Parse NAME (null terminated) and store information in FONT
1305 (font-spec or font-entity). NAME is supplied in either the
1306 Fontconfig or GTK font name format. If NAME is successfully
1307 parsed, return 0. Otherwise return -1.
1308
1309 The fontconfig format is
1310
1311 FAMILY[-SIZE][:PROP1[=VAL1][:PROP2[=VAL2]...]]
1312
1313 The GTK format is
1314
1315 FAMILY [PROPS...] [SIZE]
1316
1317 This function tries to guess which format it is. */
ef18374f 1318
2f7c71a1 1319static int
984e7f30 1320font_parse_fcname (char *name, ptrdiff_t len, Lisp_Object font)
ef18374f 1321{
8c102d5b
CY
1322 char *p, *q;
1323 char *size_beg = NULL, *size_end = NULL;
1324 char *props_beg = NULL, *family_end = NULL;
ef18374f 1325
ec6fe57c
KH
1326 if (len == 0)
1327 return -1;
8c102d5b
CY
1328
1329 for (p = name; *p; p++)
ef18374f 1330 {
8c102d5b
CY
1331 if (*p == '\\' && p[1])
1332 p++;
1333 else if (*p == ':')
ef18374f 1334 {
59facb78 1335 props_beg = family_end = p;
8c102d5b
CY
1336 break;
1337 }
1338 else if (*p == '-')
1339 {
a864ef14 1340 bool decimal = 0, size_found = 1;
8c102d5b 1341 for (q = p + 1; *q && *q != ':'; q++)
620f13b0 1342 if (! c_isdigit (*q))
8c102d5b 1343 {
b1868a1a
CY
1344 if (*q != '.' || decimal)
1345 {
1346 size_found = 0;
1347 break;
1348 }
1349 decimal = 1;
8c102d5b
CY
1350 }
1351 if (size_found)
1352 {
1353 family_end = p;
1354 size_beg = p + 1;
1355 size_end = q;
1356 break;
1357 }
ef18374f 1358 }
ef18374f 1359 }
9331887d 1360
8c102d5b
CY
1361 if (family_end)
1362 {
637fa988
JD
1363 Lisp_Object extra_props = Qnil;
1364
8c102d5b
CY
1365 /* A fontconfig name with size and/or property data. */
1366 if (family_end > name)
1367 {
1368 Lisp_Object family;
1369 family = font_intern_prop (name, family_end - name, 1);
1370 ASET (font, FONT_FAMILY_INDEX, family);
1371 }
1372 if (size_beg)
1373 {
1374 double point_size = strtod (size_beg, &size_end);
1375 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1376 if (*size_end == ':' && size_end[1])
59facb78 1377 props_beg = size_end;
8c102d5b
CY
1378 }
1379 if (props_beg)
1380 {
d26424c5 1381 /* Now parse ":KEY=VAL" patterns. */
59facb78 1382 Lisp_Object val;
8c102d5b 1383
59facb78 1384 for (p = props_beg; *p; p = q)
8c102d5b 1385 {
8c102d5b 1386 for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
8c102d5b
CY
1387 if (*q != '=')
1388 {
1389 /* Must be an enumerated value. */
b5b8c9e5 1390 ptrdiff_t word_len;
59facb78
CY
1391 p = p + 1;
1392 word_len = q - p;
8c102d5b 1393 val = font_intern_prop (p, q - p, 1);
9277a69d 1394
4ec88040
AS
1395#define PROP_MATCH(STR) (word_len == strlen (STR) \
1396 && memcmp (p, STR, strlen (STR)) == 0)
1397
1398 if (PROP_MATCH ("light")
1399 || PROP_MATCH ("medium")
1400 || PROP_MATCH ("demibold")
1401 || PROP_MATCH ("bold")
1402 || PROP_MATCH ("black"))
8c102d5b 1403 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
4ec88040
AS
1404 else if (PROP_MATCH ("roman")
1405 || PROP_MATCH ("italic")
1406 || PROP_MATCH ("oblique"))
8c102d5b 1407 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
4ec88040 1408 else if (PROP_MATCH ("charcell"))
8c102d5b
CY
1409 ASET (font, FONT_SPACING_INDEX,
1410 make_number (FONT_SPACING_CHARCELL));
4ec88040 1411 else if (PROP_MATCH ("mono"))
8c102d5b
CY
1412 ASET (font, FONT_SPACING_INDEX,
1413 make_number (FONT_SPACING_MONO));
4ec88040 1414 else if (PROP_MATCH ("proportional"))
8c102d5b
CY
1415 ASET (font, FONT_SPACING_INDEX,
1416 make_number (FONT_SPACING_PROPORTIONAL));
9277a69d 1417#undef PROP_MATCH
8c102d5b 1418 }
59facb78 1419 else
8c102d5b 1420 {
59facb78 1421 /* KEY=VAL pairs */
8c102d5b 1422 Lisp_Object key;
59facb78 1423 int prop;
51c01100 1424
59facb78 1425 if (q - p == 10 && memcmp (p + 1, "pixelsize", 9) == 0)
8c102d5b
CY
1426 prop = FONT_SIZE_INDEX;
1427 else
1428 {
1429 key = font_intern_prop (p, q - p, 1);
1430 prop = get_font_prop_index (key);
1431 }
77989187 1432
8c102d5b
CY
1433 p = q + 1;
1434 for (q = p; *q && *q != ':'; q++);
90c00b01 1435 val = font_intern_prop (p, q - p, 0);
77989187 1436
d26424c5
KH
1437 if (prop >= FONT_FOUNDRY_INDEX
1438 && prop < FONT_EXTRA_INDEX)
637fa988 1439 ASET (font, prop, font_prop_validate (prop, Qnil, val));
ce75f06e 1440 else
637fa988
JD
1441 {
1442 extra_props = nconc2 (extra_props,
1443 Fcons (Fcons (key, val), Qnil));
1444 }
8c102d5b 1445 }
d26424c5 1446 p = q;
8c102d5b 1447 }
8c102d5b 1448 }
637fa988
JD
1449
1450 if (! NILP (extra_props))
1451 {
1452 struct font_driver_list *driver_list = font_driver_list;
1453 for ( ; driver_list; driver_list = driver_list->next)
1454 if (driver_list->driver->filter_properties)
1455 (*driver_list->driver->filter_properties) (font, extra_props);
1456 }
ce75f06e 1457
8c102d5b
CY
1458 }
1459 else
ef18374f 1460 {
8c102d5b
CY
1461 /* Either a fontconfig-style name with no size and property
1462 data, or a GTK-style name. */
6608a7d8
CY
1463 Lisp_Object weight = Qnil, slant = Qnil;
1464 Lisp_Object width = Qnil, size = Qnil;
1465 char *word_start;
b5b8c9e5 1466 ptrdiff_t word_len;
6608a7d8
CY
1467
1468 /* Scan backwards from the end, looking for a size. */
1469 for (p = name + len - 1; p >= name; p--)
620f13b0 1470 if (!c_isdigit (*p))
6608a7d8
CY
1471 break;
1472
1473 if ((p < name + len - 1) && ((p + 1 == name) || *p == ' '))
1474 /* Found a font size. */
1475 size = make_float (strtod (p + 1, NULL));
1476 else
1477 p = name + len;
ef18374f 1478
6608a7d8
CY
1479 /* Now P points to the termination of the string, sans size.
1480 Scan backwards, looking for font properties. */
1481 for (; p > name; p = q)
ef18374f 1482 {
6608a7d8 1483 for (q = p - 1; q >= name; q--)
9331887d 1484 {
6608a7d8
CY
1485 if (q > name && *(q-1) == '\\')
1486 --q; /* Skip quoting backslashes. */
1487 else if (*q == ' ')
1488 break;
027a33c0 1489 }
8c102d5b 1490
6608a7d8
CY
1491 word_start = q + 1;
1492 word_len = p - word_start;
8c102d5b 1493
4ec88040
AS
1494#define PROP_MATCH(STR) \
1495 (word_len == strlen (STR) \
1496 && memcmp (word_start, STR, strlen (STR)) == 0)
1497#define PROP_SAVE(VAR, STR) \
1498 (VAR = NILP (VAR) ? font_intern_prop (STR, strlen (STR), 1) : VAR)
1499
1500 if (PROP_MATCH ("Ultra-Light"))
1501 PROP_SAVE (weight, "ultra-light");
1502 else if (PROP_MATCH ("Light"))
1503 PROP_SAVE (weight, "light");
1504 else if (PROP_MATCH ("Book"))
1505 PROP_SAVE (weight, "book");
1506 else if (PROP_MATCH ("Medium"))
1507 PROP_SAVE (weight, "medium");
1508 else if (PROP_MATCH ("Semi-Bold"))
1509 PROP_SAVE (weight, "semi-bold");
1510 else if (PROP_MATCH ("Bold"))
1511 PROP_SAVE (weight, "bold");
1512 else if (PROP_MATCH ("Italic"))
1513 PROP_SAVE (slant, "italic");
1514 else if (PROP_MATCH ("Oblique"))
1515 PROP_SAVE (slant, "oblique");
1516 else if (PROP_MATCH ("Semi-Condensed"))
1517 PROP_SAVE (width, "semi-condensed");
1518 else if (PROP_MATCH ("Condensed"))
1519 PROP_SAVE (width, "condensed");
6608a7d8
CY
1520 /* An unknown word must be part of the font name. */
1521 else
fe69a722 1522 {
6608a7d8
CY
1523 family_end = p;
1524 break;
fe69a722 1525 }
ef18374f 1526 }
8c102d5b 1527#undef PROP_MATCH
372fb76b 1528#undef PROP_SAVE
9ba6fd41 1529
8c102d5b 1530 if (family_end)
6608a7d8
CY
1531 ASET (font, FONT_FAMILY_INDEX,
1532 font_intern_prop (name, family_end - name, 1));
1533 if (!NILP (size))
1534 ASET (font, FONT_SIZE_INDEX, size);
1535 if (!NILP (weight))
1536 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, weight);
1537 if (!NILP (slant))
1538 FONT_SET_STYLE (font, FONT_SLANT_INDEX, slant);
1539 if (!NILP (width))
1540 FONT_SET_STYLE (font, FONT_WIDTH_INDEX, width);
8c102d5b 1541 }
17ab8f5d 1542
9331887d 1543 return 0;
ef18374f
KH
1544}
1545
1546/* Store fontconfig's font name of FONT (font-spec or font-entity) in
1547 NAME (NBYTES length), and return the name length. If
1548 FONT_SIZE_INDEX of FONT is 0, use PIXEL_SIZE instead. */
1549
1550int
09d93395 1551font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
ef18374f 1552{
b1868a1a 1553 Lisp_Object family, foundry;
c21721cc 1554 Lisp_Object val;
ec6fe57c 1555 int point_size;
b5b8c9e5 1556 int i;
ef18374f 1557 char *p;
c21721cc 1558 char *lim;
a9262bb8 1559 Lisp_Object styles[3];
675e2c69 1560 const char *style_names[3] = { "weight", "slant", "width" };
ef18374f 1561
b1868a1a
CY
1562 family = AREF (font, FONT_FAMILY_INDEX);
1563 if (! NILP (family))
1564 {
1565 if (SYMBOLP (family))
c21721cc 1566 family = SYMBOL_NAME (family);
b1868a1a
CY
1567 else
1568 family = Qnil;
1569 }
ec6fe57c
KH
1570
1571 val = AREF (font, FONT_SIZE_INDEX);
1572 if (INTEGERP (val))
ef18374f 1573 {
ec6fe57c
KH
1574 if (XINT (val) != 0)
1575 pixel_size = XINT (val);
1576 point_size = -1;
ef18374f 1577 }
3ddb0639 1578 else
ef18374f 1579 {
4e6a86c6 1580 eassert (FLOATP (val));
ec6fe57c
KH
1581 pixel_size = -1;
1582 point_size = (int) XFLOAT_DATA (val);
ef18374f 1583 }
ec6fe57c 1584
b1868a1a
CY
1585 foundry = AREF (font, FONT_FOUNDRY_INDEX);
1586 if (! NILP (foundry))
1587 {
1588 if (SYMBOLP (foundry))
c21721cc 1589 foundry = SYMBOL_NAME (foundry);
b1868a1a
CY
1590 else
1591 foundry = Qnil;
1592 }
ec6fe57c 1593
35027d0c 1594 for (i = 0; i < 3; i++)
c21721cc 1595 styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
35027d0c 1596
ef18374f 1597 p = name;
c21721cc 1598 lim = name + nbytes;
b1868a1a 1599 if (! NILP (family))
8666506e
PE
1600 {
1601 int len = snprintf (p, lim - p, "%s", SSDATA (family));
1602 if (! (0 <= len && len < lim - p))
1603 return -1;
1604 p += len;
1605 }
ec6fe57c 1606 if (point_size > 0)
8666506e
PE
1607 {
1608 int len = snprintf (p, lim - p, "-%d" + (p == name), point_size);
1609 if (! (0 <= len && len < lim - p))
1610 return -1;
1611 p += len;
1612 }
ef18374f 1613 else if (pixel_size > 0)
8666506e
PE
1614 {
1615 int len = snprintf (p, lim - p, ":pixelsize=%d", pixel_size);
1616 if (! (0 <= len && len < lim - p))
1617 return -1;
1618 p += len;
1619 }
35027d0c 1620 if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
8666506e
PE
1621 {
1622 int len = snprintf (p, lim - p, ":foundry=%s",
1623 SSDATA (SYMBOL_NAME (AREF (font,
1624 FONT_FOUNDRY_INDEX))));
1625 if (! (0 <= len && len < lim - p))
1626 return -1;
1627 p += len;
1628 }
a9262bb8 1629 for (i = 0; i < 3; i++)
35027d0c 1630 if (! NILP (styles[i]))
8666506e
PE
1631 {
1632 int len = snprintf (p, lim - p, ":%s=%s", style_names[i],
1633 SSDATA (SYMBOL_NAME (styles[i])));
1634 if (! (0 <= len && len < lim - p))
1635 return -1;
1636 p += len;
1637 }
1638
35027d0c 1639 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
8666506e
PE
1640 {
1641 int len = snprintf (p, lim - p, ":dpi=%"pI"d",
1642 XINT (AREF (font, FONT_DPI_INDEX)));
1643 if (! (0 <= len && len < lim - p))
1644 return -1;
1645 p += len;
1646 }
1647
35027d0c 1648 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
8666506e
PE
1649 {
1650 int len = snprintf (p, lim - p, ":spacing=%"pI"d",
1651 XINT (AREF (font, FONT_SPACING_INDEX)));
1652 if (! (0 <= len && len < lim - p))
1653 return -1;
1654 p += len;
1655 }
1656
35027d0c 1657 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
8666506e
PE
1658 {
1659 int len = snprintf (p, lim - p,
1660 (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0
1661 ? ":scalable=true"
1662 : ":scalable=false"));
1663 if (! (0 <= len && len < lim - p))
1664 return -1;
1665 p += len;
1666 }
1667
1668 return (p - name);
ef18374f
KH
1669}
1670
1671/* Parse NAME (null terminated) and store information in FONT
1672 (font-spec or font-entity). If NAME is successfully parsed, return
35027d0c 1673 0. Otherwise return -1. */
ef18374f
KH
1674
1675static int
984e7f30 1676font_parse_name (char *name, ptrdiff_t namelen, Lisp_Object font)
ef18374f 1677{
8966b757 1678 if (name[0] == '-' || strchr (name, '*') || strchr (name, '?'))
984e7f30
DA
1679 return font_parse_xlfd (name, namelen, font);
1680 return font_parse_fcname (name, namelen, font);
ef18374f
KH
1681}
1682
35027d0c
KH
1683
1684/* Merge FAMILY and REGISTRY into FONT_SPEC. FAMILY may have the form
1685 "FAMILY-FOUNDRY". REGISTRY may not contain charset-encoding
1686 part. */
45eb10fb 1687
c2f5bfd6 1688void
971de7fb 1689font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Object font_spec)
c2f5bfd6 1690{
35027d0c
KH
1691 int len;
1692 char *p0, *p1;
1693
d0ab1ebe
KH
1694 if (! NILP (family)
1695 && NILP (AREF (font_spec, FONT_FAMILY_INDEX)))
c2f5bfd6 1696 {
35027d0c
KH
1697 CHECK_STRING (family);
1698 len = SBYTES (family);
51b59d79 1699 p0 = SSDATA (family);
8966b757 1700 p1 = strchr (p0, '-');
35027d0c 1701 if (p1)
c2f5bfd6 1702 {
9903d1e6 1703 if ((*p0 != '*' && p1 - p0 > 0)
d0ab1ebe 1704 && NILP (AREF (font_spec, FONT_FOUNDRY_INDEX)))
2f286d4f 1705 Ffont_put (font_spec, QCfoundry, font_intern_prop (p0, p1 - p0, 1));
35027d0c
KH
1706 p1++;
1707 len -= p1 - p0;
2f286d4f 1708 Ffont_put (font_spec, QCfamily, font_intern_prop (p1, len, 1));
c2f5bfd6 1709 }
35027d0c
KH
1710 else
1711 ASET (font_spec, FONT_FAMILY_INDEX, Fintern (family, Qnil));
c2f5bfd6 1712 }
35027d0c 1713 if (! NILP (registry))
c2f5bfd6 1714 {
35027d0c
KH
1715 /* Convert "XXX" and "XXX*" to "XXX*-*". */
1716 CHECK_STRING (registry);
1717 len = SBYTES (registry);
51b59d79 1718 p0 = SSDATA (registry);
8966b757 1719 p1 = strchr (p0, '-');
35027d0c 1720 if (! p1)
c2f5bfd6 1721 {
35027d0c
KH
1722 if (SDATA (registry)[len - 1] == '*')
1723 registry = concat2 (registry, build_string ("-*"));
1724 else
1725 registry = concat2 (registry, build_string ("*-*"));
c2f5bfd6 1726 }
35027d0c
KH
1727 registry = Fdowncase (registry);
1728 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
c2f5bfd6
KH
1729 }
1730}
1731
45eb10fb 1732\f
35027d0c
KH
1733/* This part (through the next ^L) is still experimental and not
1734 tested much. We may drastically change codes. */
10d16101 1735
45eb10fb 1736/* OTF handler */
10d16101 1737
6a3dadd2
KH
1738#if 0
1739
e950d6f1
KH
1740#define LGSTRING_HEADER_SIZE 6
1741#define LGSTRING_GLYPH_SIZE 8
1742
1743static int
1dae0f0a 1744check_gstring (Lisp_Object gstring)
e950d6f1
KH
1745{
1746 Lisp_Object val;
d311d28c
PE
1747 ptrdiff_t i;
1748 int j;
e950d6f1
KH
1749
1750 CHECK_VECTOR (gstring);
1751 val = AREF (gstring, 0);
1752 CHECK_VECTOR (val);
1753 if (ASIZE (val) < LGSTRING_HEADER_SIZE)
1754 goto err;
1755 CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
f9ffa1ea
SM
1756 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING)))
1757 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING));
1758 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING)))
1759 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING));
1760 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH)))
1761 CHECK_NATNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH));
1762 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1763 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
1764 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1765 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
e950d6f1 1766
071132a9 1767 for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
e950d6f1
KH
1768 {
1769 val = LGSTRING_GLYPH (gstring, i);
1770 CHECK_VECTOR (val);
1771 if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
1772 goto err;
f9ffa1ea 1773 if (NILP (AREF (val, LGLYPH_IX_CHAR)))
e950d6f1 1774 break;
f9ffa1ea
SM
1775 CHECK_NATNUM (AREF (val, LGLYPH_IX_FROM));
1776 CHECK_NATNUM (AREF (val, LGLYPH_IX_TO));
1777 CHECK_CHARACTER (AREF (val, LGLYPH_IX_CHAR));
1778 if (!NILP (AREF (val, LGLYPH_IX_CODE)))
1779 CHECK_NATNUM (AREF (val, LGLYPH_IX_CODE));
1780 if (!NILP (AREF (val, LGLYPH_IX_WIDTH)))
1781 CHECK_NATNUM (AREF (val, LGLYPH_IX_WIDTH));
1782 if (!NILP (AREF (val, LGLYPH_IX_ADJUSTMENT)))
e950d6f1 1783 {
f9ffa1ea 1784 val = AREF (val, LGLYPH_IX_ADJUSTMENT);
e950d6f1
KH
1785 CHECK_VECTOR (val);
1786 if (ASIZE (val) < 3)
1787 goto err;
1788 for (j = 0; j < 3; j++)
1789 CHECK_NUMBER (AREF (val, j));
1790 }
1791 }
1792 return i;
1793 err:
1794 error ("Invalid glyph-string format");
1795 return -1;
1796}
1797
cf385d93 1798static void
1dae0f0a 1799check_otf_features (Lisp_Object otf_features)
cf385d93 1800{
35027d0c 1801 Lisp_Object val;
cf385d93
KH
1802
1803 CHECK_CONS (otf_features);
1804 CHECK_SYMBOL (XCAR (otf_features));
1805 otf_features = XCDR (otf_features);
1806 CHECK_CONS (otf_features);
1807 CHECK_SYMBOL (XCAR (otf_features));
1808 otf_features = XCDR (otf_features);
7d7bbefd 1809 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
cf385d93 1810 {
34348bd4 1811 CHECK_SYMBOL (XCAR (val));
cf385d93 1812 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
e6c3da20
EZ
1813 error ("Invalid OTF GSUB feature: %s",
1814 SDATA (SYMBOL_NAME (XCAR (val))));
cf385d93
KH
1815 }
1816 otf_features = XCDR (otf_features);
7d7bbefd 1817 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
cf385d93 1818 {
34348bd4 1819 CHECK_SYMBOL (XCAR (val));
cf385d93 1820 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
e6c3da20
EZ
1821 error ("Invalid OTF GPOS feature: %s",
1822 SDATA (SYMBOL_NAME (XCAR (val))));
cf385d93
KH
1823 }
1824}
1825
c2f5bfd6
KH
1826#ifdef HAVE_LIBOTF
1827#include <otf.h>
1828
733fd013 1829Lisp_Object otf_list;
c2f5bfd6
KH
1830
1831static Lisp_Object
1dae0f0a 1832otf_tag_symbol (OTF_Tag tag)
c2f5bfd6
KH
1833{
1834 char name[5];
1835
1836 OTF_tag_name (tag, name);
1837 return Fintern (make_unibyte_string (name, 4), Qnil);
1838}
1839
1840static OTF *
1dae0f0a 1841otf_open (Lisp_Object file)
c2f5bfd6 1842{
35027d0c 1843 Lisp_Object val = Fassoc (file, otf_list);
733fd013
KH
1844 OTF *otf;
1845
1846 if (! NILP (val))
1847 otf = XSAVE_VALUE (XCDR (val))->pointer;
1848 else
c2f5bfd6 1849 {
51b59d79 1850 otf = STRINGP (file) ? OTF_open (SSDATA (file)) : NULL;
733fd013 1851 val = make_save_value (otf, 0);
35027d0c 1852 otf_list = Fcons (Fcons (file, val), otf_list);
c2f5bfd6 1853 }
733fd013 1854 return otf;
c2f5bfd6
KH
1855}
1856
1857
1858/* Return a list describing which scripts/languages FONT supports by
1859 which GSUB/GPOS features of OpenType tables. See the comment of
51c01100 1860 (struct font_driver).otf_capability. */
c2f5bfd6
KH
1861
1862Lisp_Object
1dae0f0a 1863font_otf_capability (struct font *font)
c2f5bfd6
KH
1864{
1865 OTF *otf;
1866 Lisp_Object capability = Fcons (Qnil, Qnil);
1867 int i;
1868
35027d0c 1869 otf = otf_open (font->props[FONT_FILE_INDEX]);
c2f5bfd6
KH
1870 if (! otf)
1871 return Qnil;
1872 for (i = 0; i < 2; i++)
1873 {
1874 OTF_GSUB_GPOS *gsub_gpos;
1875 Lisp_Object script_list = Qnil;
1876 int j;
1877
1878 if (OTF_get_features (otf, i == 0) < 0)
1879 continue;
1880 gsub_gpos = i == 0 ? otf->gsub : otf->gpos;
1881 for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--)
1882 {
1883 OTF_Script *script = gsub_gpos->ScriptList.Script + j;
1884 Lisp_Object langsys_list = Qnil;
1885 Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag);
1886 int k;
1887
1888 for (k = script->LangSysCount; k >= 0; k--)
1889 {
1890 OTF_LangSys *langsys;
1891 Lisp_Object feature_list = Qnil;
1892 Lisp_Object langsys_tag;
1893 int l;
1894
e80e09b4 1895 if (k == script->LangSysCount)
c2f5bfd6
KH
1896 {
1897 langsys = &script->DefaultLangSys;
1898 langsys_tag = Qnil;
1899 }
1900 else
1901 {
1902 langsys = script->LangSys + k;
1903 langsys_tag
1904 = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
1905 }
e80e09b4 1906 for (l = langsys->FeatureCount - 1; l >= 0; l--)
c2f5bfd6
KH
1907 {
1908 OTF_Feature *feature
1909 = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
1910 Lisp_Object feature_tag
1911 = otf_tag_symbol (feature->FeatureTag);
1912
1913 feature_list = Fcons (feature_tag, feature_list);
1914 }
1915 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
1916 langsys_list);
1917 }
1918 script_list = Fcons (Fcons (script_tag, langsys_list),
1919 script_list);
1920 }
1921
1922 if (i == 0)
1923 XSETCAR (capability, script_list);
1924 else
1925 XSETCDR (capability, script_list);
1926 }
1927
1928 return capability;
1929}
1930
733fd013
KH
1931/* Parse OTF features in SPEC and write a proper features spec string
1932 in FEATURES for the call of OTF_drive_gsub/gpos (of libotf). It is
1933 assured that the sufficient memory has already allocated for
1934 FEATURES. */
1935
e80e09b4 1936static void
1dae0f0a 1937generate_otf_features (Lisp_Object spec, char *features)
c2f5bfd6
KH
1938{
1939 Lisp_Object val;
35027d0c 1940 char *p;
a864ef14 1941 bool asterisk;
c2f5bfd6 1942
733fd013 1943 p = features;
e80e09b4 1944 *p = '\0';
c2f5bfd6
KH
1945 for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
1946 {
1947 val = XCAR (spec);
e80e09b4
KH
1948 CHECK_SYMBOL (val);
1949 if (p > features)
733fd013 1950 *p++ = ',';
c2f5bfd6
KH
1951 if (SREF (SYMBOL_NAME (val), 0) == '*')
1952 {
1953 asterisk = 1;
e80e09b4 1954 *p++ = '*';
c2f5bfd6
KH
1955 }
1956 else if (! asterisk)
e80e09b4
KH
1957 {
1958 val = SYMBOL_NAME (val);
c21721cc 1959 p += esprintf (p, "%s", SDATA (val));
e80e09b4 1960 }
c2f5bfd6 1961 else
e80e09b4
KH
1962 {
1963 val = SYMBOL_NAME (val);
c21721cc 1964 p += esprintf (p, "~%s", SDATA (val));
e80e09b4 1965 }
c2f5bfd6 1966 }
e80e09b4
KH
1967 if (CONSP (spec))
1968 error ("OTF spec too long");
1969}
1970
733fd013 1971Lisp_Object
1dae0f0a 1972font_otf_DeviceTable (OTF_DeviceTable *device_table)
733fd013
KH
1973{
1974 int len = device_table->StartSize - device_table->EndSize + 1;
1975
1976 return Fcons (make_number (len),
1977 make_unibyte_string (device_table->DeltaValue, len));
1978}
1979
1980Lisp_Object
1dae0f0a 1981font_otf_ValueRecord (int value_format, OTF_ValueRecord *value_record)
733fd013
KH
1982{
1983 Lisp_Object val = Fmake_vector (make_number (8), Qnil);
1984
1985 if (value_format & OTF_XPlacement)
43c0454d 1986 ASET (val, 0, make_number (value_record->XPlacement));
733fd013 1987 if (value_format & OTF_YPlacement)
43c0454d 1988 ASET (val, 1, make_number (value_record->YPlacement));
733fd013 1989 if (value_format & OTF_XAdvance)
43c0454d 1990 ASET (val, 2, make_number (value_record->XAdvance));
733fd013 1991 if (value_format & OTF_YAdvance)
43c0454d 1992 ASET (val, 3, make_number (value_record->YAdvance));
733fd013
KH
1993 if (value_format & OTF_XPlaDevice)
1994 ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
1995 if (value_format & OTF_YPlaDevice)
1996 ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
1997 if (value_format & OTF_XAdvDevice)
1998 ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
1999 if (value_format & OTF_YAdvDevice)
2000 ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
2001 return val;
2002}
2003
2004Lisp_Object
1dae0f0a 2005font_otf_Anchor (OTF_Anchor *anchor)
733fd013
KH
2006{
2007 Lisp_Object val;
2008
2009 val = Fmake_vector (make_number (anchor->AnchorFormat + 1), Qnil);
2010 ASET (val, 0, make_number (anchor->XCoordinate));
2011 ASET (val, 1, make_number (anchor->YCoordinate));
2012 if (anchor->AnchorFormat == 2)
2013 ASET (val, 2, make_number (anchor->f.f1.AnchorPoint));
2014 else
2015 {
2016 ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
2017 ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
2018 }
2019 return val;
2020}
c2f5bfd6 2021#endif /* HAVE_LIBOTF */
6a3dadd2 2022#endif /* 0 */
c2f5bfd6 2023
c2f5bfd6
KH
2024\f
2025/* Font sorting */
2026
f57e2426
J
2027static unsigned font_score (Lisp_Object, Lisp_Object *);
2028static int font_compare (const void *, const void *);
2029static Lisp_Object font_sort_entities (Lisp_Object, Lisp_Object,
2030 Lisp_Object, int);
c2f5bfd6 2031
55e41770 2032static double
971de7fb 2033font_rescale_ratio (Lisp_Object font_entity)
55e41770
KH
2034{
2035 Lisp_Object tail, elt;
2036 Lisp_Object name = Qnil;
2037
2038 for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail))
2039 {
2040 elt = XCAR (tail);
2041 if (FLOATP (XCDR (elt)))
2042 {
2043 if (STRINGP (XCAR (elt)))
2044 {
2045 if (NILP (name))
2046 name = Ffont_xlfd_name (font_entity, Qnil);
2047 if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
2048 return XFLOAT_DATA (XCDR (elt));
2049 }
2050 else if (FONT_SPEC_P (XCAR (elt)))
2051 {
2052 if (font_match_p (XCAR (elt), font_entity))
2053 return XFLOAT_DATA (XCDR (elt));
2054 }
2055 }
2056 }
2057 return 1.0;
2058}
2059
c2f5bfd6
KH
2060/* We sort fonts by scoring each of them against a specified
2061 font-spec. The score value is 32 bit (`unsigned'), and the smaller
2062 the value is, the closer the font is to the font-spec.
2063
56dd2d86 2064 The lowest 2 bits of the score are used for driver type. The font
4007dd1c 2065 available by the most preferred font driver is 0.
35027d0c 2066
56dd2d86 2067 The 4 7-bit fields in the higher 28 bits are used for numeric properties
c2f5bfd6
KH
2068 WEIGHT, SLANT, WIDTH, and SIZE. */
2069
2070/* How many bits to shift to store the difference value of each font
56dd2d86 2071 property in a score. Note that floats for FONT_TYPE_INDEX and
35027d0c 2072 FONT_REGISTRY_INDEX are not used. */
c2f5bfd6
KH
2073static int sort_shift_bits[FONT_SIZE_INDEX + 1];
2074
9331887d
KH
2075/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
2076 The return value indicates how different ENTITY is compared with
51c13510 2077 SPEC_PROP. */
c2f5bfd6
KH
2078
2079static unsigned
971de7fb 2080font_score (Lisp_Object entity, Lisp_Object *spec_prop)
c2f5bfd6
KH
2081{
2082 unsigned score = 0;
2083 int i;
c2f5bfd6 2084
35027d0c
KH
2085 /* Score three style numeric fields. Maximum difference is 127. */
2086 for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
2087 if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
2088 {
790771b1
PE
2089 EMACS_INT diff = ((XINT (AREF (entity, i)) >> 8)
2090 - (XINT (spec_prop[i]) >> 8));
35027d0c
KH
2091 if (diff < 0)
2092 diff = - diff;
790771b1 2093 score |= min (diff, 127) << sort_shift_bits[i];
35027d0c
KH
2094 }
2095
2096 /* Score the size. Maximum difference is 127. */
2097 i = FONT_SIZE_INDEX;
55e41770
KH
2098 if (! NILP (spec_prop[FONT_SIZE_INDEX])
2099 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
35027d0c
KH
2100 {
2101 /* We use the higher 6-bit for the actual size difference. The
2102 lowest bit is set if the DPI is different. */
b79e8648
PE
2103 EMACS_INT diff;
2104 EMACS_INT pixel_size = XINT (spec_prop[FONT_SIZE_INDEX]);
35027d0c 2105
55e41770
KH
2106 if (CONSP (Vface_font_rescale_alist))
2107 pixel_size *= font_rescale_ratio (entity);
2108 diff = pixel_size - XINT (AREF (entity, FONT_SIZE_INDEX));
35027d0c
KH
2109 if (diff < 0)
2110 diff = - diff;
d0ab1ebe 2111 diff <<= 1;
35027d0c
KH
2112 if (! NILP (spec_prop[FONT_DPI_INDEX])
2113 && ! EQ (spec_prop[FONT_DPI_INDEX], AREF (entity, FONT_DPI_INDEX)))
2114 diff |= 1;
c0a6070d
KH
2115 if (! NILP (spec_prop[FONT_AVGWIDTH_INDEX])
2116 && ! EQ (spec_prop[FONT_AVGWIDTH_INDEX], AREF (entity, FONT_AVGWIDTH_INDEX)))
2117 diff |= 1;
35027d0c 2118 score |= min (diff, 127) << sort_shift_bits[FONT_SIZE_INDEX];
c2f5bfd6
KH
2119 }
2120
2121 return score;
2122}
2123
2124
72d36834
KH
2125/* Concatenate all elements of LIST into one vector. LIST is a list
2126 of font-entity vectors. */
c2f5bfd6 2127
72d36834
KH
2128static Lisp_Object
2129font_vconcat_entity_vectors (Lisp_Object list)
c2f5bfd6 2130{
72d36834 2131 int nargs = XINT (Flength (list));
663e2b3f 2132 Lisp_Object *args = alloca (word_size * nargs);
72d36834
KH
2133 int i;
2134
2135 for (i = 0; i < nargs; i++, list = XCDR (list))
2136 args[i] = XCAR (list);
2137 return Fvconcat (nargs, args);
c2f5bfd6
KH
2138}
2139
2140
2141/* The structure for elements being sorted by qsort. */
2142struct font_sort_data
2143{
2144 unsigned score;
72d36834 2145 int font_driver_preference;
c2f5bfd6
KH
2146 Lisp_Object entity;
2147};
2148
2149
72d36834
KH
2150/* The comparison function for qsort. */
2151
2152static int
971de7fb 2153font_compare (const void *d1, const void *d2)
72d36834
KH
2154{
2155 const struct font_sort_data *data1 = d1;
2156 const struct font_sort_data *data2 = d2;
2157
2158 if (data1->score < data2->score)
2159 return -1;
2160 else if (data1->score > data2->score)
2161 return 1;
2162 return (data1->font_driver_preference - data2->font_driver_preference);
2163}
2164
2165
2166/* Sort each font-entity vector in LIST by closeness to font-spec PREFER.
c2f5bfd6 2167 If PREFER specifies a point-size, calculate the corresponding
9331887d 2168 pixel-size from QCdpi property of PREFER or from the Y-resolution
7181ea6a 2169 of FRAME before sorting.
35027d0c 2170
c9477f01
KH
2171 If BEST-ONLY is nonzero, return the best matching entity (that
2172 supports the character BEST-ONLY if BEST-ONLY is positive, or any
72d36834
KH
2173 if BEST-ONLY is negative). Otherwise, return the sorted result as
2174 a single vector of font-entities.
c9477f01 2175
72d36834
KH
2176 This function does no optimization for the case that the total
2177 number of elements is 1. The caller should avoid calling this in
2178 such a case. */
c2f5bfd6
KH
2179
2180static Lisp_Object
971de7fb 2181font_sort_entities (Lisp_Object list, Lisp_Object prefer, Lisp_Object frame, int best_only)
c2f5bfd6 2182{
9331887d 2183 Lisp_Object prefer_prop[FONT_SPEC_MAX];
72d36834 2184 int len, maxlen, i;
c2f5bfd6 2185 struct font_sort_data *data;
35027d0c 2186 unsigned best_score;
72d36834 2187 Lisp_Object best_entity;
4007dd1c 2188 struct frame *f = XFRAME (frame);
5ad03b97 2189 Lisp_Object tail, vec IF_LINT (= Qnil);
c2f5bfd6
KH
2190 USE_SAFE_ALLOCA;
2191
9903d1e6 2192 for (i = FONT_WEIGHT_INDEX; i <= FONT_AVGWIDTH_INDEX; i++)
9331887d 2193 prefer_prop[i] = AREF (prefer, i);
9331887d
KH
2194 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2195 prefer_prop[FONT_SIZE_INDEX]
2196 = make_number (font_pixel_size (XFRAME (frame), prefer));
2197
72d36834
KH
2198 if (NILP (XCDR (list)))
2199 {
2200 /* What we have to take care of is this single vector. */
2201 vec = XCAR (list);
2202 maxlen = ASIZE (vec);
2203 }
2204 else if (best_only)
2205 {
2206 /* We don't have to perform sort, so there's no need of creating
2207 a single vector. But, we must find the length of the longest
2208 vector. */
2209 maxlen = 0;
2210 for (tail = list; CONSP (tail); tail = XCDR (tail))
2211 if (maxlen < ASIZE (XCAR (tail)))
2212 maxlen = ASIZE (XCAR (tail));
2213 }
2214 else
2215 {
2216 /* We have to create a single vector to sort it. */
2217 vec = font_vconcat_entity_vectors (list);
2218 maxlen = ASIZE (vec);
2219 }
2220
98c6f1e3 2221 data = SAFE_ALLOCA (maxlen * sizeof *data);
c9477f01
KH
2222 best_score = 0xFFFFFFFF;
2223 best_entity = Qnil;
72d36834
KH
2224
2225 for (tail = list; CONSP (tail); tail = XCDR (tail))
c2f5bfd6 2226 {
72d36834
KH
2227 int font_driver_preference = 0;
2228 Lisp_Object current_font_driver;
ce75f06e 2229
72d36834
KH
2230 if (best_only)
2231 vec = XCAR (tail);
2232 len = ASIZE (vec);
2233
2234 /* We are sure that the length of VEC > 0. */
2235 current_font_driver = AREF (AREF (vec, 0), FONT_TYPE_INDEX);
2236 /* Score the elements. */
2237 for (i = 0; i < len; i++)
35027d0c 2238 {
72d36834
KH
2239 data[i].entity = AREF (vec, i);
2240 data[i].score
2241 = ((best_only <= 0 || font_has_char (f, data[i].entity, best_only)
2242 > 0)
2243 ? font_score (data[i].entity, prefer_prop)
2244 : 0xFFFFFFFF);
2245 if (best_only && best_score > data[i].score)
2246 {
2247 best_score = data[i].score;
2248 best_entity = data[i].entity;
2249 if (best_score == 0)
2250 break;
2251 }
2252 if (! EQ (current_font_driver, AREF (AREF (vec, i), FONT_TYPE_INDEX)))
2253 {
2254 current_font_driver = AREF (AREF (vec, i), FONT_TYPE_INDEX);
2255 font_driver_preference++;
2256 }
2257 data[i].font_driver_preference = font_driver_preference;
35027d0c 2258 }
72d36834
KH
2259
2260 /* Sort if necessary. */
2261 if (! best_only)
2262 {
2263 qsort (data, len, sizeof *data, font_compare);
2264 for (i = 0; i < len; i++)
2265 ASET (vec, i, data[i].entity);
2266 break;
2267 }
2268 else
2269 vec = best_entity;
c2f5bfd6 2270 }
72d36834 2271
c2f5bfd6
KH
2272 SAFE_FREE ();
2273
652b9560 2274 FONT_ADD_LOG ("sort-by", prefer, vec);
c2f5bfd6
KH
2275 return vec;
2276}
2277
2278\f
2279/* API of Font Service Layer. */
2280
45eb10fb
KH
2281/* Reflect ORDER (see the variable font_sort_order in xfaces.c) to
2282 sort_shift_bits. Finternal_set_font_selection_order calls this
2283 function with font_sort_order after setting up it. */
2284
c2f5bfd6 2285void
971de7fb 2286font_update_sort_order (int *order)
c2f5bfd6 2287{
35027d0c 2288 int i, shift_bits;
c2f5bfd6 2289
943b7eea 2290 for (i = 0, shift_bits = 23; i < 4; i++, shift_bits -= 7)
c2f5bfd6
KH
2291 {
2292 int xlfd_idx = order[i];
2293
2294 if (xlfd_idx == XLFD_WEIGHT_INDEX)
2295 sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits;
2296 else if (xlfd_idx == XLFD_SLANT_INDEX)
2297 sort_shift_bits[FONT_SLANT_INDEX] = shift_bits;
2298 else if (xlfd_idx == XLFD_SWIDTH_INDEX)
2299 sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits;
2300 else
2301 sort_shift_bits[FONT_SIZE_INDEX] = shift_bits;
2302 }
2303}
2304
a864ef14
PE
2305static bool
2306font_check_otf_features (Lisp_Object script, Lisp_Object langsys,
2307 Lisp_Object features, Lisp_Object table)
51c13510
KH
2308{
2309 Lisp_Object val;
a864ef14 2310 bool negative;
51c13510
KH
2311
2312 table = assq_no_quit (script, table);
2313 if (NILP (table))
2314 return 0;
2315 table = XCDR (table);
2316 if (! NILP (langsys))
2317 {
2318 table = assq_no_quit (langsys, table);
2319 if (NILP (table))
2320 return 0;
2321 }
2322 else
2323 {
2324 val = assq_no_quit (Qnil, table);
2325 if (NILP (val))
2326 table = XCAR (table);
2327 else
2328 table = val;
2329 }
2330 table = XCDR (table);
2331 for (negative = 0; CONSP (features); features = XCDR (features))
2332 {
2333 if (NILP (XCAR (features)))
c423ecca
KH
2334 {
2335 negative = 1;
2336 continue;
2337 }
51c13510
KH
2338 if (NILP (Fmemq (XCAR (features), table)) != negative)
2339 return 0;
2340 }
2341 return 1;
2342}
2343
2344/* Check if OTF_CAPABILITY satisfies SPEC (otf-spec). */
2345
a864ef14 2346static bool
3cba9369 2347font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
51c13510
KH
2348{
2349 Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
2350
2351 script = XCAR (spec);
2352 spec = XCDR (spec);
2353 if (! NILP (spec))
2354 {
2355 langsys = XCAR (spec);
2356 spec = XCDR (spec);
2357 if (! NILP (spec))
2358 {
2359 gsub = XCAR (spec);
2360 spec = XCDR (spec);
2361 if (! NILP (spec))
2362 gpos = XCAR (spec);
2363 }
2364 }
2365
2366 if (! NILP (gsub) && ! font_check_otf_features (script, langsys, gsub,
2367 XCAR (otf_capability)))
2368 return 0;
2369 if (! NILP (gpos) && ! font_check_otf_features (script, langsys, gpos,
2370 XCDR (otf_capability)))
2371 return 0;
2372 return 1;
2373}
2374
45eb10fb 2375
51c13510
KH
2376
2377/* Check if FONT (font-entity or font-object) matches with the font
2378 specification SPEC. */
45eb10fb 2379
a864ef14 2380bool
971de7fb 2381font_match_p (Lisp_Object spec, Lisp_Object font)
ef18374f 2382{
51c13510
KH
2383 Lisp_Object prop[FONT_SPEC_MAX], *props;
2384 Lisp_Object extra, font_extra;
ef18374f
KH
2385 int i;
2386
51c13510
KH
2387 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
2388 if (! NILP (AREF (spec, i))
2389 && ! NILP (AREF (font, i))
2390 && ! EQ (AREF (spec, i), AREF (font, i)))
2391 return 0;
2392 props = XFONT_SPEC (spec)->props;
2393 if (FLOATP (props[FONT_SIZE_INDEX]))
2394 {
2395 for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
2396 prop[i] = AREF (spec, i);
2397 prop[FONT_SIZE_INDEX]
2398 = make_number (font_pixel_size (XFRAME (selected_frame), spec));
2399 props = prop;
2400 }
2401
2402 if (font_score (font, props) > 0)
2403 return 0;
2404 extra = AREF (spec, FONT_EXTRA_INDEX);
2405 font_extra = AREF (font, FONT_EXTRA_INDEX);
2406 for (; CONSP (extra); extra = XCDR (extra))
35027d0c 2407 {
51c13510
KH
2408 Lisp_Object key = XCAR (XCAR (extra));
2409 Lisp_Object val = XCDR (XCAR (extra)), val2;
2410
2411 if (EQ (key, QClang))
2412 {
2413 val2 = assq_no_quit (key, font_extra);
2414 if (NILP (val2))
2415 return 0;
2416 val2 = XCDR (val2);
2417 if (CONSP (val))
2418 {
2419 if (! CONSP (val2))
2420 return 0;
2421 while (CONSP (val))
2422 if (NILP (Fmemq (val, val2)))
2423 return 0;
2424 }
2425 else
2426 if (CONSP (val2)
2427 ? NILP (Fmemq (val, XCDR (val2)))
2428 : ! EQ (val, val2))
2429 return 0;
2430 }
2431 else if (EQ (key, QCscript))
2432 {
2433 val2 = assq_no_quit (val, Vscript_representative_chars);
5bdd4dd2
KH
2434 if (CONSP (val2))
2435 {
2436 val2 = XCDR (val2);
2437 if (CONSP (val2))
2438 {
2439 /* All characters in the list must be supported. */
2440 for (; CONSP (val2); val2 = XCDR (val2))
2441 {
d311d28c 2442 if (! CHARACTERP (XCAR (val2)))
5bdd4dd2
KH
2443 continue;
2444 if (font_encode_char (font, XFASTINT (XCAR (val2)))
2445 == FONT_INVALID_CODE)
2446 return 0;
2447 }
2448 }
2449 else if (VECTORP (val2))
2450 {
2451 /* At most one character in the vector must be supported. */
2452 for (i = 0; i < ASIZE (val2); i++)
2453 {
d311d28c 2454 if (! CHARACTERP (AREF (val2, i)))
5bdd4dd2
KH
2455 continue;
2456 if (font_encode_char (font, XFASTINT (AREF (val2, i)))
2457 != FONT_INVALID_CODE)
f5485732 2458 break;
5bdd4dd2
KH
2459 }
2460 if (i == ASIZE (val2))
2461 return 0;
2462 }
2463 }
51c13510
KH
2464 }
2465 else if (EQ (key, QCotf))
2466 {
2467 struct font *fontp;
2468
2469 if (! FONT_OBJECT_P (font))
2470 return 0;
2471 fontp = XFONT_OBJECT (font);
2472 if (! fontp->driver->otf_capability)
2473 return 0;
2474 val2 = fontp->driver->otf_capability (fontp);
2475 if (NILP (val2) || ! font_check_otf (val, val2))
2476 return 0;
2477 }
35027d0c
KH
2478 }
2479
51c13510 2480 return 1;
ef18374f 2481}
ca4da08a 2482\f
819e81df 2483
ca4da08a
KH
2484/* Font cache
2485
2486 Each font backend has the callback function get_cache, and it
2487 returns a cons cell of which cdr part can be freely used for
2488 caching fonts. The cons cell may be shared by multiple frames
2489 and/or multiple font drivers. So, we arrange the cdr part as this:
2490
2491 ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...)
2492
2493 where DRIVER-TYPE is a symbol such as `x', `xft', etc., NUM-FRAMES
2494 is a number frames sharing this cache, and FONT-CACHE-DATA is a
2495 cons (FONT-SPEC FONT-ENTITY ...). */
2496
f57e2426
J
2497static void font_prepare_cache (FRAME_PTR, struct font_driver *);
2498static void font_finish_cache (FRAME_PTR, struct font_driver *);
2499static Lisp_Object font_get_cache (FRAME_PTR, struct font_driver *);
2500static void font_clear_cache (FRAME_PTR, Lisp_Object,
2501 struct font_driver *);
ca4da08a
KH
2502
2503static void
971de7fb 2504font_prepare_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2505{
2506 Lisp_Object cache, val;
2507
2508 cache = driver->get_cache (f);
2509 val = XCDR (cache);
2510 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2511 val = XCDR (val);
2512 if (NILP (val))
2513 {
2514 val = Fcons (driver->type, Fcons (make_number (1), Qnil));
2515 XSETCDR (cache, Fcons (val, XCDR (cache)));
2516 }
2517 else
2518 {
2519 val = XCDR (XCAR (val));
2520 XSETCAR (val, make_number (XINT (XCAR (val)) + 1));
2521 }
2522}
2523
43c0454d 2524
ca4da08a 2525static void
971de7fb 2526font_finish_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2527{
2528 Lisp_Object cache, val, tmp;
2529
2530
2531 cache = driver->get_cache (f);
2532 val = XCDR (cache);
2533 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2534 cache = val, val = XCDR (val);
4e6a86c6 2535 eassert (! NILP (val));
ca4da08a 2536 tmp = XCDR (XCAR (val));
43c0454d 2537 XSETCAR (tmp, make_number (XINT (XCAR (tmp)) - 1));
ca4da08a
KH
2538 if (XINT (XCAR (tmp)) == 0)
2539 {
2540 font_clear_cache (f, XCAR (val), driver);
2541 XSETCDR (cache, XCDR (val));
2542 }
ca4da08a
KH
2543}
2544
43c0454d 2545
ca4da08a 2546static Lisp_Object
971de7fb 2547font_get_cache (FRAME_PTR f, struct font_driver *driver)
ca4da08a
KH
2548{
2549 Lisp_Object val = driver->get_cache (f);
2550 Lisp_Object type = driver->type;
2551
4e6a86c6 2552 eassert (CONSP (val));
ca4da08a 2553 for (val = XCDR (val); ! EQ (XCAR (XCAR (val)), type); val = XCDR (val));
4e6a86c6 2554 eassert (CONSP (val));
ca4da08a
KH
2555 /* VAL = ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...) */
2556 val = XCDR (XCAR (val));
2557 return val;
2558}
2559
43c0454d
KH
2560static int num_fonts;
2561
ca4da08a 2562static void
971de7fb 2563font_clear_cache (FRAME_PTR f, Lisp_Object cache, struct font_driver *driver)
ca4da08a
KH
2564{
2565 Lisp_Object tail, elt;
6136b72f 2566 Lisp_Object tail2, entity;
51c01100 2567
ca4da08a
KH
2568 /* CACHE = (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) */
2569 for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
2570 {
2571 elt = XCAR (tail);
6136b72f
CY
2572 /* elt should have the form (FONT-SPEC FONT-ENTITY ...) */
2573 if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
ca4da08a 2574 {
6136b72f 2575 for (tail2 = XCDR (elt); CONSP (tail2); tail2 = XCDR (tail2))
ca4da08a 2576 {
6136b72f 2577 entity = XCAR (tail2);
ca4da08a 2578
6136b72f
CY
2579 if (FONT_ENTITY_P (entity)
2580 && EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
ca4da08a
KH
2581 {
2582 Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
2583
2584 for (; CONSP (objlist); objlist = XCDR (objlist))
2585 {
2586 Lisp_Object val = XCAR (objlist);
35027d0c 2587 struct font *font = XFONT_OBJECT (val);
ca4da08a 2588
5e634ec9
KH
2589 if (! NILP (AREF (val, FONT_TYPE_INDEX)))
2590 {
4e6a86c6 2591 eassert (font && driver == font->driver);
5e634ec9
KH
2592 driver->close (f, font);
2593 num_fonts--;
2594 }
ca4da08a
KH
2595 }
2596 if (driver->free_entity)
2597 driver->free_entity (entity);
2598 }
2599 }
2600 }
2601 }
2602 XSETCDR (cache, Qnil);
2603}
2604\f
2605
c2f5bfd6
KH
2606static Lisp_Object scratch_font_spec, scratch_font_prefer;
2607
7d56b2dd 2608/* Check each font-entity in VEC, and return a list of font-entities
56dd2d86 2609 that satisfy these conditions:
7d56b2dd
KH
2610 (1) matches with SPEC and SIZE if SPEC is not nil, and
2611 (2) doesn't match with any regexps in Vface_ignored_fonts (if non-nil).
2612*/
2613
7b81e2d0 2614static Lisp_Object
971de7fb 2615font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
35027d0c 2616{
d0ab1ebe 2617 Lisp_Object entity, val;
35027d0c 2618 enum font_property_index prop;
72d36834 2619 int i;
45eb10fb 2620
72d36834 2621 for (val = Qnil, i = ASIZE (vec) - 1; i >= 0; i--)
35027d0c 2622 {
72d36834 2623 entity = AREF (vec, i);
7d56b2dd
KH
2624 if (! NILP (Vface_ignored_fonts))
2625 {
2626 char name[256];
d923b542 2627 ptrdiff_t namelen;
7d56b2dd
KH
2628 Lisp_Object tail, regexp;
2629
d923b542
DA
2630 namelen = font_unparse_xlfd (entity, 0, name, 256);
2631 if (namelen >= 0)
7d56b2dd
KH
2632 {
2633 for (tail = Vface_ignored_fonts; CONSP (tail); tail = XCDR (tail))
2634 {
2635 regexp = XCAR (tail);
2636 if (STRINGP (regexp)
d923b542
DA
2637 && fast_c_string_match_ignore_case (regexp, name,
2638 namelen) >= 0)
7d56b2dd
KH
2639 break;
2640 }
2641 if (CONSP (tail))
2642 continue;
2643 }
2644 }
2645 if (NILP (spec))
2646 {
2647 val = Fcons (entity, val);
2648 continue;
2649 }
35027d0c
KH
2650 for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
2651 if (INTEGERP (AREF (spec, prop))
2652 && ((XINT (AREF (spec, prop)) >> 8)
2653 != (XINT (AREF (entity, prop)) >> 8)))
2654 prop = FONT_SPEC_MAX;
7181ea6a 2655 if (prop < FONT_SPEC_MAX
35027d0c
KH
2656 && size
2657 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
2658 {
2659 int diff = XINT (AREF (entity, FONT_SIZE_INDEX)) - size;
c2f5bfd6 2660
35027d0c
KH
2661 if (diff != 0
2662 && (diff < 0 ? -diff > FONT_PIXEL_SIZE_QUANTUM
2663 : diff > FONT_PIXEL_SIZE_QUANTUM))
2664 prop = FONT_SPEC_MAX;
2665 }
7181ea6a
KH
2666 if (prop < FONT_SPEC_MAX
2667 && INTEGERP (AREF (spec, FONT_DPI_INDEX))
2668 && INTEGERP (AREF (entity, FONT_DPI_INDEX))
c576d6dc 2669 && XINT (AREF (entity, FONT_DPI_INDEX)) != 0
7181ea6a
KH
2670 && ! EQ (AREF (spec, FONT_DPI_INDEX), AREF (entity, FONT_DPI_INDEX)))
2671 prop = FONT_SPEC_MAX;
2672 if (prop < FONT_SPEC_MAX
2673 && INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
2674 && INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
c576d6dc 2675 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) != 0
7181ea6a
KH
2676 && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
2677 AREF (entity, FONT_AVGWIDTH_INDEX)))
2678 prop = FONT_SPEC_MAX;
35027d0c 2679 if (prop < FONT_SPEC_MAX)
d0ab1ebe 2680 val = Fcons (entity, val);
35027d0c 2681 }
72d36834 2682 return (Fvconcat (1, &val));
35027d0c
KH
2683}
2684
2685
72d36834 2686/* Return a list of vectors of font-entities matching with SPEC on
ce75f06e
CY
2687 FRAME. Each elements in the list is a vector of entities from the
2688 same font-driver. */
35027d0c
KH
2689
2690Lisp_Object
971de7fb 2691font_list_entities (Lisp_Object frame, Lisp_Object spec)
c2f5bfd6
KH
2692{
2693 FRAME_PTR f = XFRAME (frame);
2694 struct font_driver_list *driver_list = f->font_driver_list;
4007dd1c 2695 Lisp_Object ftype, val;
72d36834 2696 Lisp_Object list = Qnil;
35027d0c 2697 int size;
a864ef14 2698 bool need_filtering = 0;
c2f5bfd6
KH
2699 int i;
2700
4e6a86c6 2701 eassert (FONT_SPEC_P (spec));
c2f5bfd6 2702
35027d0c
KH
2703 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
2704 size = XINT (AREF (spec, FONT_SIZE_INDEX));
2705 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2706 size = font_pixel_size (f, spec);
2707 else
2708 size = 0;
2709
c2f5bfd6 2710 ftype = AREF (spec, FONT_TYPE_INDEX);
4007dd1c 2711 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
35027d0c 2712 ASET (scratch_font_spec, i, AREF (spec, i));
4007dd1c 2713 for (i = FONT_WEIGHT_INDEX; i < FONT_EXTRA_INDEX; i++)
56201685
PE
2714 if (i != FONT_SPACING_INDEX)
2715 {
2716 ASET (scratch_font_spec, i, Qnil);
2717 if (! NILP (AREF (spec, i)))
2718 need_filtering = 1;
2719 }
aa50ca2f 2720 ASET (scratch_font_spec, FONT_SPACING_INDEX, AREF (spec, FONT_SPACING_INDEX));
35027d0c
KH
2721 ASET (scratch_font_spec, FONT_EXTRA_INDEX, AREF (spec, FONT_EXTRA_INDEX));
2722
c2f5bfd6 2723 for (i = 0; driver_list; driver_list = driver_list->next)
417a1b10
KH
2724 if (driver_list->on
2725 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
c2f5bfd6 2726 {
ca4da08a 2727 Lisp_Object cache = font_get_cache (f, driver_list->driver);
c2f5bfd6 2728
e4c93315 2729 ASET (scratch_font_spec, FONT_TYPE_INDEX, driver_list->driver->type);
4007dd1c
KH
2730 val = assoc_no_quit (scratch_font_spec, XCDR (cache));
2731 if (CONSP (val))
2732 val = XCDR (val);
2733 else
c2f5bfd6 2734 {
4007dd1c 2735 Lisp_Object copy;
35027d0c 2736
4007dd1c 2737 val = driver_list->driver->list (frame, scratch_font_spec);
72d36834 2738 if (NILP (val))
9730daca 2739 val = zero_vector;
72d36834
KH
2740 else
2741 val = Fvconcat (1, &val);
92470028 2742 copy = copy_font_spec (scratch_font_spec);
4007dd1c
KH
2743 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2744 XSETCDR (cache, Fcons (Fcons (copy, val), XCDR (cache)));
c2f5bfd6 2745 }
7d56b2dd
KH
2746 if (ASIZE (val) > 0
2747 && (need_filtering
2748 || ! NILP (Vface_ignored_fonts)))
2749 val = font_delete_unmatched (val, need_filtering ? spec : Qnil, size);
72d36834
KH
2750 if (ASIZE (val) > 0)
2751 list = Fcons (val, list);
c2f5bfd6 2752 }
35027d0c 2753
72d36834
KH
2754 list = Fnreverse (list);
2755 FONT_ADD_LOG ("list", spec, list);
2756 return list;
c2f5bfd6
KH
2757}
2758
45eb10fb 2759
35027d0c
KH
2760/* Return a font entity matching with SPEC on FRAME. ATTRS, if non
2761 nil, is an array of face's attributes, which specifies preferred
2762 font-related attributes. */
45eb10fb 2763
e950d6f1 2764static Lisp_Object
971de7fb 2765font_matching_entity (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec)
e950d6f1 2766{
e950d6f1
KH
2767 struct font_driver_list *driver_list = f->font_driver_list;
2768 Lisp_Object ftype, size, entity;
35027d0c 2769 Lisp_Object frame;
92470028 2770 Lisp_Object work = copy_font_spec (spec);
e950d6f1 2771
35027d0c 2772 XSETFRAME (frame, f);
e950d6f1
KH
2773 ftype = AREF (spec, FONT_TYPE_INDEX);
2774 size = AREF (spec, FONT_SIZE_INDEX);
819ab95f 2775
8d0e382e
AR
2776 if (FLOATP (size))
2777 ASET (work, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
819ab95f
KH
2778 FONT_SET_STYLE (work, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2779 FONT_SET_STYLE (work, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2780 FONT_SET_STYLE (work, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
2781
e950d6f1
KH
2782 entity = Qnil;
2783 for (; driver_list; driver_list = driver_list->next)
2784 if (driver_list->on
2785 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2786 {
ca4da08a 2787 Lisp_Object cache = font_get_cache (f, driver_list->driver);
7cee5d63 2788 Lisp_Object copy;
e950d6f1 2789
819ab95f
KH
2790 ASET (work, FONT_TYPE_INDEX, driver_list->driver->type);
2791 entity = assoc_no_quit (work, XCDR (cache));
7cee5d63 2792 if (CONSP (entity))
e950d6f1
KH
2793 entity = XCDR (entity);
2794 else
2795 {
819ab95f 2796 entity = driver_list->driver->match (frame, work);
92470028 2797 copy = copy_font_spec (work);
7cee5d63
KH
2798 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2799 XSETCDR (cache, Fcons (Fcons (copy, entity), XCDR (cache)));
e950d6f1
KH
2800 }
2801 if (! NILP (entity))
2802 break;
2803 }
652b9560 2804 FONT_ADD_LOG ("match", work, entity);
e950d6f1
KH
2805 return entity;
2806}
2807
45eb10fb
KH
2808
2809/* Open a font of ENTITY and PIXEL_SIZE on frame F, and return the
2810 opened font object. */
2811
c2f5bfd6 2812static Lisp_Object
971de7fb 2813font_open_entity (FRAME_PTR f, Lisp_Object entity, int pixel_size)
c2f5bfd6
KH
2814{
2815 struct font_driver_list *driver_list;
43c0454d 2816 Lisp_Object objlist, size, val, font_object;
c2f5bfd6 2817 struct font *font;
d26424c5 2818 int min_width, height;
c2f5bfd6 2819
4e6a86c6 2820 eassert (FONT_ENTITY_P (entity));
c2f5bfd6 2821 size = AREF (entity, FONT_SIZE_INDEX);
c2f5bfd6 2822 if (XINT (size) != 0)
7e70a152 2823 pixel_size = XINT (size);
c2f5bfd6 2824
35027d0c
KH
2825 val = AREF (entity, FONT_TYPE_INDEX);
2826 for (driver_list = f->font_driver_list;
2827 driver_list && ! EQ (driver_list->driver->type, val);
2828 driver_list = driver_list->next);
2829 if (! driver_list)
2830 return Qnil;
c2f5bfd6 2831
d0cf45b7
JD
2832 for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
2833 objlist = XCDR (objlist))
2834 {
2835 Lisp_Object fn = XCAR (objlist);
2836 if (! NILP (AREF (fn, FONT_TYPE_INDEX))
2837 && XFONT_OBJECT (fn)->pixel_size == pixel_size)
2838 {
2839 if (driver_list->driver->cached_font_ok == NULL
2840 || driver_list->driver->cached_font_ok (f, fn, entity))
2841 return fn;
2842 }
2843 }
2844
7e70a152 2845 font_object = driver_list->driver->open (f, entity, pixel_size);
66f5ced0
YM
2846 if (!NILP (font_object))
2847 ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
652b9560 2848 FONT_ADD_LOG ("open", entity, font_object);
43c0454d 2849 if (NILP (font_object))
35027d0c
KH
2850 return Qnil;
2851 ASET (entity, FONT_OBJLIST_INDEX,
2852 Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
35027d0c
KH
2853 num_fonts++;
2854
2855 font = XFONT_OBJECT (font_object);
2856 min_width = (font->min_width ? font->min_width
2857 : font->average_width ? font->average_width
2858 : font->space_width ? font->space_width
2859 : 1);
d26424c5 2860 height = (font->height ? font->height : 1);
819e81df 2861#ifdef HAVE_WINDOW_SYSTEM
35027d0c
KH
2862 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
2863 if (FRAME_X_DISPLAY_INFO (f)->n_fonts == 1)
43c0454d 2864 {
35027d0c 2865 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
d26424c5 2866 FRAME_SMALLEST_FONT_HEIGHT (f) = height;
35027d0c
KH
2867 fonts_changed_p = 1;
2868 }
2869 else
2870 {
2871 if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
2872 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, fonts_changed_p = 1;
d26424c5
KH
2873 if (FRAME_SMALLEST_FONT_HEIGHT (f) > height)
2874 FRAME_SMALLEST_FONT_HEIGHT (f) = height, fonts_changed_p = 1;
43c0454d 2875 }
819e81df 2876#endif
43c0454d
KH
2877
2878 return font_object;
c2f5bfd6
KH
2879}
2880
45eb10fb
KH
2881
2882/* Close FONT_OBJECT that is opened on frame F. */
2883
239f9db9 2884static void
971de7fb 2885font_close_object (FRAME_PTR f, Lisp_Object font_object)
c2f5bfd6 2886{
35027d0c 2887 struct font *font = XFONT_OBJECT (font_object);
c2f5bfd6 2888
5e634ec9
KH
2889 if (NILP (AREF (font_object, FONT_TYPE_INDEX)))
2890 /* Already closed. */
2891 return;
652b9560 2892 FONT_ADD_LOG ("close", font_object, Qnil);
5e634ec9 2893 font->driver->close (f, font);
819e81df 2894#ifdef HAVE_WINDOW_SYSTEM
4e6a86c6 2895 eassert (FRAME_X_DISPLAY_INFO (f)->n_fonts);
5e634ec9 2896 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
819e81df 2897#endif
5e634ec9 2898 num_fonts--;
c2f5bfd6
KH
2899}
2900
45eb10fb 2901
1701724c
KH
2902/* Return 1 if FONT on F has a glyph for character C, 0 if not, -1 if
2903 FONT is a font-entity and it must be opened to check. */
45eb10fb 2904
c2f5bfd6 2905int
971de7fb 2906font_has_char (FRAME_PTR f, Lisp_Object font, int c)
c2f5bfd6 2907{
1b834a8d 2908 struct font *fontp;
c2f5bfd6 2909
1b834a8d
KH
2910 if (FONT_ENTITY_P (font))
2911 {
2912 Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
2913 struct font_driver_list *driver_list;
2914
2915 for (driver_list = f->font_driver_list;
2916 driver_list && ! EQ (driver_list->driver->type, type);
2917 driver_list = driver_list->next);
2918 if (! driver_list)
2919 return 0;
2920 if (! driver_list->driver->has_char)
2921 return -1;
2922 return driver_list->driver->has_char (font, c);
2923 }
2924
4e6a86c6 2925 eassert (FONT_OBJECT_P (font));
35027d0c 2926 fontp = XFONT_OBJECT (font);
1b834a8d
KH
2927 if (fontp->driver->has_char)
2928 {
35027d0c 2929 int result = fontp->driver->has_char (font, c);
1b834a8d
KH
2930
2931 if (result >= 0)
2932 return result;
2933 }
2934 return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
c2f5bfd6
KH
2935}
2936
45eb10fb
KH
2937
2938/* Return the glyph ID of FONT_OBJECT for character C. */
2939
2f7c71a1 2940static unsigned
971de7fb 2941font_encode_char (Lisp_Object font_object, int c)
c2f5bfd6 2942{
35027d0c 2943 struct font *font;
c2f5bfd6 2944
4e6a86c6 2945 eassert (FONT_OBJECT_P (font_object));
35027d0c 2946 font = XFONT_OBJECT (font_object);
c2f5bfd6
KH
2947 return font->driver->encode_char (font, c);
2948}
2949
45eb10fb
KH
2950
2951/* Return the name of FONT_OBJECT. */
2952
ef18374f 2953Lisp_Object
971de7fb 2954font_get_name (Lisp_Object font_object)
c2f5bfd6 2955{
4e6a86c6 2956 eassert (FONT_OBJECT_P (font_object));
35027d0c 2957 return AREF (font_object, FONT_NAME_INDEX);
ef18374f
KH
2958}
2959
45eb10fb 2960
05802645
CY
2961/* Create a new font spec from FONT_NAME, and return it. If FONT_NAME
2962 could not be parsed by font_parse_name, return Qnil. */
2963
35027d0c 2964Lisp_Object
971de7fb 2965font_spec_from_name (Lisp_Object font_name)
35027d0c 2966{
05802645 2967 Lisp_Object spec = Ffont_spec (0, NULL);
35027d0c 2968
05802645 2969 CHECK_STRING (font_name);
984e7f30 2970 if (font_parse_name (SSDATA (font_name), SBYTES (font_name), spec) == -1)
05802645
CY
2971 return Qnil;
2972 font_put_extra (spec, QCname, font_name);
42707278 2973 font_put_extra (spec, QCuser_spec, font_name);
05802645 2974 return spec;
35027d0c
KH
2975}
2976
45eb10fb 2977
35027d0c 2978void
971de7fb 2979font_clear_prop (Lisp_Object *attrs, enum font_property_index prop)
35027d0c
KH
2980{
2981 Lisp_Object font = attrs[LFACE_FONT_INDEX];
45eb10fb 2982
35027d0c
KH
2983 if (! FONTP (font))
2984 return;
42707278 2985
483670b5
KH
2986 if (! NILP (Ffont_get (font, QCname)))
2987 {
92470028 2988 font = copy_font_spec (font);
483670b5
KH
2989 font_put_extra (font, QCname, Qnil);
2990 }
2991
35027d0c 2992 if (NILP (AREF (font, prop))
e234927a
CY
2993 && prop != FONT_FAMILY_INDEX
2994 && prop != FONT_FOUNDRY_INDEX
2995 && prop != FONT_WIDTH_INDEX
4007dd1c 2996 && prop != FONT_SIZE_INDEX)
35027d0c 2997 return;
483670b5 2998 if (EQ (font, attrs[LFACE_FONT_INDEX]))
92470028 2999 font = copy_font_spec (font);
35027d0c 3000 ASET (font, prop, Qnil);
4007dd1c 3001 if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
35027d0c 3002 {
4007dd1c 3003 if (prop == FONT_FAMILY_INDEX)
962e8aa9
CY
3004 {
3005 ASET (font, FONT_FOUNDRY_INDEX, Qnil);
3006 /* If we are setting the font family, we must also clear
3007 FONT_WIDTH_INDEX to avoid rejecting families that lack
3008 support for some widths. */
3009 ASET (font, FONT_WIDTH_INDEX, Qnil);
3010 }
35027d0c 3011 ASET (font, FONT_ADSTYLE_INDEX, Qnil);
4007dd1c 3012 ASET (font, FONT_REGISTRY_INDEX, Qnil);
35027d0c
KH
3013 ASET (font, FONT_SIZE_INDEX, Qnil);
3014 ASET (font, FONT_DPI_INDEX, Qnil);
3015 ASET (font, FONT_SPACING_INDEX, Qnil);
3016 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3017 }
3018 else if (prop == FONT_SIZE_INDEX)
3019 {
3020 ASET (font, FONT_DPI_INDEX, Qnil);
3021 ASET (font, FONT_SPACING_INDEX, Qnil);
3022 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3023 }
e234927a
CY
3024 else if (prop == FONT_WIDTH_INDEX)
3025 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
35027d0c
KH
3026 attrs[LFACE_FONT_INDEX] = font;
3027}
3028
56dd2d86
EZ
3029/* Select a font from ENTITIES (list of font-entity vectors) that
3030 supports C and is the best match for ATTRS and PIXEL_SIZE. */
988a7ddb
KH
3031
3032static Lisp_Object
971de7fb 3033font_select_entity (Lisp_Object frame, Lisp_Object entities, Lisp_Object *attrs, int pixel_size, int c)
988a7ddb
KH
3034{
3035 Lisp_Object font_entity;
3036 Lisp_Object prefer;
a864ef14 3037 int i;
988a7ddb
KH
3038 FRAME_PTR f = XFRAME (frame);
3039
72d36834
KH
3040 if (NILP (XCDR (entities))
3041 && ASIZE (XCAR (entities)) == 1)
988a7ddb 3042 {
72d36834 3043 font_entity = AREF (XCAR (entities), 0);
a864ef14 3044 if (c < 0 || font_has_char (f, font_entity, c) > 0)
988a7ddb
KH
3045 return font_entity;
3046 return Qnil;
3047 }
3048
3049 /* Sort fonts by properties specified in ATTRS. */
3050 prefer = scratch_font_prefer;
3051
3052 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3053 ASET (prefer, i, Qnil);
3054 if (FONTP (attrs[LFACE_FONT_INDEX]))
3055 {
3056 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3057
3058 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3059 ASET (prefer, i, AREF (face_font, i));
3060 }
3061 if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
3062 FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
3063 if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
3064 FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
3065 if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
3066 FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
3067 ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
988a7ddb 3068
2645d15b 3069 return font_sort_entities (entities, prefer, frame, c);
988a7ddb
KH
3070}
3071
56dd2d86
EZ
3072/* Return a font-entity that satisfies SPEC and is the best match for
3073 face's font related attributes in ATTRS. C, if not negative, is a
1701724c 3074 character that the entity must support. */
c2f5bfd6
KH
3075
3076Lisp_Object
971de7fb 3077font_find_for_lface (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec, int c)
c2f5bfd6 3078{
4007dd1c 3079 Lisp_Object work;
72d36834 3080 Lisp_Object frame, entities, val;
78834453 3081 Lisp_Object foundry[3], *family, registry[3], adstyle[3];
1d1e1245 3082 int pixel_size;
72d36834 3083 int i, j, k, l;
d311d28c 3084 USE_SAFE_ALLOCA;
d0a47776
KH
3085
3086 registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
3087 if (NILP (registry[0]))
3088 {
edfda783 3089 registry[0] = DEFAULT_ENCODING;
d0a47776 3090 registry[1] = Qascii_0;
9730daca 3091 registry[2] = zero_vector;
d0a47776
KH
3092 }
3093 else
9730daca 3094 registry[1] = zero_vector;
c2f5bfd6 3095
4007dd1c 3096 if (c >= 0 && ! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
fe5ddfbc 3097 {
35027d0c 3098 struct charset *encoding, *repertory;
1701724c 3099
4007dd1c
KH
3100 if (font_registry_charsets (AREF (spec, FONT_REGISTRY_INDEX),
3101 &encoding, &repertory) < 0)
35027d0c 3102 return Qnil;
72d36834
KH
3103 if (repertory
3104 && ENCODE_CHAR (repertory, c) == CHARSET_INVALID_CODE (repertory))
3105 return Qnil;
35027d0c
KH
3106 else if (c > encoding->max_char)
3107 return Qnil;
c2f5bfd6
KH
3108 }
3109
92470028 3110 work = copy_font_spec (spec);
227f12fa 3111 ASET (work, FONT_TYPE_INDEX, AREF (spec, FONT_TYPE_INDEX));
35027d0c 3112 XSETFRAME (frame, f);
1d1e1245 3113 pixel_size = font_pixel_size (f, spec);
dbc05432 3114 if (pixel_size == 0 && INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
1d1e1245
KH
3115 {
3116 double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3117
3118 pixel_size = POINT_TO_PIXEL (pt / 10, f->resy);
3119 }
4007dd1c
KH
3120 ASET (work, FONT_SIZE_INDEX, Qnil);
3121 foundry[0] = AREF (work, FONT_FOUNDRY_INDEX);
3122 if (! NILP (foundry[0]))
9730daca 3123 foundry[1] = zero_vector;
4007dd1c
KH
3124 else if (STRINGP (attrs[LFACE_FOUNDRY_INDEX]))
3125 {
071132a9 3126 val = attrs[LFACE_FOUNDRY_INDEX];
51b59d79 3127 foundry[0] = font_intern_prop (SSDATA (val), SBYTES (val), 1);
4007dd1c 3128 foundry[1] = Qnil;
9730daca 3129 foundry[2] = zero_vector;
4007dd1c
KH
3130 }
3131 else
9730daca 3132 foundry[0] = Qnil, foundry[1] = zero_vector;
4007dd1c 3133
22459668
KH
3134 adstyle[0] = AREF (work, FONT_ADSTYLE_INDEX);
3135 if (! NILP (adstyle[0]))
9730daca 3136 adstyle[1] = zero_vector;
22459668
KH
3137 else if (FONTP (attrs[LFACE_FONT_INDEX]))
3138 {
3139 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3140
3141 if (! NILP (AREF (face_font, FONT_ADSTYLE_INDEX)))
3142 {
3143 adstyle[0] = AREF (face_font, FONT_ADSTYLE_INDEX);
3144 adstyle[1] = Qnil;
9730daca 3145 adstyle[2] = zero_vector;
22459668
KH
3146 }
3147 else
9730daca 3148 adstyle[0] = Qnil, adstyle[1] = zero_vector;
22459668
KH
3149 }
3150 else
9730daca 3151 adstyle[0] = Qnil, adstyle[1] = zero_vector;
22459668
KH
3152
3153
4007dd1c
KH
3154 val = AREF (work, FONT_FAMILY_INDEX);
3155 if (NILP (val) && STRINGP (attrs[LFACE_FAMILY_INDEX]))
071132a9
KH
3156 {
3157 val = attrs[LFACE_FAMILY_INDEX];
51b59d79 3158 val = font_intern_prop (SSDATA (val), SBYTES (val), 1);
071132a9 3159 }
4007dd1c
KH
3160 if (NILP (val))
3161 {
3162 family = alloca ((sizeof family[0]) * 2);
3163 family[0] = Qnil;
9730daca 3164 family[1] = zero_vector; /* terminator. */
4007dd1c
KH
3165 }
3166 else
3167 {
3168 Lisp_Object alters
b6e64c41 3169 = Fassoc_string (val, Vface_alternative_font_family_alist, Qt);
4007dd1c
KH
3170
3171 if (! NILP (alters))
3172 {
d311d28c
PE
3173 EMACS_INT alterslen = XFASTINT (Flength (alters));
3174 SAFE_ALLOCA_LISP (family, alterslen + 2);
4007dd1c
KH
3175 for (i = 0; CONSP (alters); i++, alters = XCDR (alters))
3176 family[i] = XCAR (alters);
3177 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3178 family[i++] = Qnil;
9730daca 3179 family[i] = zero_vector;
4007dd1c
KH
3180 }
3181 else
3182 {
3183 family = alloca ((sizeof family[0]) * 3);
3184 i = 0;
3185 family[i++] = val;
3186 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3187 family[i++] = Qnil;
9730daca 3188 family[i] = zero_vector;
4007dd1c
KH
3189 }
3190 }
3191
d0a47776 3192 for (i = 0; SYMBOLP (family[i]); i++)
4007dd1c 3193 {
d0a47776
KH
3194 ASET (work, FONT_FAMILY_INDEX, family[i]);
3195 for (j = 0; SYMBOLP (foundry[j]); j++)
4007dd1c 3196 {
d0a47776
KH
3197 ASET (work, FONT_FOUNDRY_INDEX, foundry[j]);
3198 for (k = 0; SYMBOLP (registry[k]); k++)
3199 {
904a2e0e 3200 ASET (work, FONT_REGISTRY_INDEX, registry[k]);
22459668
KH
3201 for (l = 0; SYMBOLP (adstyle[l]); l++)
3202 {
3203 ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
3204 entities = font_list_entities (frame, work);
72d36834 3205 if (! NILP (entities))
988a7ddb
KH
3206 {
3207 val = font_select_entity (frame, entities,
3208 attrs, pixel_size, c);
3209 if (! NILP (val))
637fa988 3210 return val;
988a7ddb 3211 }
22459668 3212 }
d0a47776 3213 }
4007dd1c 3214 }
4007dd1c 3215 }
d311d28c
PE
3216
3217 SAFE_FREE ();
d0a47776 3218 return Qnil;
1701724c 3219}
45eb10fb
KH
3220
3221
c2f5bfd6 3222Lisp_Object
971de7fb 3223font_open_for_lface (FRAME_PTR f, Lisp_Object entity, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3224{
9331887d 3225 int size;
c2f5bfd6 3226
4007dd1c
KH
3227 if (INTEGERP (AREF (entity, FONT_SIZE_INDEX))
3228 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
3229 size = XINT (AREF (entity, FONT_SIZE_INDEX));
733fd013
KH
3230 else
3231 {
7e70a152
KH
3232 if (FONT_SPEC_P (spec) && ! NILP (AREF (spec, FONT_SIZE_INDEX)))
3233 size = font_pixel_size (f, spec);
50b0cd29
CY
3234 else
3235 {
7e70a152
KH
3236 double pt;
3237 if (INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
3238 pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3239 else
3240 {
3241 struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
3242 Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
3243 eassert (INTEGERP (height));
3244 pt = XINT (height);
3245 }
733fd013 3246
7e70a152
KH
3247 pt /= 10;
3248 size = POINT_TO_PIXEL (pt, f->resy);
ed96cde8 3249#ifdef HAVE_NS
7e70a152
KH
3250 if (size == 0)
3251 {
3252 Lisp_Object ffsize = get_frame_param (f, Qfontsize);
3253 size = NUMBERP (ffsize) ? POINT_TO_PIXEL (XINT (ffsize), f->resy) : 0;
3254 }
ed96cde8 3255#endif
7e70a152
KH
3256 }
3257 size *= font_rescale_ratio (entity);
733fd013 3258 }
7e70a152 3259
c2f5bfd6
KH
3260 return font_open_entity (f, entity, size);
3261}
3262
45eb10fb 3263
56dd2d86
EZ
3264/* Find a font that satisfies SPEC and is the best match for
3265 face's attributes in ATTRS on FRAME, and return the opened
35027d0c 3266 font-object. */
45eb10fb 3267
35027d0c 3268Lisp_Object
971de7fb 3269font_load_for_lface (FRAME_PTR f, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3270{
637fa988 3271 Lisp_Object entity, name;
ef18374f 3272
908567ef 3273 entity = font_find_for_lface (f, attrs, spec, -1);
35027d0c 3274 if (NILP (entity))
ef18374f 3275 {
35027d0c 3276 /* No font is listed for SPEC, but each font-backend may have
56dd2d86 3277 different criteria about "font matching". So, try it. */
35027d0c
KH
3278 entity = font_matching_entity (f, attrs, spec);
3279 if (NILP (entity))
3280 return Qnil;
c2f5bfd6 3281 }
537b04b9 3282 /* Don't lose the original name that was put in initially. We need
637fa988
JD
3283 it to re-apply the font when font parameters (like hinting or dpi) have
3284 changed. */
3285 entity = font_open_for_lface (f, entity, attrs, spec);
8096a0ff
YM
3286 if (!NILP (entity))
3287 {
42707278
JD
3288 name = Ffont_get (spec, QCuser_spec);
3289 if (STRINGP (name)) font_put_extra (entity, QCuser_spec, name);
8096a0ff 3290 }
637fa988 3291 return entity;
c2f5bfd6
KH
3292}
3293
45eb10fb
KH
3294
3295/* Make FACE on frame F ready to use the font opened for FACE. */
3296
c2f5bfd6 3297void
971de7fb 3298font_prepare_for_face (FRAME_PTR f, struct face *face)
c2f5bfd6 3299{
35027d0c
KH
3300 if (face->font->driver->prepare_face)
3301 face->font->driver->prepare_face (f, face);
c2f5bfd6
KH
3302}
3303
45eb10fb
KH
3304
3305/* Make FACE on frame F stop using the font opened for FACE. */
3306
c2f5bfd6 3307void
971de7fb 3308font_done_for_face (FRAME_PTR f, struct face *face)
c2f5bfd6 3309{
35027d0c
KH
3310 if (face->font->driver->done_face)
3311 face->font->driver->done_face (f, face);
c2f5bfd6
KH
3312 face->extra = NULL;
3313}
3314
45eb10fb 3315
56dd2d86 3316/* Open a font that is a match for font-spec SPEC on frame F. If no proper
c50b7e98 3317 font is found, return Qnil. */
45eb10fb 3318
c2f5bfd6 3319Lisp_Object
971de7fb 3320font_open_by_spec (FRAME_PTR f, Lisp_Object spec)
c2f5bfd6 3321{
c50b7e98 3322 Lisp_Object attrs[LFACE_VECTOR_SIZE];
a9262bb8 3323
4007dd1c
KH
3324 /* We set up the default font-related attributes of a face to prefer
3325 a moderate font. */
3326 attrs[LFACE_FAMILY_INDEX] = attrs[LFACE_FOUNDRY_INDEX] = Qnil;
3327 attrs[LFACE_SWIDTH_INDEX] = attrs[LFACE_WEIGHT_INDEX]
3328 = attrs[LFACE_SLANT_INDEX] = Qnormal;
ed96cde8 3329#ifndef HAVE_NS
4007dd1c 3330 attrs[LFACE_HEIGHT_INDEX] = make_number (120);
ed96cde8
AR
3331#else
3332 attrs[LFACE_HEIGHT_INDEX] = make_number (0);
3333#endif
4007dd1c
KH
3334 attrs[LFACE_FONT_INDEX] = Qnil;
3335
3336 return font_load_for_lface (f, attrs, spec);
c2f5bfd6
KH
3337}
3338
3339
56dd2d86 3340/* Open a font that matches NAME on frame F. If no proper font is
c50b7e98
KH
3341 found, return Qnil. */
3342
3343Lisp_Object
d7ea76b4 3344font_open_by_name (FRAME_PTR f, Lisp_Object name)
c50b7e98
KH
3345{
3346 Lisp_Object args[2];
581e51e8 3347 Lisp_Object spec, ret;
c50b7e98
KH
3348
3349 args[0] = QCname;
d7ea76b4 3350 args[1] = name;
c50b7e98 3351 spec = Ffont_spec (2, args);
581e51e8 3352 ret = font_open_by_spec (f, spec);
537b04b9 3353 /* Do not lose name originally put in. */
8096a0ff 3354 if (!NILP (ret))
42707278 3355 font_put_extra (ret, QCuser_spec, args[1]);
581e51e8
JD
3356
3357 return ret;
c50b7e98
KH
3358}
3359
3360
c2f5bfd6
KH
3361/* Register font-driver DRIVER. This function is used in two ways.
3362
417a1b10 3363 The first is with frame F non-NULL. In this case, make DRIVER
56dd2d86 3364 available (but not yet activated) on F. All frame creators
417a1b10
KH
3365 (e.g. Fx_create_frame) must call this function at least once with
3366 an available font-driver.
c2f5bfd6
KH
3367
3368 The second is with frame F NULL. In this case, DRIVER is globally
3369 registered in the variable `font_driver_list'. All font-driver
3370 implementations must call this function in its syms_of_XXXX
3371 (e.g. syms_of_xfont). */
3372
3373void
971de7fb 3374register_font_driver (struct font_driver *driver, FRAME_PTR f)
c2f5bfd6
KH
3375{
3376 struct font_driver_list *root = f ? f->font_driver_list : font_driver_list;
3377 struct font_driver_list *prev, *list;
3378
3379 if (f && ! driver->draw)
43a1d19b 3380 error ("Unusable font driver for a frame: %s",
c2f5bfd6
KH
3381 SDATA (SYMBOL_NAME (driver->type)));
3382
3383 for (prev = NULL, list = root; list; prev = list, list = list->next)
cf23b845 3384 if (EQ (list->driver->type, driver->type))
c2f5bfd6
KH
3385 error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type)));
3386
38182d90 3387 list = xmalloc (sizeof *list);
417a1b10 3388 list->on = 0;
c2f5bfd6
KH
3389 list->driver = driver;
3390 list->next = NULL;
3391 if (prev)
3392 prev->next = list;
3393 else if (f)
3394 f->font_driver_list = list;
3395 else
3396 font_driver_list = list;
72606e45
KH
3397 if (! f)
3398 num_font_drivers++;
c2f5bfd6
KH
3399}
3400
2ed98482 3401void
971de7fb 3402free_font_driver_list (FRAME_PTR f)
2ed98482
CY
3403{
3404 struct font_driver_list *list, *next;
3405
3406 for (list = f->font_driver_list; list; list = next)
3407 {
3408 next = list->next;
3409 xfree (list);
3410 }
3411 f->font_driver_list = NULL;
3412}
3413
45eb10fb 3414
f697fff0 3415/* Make the frame F use font backends listed in NEW_DRIVERS (list of
ca4da08a
KH
3416 symbols, e.g. xft, x). If NEW_DRIVERS is t, make F use all
3417 available font drivers. If NEW_DRIVERS is nil, finalize all drivers.
417a1b10 3418
ca4da08a
KH
3419 A caller must free all realized faces if any in advance. The
3420 return value is a list of font backends actually made used on
3421 F. */
e950d6f1
KH
3422
3423Lisp_Object
971de7fb 3424font_update_drivers (FRAME_PTR f, Lisp_Object new_drivers)
417a1b10
KH
3425{
3426 Lisp_Object active_drivers = Qnil;
417a1b10
KH
3427 struct font_driver_list *list;
3428
4007dd1c
KH
3429 /* At first, turn off non-requested drivers, and turn on requested
3430 drivers. */
f697fff0 3431 for (list = f->font_driver_list; list; list = list->next)
4007dd1c 3432 {
13a547c6 3433 struct font_driver *driver = list->driver;
4007dd1c
KH
3434 if ((EQ (new_drivers, Qt) || ! NILP (Fmemq (driver->type, new_drivers)))
3435 != list->on)
3436 {
3437 if (list->on)
3438 {
3439 if (driver->end_for_frame)
3440 driver->end_for_frame (f);
3441 font_finish_cache (f, driver);
3442 list->on = 0;
3443 }
3444 else
3445 {
3446 if (! driver->start_for_frame
3447 || driver->start_for_frame (f) == 0)
3448 {
3449 font_prepare_cache (f, driver);
3450 list->on = 1;
3451 }
3452 }
3453 }
3454 }
3455
3456 if (NILP (new_drivers))
3457 return Qnil;
3458
3459 if (! EQ (new_drivers, Qt))
3460 {
3461 /* Re-order the driver list according to new_drivers. */
3306c6dc 3462 struct font_driver_list **list_table, **next;
4007dd1c
KH
3463 Lisp_Object tail;
3464 int i;
3465
3466 list_table = alloca (sizeof list_table[0] * (num_font_drivers + 1));
3467 for (i = 0, tail = new_drivers; ! NILP (tail); tail = XCDR (tail))
3468 {
3469 for (list = f->font_driver_list; list; list = list->next)
3470 if (list->on && EQ (list->driver->type, XCAR (tail)))
3471 break;
3472 if (list)
3473 list_table[i++] = list;
3474 }
3475 for (list = f->font_driver_list; list; list = list->next)
3476 if (! list->on)
6136b72f 3477 list_table[i++] = list;
4007dd1c
KH
3478 list_table[i] = NULL;
3479
3306c6dc 3480 next = &f->font_driver_list;
4007dd1c
KH
3481 for (i = 0; list_table[i]; i++)
3482 {
3306c6dc
AS
3483 *next = list_table[i];
3484 next = &(*next)->next;
4007dd1c 3485 }
3306c6dc 3486 *next = NULL;
ba98e3a0
SM
3487
3488 if (! f->font_driver_list->on)
3489 { /* None of the drivers is enabled: enable them all.
3490 Happens if you set the list of drivers to (xft x) in your .emacs
3491 and then use it under w32 or ns. */
3492 for (list = f->font_driver_list; list; list = list->next)
3493 {
3494 struct font_driver *driver = list->driver;
3495 eassert (! list->on);
3496 if (! driver->start_for_frame
3497 || driver->start_for_frame (f) == 0)
3498 {
3499 font_prepare_cache (f, driver);
3500 list->on = 1;
3501 }
3502 }
3503 }
4007dd1c 3504 }
417a1b10 3505
4007dd1c
KH
3506 for (list = f->font_driver_list; list; list = list->next)
3507 if (list->on)
3508 active_drivers = nconc2 (active_drivers,
3509 Fcons (list->driver->type, Qnil));
e950d6f1 3510 return active_drivers;
417a1b10
KH
3511}
3512
f697fff0 3513int
971de7fb 3514font_put_frame_data (FRAME_PTR f, struct font_driver *driver, void *data)
f697fff0
KH
3515{
3516 struct font_data_list *list, *prev;
3517
3518 for (prev = NULL, list = f->font_data_list; list;
3519 prev = list, list = list->next)
3520 if (list->driver == driver)
3521 break;
3522 if (! data)
3523 {
3524 if (list)
3525 {
3526 if (prev)
3527 prev->next = list->next;
3528 else
3529 f->font_data_list = list->next;
973e7849 3530 xfree (list);
f697fff0
KH
3531 }
3532 return 0;
3533 }
3534
3535 if (! list)
3536 {
38182d90 3537 list = xmalloc (sizeof *list);
f697fff0
KH
3538 list->driver = driver;
3539 list->next = f->font_data_list;
3540 f->font_data_list = list;
3541 }
3542 list->data = data;
3543 return 0;
3544}
3545
3546
3547void *
971de7fb 3548font_get_frame_data (FRAME_PTR f, struct font_driver *driver)
f697fff0
KH
3549{
3550 struct font_data_list *list;
3551
3552 for (list = f->font_data_list; list; list = list->next)
3553 if (list->driver == driver)
3554 break;
3555 if (! list)
3556 return NULL;
3557 return list->data;
3558}
3559
417a1b10 3560
9fa82824
DP
3561/* Sets attributes on a font. Any properties that appear in ALIST and
3562 BOOLEAN_PROPERTIES or NON_BOOLEAN_PROPERTIES are set on the font.
3563 BOOLEAN_PROPERTIES and NON_BOOLEAN_PROPERTIES are NULL-terminated
3564 arrays of strings. This function is intended for use by the font
3565 drivers to implement their specific font_filter_properties. */
3566void
220d91b8
JB
3567font_filter_properties (Lisp_Object font,
3568 Lisp_Object alist,
3106121c
YM
3569 const char *const boolean_properties[],
3570 const char *const non_boolean_properties[])
9fa82824
DP
3571{
3572 Lisp_Object it;
3573 int i;
3574
3575 /* Set boolean values to Qt or Qnil */
3576 for (i = 0; boolean_properties[i] != NULL; ++i)
3577 for (it = alist; ! NILP (it); it = XCDR (it))
3578 {
3579 Lisp_Object key = XCAR (XCAR (it));
3580 Lisp_Object val = XCDR (XCAR (it));
42a5b22f 3581 char *keystr = SSDATA (SYMBOL_NAME (key));
9fa82824
DP
3582
3583 if (strcmp (boolean_properties[i], keystr) == 0)
3584 {
3585 const char *str = INTEGERP (val) ? (XINT (val) ? "true" : "false")
51b59d79 3586 : SYMBOLP (val) ? SSDATA (SYMBOL_NAME (val))
9fa82824
DP
3587 : "true";
3588
3589 if (strcmp ("false", str) == 0 || strcmp ("False", str) == 0
3590 || strcmp ("FALSE", str) == 0 || strcmp ("FcFalse", str) == 0
3591 || strcmp ("off", str) == 0 || strcmp ("OFF", str) == 0
3592 || strcmp ("Off", str) == 0)
3593 val = Qnil;
3594 else
3595 val = Qt;
3596
3597 Ffont_put (font, key, val);
3598 }
3599 }
3600
3601 for (i = 0; non_boolean_properties[i] != NULL; ++i)
3602 for (it = alist; ! NILP (it); it = XCDR (it))
3603 {
3604 Lisp_Object key = XCAR (XCAR (it));
3605 Lisp_Object val = XCDR (XCAR (it));
42a5b22f 3606 char *keystr = SSDATA (SYMBOL_NAME (key));
9fa82824
DP
3607 if (strcmp (non_boolean_properties[i], keystr) == 0)
3608 Ffont_put (font, key, val);
3609 }
3610}
3611
3612
45eb10fb 3613/* Return the font used to draw character C by FACE at buffer position
e3ee0340
KH
3614 POS in window W. If STRING is non-nil, it is a string containing C
3615 at index POS. If C is negative, get C from the current buffer or
3616 STRING. */
45eb10fb 3617
2f7c71a1 3618static Lisp_Object
d311d28c 3619font_at (int c, ptrdiff_t pos, struct face *face, struct window *w,
2f7c71a1 3620 Lisp_Object string)
10d16101
KH
3621{
3622 FRAME_PTR f;
a864ef14 3623 bool multibyte;
35027d0c 3624 Lisp_Object font_object;
e3ee0340 3625
e500c47d 3626 multibyte = (NILP (string)
4b4deea2 3627 ? ! NILP (BVAR (current_buffer, enable_multibyte_characters))
e500c47d 3628 : STRING_MULTIBYTE (string));
e3ee0340
KH
3629 if (c < 0)
3630 {
3631 if (NILP (string))
3632 {
e3ee0340
KH
3633 if (multibyte)
3634 {
d311d28c 3635 ptrdiff_t pos_byte = CHAR_TO_BYTE (pos);
e3ee0340
KH
3636
3637 c = FETCH_CHAR (pos_byte);
3638 }
3639 else
3640 c = FETCH_BYTE (pos);
3641 }
3642 else
3643 {
3644 unsigned char *str;
3645
3646 multibyte = STRING_MULTIBYTE (string);
3647 if (multibyte)
3648 {
d311d28c 3649 ptrdiff_t pos_byte = string_char_to_byte (string, pos);
e3ee0340
KH
3650
3651 str = SDATA (string) + pos_byte;
62a6e103 3652 c = STRING_CHAR (str);
e3ee0340
KH
3653 }
3654 else
3655 c = SDATA (string)[pos];
3656 }
3657 }
10d16101 3658
d3d50620 3659 f = XFRAME (w->frame);
1385a806
KH
3660 if (! FRAME_WINDOW_P (f))
3661 return Qnil;
10d16101
KH
3662 if (! face)
3663 {
e3ee0340 3664 int face_id;
d311d28c 3665 ptrdiff_t endptr;
e3ee0340
KH
3666
3667 if (STRINGP (string))
3668 face_id = face_at_string_position (w, string, pos, 0, -1, -1, &endptr,
10d16101
KH
3669 DEFAULT_FACE_ID, 0);
3670 else
e3ee0340 3671 face_id = face_at_buffer_position (w, pos, -1, -1, &endptr,
6970f632 3672 pos + 100, 0, -1);
10d16101
KH
3673 face = FACE_FROM_ID (f, face_id);
3674 }
e3ee0340
KH
3675 if (multibyte)
3676 {
3677 int face_id = FACE_FOR_CHAR (f, face, c, pos, string);
3678 face = FACE_FROM_ID (f, face_id);
3679 }
35027d0c 3680 if (! face->font)
10d16101 3681 return Qnil;
35027d0c 3682
35027d0c
KH
3683 XSETFONT (font_object, face->font);
3684 return font_object;
3685}
3686
3687
071132a9
KH
3688#ifdef HAVE_WINDOW_SYSTEM
3689
3690/* Check how many characters after POS (at most to *LIMIT) can be
56dd2d86 3691 displayed by the same font in the window W. FACE, if non-NULL, is
071132a9
KH
3692 the face selected for the character at POS. If STRING is not nil,
3693 it is the string to check instead of the current buffer. In that
3694 case, FACE must be not NULL.
027a33c0 3695
071132a9
KH
3696 The return value is the font-object for the character at POS.
3697 *LIMIT is set to the position where that font can't be used.
35027d0c 3698
071132a9
KH
3699 It is assured that the current buffer (or STRING) is multibyte. */
3700
3701Lisp_Object
d311d28c 3702font_range (ptrdiff_t pos, ptrdiff_t *limit, struct window *w, struct face *face, Lisp_Object string)
35027d0c 3703{
d311d28c 3704 ptrdiff_t pos_byte, ignore;
35027d0c 3705 int c;
071132a9 3706 Lisp_Object font_object = Qnil;
35027d0c
KH
3707
3708 if (NILP (string))
3709 {
35027d0c 3710 pos_byte = CHAR_TO_BYTE (pos);
071132a9
KH
3711 if (! face)
3712 {
3713 int face_id;
3714
6970f632
CY
3715 face_id = face_at_buffer_position (w, pos, 0, 0, &ignore,
3716 *limit, 0, -1);
d3d50620 3717 face = FACE_FROM_ID (XFRAME (w->frame), face_id);
071132a9 3718 }
35027d0c
KH
3719 }
3720 else
3721 {
4e6a86c6 3722 eassert (face);
35027d0c
KH
3723 pos_byte = string_char_to_byte (string, pos);
3724 }
3725
071132a9 3726 while (pos < *limit)
35027d0c 3727 {
071132a9 3728 Lisp_Object category;
35027d0c
KH
3729
3730 if (NILP (string))
3731 FETCH_CHAR_ADVANCE_NO_CHECK (c, pos, pos_byte);
3732 else
3733 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, pos, pos_byte);
0e5d7800 3734 category = CHAR_TABLE_REF (Vunicode_category_table, c);
c805dec0
KH
3735 if (INTEGERP (category)
3736 && (XINT (category) == UNICODE_CATEGORY_Cf
3737 || CHAR_VARIATION_SELECTOR_P (c)))
0e5d7800 3738 continue;
071132a9 3739 if (NILP (font_object))
35027d0c 3740 {
071132a9
KH
3741 font_object = font_for_char (face, c, pos - 1, string);
3742 if (NILP (font_object))
3743 return Qnil;
35027d0c
KH
3744 continue;
3745 }
0e5d7800
KH
3746 if (font_encode_char (font_object, c) == FONT_INVALID_CODE)
3747 *limit = pos - 1;
35027d0c 3748 }
071132a9 3749 return font_object;
10d16101 3750}
071132a9 3751#endif
10d16101 3752
c2f5bfd6
KH
3753\f
3754/* Lisp API */
3755
35027d0c 3756DEFUN ("fontp", Ffontp, Sfontp, 1, 2, 0,
6c8ec042 3757 doc: /* Return t if OBJECT is a font-spec, font-entity, or font-object.
35027d0c
KH
3758Return nil otherwise.
3759Optional 2nd argument EXTRA-TYPE, if non-nil, specifies to check
027a33c0 3760which kind of font it is. It must be one of `font-spec', `font-entity',
35027d0c 3761`font-object'. */)
5842a27b 3762 (Lisp_Object object, Lisp_Object extra_type)
c2f5bfd6 3763{
35027d0c
KH
3764 if (NILP (extra_type))
3765 return (FONTP (object) ? Qt : Qnil);
3766 if (EQ (extra_type, Qfont_spec))
3767 return (FONT_SPEC_P (object) ? Qt : Qnil);
3768 if (EQ (extra_type, Qfont_entity))
3769 return (FONT_ENTITY_P (object) ? Qt : Qnil);
3770 if (EQ (extra_type, Qfont_object))
3771 return (FONT_OBJECT_P (object) ? Qt : Qnil);
3772 wrong_type_argument (intern ("font-extra-type"), extra_type);
c2f5bfd6
KH
3773}
3774
a7ca3326 3775DEFUN ("font-spec", Ffont_spec, Sfont_spec, 0, MANY, 0,
45eb10fb
KH
3776 doc: /* Return a newly created font-spec with arguments as properties.
3777
3778ARGS must come in pairs KEY VALUE of font properties. KEY must be a
3779valid font property name listed below:
3780
3781`:family', `:weight', `:slant', `:width'
3782
3783They are the same as face attributes of the same name. See
51c01100 3784`set-face-attribute'.
45eb10fb
KH
3785
3786`:foundry'
3787
3788VALUE must be a string or a symbol specifying the font foundry, e.g. ``misc''.
3789
3790`:adstyle'
3791
3792VALUE must be a string or a symbol specifying the additional
35027d0c 3793typographic style information of a font, e.g. ``sans''.
45eb10fb
KH
3794
3795`:registry'
3796
3797VALUE must be a string or a symbol specifying the charset registry and
3798encoding of a font, e.g. ``iso8859-1''.
3799
3800`:size'
3801
3802VALUE must be a non-negative integer or a floating point number
c423ecca
KH
3803specifying the font size. It specifies the font size in pixels (if
3804VALUE is an integer), or in points (if VALUE is a float).
2babb359
KH
3805
3806`:name'
3807
7a18a178 3808VALUE must be a string of XLFD-style or fontconfig-style font name.
5bdd4dd2
KH
3809
3810`:script'
3811
3812VALUE must be a symbol representing a script that the font must
209f39ac
KH
3813support. It may be a symbol representing a subgroup of a script
3814listed in the variable `script-representative-chars'.
c423ecca
KH
3815
3816`:lang'
3817
3818VALUE must be a symbol of two-letter ISO-639 language names,
3819e.g. `ja'.
3820
3821`:otf'
3822
3823VALUE must be a list (SCRIPT-TAG LANGSYS-TAG GSUB [ GPOS ]) to specify
3824required OpenType features.
3825
3826 SCRIPT-TAG: OpenType script tag symbol (e.g. `deva').
3827 LANGSYS-TAG: OpenType language system tag symbol,
3828 or nil for the default language system.
3829 GSUB: List of OpenType GSUB feature tag symbols, or nil if none required.
3830 GPOS: List of OpenType GPOS feature tag symbols, or nil if none required.
3831
3832GSUB and GPOS may contain `nil' element. In such a case, the font
3833must not have any of the remaining elements.
3834
3835For instance, if the VALUE is `(thai nil nil (mark))', the font must
56dd2d86 3836be an OpenType font whose GPOS table of `thai' script's default
c423ecca
KH
3837language system must contain `mark' feature.
3838
ba3de0e8 3839usage: (font-spec ARGS...) */)
f66c7cf8 3840 (ptrdiff_t nargs, Lisp_Object *args)
c2f5bfd6 3841{
35027d0c 3842 Lisp_Object spec = font_make_spec ();
f66c7cf8 3843 ptrdiff_t i;
c2f5bfd6
KH
3844
3845 for (i = 0; i < nargs; i += 2)
3846 {
cccd42d5
KH
3847 Lisp_Object key = args[i], val;
3848
3849 CHECK_SYMBOL (key);
3850 if (i + 1 >= nargs)
3851 error ("No value for key `%s'", SDATA (SYMBOL_NAME (key)));
3852 val = args[i + 1];
c2f5bfd6 3853
35027d0c
KH
3854 if (EQ (key, QCname))
3855 {
3856 CHECK_STRING (val);
984e7f30 3857 font_parse_name (SSDATA (val), SBYTES (val), spec);
35027d0c
KH
3858 font_put_extra (spec, key, val);
3859 }
c2f5bfd6 3860 else
4485a28e 3861 {
35027d0c
KH
3862 int idx = get_font_prop_index (key);
3863
3864 if (idx >= 0)
ec6fe57c 3865 {
35027d0c
KH
3866 val = font_prop_validate (idx, Qnil, val);
3867 if (idx < FONT_EXTRA_INDEX)
3868 ASET (spec, idx, val);
3869 else
3870 font_put_extra (spec, key, val);
ec6fe57c 3871 }
35027d0c
KH
3872 else
3873 font_put_extra (spec, key, font_prop_validate (0, key, val));
4485a28e 3874 }
e950d6f1 3875 }
c2f5bfd6
KH
3876 return spec;
3877}
3878
92470028
PE
3879/* Return a copy of FONT as a font-spec. */
3880Lisp_Object
3881copy_font_spec (Lisp_Object font)
35027d0c 3882{
d26424c5 3883 Lisp_Object new_spec, tail, prev, extra;
35027d0c
KH
3884 int i;
3885
3886 CHECK_FONT (font);
3887 new_spec = font_make_spec ();
3888 for (i = 1; i < FONT_EXTRA_INDEX; i++)
3889 ASET (new_spec, i, AREF (font, i));
581e51e8 3890 extra = Fcopy_alist (AREF (font, FONT_EXTRA_INDEX));
d26424c5
KH
3891 /* We must remove :font-entity property. */
3892 for (prev = Qnil, tail = extra; CONSP (tail); prev = tail, tail = XCDR (tail))
3893 if (EQ (XCAR (XCAR (tail)), QCfont_entity))
3894 {
3895 if (NILP (prev))
3896 extra = XCDR (extra);
3897 else
3898 XSETCDR (prev, XCDR (tail));
3899 break;
3900 }
35027d0c
KH
3901 ASET (new_spec, FONT_EXTRA_INDEX, extra);
3902 return new_spec;
3903}
3904
92470028
PE
3905/* Merge font-specs FROM and TO, and return a new font-spec.
3906 Every specified property in FROM overrides the corresponding
3907 property in TO. */
3908Lisp_Object
3909merge_font_spec (Lisp_Object from, Lisp_Object to)
35027d0c
KH
3910{
3911 Lisp_Object extra, tail;
3912 int i;
3913
3914 CHECK_FONT (from);
3915 CHECK_FONT (to);
92470028 3916 to = copy_font_spec (to);
35027d0c
KH
3917 for (i = 0; i < FONT_EXTRA_INDEX; i++)
3918 ASET (to, i, AREF (from, i));
3919 extra = AREF (to, FONT_EXTRA_INDEX);
3920 for (tail = AREF (from, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
3921 if (! EQ (XCAR (XCAR (tail)), Qfont_entity))
3922 {
3923 Lisp_Object slot = assq_no_quit (XCAR (XCAR (tail)), extra);
3924
3925 if (! NILP (slot))
3926 XSETCDR (slot, XCDR (XCAR (tail)));
3927 else
3928 extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
3929 }
3930 ASET (to, FONT_EXTRA_INDEX, extra);
3931 return to;
3932}
c2f5bfd6 3933
a7ca3326 3934DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
45eb10fb 3935 doc: /* Return the value of FONT's property KEY.
5bdd4dd2 3936FONT is a font-spec, a font-entity, or a font-object.
a7840ffb 3937KEY is any symbol, but these are reserved for specific meanings:
5bdd4dd2 3938 :family, :weight, :slant, :width, :foundry, :adstyle, :registry,
a7840ffb 3939 :size, :name, :script, :otf
5bdd4dd2 3940See the documentation of `font-spec' for their meanings.
a7840ffb
KH
3941In addition, if FONT is a font-entity or a font-object, values of
3942:script and :otf are different from those of a font-spec as below:
3943
3944The value of :script may be a list of scripts that are supported by the font.
3945
3946The value of :otf is a cons (GSUB . GPOS) where GSUB and GPOS are lists
3947representing the OpenType features supported by the font by this form:
3948 ((SCRIPT (LANGSYS FEATURE ...) ...) ...)
3949SCRIPT, LANGSYS, and FEATURE are all symbols representing OpenType
3950Layout tags. */)
5842a27b 3951 (Lisp_Object font, Lisp_Object key)
c2f5bfd6 3952{
35027d0c 3953 int idx;
a7840ffb 3954 Lisp_Object val;
c2f5bfd6 3955
35027d0c
KH
3956 CHECK_FONT (font);
3957 CHECK_SYMBOL (key);
e80e09b4 3958
35027d0c 3959 idx = get_font_prop_index (key);
2babb359
KH
3960 if (idx >= FONT_WEIGHT_INDEX && idx <= FONT_WIDTH_INDEX)
3961 return font_style_symbolic (font, idx, 0);
35027d0c 3962 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
c2f5bfd6 3963 return AREF (font, idx);
a7840ffb
KH
3964 val = Fassq (key, AREF (font, FONT_EXTRA_INDEX));
3965 if (NILP (val) && EQ (key, QCotf) && FONT_OBJECT_P (font))
3966 {
3967 struct font *fontp = XFONT_OBJECT (font);
a7840ffb 3968
f6c1c771
KH
3969 if (fontp->driver->otf_capability)
3970 val = fontp->driver->otf_capability (fontp);
a7840ffb 3971 else
f6c1c771 3972 val = Fcons (Qnil, Qnil);
a7840ffb
KH
3973 }
3974 else
3975 val = Fcdr (val);
3976 return val;
c2f5bfd6
KH
3977}
3978
51cf11be
AS
3979#ifdef HAVE_WINDOW_SYSTEM
3980
b1868a1a
CY
3981DEFUN ("font-face-attributes", Ffont_face_attributes, Sfont_face_attributes, 1, 2, 0,
3982 doc: /* Return a plist of face attributes generated by FONT.
3983FONT is a font name, a font-spec, a font-entity, or a font-object.
3984The return value is a list of the form
3985
6f568955 3986\(:family FAMILY :height HEIGHT :weight WEIGHT :slant SLANT :width WIDTH)
b1868a1a 3987
48105a6a 3988where FAMILY, HEIGHT, WEIGHT, SLANT, and WIDTH are face attribute values
5989ba2f
CY
3989compatible with `set-face-attribute'. Some of these key-attribute pairs
3990may be omitted from the list if they are not specified by FONT.
b1868a1a 3991
48105a6a
JB
3992The optional argument FRAME specifies the frame that the face attributes
3993are to be displayed on. If omitted, the selected frame is used. */)
5842a27b 3994 (Lisp_Object font, Lisp_Object frame)
b1868a1a
CY
3995{
3996 struct frame *f;
3997 Lisp_Object plist[10];
3998 Lisp_Object val;
5989ba2f 3999 int n = 0;
b1868a1a
CY
4000
4001 if (NILP (frame))
4002 frame = selected_frame;
4003 CHECK_LIVE_FRAME (frame);
4004 f = XFRAME (frame);
4005
4006 if (STRINGP (font))
4007 {
4008 int fontset = fs_query_fontset (font, 0);
4009 Lisp_Object name = font;
4010 if (fontset >= 0)
4011 font = fontset_ascii (fontset);
4012 font = font_spec_from_name (name);
4013 if (! FONTP (font))
4014 signal_error ("Invalid font name", name);
4015 }
4016 else if (! FONTP (font))
4017 signal_error ("Invalid font object", font);
4018
b1868a1a 4019 val = AREF (font, FONT_FAMILY_INDEX);
5989ba2f
CY
4020 if (! NILP (val))
4021 {
4022 plist[n++] = QCfamily;
4023 plist[n++] = SYMBOL_NAME (val);
4024 }
b1868a1a 4025
b1868a1a
CY
4026 val = AREF (font, FONT_SIZE_INDEX);
4027 if (INTEGERP (val))
4028 {
4029 Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
4030 int dpi = INTEGERP (font_dpi) ? XINT (font_dpi) : f->resy;
5989ba2f 4031 plist[n++] = QCheight;
c3bb5465 4032 plist[n++] = make_number (PIXEL_TO_POINT (XINT (val) * 10, dpi));
b1868a1a
CY
4033 }
4034 else if (FLOATP (val))
5989ba2f
CY
4035 {
4036 plist[n++] = QCheight;
4037 plist[n++] = make_number (10 * (int) XFLOAT_DATA (val));
4038 }
b1868a1a 4039
b1868a1a 4040 val = FONT_WEIGHT_FOR_FACE (font);
5989ba2f
CY
4041 if (! NILP (val))
4042 {
4043 plist[n++] = QCweight;
4044 plist[n++] = val;
4045 }
b1868a1a 4046
b1868a1a 4047 val = FONT_SLANT_FOR_FACE (font);
5989ba2f
CY
4048 if (! NILP (val))
4049 {
4050 plist[n++] = QCslant;
4051 plist[n++] = val;
4052 }
b1868a1a 4053
b1868a1a 4054 val = FONT_WIDTH_FOR_FACE (font);
5989ba2f
CY
4055 if (! NILP (val))
4056 {
4057 plist[n++] = QCwidth;
4058 plist[n++] = val;
4059 }
b1868a1a 4060
5989ba2f 4061 return Flist (n, plist);
b1868a1a 4062}
c2f5bfd6 4063
51cf11be
AS
4064#endif
4065
a7ca3326 4066DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
a7840ffb
KH
4067 doc: /* Set one property of FONT: give property KEY value VAL.
4068FONT is a font-spec, a font-entity, or a font-object.
4069
4070If FONT is a font-spec, KEY can be any symbol. But if KEY is the one
4071accepted by the function `font-spec' (which see), VAL must be what
4072allowed in `font-spec'.
4073
4074If FONT is a font-entity or a font-object, KEY must not be the one
4075accepted by `font-spec'. */)
e1ffae3b 4076 (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
c2f5bfd6 4077{
35027d0c 4078 int idx;
c2f5bfd6 4079
35027d0c
KH
4080 idx = get_font_prop_index (prop);
4081 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
a7840ffb
KH
4082 {
4083 CHECK_FONT_SPEC (font);
4084 ASET (font, idx, font_prop_validate (idx, Qnil, val));
4085 }
c2f5bfd6 4086 else
a7840ffb
KH
4087 {
4088 if (EQ (prop, QCname)
4089 || EQ (prop, QCscript)
4090 || EQ (prop, QClang)
4091 || EQ (prop, QCotf))
4092 CHECK_FONT_SPEC (font);
4093 else
4094 CHECK_FONT (font);
4095 font_put_extra (font, prop, font_prop_validate (0, prop, val));
4096 }
c2f5bfd6
KH
4097 return val;
4098}
4099
a7ca3326 4100DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0,
c2f5bfd6
KH
4101 doc: /* List available fonts matching FONT-SPEC on the current frame.
4102Optional 2nd argument FRAME specifies the target frame.
4103Optional 3rd argument NUM, if non-nil, limits the number of returned fonts.
45eb10fb
KH
4104Optional 4th argument PREFER, if non-nil, is a font-spec to
4105control the order of the returned list. Fonts are sorted by
027a33c0 4106how close they are to PREFER. */)
5842a27b 4107 (Lisp_Object font_spec, Lisp_Object frame, Lisp_Object num, Lisp_Object prefer)
c2f5bfd6 4108{
72d36834 4109 Lisp_Object vec, list;
d311d28c 4110 EMACS_INT n = 0;
c2f5bfd6
KH
4111
4112 if (NILP (frame))
4113 frame = selected_frame;
4114 CHECK_LIVE_FRAME (frame);
35027d0c 4115 CHECK_FONT_SPEC (font_spec);
c2f5bfd6
KH
4116 if (! NILP (num))
4117 {
4118 CHECK_NUMBER (num);
4119 n = XINT (num);
4120 if (n <= 0)
4121 return Qnil;
4122 }
4123 if (! NILP (prefer))
35027d0c 4124 CHECK_FONT_SPEC (prefer);
c2f5bfd6 4125
72d36834
KH
4126 list = font_list_entities (frame, font_spec);
4127 if (NILP (list))
c2f5bfd6 4128 return Qnil;
72d36834
KH
4129 if (NILP (XCDR (list))
4130 && ASIZE (XCAR (list)) == 1)
4131 return Fcons (AREF (XCAR (list), 0), Qnil);
c2f5bfd6
KH
4132
4133 if (! NILP (prefer))
72d36834
KH
4134 vec = font_sort_entities (list, prefer, frame, 0);
4135 else
4136 vec = font_vconcat_entity_vectors (list);
4137 if (n == 0 || n >= ASIZE (vec))
c2f5bfd6 4138 {
72d36834 4139 Lisp_Object args[2];
c2f5bfd6 4140
72d36834
KH
4141 args[0] = vec;
4142 args[1] = Qnil;
4143 list = Fappend (2, args);
4144 }
4145 else
4146 {
4147 for (list = Qnil, n--; n >= 0; n--)
4148 list = Fcons (AREF (vec, n), list);
c2f5bfd6
KH
4149 }
4150 return list;
4151}
4152
35027d0c 4153DEFUN ("font-family-list", Ffont_family_list, Sfont_family_list, 0, 1, 0,
c2f5bfd6 4154 doc: /* List available font families on the current frame.
027a33c0 4155Optional argument FRAME, if non-nil, specifies the target frame. */)
5842a27b 4156 (Lisp_Object frame)
c2f5bfd6
KH
4157{
4158 FRAME_PTR f;
4159 struct font_driver_list *driver_list;
4160 Lisp_Object list;
4161
4162 if (NILP (frame))
4163 frame = selected_frame;
4164 CHECK_LIVE_FRAME (frame);
4165 f = XFRAME (frame);
4166 list = Qnil;
4167 for (driver_list = f->font_driver_list; driver_list;
4168 driver_list = driver_list->next)
4169 if (driver_list->driver->list_family)
4170 {
4171 Lisp_Object val = driver_list->driver->list_family (frame);
13bf758b 4172 Lisp_Object tail = list;
c2f5bfd6 4173
13bf758b
CY
4174 for (; CONSP (val); val = XCDR (val))
4175 if (NILP (Fmemq (XCAR (val), tail))
4176 && SYMBOLP (XCAR (val)))
4177 list = Fcons (SYMBOL_NAME (XCAR (val)), list);
c2f5bfd6
KH
4178 }
4179 return list;
4180}
4181
4182DEFUN ("find-font", Ffind_font, Sfind_font, 1, 2, 0,
4183 doc: /* Return a font-entity matching with FONT-SPEC on the current frame.
4184Optional 2nd argument FRAME, if non-nil, specifies the target frame. */)
5842a27b 4185 (Lisp_Object font_spec, Lisp_Object frame)
c2f5bfd6
KH
4186{
4187 Lisp_Object val = Flist_fonts (font_spec, frame, make_number (1), Qnil);
4188
4189 if (CONSP (val))
4190 val = XCAR (val);
4191 return val;
4192}
4193
a7ca3326 4194DEFUN ("font-xlfd-name", Ffont_xlfd_name, Sfont_xlfd_name, 1, 2, 0,
c2f5bfd6
KH
4195 doc: /* Return XLFD name of FONT.
4196FONT is a font-spec, font-entity, or font-object.
d0ab1ebe
KH
4197If the name is too long for XLFD (maximum 255 chars), return nil.
4198If the 2nd optional arg FOLD-WILDCARDS is non-nil,
56dd2d86 4199the consecutive wildcards are folded into one. */)
5842a27b 4200 (Lisp_Object font, Lisp_Object fold_wildcards)
c2f5bfd6
KH
4201{
4202 char name[256];
cb1caeaf 4203 int namelen, pixel_size = 0;
c2f5bfd6 4204
35027d0c
KH
4205 CHECK_FONT (font);
4206
4207 if (FONT_OBJECT_P (font))
c2f5bfd6 4208 {
35027d0c 4209 Lisp_Object font_name = AREF (font, FONT_NAME_INDEX);
c2f5bfd6 4210
35027d0c
KH
4211 if (STRINGP (font_name)
4212 && SDATA (font_name)[0] == '-')
d0ab1ebe
KH
4213 {
4214 if (NILP (fold_wildcards))
4215 return font_name;
51b59d79 4216 strcpy (name, SSDATA (font_name));
cb1caeaf 4217 namelen = SBYTES (font_name);
d0ab1ebe
KH
4218 goto done;
4219 }
35027d0c 4220 pixel_size = XFONT_OBJECT (font)->pixel_size;
c2f5bfd6 4221 }
cb1caeaf
DA
4222 namelen = font_unparse_xlfd (font, pixel_size, name, 256);
4223 if (namelen < 0)
c2f5bfd6 4224 return Qnil;
d0ab1ebe
KH
4225 done:
4226 if (! NILP (fold_wildcards))
4227 {
4228 char *p0 = name, *p1;
4229
4230 while ((p1 = strstr (p0, "-*-*")))
4231 {
4232 strcpy (p1, p1 + 2);
cb1caeaf 4233 namelen -= 2;
d0ab1ebe
KH
4234 p0 = p1;
4235 }
4236 }
4237
cb1caeaf 4238 return make_string (name, namelen);
c2f5bfd6
KH
4239}
4240
4241DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
4242 doc: /* Clear font cache. */)
5842a27b 4243 (void)
c2f5bfd6
KH
4244{
4245 Lisp_Object list, frame;
4246
4247 FOR_EACH_FRAME (list, frame)
4248 {
4249 FRAME_PTR f = XFRAME (frame);
4250 struct font_driver_list *driver_list = f->font_driver_list;
4251
4252 for (; driver_list; driver_list = driver_list->next)
417a1b10
KH
4253 if (driver_list->on)
4254 {
ca4da08a 4255 Lisp_Object cache = driver_list->driver->get_cache (f);
7a6f7fea 4256 Lisp_Object val, tmp;
51c01100 4257
ca4da08a 4258 val = XCDR (cache);
43c0454d
KH
4259 while (! NILP (val)
4260 && ! EQ (XCAR (XCAR (val)), driver_list->driver->type))
ca4da08a 4261 val = XCDR (val);
4e6a86c6 4262 eassert (! NILP (val));
7a6f7fea
AS
4263 tmp = XCDR (XCAR (val));
4264 if (XINT (XCAR (tmp)) == 0)
417a1b10 4265 {
ca4da08a
KH
4266 font_clear_cache (f, XCAR (val), driver_list->driver);
4267 XSETCDR (cache, XCDR (val));
417a1b10 4268 }
417a1b10 4269 }
c2f5bfd6
KH
4270 }
4271
4272 return Qnil;
4273}
4274
071132a9
KH
4275\f
4276void
971de7fb 4277font_fill_lglyph_metrics (Lisp_Object glyph, Lisp_Object font_object)
c2f5bfd6 4278{
071132a9 4279 struct font *font = XFONT_OBJECT (font_object);
d311d28c 4280 unsigned code = font->driver->encode_char (font, LGLYPH_CHAR (glyph));
071132a9 4281 struct font_metrics metrics;
c2f5bfd6 4282
d311d28c 4283 LGLYPH_SET_CODE (glyph, code);
071132a9
KH
4284 font->driver->text_extents (font, &code, 1, &metrics);
4285 LGLYPH_SET_LBEARING (glyph, metrics.lbearing);
4286 LGLYPH_SET_RBEARING (glyph, metrics.rbearing);
4287 LGLYPH_SET_WIDTH (glyph, metrics.width);
4288 LGLYPH_SET_ASCENT (glyph, metrics.ascent);
4289 LGLYPH_SET_DESCENT (glyph, metrics.descent);
c2f5bfd6
KH
4290}
4291
c2f5bfd6 4292
071132a9
KH
4293DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 1, 1, 0,
4294 doc: /* Shape the glyph-string GSTRING.
4295Shaping means substituting glyphs and/or adjusting positions of glyphs
4296to get the correct visual image of character sequences set in the
4297header of the glyph-string.
1701724c 4298
071132a9 4299If the shaping was successful, the value is GSTRING itself or a newly
ea964864
KH
4300created glyph-string. Otherwise, the value is nil.
4301
4302See the documentation of `composition-get-gstring' for the format of
4303GSTRING. */)
5842a27b 4304 (Lisp_Object gstring)
1701724c
KH
4305{
4306 struct font *font;
071132a9 4307 Lisp_Object font_object, n, glyph;
634b8cac 4308 ptrdiff_t i, from, to;
ba3de0e8 4309
071132a9
KH
4310 if (! composition_gstring_p (gstring))
4311 signal_error ("Invalid glyph-string: ", gstring);
4312 if (! NILP (LGSTRING_ID (gstring)))
4313 return gstring;
4314 font_object = LGSTRING_FONT (gstring);
4315 CHECK_FONT_OBJECT (font_object);
35027d0c 4316 font = XFONT_OBJECT (font_object);
b876ea91
KH
4317 if (! font->driver->shape)
4318 return Qnil;
4319
40fb53d6
KH
4320 /* Try at most three times with larger gstring each time. */
4321 for (i = 0; i < 3; i++)
4322 {
40fb53d6
KH
4323 n = font->driver->shape (gstring);
4324 if (INTEGERP (n))
4325 break;
071132a9 4326 gstring = larger_vector (gstring,
d311d28c 4327 LGSTRING_GLYPH_LEN (gstring), -1);
40fb53d6 4328 }
071132a9 4329 if (i == 3 || XINT (n) == 0)
1701724c 4330 return Qnil;
dfe3c90f
KH
4331 if (XINT (n) < LGSTRING_GLYPH_LEN (gstring))
4332 LGSTRING_SET_GLYPH (gstring, XINT (n), Qnil);
ba3de0e8 4333
ea964864 4334 /* Check FROM_IDX and TO_IDX of each GLYPH in GSTRING to assure that
85a43e2e
KH
4335 GLYPHS covers all characters (except for the last few ones) in
4336 GSTRING. More formally, provided that NCHARS is the number of
4337 characters in GSTRING and GLYPHS[i] is the ith glyph, FROM_IDX
4338 and TO_IDX of each glyph must satisfy these conditions:
ea964864
KH
4339
4340 GLYPHS[0].FROM_IDX == 0
4341 GLYPHS[i].FROM_IDX <= GLYPHS[i].TO_IDX
4342 if (GLYPHS[i].FROM_IDX == GLYPHS[i-1].FROM_IDX)
4343 ;; GLYPHS[i] and GLYPHS[i-1] belongs to the same grapheme cluster
4344 GLYPHS[i].TO_IDX == GLYPHS[i-1].TO_IDX
4345 else
4346 ;; Be sure to cover all characters.
85a43e2e 4347 GLYPHS[i].FROM_IDX == GLYPHS[i-1].TO_IDX + 1 */
071132a9 4348 glyph = LGSTRING_GLYPH (gstring, 0);
fc3a285e
KH
4349 from = LGLYPH_FROM (glyph);
4350 to = LGLYPH_TO (glyph);
ea964864
KH
4351 if (from != 0 || to < from)
4352 goto shaper_error;
4353 for (i = 1; i < LGSTRING_GLYPH_LEN (gstring); i++)
071132a9 4354 {
ea964864
KH
4355 glyph = LGSTRING_GLYPH (gstring, i);
4356 if (NILP (glyph))
071132a9 4357 break;
ea964864
KH
4358 if (! (LGLYPH_FROM (glyph) <= LGLYPH_TO (glyph)
4359 && (LGLYPH_FROM (glyph) == from
4360 ? LGLYPH_TO (glyph) == to
4361 : LGLYPH_FROM (glyph) == to + 1)))
4362 goto shaper_error;
4363 from = LGLYPH_FROM (glyph);
4364 to = LGLYPH_TO (glyph);
10d16101 4365 }
071132a9 4366 return composition_gstring_put_cache (gstring, XINT (n));
ea964864
KH
4367
4368 shaper_error:
4369 return Qnil;
c2f5bfd6
KH
4370}
4371
78a2f9cd
KH
4372DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
4373 2, 2, 0,
4374 doc: /* Return a list of variation glyphs for CHAR in FONT-OBJECT.
4375Each element of the value is a cons (VARIATION-SELECTOR . GLYPH-ID),
4376where
c0943d3d 4377 VARIATION-SELECTOR is a character code of variation selection
78a2f9cd
KH
4378 (#xFE00..#xFE0F or #xE0100..#xE01EF)
4379 GLYPH-ID is a glyph code of the corresponding variation glyph. */)
5842a27b 4380 (Lisp_Object font_object, Lisp_Object character)
78a2f9cd
KH
4381{
4382 unsigned variations[256];
4383 struct font *font;
4384 int i, n;
4385 Lisp_Object val;
4386
4387 CHECK_FONT_OBJECT (font_object);
4388 CHECK_CHARACTER (character);
4389 font = XFONT_OBJECT (font_object);
4390 if (! font->driver->get_variation_glyphs)
4391 return Qnil;
4392 n = font->driver->get_variation_glyphs (font, XINT (character), variations);
4393 if (! n)
4394 return Qnil;
4395 val = Qnil;
4396 for (i = 0; i < 255; i++)
4397 if (variations[i])
4398 {
78a2f9cd 4399 int vs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
be44ca6c 4400 Lisp_Object code = INTEGER_TO_CONS (variations[i]);
78a2f9cd
KH
4401 val = Fcons (Fcons (make_number (vs), code), val);
4402 }
4403 return val;
4404}
4405
6a3dadd2
KH
4406#if 0
4407
a7ca3326 4408DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
733fd013 4409 doc: /* Apply OpenType features on glyph-string GSTRING-IN.
51c01100 4410OTF-FEATURES specifies which features to apply in this format:
733fd013 4411 (SCRIPT LANGSYS GSUB GPOS)
e80e09b4
KH
4412where
4413 SCRIPT is a symbol specifying a script tag of OpenType,
4414 LANGSYS is a symbol specifying a langsys tag of OpenType,
733fd013 4415 GSUB and GPOS, if non-nil, are lists of symbols specifying feature tags.
e80e09b4
KH
4416
4417If LANGYS is nil, the default langsys is selected.
4418
51c01100
JB
4419The features are applied in the order they appear in the list. The
4420symbol `*' means to apply all available features not present in this
733fd013
KH
4421list, and the remaining features are ignored. For instance, (vatu
4422pstf * haln) is to apply vatu and pstf in this order, then to apply
4423all available features other than vatu, pstf, and haln.
e80e09b4
KH
4424
4425The features are applied to the glyphs in the range FROM and TO of
733fd013 4426the glyph-string GSTRING-IN.
e80e09b4 4427
51c01100 4428If some feature is actually applicable, the resulting glyphs are
e80e09b4
KH
4429produced in the glyph-string GSTRING-OUT from the index INDEX. In
4430this case, the value is the number of produced glyphs.
4431
4432If no feature is applicable, no glyph is produced in GSTRING-OUT, and
4433the value is 0.
4434
51c01100 4435If GSTRING-OUT is too short to hold produced glyphs, no glyphs are
e80e09b4
KH
4436produced in GSTRING-OUT, and the value is nil.
4437
56dd2d86 4438See the documentation of `composition-get-gstring' for the format of
e80e09b4 4439glyph-string. */)
5842a27b 4440 (Lisp_Object otf_features, Lisp_Object gstring_in, Lisp_Object from, Lisp_Object to, Lisp_Object gstring_out, Lisp_Object index)
e80e09b4
KH
4441{
4442 Lisp_Object font_object = LGSTRING_FONT (gstring_in);
733fd013
KH
4443 Lisp_Object val;
4444 struct font *font;
e80e09b4
KH
4445 int len, num;
4446
733fd013 4447 check_otf_features (otf_features);
35027d0c
KH
4448 CHECK_FONT_OBJECT (font_object);
4449 font = XFONT_OBJECT (font_object);
733fd013 4450 if (! font->driver->otf_drive)
e80e09b4
KH
4451 error ("Font backend %s can't drive OpenType GSUB table",
4452 SDATA (SYMBOL_NAME (font->driver->type)));
733fd013
KH
4453 CHECK_CONS (otf_features);
4454 CHECK_SYMBOL (XCAR (otf_features));
4455 val = XCDR (otf_features);
4456 CHECK_SYMBOL (XCAR (val));
4457 val = XCDR (otf_features);
4458 if (! NILP (val))
4459 CHECK_CONS (val);
e80e09b4
KH
4460 len = check_gstring (gstring_in);
4461 CHECK_VECTOR (gstring_out);
4462 CHECK_NATNUM (from);
4463 CHECK_NATNUM (to);
4464 CHECK_NATNUM (index);
4465
4466 if (XINT (from) >= XINT (to) || XINT (to) > len)
4467 args_out_of_range_3 (from, to, make_number (len));
4468 if (XINT (index) >= ASIZE (gstring_out))
4469 args_out_of_range (index, make_number (ASIZE (gstring_out)));
733fd013
KH
4470 num = font->driver->otf_drive (font, otf_features,
4471 gstring_in, XINT (from), XINT (to),
4472 gstring_out, XINT (index), 0);
e80e09b4
KH
4473 if (num < 0)
4474 return Qnil;
4475 return make_number (num);
4476}
4477
a7ca3326 4478DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
e80e09b4
KH
4479 3, 3, 0,
4480 doc: /* Return a list of alternate glyphs of CHARACTER in FONT-OBJECT.
51c01100 4481OTF-FEATURES specifies which features of the font FONT-OBJECT to apply
e80e09b4
KH
4482in this format:
4483 (SCRIPT LANGSYS FEATURE ...)
027a33c0 4484See the documentation of `font-drive-otf' for more detail.
e80e09b4
KH
4485
4486The value is a list of cons cells of the format (GLYPH-ID . CHARACTER),
4487where GLYPH-ID is a glyph index of the font, and CHARACTER is a
4488character code corresponding to the glyph or nil if there's no
4489corresponding character. */)
5842a27b 4490 (Lisp_Object font_object, Lisp_Object character, Lisp_Object otf_features)
e80e09b4
KH
4491{
4492 struct font *font;
4493 Lisp_Object gstring_in, gstring_out, g;
4494 Lisp_Object alternates;
4495 int i, num;
4496
4497 CHECK_FONT_GET_OBJECT (font_object, font);
733fd013 4498 if (! font->driver->otf_drive)
e950d6f1
KH
4499 error ("Font backend %s can't drive OpenType GSUB table",
4500 SDATA (SYMBOL_NAME (font->driver->type)));
e80e09b4 4501 CHECK_CHARACTER (character);
733fd013 4502 CHECK_CONS (otf_features);
e80e09b4
KH
4503
4504 gstring_in = Ffont_make_gstring (font_object, make_number (1));
4505 g = LGSTRING_GLYPH (gstring_in, 0);
f9ffa1ea 4506 LGLYPH_SET_CHAR (g, XINT (character));
e80e09b4 4507 gstring_out = Ffont_make_gstring (font_object, make_number (10));
733fd013
KH
4508 while ((num = font->driver->otf_drive (font, otf_features, gstring_in, 0, 1,
4509 gstring_out, 0, 1)) < 0)
e80e09b4
KH
4510 gstring_out = Ffont_make_gstring (font_object,
4511 make_number (ASIZE (gstring_out) * 2));
4512 alternates = Qnil;
4513 for (i = 0; i < num; i++)
4514 {
4515 Lisp_Object g = LGSTRING_GLYPH (gstring_out, i);
f9ffa1ea
SM
4516 int c = LGLYPH_CHAR (g);
4517 unsigned code = LGLYPH_CODE (g);
e80e09b4
KH
4518
4519 alternates = Fcons (Fcons (make_number (code),
4520 c > 0 ? make_number (c) : Qnil),
4521 alternates);
4522 }
4523 return Fnreverse (alternates);
4524}
6a3dadd2 4525#endif /* 0 */
c2f5bfd6
KH
4526
4527#ifdef FONT_DEBUG
4528
4529DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0,
4530 doc: /* Open FONT-ENTITY. */)
5842a27b 4531 (Lisp_Object font_entity, Lisp_Object size, Lisp_Object frame)
c2f5bfd6 4532{
d311d28c 4533 EMACS_INT isize;
c2f5bfd6
KH
4534
4535 CHECK_FONT_ENTITY (font_entity);
c2f5bfd6
KH
4536 if (NILP (frame))
4537 frame = selected_frame;
4538 CHECK_LIVE_FRAME (frame);
51c01100 4539
35027d0c
KH
4540 if (NILP (size))
4541 isize = XINT (AREF (font_entity, FONT_SIZE_INDEX));
4542 else
4543 {
4544 CHECK_NUMBER_OR_FLOAT (size);
4545 if (FLOATP (size))
d03b5cdb 4546 isize = POINT_TO_PIXEL (XFLOAT_DATA (size), XFRAME (frame)->resy);
35027d0c
KH
4547 else
4548 isize = XINT (size);
d311d28c
PE
4549 if (! (INT_MIN <= isize && isize <= INT_MAX))
4550 args_out_of_range (font_entity, size);
35027d0c
KH
4551 if (isize == 0)
4552 isize = 120;
4553 }
c2f5bfd6
KH
4554 return font_open_entity (XFRAME (frame), font_entity, isize);
4555}
4556
4557DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0,
4558 doc: /* Close FONT-OBJECT. */)
5842a27b 4559 (Lisp_Object font_object, Lisp_Object frame)
c2f5bfd6
KH
4560{
4561 CHECK_FONT_OBJECT (font_object);
4562 if (NILP (frame))
4563 frame = selected_frame;
4564 CHECK_LIVE_FRAME (frame);
4565 font_close_object (XFRAME (frame), font_object);
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
KH
4767{
4768 struct window *w;
d311d28c 4769 ptrdiff_t pos;
10d16101 4770
aee5b18e
KH
4771 if (NILP (window))
4772 window = selected_window;
4773 CHECK_LIVE_WINDOW (window);
4774 w = XWINDOW (window);
1701724c
KH
4775 if (NILP (string))
4776 {
aee5b18e
KH
4777 if (XBUFFER (w->buffer) != current_buffer)
4778 error ("Specified window is not displaying the current buffer.");
1701724c 4779 CHECK_NUMBER_COERCE_MARKER (position);
d311d28c 4780 if (! (BEGV <= XINT (position) && XINT (position) < ZV))
1701724c 4781 args_out_of_range_3 (position, make_number (BEGV), make_number (ZV));
d311d28c 4782 pos = XINT (position);
1701724c
KH
4783 }
4784 else
4785 {
1701724c
KH
4786 CHECK_NUMBER (position);
4787 CHECK_STRING (string);
a0d7415f 4788 if (! (0 <= XINT (position) && XINT (position) < SCHARS (string)))
1701724c 4789 args_out_of_range (string, position);
d311d28c 4790 pos = XINT (position);
1701724c 4791 }
10d16101 4792
40fb53d6 4793 return font_at (-1, pos, NULL, w, string);
10d16101
KH
4794}
4795
c2f5bfd6
KH
4796#if 0
4797DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
4798 doc: /* Draw STRING by FONT-OBJECT on the top left corner of the current frame.
4799The value is a number of glyphs drawn.
4800Type C-l to recover what previously shown. */)
5842a27b 4801 (Lisp_Object font_object, Lisp_Object string)
c2f5bfd6
KH
4802{
4803 Lisp_Object frame = selected_frame;
4804 FRAME_PTR f = XFRAME (frame);
4805 struct font *font;
4806 struct face *face;
4807 int i, len, width;
4808 unsigned *code;
4809
4810 CHECK_FONT_GET_OBJECT (font_object, font);
4811 CHECK_STRING (string);
4812 len = SCHARS (string);
4813 code = alloca (sizeof (unsigned) * len);
4814 for (i = 0; i < len; i++)
4815 {
4816 Lisp_Object ch = Faref (string, make_number (i));
4817 Lisp_Object val;
4818 int c = XINT (ch);
4819
4820 code[i] = font->driver->encode_char (font, c);
4821 if (code[i] == FONT_INVALID_CODE)
4822 break;
4823 }
4824 face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
4825 face->fontp = font;
4826 if (font->driver->prepare_face)
4827 font->driver->prepare_face (f, face);
4828 width = font->driver->text_extents (font, code, i, NULL);
4829 len = font->driver->draw_text (f, face, 0, font->ascent, code, i, width);
4830 if (font->driver->done_face)
4831 font->driver->done_face (f, face);
4832 face->fontp = NULL;
4833 return make_number (len);
4834}
4835#endif
4836
4837#endif /* FONT_DEBUG */
4838
a266686a
KH
4839#ifdef HAVE_WINDOW_SYSTEM
4840
72606e45
KH
4841DEFUN ("font-info", Ffont_info, Sfont_info, 1, 2, 0,
4842 doc: /* Return information about a font named NAME on frame FRAME.
4843If FRAME is omitted or nil, use the selected frame.
06f19b91 4844The returned value is a vector of OPENED-NAME, FULL-NAME, SIZE,
72606e45
KH
4845 HEIGHT, BASELINE-OFFSET, RELATIVE-COMPOSE, and DEFAULT-ASCENT,
4846where
4847 OPENED-NAME is the name used for opening the font,
4848 FULL-NAME is the full name of the font,
06f19b91
KH
4849 SIZE is the pixelsize of the font,
4850 HEIGHT is the pixel-height of the font (i.e ascent + descent),
72606e45
KH
4851 BASELINE-OFFSET is the upward offset pixels from ASCII baseline,
4852 RELATIVE-COMPOSE and DEFAULT-ASCENT are the numbers controlling
4853 how to compose characters.
4854If the named font is not yet loaded, return nil. */)
5842a27b 4855 (Lisp_Object name, Lisp_Object frame)
72606e45
KH
4856{
4857 FRAME_PTR f;
4858 struct font *font;
4859 Lisp_Object info;
4860 Lisp_Object font_object;
4861
4862 (*check_window_system_func) ();
4863
4864 if (! FONTP (name))
4865 CHECK_STRING (name);
4866 if (NILP (frame))
4867 frame = selected_frame;
4868 CHECK_LIVE_FRAME (frame);
4869 f = XFRAME (frame);
4870
4871 if (STRINGP (name))
4872 {
4873 int fontset = fs_query_fontset (name, 0);
4874
4875 if (fontset >= 0)
4876 name = fontset_ascii (fontset);
d7ea76b4 4877 font_object = font_open_by_name (f, name);
72606e45
KH
4878 }
4879 else if (FONT_OBJECT_P (name))
4880 font_object = name;
4881 else if (FONT_ENTITY_P (name))
4882 font_object = font_open_entity (f, name, 0);
4883 else
4884 {
4885 struct face *face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
4886 Lisp_Object entity = font_matching_entity (f, face->lface, name);
4887
4888 font_object = ! NILP (entity) ? font_open_entity (f, entity, 0) : Qnil;
4889 }
4890 if (NILP (font_object))
4891 return Qnil;
4892 font = XFONT_OBJECT (font_object);
4893
4894 info = Fmake_vector (make_number (7), Qnil);
28be1ada
DA
4895 ASET (info, 0, AREF (font_object, FONT_NAME_INDEX));
4896 ASET (info, 1, AREF (font_object, FONT_FULLNAME_INDEX));
4897 ASET (info, 2, make_number (font->pixel_size));
4898 ASET (info, 3, make_number (font->height));
4899 ASET (info, 4, make_number (font->baseline_offset));
4900 ASET (info, 5, make_number (font->relative_compose));
4901 ASET (info, 6, make_number (font->default_ascent));
72606e45
KH
4902
4903#if 0
4904 /* As font_object is still in FONT_OBJLIST of the entity, we can't
4905 close it now. Perhaps, we should manage font-objects
4906 by `reference-count'. */
4907 font_close_object (f, font_object);
4908#endif
4909 return info;
4910}
a266686a 4911#endif
72606e45 4912
c2f5bfd6 4913\f
d0ab1ebe
KH
4914#define BUILD_STYLE_TABLE(TBL) \
4915 build_style_table ((TBL), sizeof TBL / sizeof (struct table_entry))
4916
4917static Lisp_Object
971de7fb 4918build_style_table (const struct table_entry *entry, int nelement)
d0ab1ebe
KH
4919{
4920 int i, j;
4921 Lisp_Object table, elt;
17ab8f5d 4922
d0ab1ebe
KH
4923 table = Fmake_vector (make_number (nelement), Qnil);
4924 for (i = 0; i < nelement; i++)
4925 {
4926 for (j = 0; entry[i].names[j]; j++);
4927 elt = Fmake_vector (make_number (j + 1), Qnil);
4928 ASET (elt, 0, make_number (entry[i].numeric));
4929 for (j = 0; entry[i].names[j]; j++)
d67b4f80 4930 ASET (elt, j + 1, intern_c_string (entry[i].names[j]));
d0ab1ebe
KH
4931 ASET (table, i, elt);
4932 }
4933 return table;
4934}
4935
d0818984
KH
4936/* The deferred font-log data of the form [ACTION ARG RESULT].
4937 If ACTION is not nil, that is added to the log when font_add_log is
4938 called next time. At that time, ACTION is set back to nil. */
4939static Lisp_Object Vfont_log_deferred;
4940
4941/* Prepend the font-related logging data in Vfont_log if it is not
4942 `t'. ACTION describes a kind of font-related action (e.g. listing,
4943 opening), ARG is the argument for the action, and RESULT is the
4944 result of the action. */
d0ab1ebe 4945void
675e2c69 4946font_add_log (const char *action, Lisp_Object arg, Lisp_Object result)
d0ab1ebe 4947{
13a547c6 4948 Lisp_Object val;
d0ab1ebe
KH
4949 int i;
4950
d0ab1ebe
KH
4951 if (EQ (Vfont_log, Qt))
4952 return;
d0818984
KH
4953 if (STRINGP (AREF (Vfont_log_deferred, 0)))
4954 {
51b59d79 4955 char *str = SSDATA (AREF (Vfont_log_deferred, 0));
d0818984
KH
4956
4957 ASET (Vfont_log_deferred, 0, Qnil);
4958 font_add_log (str, AREF (Vfont_log_deferred, 1),
4959 AREF (Vfont_log_deferred, 2));
4960 }
4961
d0ab1ebe 4962 if (FONTP (arg))
db716644
KH
4963 {
4964 Lisp_Object tail, elt;
4965 Lisp_Object equalstr = build_string ("=");
4966
4967 val = Ffont_xlfd_name (arg, Qt);
4968 for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
4969 tail = XCDR (tail))
4970 {
4971 elt = XCAR (tail);
49f9c344
KH
4972 if (EQ (XCAR (elt), QCscript)
4973 && SYMBOLP (XCDR (elt)))
db716644
KH
4974 val = concat3 (val, SYMBOL_NAME (QCscript),
4975 concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
49f9c344
KH
4976 else if (EQ (XCAR (elt), QClang)
4977 && SYMBOLP (XCDR (elt)))
db716644
KH
4978 val = concat3 (val, SYMBOL_NAME (QClang),
4979 concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
49f9c344
KH
4980 else if (EQ (XCAR (elt), QCotf)
4981 && CONSP (XCDR (elt)) && SYMBOLP (XCAR (XCDR (elt))))
db716644
KH
4982 val = concat3 (val, SYMBOL_NAME (QCotf),
4983 concat2 (equalstr,
4984 SYMBOL_NAME (XCAR (XCDR (elt)))));
4985 }
4986 arg = val;
4987 }
72d36834
KH
4988
4989 if (CONSP (result)
4990 && VECTORP (XCAR (result))
4991 && ASIZE (XCAR (result)) > 0
4992 && FONTP (AREF (XCAR (result), 0)))
4993 result = font_vconcat_entity_vectors (result);
d0ab1ebe 4994 if (FONTP (result))
d26424c5
KH
4995 {
4996 val = Ffont_xlfd_name (result, Qt);
4997 if (! FONT_SPEC_P (result))
4998 val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
4999 build_string (":"), val);
5000 result = val;
5001 }
d0ab1ebe
KH
5002 else if (CONSP (result))
5003 {
13a547c6 5004 Lisp_Object tail;
d0ab1ebe
KH
5005 result = Fcopy_sequence (result);
5006 for (tail = result; CONSP (tail); tail = XCDR (tail))
5007 {
5008 val = XCAR (tail);
5009 if (FONTP (val))
5010 val = Ffont_xlfd_name (val, Qt);
5011 XSETCAR (tail, val);
5012 }
5013 }
5014 else if (VECTORP (result))
5015 {
5016 result = Fcopy_sequence (result);
5017 for (i = 0; i < ASIZE (result); i++)
5018 {
5019 val = AREF (result, i);
5020 if (FONTP (val))
5021 val = Ffont_xlfd_name (val, Qt);
5022 ASET (result, i, val);
5023 }
5024 }
5025 Vfont_log = Fcons (list3 (intern (action), arg, result), Vfont_log);
5026}
5027
d0818984
KH
5028/* Record a font-related logging data to be added to Vfont_log when
5029 font_add_log is called next time. ACTION, ARG, RESULT are the same
5030 as font_add_log. */
5031
5032void
675e2c69 5033font_deferred_log (const char *action, Lisp_Object arg, Lisp_Object result)
d0818984 5034{
652b9560
KH
5035 if (EQ (Vfont_log, Qt))
5036 return;
d0818984
KH
5037 ASET (Vfont_log_deferred, 0, build_string (action));
5038 ASET (Vfont_log_deferred, 1, arg);
5039 ASET (Vfont_log_deferred, 2, result);
ba3de0e8 5040}
d0818984 5041
c2f5bfd6 5042void
971de7fb 5043syms_of_font (void)
c2f5bfd6 5044{
4007dd1c
KH
5045 sort_shift_bits[FONT_TYPE_INDEX] = 0;
5046 sort_shift_bits[FONT_SLANT_INDEX] = 2;
5047 sort_shift_bits[FONT_WEIGHT_INDEX] = 9;
5048 sort_shift_bits[FONT_SIZE_INDEX] = 16;
5049 sort_shift_bits[FONT_WIDTH_INDEX] = 23;
5050 /* Note that the other elements in sort_shift_bits are not used. */
c2f5bfd6 5051
1701724c
KH
5052 staticpro (&font_charset_alist);
5053 font_charset_alist = Qnil;
5054
e0708580 5055 DEFSYM (Qopentype, "opentype");
c2f5bfd6 5056
9e1bb909 5057 DEFSYM (Qascii_0, "ascii-0");
1bb1d99b
KH
5058 DEFSYM (Qiso8859_1, "iso8859-1");
5059 DEFSYM (Qiso10646_1, "iso10646-1");
5060 DEFSYM (Qunicode_bmp, "unicode-bmp");
cf96c5c2 5061 DEFSYM (Qunicode_sip, "unicode-sip");
1bb1d99b 5062
071132a9
KH
5063 DEFSYM (QCf, "Cf");
5064
c2f5bfd6 5065 DEFSYM (QCotf, ":otf");
35027d0c 5066 DEFSYM (QClang, ":lang");
c2f5bfd6 5067 DEFSYM (QCscript, ":script");
4c496d0d 5068 DEFSYM (QCantialias, ":antialias");
c2f5bfd6
KH
5069
5070 DEFSYM (QCfoundry, ":foundry");
5071 DEFSYM (QCadstyle, ":adstyle");
5072 DEFSYM (QCregistry, ":registry");
9331887d
KH
5073 DEFSYM (QCspacing, ":spacing");
5074 DEFSYM (QCdpi, ":dpi");
ec6fe57c 5075 DEFSYM (QCscalable, ":scalable");
35027d0c
KH
5076 DEFSYM (QCavgwidth, ":avgwidth");
5077 DEFSYM (QCfont_entity, ":font-entity");
5078 DEFSYM (QCfc_unknown_spec, ":fc-unknown-spec");
c2f5bfd6 5079
ec6fe57c
KH
5080 DEFSYM (Qc, "c");
5081 DEFSYM (Qm, "m");
5082 DEFSYM (Qp, "p");
5083 DEFSYM (Qd, "d");
5084
cf702558
CY
5085 DEFSYM (Qja, "ja");
5086 DEFSYM (Qko, "ko");
5087
42707278
JD
5088 DEFSYM (QCuser_spec, "user-spec");
5089
c2f5bfd6
KH
5090 staticpro (&scratch_font_spec);
5091 scratch_font_spec = Ffont_spec (0, NULL);
5092 staticpro (&scratch_font_prefer);
5093 scratch_font_prefer = Ffont_spec (0, NULL);
5094
d0818984
KH
5095 staticpro (&Vfont_log_deferred);
5096 Vfont_log_deferred = Fmake_vector (make_number (3), Qnil);
5097
6a3dadd2 5098#if 0
733fd013
KH
5099#ifdef HAVE_LIBOTF
5100 staticpro (&otf_list);
5101 otf_list = Qnil;
6a3dadd2
KH
5102#endif /* HAVE_LIBOTF */
5103#endif /* 0 */
733fd013 5104
c2f5bfd6
KH
5105 defsubr (&Sfontp);
5106 defsubr (&Sfont_spec);
5107 defsubr (&Sfont_get);
51cf11be 5108#ifdef HAVE_WINDOW_SYSTEM
b1868a1a 5109 defsubr (&Sfont_face_attributes);
51cf11be 5110#endif
c2f5bfd6
KH
5111 defsubr (&Sfont_put);
5112 defsubr (&Slist_fonts);
35027d0c 5113 defsubr (&Sfont_family_list);
c2f5bfd6
KH
5114 defsubr (&Sfind_font);
5115 defsubr (&Sfont_xlfd_name);
5116 defsubr (&Sclear_font_cache);
071132a9 5117 defsubr (&Sfont_shape_gstring);
78a2f9cd 5118 defsubr (&Sfont_variation_glyphs);
6a3dadd2 5119#if 0
733fd013 5120 defsubr (&Sfont_drive_otf);
e80e09b4 5121 defsubr (&Sfont_otf_alternates);
6a3dadd2 5122#endif /* 0 */
c2f5bfd6
KH
5123
5124#ifdef FONT_DEBUG
5125 defsubr (&Sopen_font);
5126 defsubr (&Sclose_font);
5127 defsubr (&Squery_font);
a7840ffb 5128 defsubr (&Sfont_get_glyphs);
ec6fe57c 5129 defsubr (&Sfont_match_p);
10d16101 5130 defsubr (&Sfont_at);
c2f5bfd6
KH
5131#if 0
5132 defsubr (&Sdraw_string);
5133#endif
5134#endif /* FONT_DEBUG */
a266686a 5135#ifdef HAVE_WINDOW_SYSTEM
72606e45 5136 defsubr (&Sfont_info);
a266686a 5137#endif
c2f5bfd6 5138
29208e82 5139 DEFVAR_LISP ("font-encoding-alist", Vfont_encoding_alist,
819e81df
KH
5140 doc: /*
5141Alist of fontname patterns vs the corresponding encoding and repertory info.
5142Each element looks like (REGEXP . (ENCODING . REPERTORY)),
5143where ENCODING is a charset or a char-table,
5144and REPERTORY is a charset, a char-table, or nil.
5145
027a33c0 5146If ENCODING and REPERTORY are the same, the element can have the form
819e81df
KH
5147\(REGEXP . ENCODING).
5148
5149ENCODING is for converting a character to a glyph code of the font.
5150If ENCODING is a charset, encoding a character by the charset gives
5151the corresponding glyph code. If ENCODING is a char-table, looking up
5152the table by a character gives the corresponding glyph code.
5153
5154REPERTORY specifies a repertory of characters supported by the font.
91af3942 5155If REPERTORY is a charset, all characters belonging to the charset are
819e81df 5156supported. If REPERTORY is a char-table, all characters who have a
027a33c0 5157non-nil value in the table are supported. If REPERTORY is nil, Emacs
819e81df
KH
5158gets the repertory information by an opened font and ENCODING. */);
5159 Vfont_encoding_alist = Qnil;
5160
933ac235
SM
5161 /* FIXME: These 3 vars are not quite what they appear: setq on them
5162 won't have any effect other than disconnect them from the style
5163 table used by the font display code. So we make them read-only,
5164 to avoid this confusing situation. */
5165
29208e82 5166 DEFVAR_LISP_NOPRO ("font-weight-table", Vfont_weight_table,
d0ab1ebe
KH
5167 doc: /* Vector of valid font weight values.
5168Each element has the form:
5169 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
17ab8f5d 5170NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */);
d0ab1ebe 5171 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
933ac235 5172 XSYMBOL (intern_c_string ("font-weight-table"))->constant = 1;
d0ab1ebe 5173
29208e82 5174 DEFVAR_LISP_NOPRO ("font-slant-table", Vfont_slant_table,
d0ab1ebe 5175 doc: /* Vector of font slant symbols vs the corresponding numeric values.
17ab8f5d 5176See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5177 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
933ac235 5178 XSYMBOL (intern_c_string ("font-slant-table"))->constant = 1;
d0ab1ebe 5179
29208e82 5180 DEFVAR_LISP_NOPRO ("font-width-table", Vfont_width_table,
d0ab1ebe 5181 doc: /* Alist of font width symbols vs the corresponding numeric values.
17ab8f5d 5182See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5183 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
933ac235 5184 XSYMBOL (intern_c_string ("font-width-table"))->constant = 1;
d0ab1ebe
KH
5185
5186 staticpro (&font_style_table);
5187 font_style_table = Fmake_vector (make_number (3), Qnil);
5188 ASET (font_style_table, 0, Vfont_weight_table);
5189 ASET (font_style_table, 1, Vfont_slant_table);
5190 ASET (font_style_table, 2, Vfont_width_table);
5191
29208e82 5192 DEFVAR_LISP ("font-log", Vfont_log, doc: /*
d0ab1ebe
KH
5193*Logging list of font related actions and results.
5194The value t means to suppress the logging.
5195The initial value is set to nil if the environment variable
5196EMACS_FONT_LOG is set. Otherwise, it is set to t. */);
5197 Vfont_log = Qnil;
5198
819e81df 5199#ifdef HAVE_WINDOW_SYSTEM
c2f5bfd6 5200#ifdef HAVE_FREETYPE
35027d0c 5201 syms_of_ftfont ();
c2f5bfd6 5202#ifdef HAVE_X_WINDOWS
35027d0c
KH
5203 syms_of_xfont ();
5204 syms_of_ftxfont ();
c2f5bfd6 5205#ifdef HAVE_XFT
35027d0c 5206 syms_of_xftfont ();
c2f5bfd6
KH
5207#endif /* HAVE_XFT */
5208#endif /* HAVE_X_WINDOWS */
5209#else /* not HAVE_FREETYPE */
5210#ifdef HAVE_X_WINDOWS
35027d0c 5211 syms_of_xfont ();
c2f5bfd6
KH
5212#endif /* HAVE_X_WINDOWS */
5213#endif /* not HAVE_FREETYPE */
5214#ifdef HAVE_BDFFONT
35027d0c 5215 syms_of_bdffont ();
c2f5bfd6 5216#endif /* HAVE_BDFFONT */
0fda9b75 5217#ifdef HAVE_NTGUI
35027d0c 5218 syms_of_w32font ();
0fda9b75 5219#endif /* HAVE_NTGUI */
edfda783
AR
5220#ifdef HAVE_NS
5221 syms_of_nsfont ();
5222#endif /* HAVE_NS */
819e81df 5223#endif /* HAVE_WINDOW_SYSTEM */
c2f5bfd6 5224}
885b7d09 5225
652b9560 5226void
971de7fb 5227init_font (void)
652b9560
KH
5228{
5229 Vfont_log = egetenv ("EMACS_FONT_LOG") ? Qnil : Qt;
5230}