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