Prefer 'ARRAYELTS (x)' to 'sizeof x / sizeof *x'.
[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
35027d0c
KH
210 XSETFONT (font_object, font);
211
51c13510
KH
212 if (! NILP (entity))
213 {
214 for (i = 1; i < FONT_SPEC_MAX; i++)
215 font->props[i] = AREF (entity, i);
216 if (! NILP (AREF (entity, FONT_EXTRA_INDEX)))
217 font->props[FONT_EXTRA_INDEX]
581e51e8 218 = Fcopy_alist (AREF (entity, FONT_EXTRA_INDEX));
51c13510
KH
219 }
220 if (size > 0)
221 font->props[FONT_SIZE_INDEX] = make_number (pixelsize);
35027d0c
KH
222 return font_object;
223}
224
225\f
226
a10c8269
DA
227static int font_pixel_size (struct frame *f, Lisp_Object);
228static Lisp_Object font_open_entity (struct frame *, Lisp_Object, int);
229static Lisp_Object font_matching_entity (struct frame *, Lisp_Object *,
f57e2426 230 Lisp_Object);
2f7c71a1 231static unsigned font_encode_char (Lisp_Object, int);
c2f5bfd6
KH
232
233/* Number of registered font drivers. */
234static int num_font_drivers;
235
35027d0c
KH
236
237/* Return a Lispy value of a font property value at STR and LEN bytes.
a864ef14
PE
238 If STR is "*", return nil. If FORCE_SYMBOL, or if STR does not
239 consist entirely of one or more digits, return a symbol interned
240 from STR. Otherwise, return an integer. */
35027d0c
KH
241
242Lisp_Object
a864ef14 243font_intern_prop (const char *str, ptrdiff_t len, bool force_symbol)
35027d0c 244{
ccd6111c 245 ptrdiff_t i;
d0ab1ebe 246 Lisp_Object tem;
35027d0c 247 Lisp_Object obarray;
d311d28c 248 ptrdiff_t nbytes, nchars;
35027d0c
KH
249
250 if (len == 1 && *str == '*')
251 return Qnil;
7216e43b 252 if (!force_symbol && 0 < len && '0' <= *str && *str <= '9')
35027d0c
KH
253 {
254 for (i = 1; i < len; i++)
da3f12b2 255 if (! ('0' <= str[i] && str[i] <= '9'))
35027d0c
KH
256 break;
257 if (i == len)
ccd6111c 258 {
da3f12b2
PE
259 EMACS_INT n;
260
261 i = 0;
262 for (n = 0; (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; n *= 10)
263 {
264 if (i == len)
265 return make_number (n);
7216e43b 266 if (MOST_POSITIVE_FIXNUM / 10 < n)
da3f12b2
PE
267 break;
268 }
269
270 xsignal1 (Qoverflow_error, make_string (str, len));
ccd6111c 271 }
35027d0c
KH
272 }
273
e8df9267
DA
274 /* This code is similar to intern function from lread.c. */
275 obarray = check_obarray (Vobarray);
72d36834 276 parse_str_as_multibyte ((unsigned char *) str, len, &nchars, &nbytes);
e8df9267
DA
277 tem = oblookup (obarray, str,
278 (len == nchars || len != nbytes) ? len : nchars, len);
279
35027d0c
KH
280 if (SYMBOLP (tem))
281 return tem;
545312c2
KH
282 if (len == nchars || len != nbytes)
283 tem = make_unibyte_string (str, len);
284 else
285 tem = make_multibyte_string (str, nchars, len);
286 return Fintern (tem, obarray);
35027d0c
KH
287}
288
9331887d 289/* Return a pixel size of font-spec SPEC on frame F. */
ec6fe57c 290
9331887d 291static int
a10c8269 292font_pixel_size (struct frame *f, Lisp_Object spec)
9331887d 293{
819e81df 294#ifdef HAVE_WINDOW_SYSTEM
9331887d
KH
295 Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
296 double point_size;
35027d0c 297 int dpi, pixel_size;
d0ab1ebe 298 Lisp_Object val;
51c01100 299
9331887d
KH
300 if (INTEGERP (size))
301 return XINT (size);
302 if (NILP (size))
819e81df 303 return 0;
4e6a86c6 304 eassert (FLOATP (size));
9331887d 305 point_size = XFLOAT_DATA (size);
35027d0c
KH
306 val = AREF (spec, FONT_DPI_INDEX);
307 if (INTEGERP (val))
17e28f6d 308 dpi = XINT (val);
9331887d 309 else
42143acd 310 dpi = FRAME_RES_Y (f);
9331887d
KH
311 pixel_size = POINT_TO_PIXEL (point_size, dpi);
312 return pixel_size;
819e81df
KH
313#else
314 return 1;
315#endif
9331887d
KH
316}
317
c2f5bfd6 318
35027d0c
KH
319/* Return a value of PROP's VAL (symbol or integer) to be stored in a
320 font vector. If VAL is not valid (i.e. not registered in
321 font_style_table), return -1 if NOERROR is zero, and return a
322 proper index if NOERROR is nonzero. In that case, register VAL in
56dd2d86 323 font_style_table if VAL is a symbol, and return the closest index if
35027d0c 324 VAL is an integer. */
c2f5bfd6 325
35027d0c 326int
a864ef14
PE
327font_style_to_value (enum font_property_index prop, Lisp_Object val,
328 bool noerror)
c2f5bfd6 329{
35027d0c 330 Lisp_Object table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
c5e4379c
AS
331 int len;
332
333 CHECK_VECTOR (table);
334 len = ASIZE (table);
c2f5bfd6 335
35027d0c 336 if (SYMBOLP (val))
c2f5bfd6 337 {
13a547c6 338 int i, j;
25a48bd0 339 char *s;
35027d0c
KH
340 Lisp_Object args[2], elt;
341
342 /* At first try exact match. */
343 for (i = 0; i < len; i++)
c5e4379c
AS
344 {
345 CHECK_VECTOR (AREF (table, i));
346 for (j = 1; j < ASIZE (AREF (table, i)); j++)
347 if (EQ (val, AREF (AREF (table, i), j)))
348 {
349 CHECK_NUMBER (AREF (AREF (table, i), 0));
350 return ((XINT (AREF (AREF (table, i), 0)) << 8)
351 | (i << 4) | (j - 1));
352 }
353 }
35027d0c 354 /* Try also with case-folding match. */
25a48bd0 355 s = SSDATA (SYMBOL_NAME (val));
35027d0c 356 for (i = 0; i < len; i++)
d0ab1ebe
KH
357 for (j = 1; j < ASIZE (AREF (table, i)); j++)
358 {
359 elt = AREF (AREF (table, i), j);
25a48bd0 360 if (xstrcasecmp (s, SSDATA (SYMBOL_NAME (elt))) == 0)
c5e4379c
AS
361 {
362 CHECK_NUMBER (AREF (AREF (table, i), 0));
363 return ((XINT (AREF (AREF (table, i), 0)) << 8)
364 | (i << 4) | (j - 1));
365 }
d0ab1ebe 366 }
35027d0c
KH
367 if (! noerror)
368 return -1;
4e6a86c6 369 eassert (len < 255);
c2694a06 370 elt = Fmake_vector (make_number (2), make_number (100));
d0ab1ebe 371 ASET (elt, 1, val);
35027d0c 372 args[0] = table;
d0ab1ebe 373 args[1] = Fmake_vector (make_number (1), elt);
35027d0c 374 ASET (font_style_table, prop - FONT_WEIGHT_INDEX, Fvconcat (2, args));
c2694a06 375 return (100 << 8) | (i << 4);
c2f5bfd6 376 }
35027d0c
KH
377 else
378 {
d0ab1ebe 379 int i, last_n;
d311d28c 380 EMACS_INT numeric = XINT (val);
c2f5bfd6 381
d0ab1ebe 382 for (i = 0, last_n = -1; i < len; i++)
35027d0c 383 {
c5e4379c 384 int n;
c2f5bfd6 385
c5e4379c
AS
386 CHECK_VECTOR (AREF (table, i));
387 CHECK_NUMBER (AREF (AREF (table, i), 0));
388 n = XINT (AREF (AREF (table, i), 0));
35027d0c 389 if (numeric == n)
d0ab1ebe 390 return (n << 8) | (i << 4);
35027d0c
KH
391 if (numeric < n)
392 {
393 if (! noerror)
394 return -1;
d0ab1ebe
KH
395 return ((i == 0 || n - numeric < numeric - last_n)
396 ? (n << 8) | (i << 4): (last_n << 8 | ((i - 1) << 4)));
35027d0c 397 }
35027d0c 398 last_n = n;
35027d0c
KH
399 }
400 if (! noerror)
401 return -1;
d0ab1ebe 402 return ((last_n << 8) | ((i - 1) << 4));
35027d0c
KH
403 }
404}
c2f5bfd6
KH
405
406Lisp_Object
a864ef14
PE
407font_style_symbolic (Lisp_Object font, enum font_property_index prop,
408 bool for_face)
c2f5bfd6 409{
3ef8c1b4 410 Lisp_Object val = AREF (font, prop);
d0ab1ebe
KH
411 Lisp_Object table, elt;
412 int i;
c2f5bfd6 413
35027d0c
KH
414 if (NILP (val))
415 return Qnil;
416 table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
c5e4379c 417 CHECK_VECTOR (table);
d0ab1ebe 418 i = XINT (val) & 0xFF;
4e6a86c6 419 eassert (((i >> 4) & 0xF) < ASIZE (table));
d0ab1ebe 420 elt = AREF (table, ((i >> 4) & 0xF));
c5e4379c 421 CHECK_VECTOR (elt);
4e6a86c6 422 eassert ((i & 0xF) + 1 < ASIZE (elt));
c5e4379c
AS
423 elt = (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));
424 CHECK_SYMBOL (elt);
425 return elt;
6fe9826d
JR
426}
427
819e81df
KH
428/* Return ENCODING or a cons of ENCODING and REPERTORY of the font
429 FONTNAME. ENCODING is a charset symbol that specifies the encoding
430 of the font. REPERTORY is a charset symbol or nil. */
431
432Lisp_Object
971de7fb 433find_font_encoding (Lisp_Object fontname)
819e81df
KH
434{
435 Lisp_Object tail, elt;
436
437 for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
438 {
439 elt = XCAR (tail);
440 if (CONSP (elt)
441 && STRINGP (XCAR (elt))
442 && fast_string_match_ignore_case (XCAR (elt), fontname) >= 0
443 && (SYMBOLP (XCDR (elt))
444 ? CHARSETP (XCDR (elt))
445 : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
446 return (XCDR (elt));
447 }
182ba28c 448 return Qnil;
819e81df
KH
449}
450
1701724c
KH
451/* Return encoding charset and repertory charset for REGISTRY in
452 ENCODING and REPERTORY correspondingly. If correct information for
453 REGISTRY is available, return 0. Otherwise return -1. */
454
455int
971de7fb 456font_registry_charsets (Lisp_Object registry, struct charset **encoding, struct charset **repertory)
1701724c
KH
457{
458 Lisp_Object val;
459 int encoding_id, repertory_id;
460
35027d0c 461 val = Fassoc_string (registry, font_charset_alist, Qt);
1701724c
KH
462 if (! NILP (val))
463 {
464 val = XCDR (val);
465 if (NILP (val))
466 return -1;
467 encoding_id = XINT (XCAR (val));
468 repertory_id = XINT (XCDR (val));
469 }
470 else
471 {
472 val = find_font_encoding (SYMBOL_NAME (registry));
473 if (SYMBOLP (val) && CHARSETP (val))
474 {
475 encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val));
476 }
477 else if (CONSP (val))
478 {
479 if (! CHARSETP (XCAR (val)))
480 goto invalid_entry;
481 encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val)));
482 if (NILP (XCDR (val)))
483 repertory_id = -1;
484 else
485 {
486 if (! CHARSETP (XCDR (val)))
487 goto invalid_entry;
488 repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val)));
489 }
51c01100 490 }
1701724c
KH
491 else
492 goto invalid_entry;
493 val = Fcons (make_number (encoding_id), make_number (repertory_id));
494 font_charset_alist
6c6f1994 495 = nconc2 (font_charset_alist, list1 (Fcons (registry, val)));
1701724c
KH
496 }
497
498 if (encoding)
499 *encoding = CHARSET_FROM_ID (encoding_id);
500 if (repertory)
501 *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
502 return 0;
503
504 invalid_entry:
505 font_charset_alist
6c6f1994 506 = nconc2 (font_charset_alist, list1 (Fcons (registry, Qnil)));
1701724c
KH
507 return -1;
508}
509
c2f5bfd6 510\f
56dd2d86 511/* Font property value validators. See the comment of
45eb10fb
KH
512 font_property_table for the meaning of the arguments. */
513
f57e2426
J
514static Lisp_Object font_prop_validate (int, Lisp_Object, Lisp_Object);
515static Lisp_Object font_prop_validate_symbol (Lisp_Object, Lisp_Object);
516static Lisp_Object font_prop_validate_style (Lisp_Object, Lisp_Object);
517static Lisp_Object font_prop_validate_non_neg (Lisp_Object, Lisp_Object);
518static Lisp_Object font_prop_validate_spacing (Lisp_Object, Lisp_Object);
519static int get_font_prop_index (Lisp_Object);
c2f5bfd6
KH
520
521static Lisp_Object
971de7fb 522font_prop_validate_symbol (Lisp_Object prop, Lisp_Object val)
c2f5bfd6
KH
523{
524 if (STRINGP (val))
35027d0c
KH
525 val = Fintern (val, Qnil);
526 if (! SYMBOLP (val))
c2f5bfd6 527 val = Qerror;
35027d0c
KH
528 else if (EQ (prop, QCregistry))
529 val = Fintern (Fdowncase (SYMBOL_NAME (val)), Qnil);
c2f5bfd6
KH
530 return val;
531}
532
35027d0c 533
c2f5bfd6 534static Lisp_Object
971de7fb 535font_prop_validate_style (Lisp_Object style, Lisp_Object val)
c2f5bfd6 536{
35027d0c
KH
537 enum font_property_index prop = (EQ (style, QCweight) ? FONT_WEIGHT_INDEX
538 : EQ (style, QCslant) ? FONT_SLANT_INDEX
539 : FONT_WIDTH_INDEX);
35027d0c 540 if (INTEGERP (val))
c2f5bfd6 541 {
d311d28c 542 EMACS_INT n = XINT (val);
c5e4379c 543 CHECK_VECTOR (AREF (font_style_table, prop - FONT_WEIGHT_INDEX));
64b900e3 544 if (((n >> 4) & 0xF)
35027d0c 545 >= ASIZE (AREF (font_style_table, prop - FONT_WEIGHT_INDEX)))
c2f5bfd6
KH
546 val = Qerror;
547 else
548 {
64b900e3
KH
549 Lisp_Object elt = AREF (AREF (font_style_table, prop - FONT_WEIGHT_INDEX), (n >> 4) & 0xF);
550
c5e4379c 551 CHECK_VECTOR (elt);
64b900e3
KH
552 if ((n & 0xF) + 1 >= ASIZE (elt))
553 val = Qerror;
c5e4379c
AS
554 else
555 {
556 CHECK_NUMBER (AREF (elt, 0));
557 if (XINT (AREF (elt, 0)) != (n >> 8))
558 val = Qerror;
559 }
c2f5bfd6
KH
560 }
561 }
35027d0c
KH
562 else if (SYMBOLP (val))
563 {
564 int n = font_style_to_value (prop, val, 0);
565
566 val = n >= 0 ? make_number (n) : Qerror;
567 }
568 else
569 val = Qerror;
c2f5bfd6
KH
570 return val;
571}
572
573static Lisp_Object
971de7fb 574font_prop_validate_non_neg (Lisp_Object prop, Lisp_Object val)
c2f5bfd6
KH
575{
576 return (NATNUMP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0)
577 ? val : Qerror);
578}
579
580static Lisp_Object
971de7fb 581font_prop_validate_spacing (Lisp_Object prop, Lisp_Object val)
ec6fe57c
KH
582{
583 if (NILP (val) || (NATNUMP (val) && XINT (val) <= FONT_SPACING_CHARCELL))
584 return val;
3692570f
KH
585 if (SYMBOLP (val) && SBYTES (SYMBOL_NAME (val)) == 1)
586 {
587 char spacing = SDATA (SYMBOL_NAME (val))[0];
588
589 if (spacing == 'c' || spacing == 'C')
590 return make_number (FONT_SPACING_CHARCELL);
591 if (spacing == 'm' || spacing == 'M')
592 return make_number (FONT_SPACING_MONO);
0615d903 593 if (spacing == 'p' || spacing == 'P')
3692570f
KH
594 return make_number (FONT_SPACING_PROPORTIONAL);
595 if (spacing == 'd' || spacing == 'D')
596 return make_number (FONT_SPACING_DUAL);
597 }
ec6fe57c
KH
598 return Qerror;
599}
600
1701724c 601static Lisp_Object
971de7fb 602font_prop_validate_otf (Lisp_Object prop, Lisp_Object val)
1701724c
KH
603{
604 Lisp_Object tail, tmp;
605 int i;
606
607 /* VAL = (SCRIPT [ LANGSYS [ GSUB-FEATURES [ GPOS-FEATURES ]]])
608 GSUB-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil
609 GPOS-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil */
610 if (! CONSP (val))
611 return Qerror;
612 if (! SYMBOLP (XCAR (val)))
613 return Qerror;
614 tail = XCDR (val);
615 if (NILP (tail))
616 return val;
617 if (! CONSP (tail) || ! SYMBOLP (XCAR (val)))
618 return Qerror;
619 for (i = 0; i < 2; i++)
620 {
621 tail = XCDR (tail);
622 if (NILP (tail))
623 return val;
624 if (! CONSP (tail))
625 return Qerror;
626 for (tmp = XCAR (tail); CONSP (tmp); tmp = XCDR (tmp))
627 if (! SYMBOLP (XCAR (tmp)))
628 return Qerror;
629 if (! NILP (tmp))
630 return Qerror;
631 }
632 return val;
633}
634
56dd2d86 635/* Structure of known font property keys and validator of the
ec6fe57c 636 values. */
04bab72c 637static const struct
c2f5bfd6 638{
ec6fe57c 639 /* Pointer to the key symbol. */
c2f5bfd6 640 Lisp_Object *key;
45eb10fb
KH
641 /* Function to validate PROP's value VAL, or NULL if any value is
642 ok. The value is VAL or its regularized value if VAL is valid,
643 and Qerror if not. */
c80e3b4a 644 Lisp_Object (*validator) (Lisp_Object prop, Lisp_Object val);
ec6fe57c
KH
645} font_property_table[] =
646 { { &QCtype, font_prop_validate_symbol },
c2f5bfd6
KH
647 { &QCfoundry, font_prop_validate_symbol },
648 { &QCfamily, font_prop_validate_symbol },
649 { &QCadstyle, font_prop_validate_symbol },
650 { &QCregistry, font_prop_validate_symbol },
651 { &QCweight, font_prop_validate_style },
652 { &QCslant, font_prop_validate_style },
653 { &QCwidth, font_prop_validate_style },
ec6fe57c 654 { &QCsize, font_prop_validate_non_neg },
ec6fe57c
KH
655 { &QCdpi, font_prop_validate_non_neg },
656 { &QCspacing, font_prop_validate_spacing },
35027d0c
KH
657 { &QCavgwidth, font_prop_validate_non_neg },
658 /* The order of the above entries must match with enum
659 font_property_index. */
660 { &QClang, font_prop_validate_symbol },
661 { &QCscript, font_prop_validate_symbol },
662 { &QCotf, font_prop_validate_otf }
c2f5bfd6
KH
663 };
664
45eb10fb 665/* Return an index number of font property KEY or -1 if KEY is not an
35027d0c 666 already known property. */
45eb10fb 667
ec6fe57c 668static int
971de7fb 669get_font_prop_index (Lisp_Object key)
c2f5bfd6 670{
35027d0c
KH
671 int i;
672
faa52174 673 for (i = 0; i < ARRAYELTS (font_property_table); i++)
35027d0c
KH
674 if (EQ (key, *font_property_table[i].key))
675 return i;
ec6fe57c 676 return -1;
c2f5bfd6
KH
677}
678
35027d0c
KH
679/* Validate the font property. The property key is specified by the
680 symbol PROP, or the index IDX (if PROP is nil). If VAL is invalid,
681 signal an error. The value is VAL or the regularized one. */
45eb10fb 682
c2f5bfd6 683static Lisp_Object
971de7fb 684font_prop_validate (int idx, Lisp_Object prop, Lisp_Object val)
c2f5bfd6 685{
35027d0c 686 Lisp_Object validated;
c2f5bfd6 687
1f09f444
KH
688 if (NILP (val))
689 return val;
35027d0c
KH
690 if (NILP (prop))
691 prop = *font_property_table[idx].key;
692 else
ec6fe57c 693 {
35027d0c
KH
694 idx = get_font_prop_index (prop);
695 if (idx < 0)
696 return val;
ec6fe57c 697 }
c80e3b4a 698 validated = (font_property_table[idx].validator) (prop, val);
35027d0c
KH
699 if (EQ (validated, Qerror))
700 signal_error ("invalid font property", Fcons (prop, val));
701 return validated;
c2f5bfd6 702}
51c01100 703
35027d0c
KH
704
705/* Store VAL as a value of extra font property PROP in FONT while
706 keeping the sorting order. Don't check the validity of VAL. */
45eb10fb 707
01dbeb0b 708Lisp_Object
971de7fb 709font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
9331887d
KH
710{
711 Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
ec6fe57c 712 Lisp_Object slot = (NILP (extra) ? Qnil : assq_no_quit (prop, extra));
9331887d
KH
713
714 if (NILP (slot))
715 {
35027d0c
KH
716 Lisp_Object prev = Qnil;
717
718 while (CONSP (extra)
719 && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
720 prev = extra, extra = XCDR (extra);
581e51e8 721
ce75f06e 722 if (NILP (prev))
581e51e8 723 ASET (font, FONT_EXTRA_INDEX, Fcons (Fcons (prop, val), extra));
ce75f06e 724 else
581e51e8 725 XSETCDR (prev, Fcons (Fcons (prop, val), extra));
ce75f06e 726
ec6fe57c 727 return val;
9331887d 728 }
9331887d 729 XSETCDR (slot, val);
483670b5
KH
730 if (NILP (val))
731 ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
ec6fe57c 732 return val;
9331887d
KH
733}
734
c2f5bfd6 735\f
266fee4f 736/* Font name parser and unparser. */
c2f5bfd6 737
8ea90aa3 738static int parse_matrix (const char *);
f57e2426 739static int font_expand_wildcards (Lisp_Object *, int);
984e7f30 740static int font_parse_name (char *, ptrdiff_t, Lisp_Object);
c2f5bfd6 741
ec6fe57c 742/* An enumerator for each field of an XLFD font name. */
c2f5bfd6
KH
743enum xlfd_field_index
744{
745 XLFD_FOUNDRY_INDEX,
746 XLFD_FAMILY_INDEX,
747 XLFD_WEIGHT_INDEX,
748 XLFD_SLANT_INDEX,
749 XLFD_SWIDTH_INDEX,
750 XLFD_ADSTYLE_INDEX,
4485a28e
KH
751 XLFD_PIXEL_INDEX,
752 XLFD_POINT_INDEX,
c2f5bfd6
KH
753 XLFD_RESX_INDEX,
754 XLFD_RESY_INDEX,
755 XLFD_SPACING_INDEX,
756 XLFD_AVGWIDTH_INDEX,
757 XLFD_REGISTRY_INDEX,
758 XLFD_ENCODING_INDEX,
759 XLFD_LAST_INDEX
760};
761
ec6fe57c 762/* An enumerator for mask bit corresponding to each XLFD field. */
4485a28e
KH
763enum xlfd_field_mask
764{
765 XLFD_FOUNDRY_MASK = 0x0001,
766 XLFD_FAMILY_MASK = 0x0002,
767 XLFD_WEIGHT_MASK = 0x0004,
768 XLFD_SLANT_MASK = 0x0008,
769 XLFD_SWIDTH_MASK = 0x0010,
770 XLFD_ADSTYLE_MASK = 0x0020,
771 XLFD_PIXEL_MASK = 0x0040,
772 XLFD_POINT_MASK = 0x0080,
773 XLFD_RESX_MASK = 0x0100,
774 XLFD_RESY_MASK = 0x0200,
775 XLFD_SPACING_MASK = 0x0400,
776 XLFD_AVGWIDTH_MASK = 0x0800,
777 XLFD_REGISTRY_MASK = 0x1000,
778 XLFD_ENCODING_MASK = 0x2000
779};
780
781
56dd2d86 782/* Parse P pointing to the pixel/point size field of the form
c2f5bfd6
KH
783 `[A B C D]' which specifies a transformation matrix:
784
785 A B 0
786 C D 0
787 0 0 1
788
789 by which all glyphs of the font are transformed. The spec says
790 that scalar value N for the pixel/point size is equivalent to:
791 A = N * resx/resy, B = C = 0, D = N.
792
793 Return the scalar value N if the form is valid. Otherwise return
794 -1. */
795
796static int
8ea90aa3 797parse_matrix (const char *p)
c2f5bfd6
KH
798{
799 double matrix[4];
800 char *end;
801 int i;
802
803 for (i = 0, p++; i < 4 && *p && *p != ']'; i++)
804 {
805 if (*p == '~')
806 matrix[i] = - strtod (p + 1, &end);
807 else
808 matrix[i] = strtod (p, &end);
809 p = end;
810 }
811 return (i == 4 ? (int) matrix[3] : -1);
812}
813
4485a28e 814/* Expand a wildcard field in FIELD (the first N fields are filled) to
56dd2d86 815 multiple fields to fill in all 14 XLFD fields while restricting a
4485a28e
KH
816 field position by its contents. */
817
ec6fe57c 818static int
971de7fb 819font_expand_wildcards (Lisp_Object *field, int n)
4485a28e
KH
820{
821 /* Copy of FIELD. */
822 Lisp_Object tmp[XLFD_LAST_INDEX];
823 /* Array of information about where this element can go. Nth
824 element is for Nth element of FIELD. */
825 struct {
826 /* Minimum possible field. */
827 int from;
09e80d9f 828 /* Maximum possible field. */
4485a28e
KH
829 int to;
830 /* Bit mask of possible field. Nth bit corresponds to Nth field. */
831 int mask;
832 } range[XLFD_LAST_INDEX];
833 int i, j;
ec6fe57c 834 int range_from, range_to;
4485a28e
KH
835 unsigned range_mask;
836
837#define XLFD_SYMBOL_MASK (XLFD_FOUNDRY_MASK | XLFD_FAMILY_MASK \
838 | XLFD_ADSTYLE_MASK | XLFD_REGISTRY_MASK)
839#define XLFD_NULL_MASK (XLFD_FOUNDRY_MASK | XLFD_ADSTYLE_MASK)
4485a28e 840#define XLFD_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \
ef18374f 841 | XLFD_AVGWIDTH_MASK)
4485a28e
KH
842#define XLFD_REGENC_MASK (XLFD_REGISTRY_MASK | XLFD_ENCODING_MASK)
843
844 /* Initialize RANGE_MASK for FIELD[0] which can be 0th to (14 - N)th
845 field. The value is shifted to left one bit by one in the
846 following loop. */
847 for (i = 0, range_mask = 0; i <= 14 - n; i++)
848 range_mask = (range_mask << 1) | 1;
849
ec6fe57c 850 /* The triplet RANGE_FROM, RANGE_TO, and RANGE_MASK is a
c80e3b4a 851 position-based restriction for FIELD[I]. */
ec6fe57c
KH
852 for (i = 0, range_from = 0, range_to = 14 - n; i < n;
853 i++, range_from++, range_to++, range_mask <<= 1)
4485a28e 854 {
4485a28e
KH
855 Lisp_Object val = field[i];
856
857 tmp[i] = val;
858 if (NILP (val))
859 {
860 /* Wildcard. */
861 range[i].from = range_from;
862 range[i].to = range_to;
863 range[i].mask = range_mask;
864 }
865 else
866 {
867 /* The triplet FROM, TO, and MASK is a value-based
c80e3b4a 868 restriction for FIELD[I]. */
4485a28e
KH
869 int from, to;
870 unsigned mask;
871
872 if (INTEGERP (val))
873 {
d311d28c 874 EMACS_INT numeric = XINT (val);
4485a28e 875
ef18374f
KH
876 if (i + 1 == n)
877 from = to = XLFD_ENCODING_INDEX,
878 mask = XLFD_ENCODING_MASK;
ec6fe57c
KH
879 else if (numeric == 0)
880 from = XLFD_PIXEL_INDEX, to = XLFD_AVGWIDTH_INDEX,
881 mask = XLFD_PIXEL_MASK | XLFD_LARGENUM_MASK;
ef18374f
KH
882 else if (numeric <= 48)
883 from = to = XLFD_PIXEL_INDEX,
884 mask = XLFD_PIXEL_MASK;
51c01100 885 else
ec6fe57c 886 from = XLFD_POINT_INDEX, to = XLFD_AVGWIDTH_INDEX,
4485a28e
KH
887 mask = XLFD_LARGENUM_MASK;
888 }
35027d0c 889 else if (SBYTES (SYMBOL_NAME (val)) == 0)
4485a28e
KH
890 from = XLFD_FOUNDRY_INDEX, to = XLFD_ADSTYLE_INDEX,
891 mask = XLFD_NULL_MASK;
892 else if (i == 0)
893 from = to = XLFD_FOUNDRY_INDEX, mask = XLFD_FOUNDRY_MASK;
894 else if (i + 1 == n)
895 {
896 Lisp_Object name = SYMBOL_NAME (val);
897
898 if (SDATA (name)[SBYTES (name) - 1] == '*')
899 from = XLFD_REGISTRY_INDEX, to = XLFD_ENCODING_INDEX,
900 mask = XLFD_REGENC_MASK;
901 else
902 from = to = XLFD_ENCODING_INDEX,
903 mask = XLFD_ENCODING_MASK;
904 }
ef18374f
KH
905 else if (range_from <= XLFD_WEIGHT_INDEX
906 && range_to >= XLFD_WEIGHT_INDEX
35027d0c 907 && FONT_WEIGHT_NAME_NUMERIC (val) >= 0)
4485a28e 908 from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK;
ef18374f
KH
909 else if (range_from <= XLFD_SLANT_INDEX
910 && range_to >= XLFD_SLANT_INDEX
35027d0c 911 && FONT_SLANT_NAME_NUMERIC (val) >= 0)
4485a28e 912 from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK;
ef18374f
KH
913 else if (range_from <= XLFD_SWIDTH_INDEX
914 && range_to >= XLFD_SWIDTH_INDEX
35027d0c 915 && FONT_WIDTH_NAME_NUMERIC (val) >= 0)
4485a28e
KH
916 from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK;
917 else
918 {
ec6fe57c 919 if (EQ (val, Qc) || EQ (val, Qm) || EQ (val, Qp) || EQ (val, Qd))
4485a28e
KH
920 from = to = XLFD_SPACING_INDEX, mask = XLFD_SPACING_MASK;
921 else
922 from = XLFD_FOUNDRY_INDEX, to = XLFD_ENCODING_INDEX,
923 mask = XLFD_SYMBOL_MASK;
924 }
925
926 /* Merge position-based and value-based restrictions. */
927 mask &= range_mask;
928 while (from < range_from)
929 mask &= ~(1 << from++);
930 while (from < 14 && ! (mask & (1 << from)))
931 from++;
932 while (to > range_to)
933 mask &= ~(1 << to--);
934 while (to >= 0 && ! (mask & (1 << to)))
935 to--;
936 if (from > to)
937 return -1;
938 range[i].from = from;
939 range[i].to = to;
940 range[i].mask = mask;
941
942 if (from > range_from || to < range_to)
ec6fe57c
KH
943 {
944 /* The range is narrowed by value-based restrictions.
945 Reflect it to the other fields. */
946
947 /* Following fields should be after FROM. */
948 range_from = from;
949 /* Preceding fields should be before TO. */
950 for (j = i - 1, from--, to--; j >= 0; j--, from--, to--)
951 {
952 /* Check FROM for non-wildcard field. */
953 if (! NILP (tmp[j]) && range[j].from < from)
954 {
955 while (range[j].from < from)
956 range[j].mask &= ~(1 << range[j].from++);
957 while (from < 14 && ! (range[j].mask & (1 << from)))
958 from++;
959 range[j].from = from;
960 }
961 else
962 from = range[j].from;
963 if (range[j].to > to)
964 {
965 while (range[j].to > to)
966 range[j].mask &= ~(1 << range[j].to--);
967 while (to >= 0 && ! (range[j].mask & (1 << to)))
968 to--;
969 range[j].to = to;
970 }
971 else
972 to = range[j].to;
973 if (from > to)
974 return -1;
975 }
976 }
4485a28e
KH
977 }
978 }
979
c5e87d10 980 /* Decide all fields from restrictions in RANGE. */
4485a28e
KH
981 for (i = j = 0; i < n ; i++)
982 {
983 if (j < range[i].from)
984 {
985 if (i == 0 || ! NILP (tmp[i - 1]))
986 /* None of TMP[X] corresponds to Jth field. */
987 return -1;
988 for (; j < range[i].from; j++)
989 field[j] = Qnil;
990 }
991 field[j++] = tmp[i];
992 }
993 if (! NILP (tmp[n - 1]) && j < XLFD_REGISTRY_INDEX)
994 return -1;
995 for (; j < XLFD_LAST_INDEX; j++)
996 field[j] = Qnil;
997 if (INTEGERP (field[XLFD_ENCODING_INDEX]))
998 field[XLFD_ENCODING_INDEX]
999 = Fintern (Fnumber_to_string (field[XLFD_ENCODING_INDEX]), Qnil);
1000 return 0;
1001}
1002
43a1d19b 1003
ef18374f 1004/* Parse NAME (null terminated) as XLFD and store information in FONT
9331887d
KH
1005 (font-spec or font-entity). Size property of FONT is set as
1006 follows:
1007 specified XLFD fields FONT property
1008 --------------------- -------------
1009 PIXEL_SIZE PIXEL_SIZE (Lisp integer)
1010 POINT_SIZE and RESY calculated pixel size (Lisp integer)
1011 POINT_SIZE POINT_SIZE/10 (Lisp float)
1012
ec6fe57c 1013 If NAME is successfully parsed, return 0. Otherwise return -1.
9331887d 1014
ec6fe57c
KH
1015 FONT is usually a font-spec, but when this function is called from
1016 X font backend driver, it is a font-entity. In that case, NAME is
35027d0c 1017 a fully specified XLFD. */
c2f5bfd6
KH
1018
1019int
984e7f30 1020font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
c2f5bfd6 1021{
35027d0c 1022 int i, j, n;
cf23b845 1023 char *f[XLFD_LAST_INDEX + 1];
c2f5bfd6 1024 Lisp_Object val;
4485a28e 1025 char *p;
c2f5bfd6 1026
e3928081 1027 if (len > 255 || !len)
c2f5bfd6
KH
1028 /* Maximum XLFD name length is 255. */
1029 return -1;
ec6fe57c 1030 /* Accept "*-.." as a fully specified XLFD. */
e3928081 1031 if (name[0] == '*' && (len == 1 || name[1] == '-'))
ec6fe57c
KH
1032 i = 1, f[XLFD_FOUNDRY_INDEX] = name;
1033 else
1034 i = 0;
1035 for (p = name + i; *p; p++)
35027d0c
KH
1036 if (*p == '-')
1037 {
1038 f[i++] = p + 1;
1039 if (i == XLFD_LAST_INDEX)
1040 break;
1041 }
1042 f[i] = name + len;
c2f5bfd6 1043
2f286d4f
KH
1044#define INTERN_FIELD(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 0)
1045#define INTERN_FIELD_SYM(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 1)
4485a28e 1046
ec6fe57c 1047 if (i == XLFD_LAST_INDEX)
4485a28e 1048 {
35027d0c 1049 /* Fully specified XLFD. */
ec6fe57c
KH
1050 int pixel_size;
1051
2f286d4f
KH
1052 ASET (font, FONT_FOUNDRY_INDEX, INTERN_FIELD_SYM (XLFD_FOUNDRY_INDEX));
1053 ASET (font, FONT_FAMILY_INDEX, INTERN_FIELD_SYM (XLFD_FAMILY_INDEX));
35027d0c
KH
1054 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1055 i <= XLFD_SWIDTH_INDEX; i++, j++)
4485a28e 1056 {
2f286d4f 1057 val = INTERN_FIELD_SYM (i);
ec6fe57c 1058 if (! NILP (val))
4485a28e 1059 {
2f286d4f 1060 if ((n = font_style_to_value (j, INTERN_FIELD_SYM (i), 0)) < 0)
35027d0c
KH
1061 return -1;
1062 ASET (font, j, make_number (n));
ec6fe57c
KH
1063 }
1064 }
2f286d4f 1065 ASET (font, FONT_ADSTYLE_INDEX, INTERN_FIELD_SYM (XLFD_ADSTYLE_INDEX));
35027d0c
KH
1066 if (strcmp (f[XLFD_REGISTRY_INDEX], "*-*") == 0)
1067 ASET (font, FONT_REGISTRY_INDEX, Qnil);
1068 else
1069 ASET (font, FONT_REGISTRY_INDEX,
1070 font_intern_prop (f[XLFD_REGISTRY_INDEX],
2f286d4f
KH
1071 f[XLFD_LAST_INDEX] - f[XLFD_REGISTRY_INDEX],
1072 1));
ec6fe57c
KH
1073 p = f[XLFD_PIXEL_INDEX];
1074 if (*p == '[' && (pixel_size = parse_matrix (p)) >= 0)
51c01100 1075 ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
ec6fe57c
KH
1076 else
1077 {
35027d0c
KH
1078 val = INTERN_FIELD (XLFD_PIXEL_INDEX);
1079 if (INTEGERP (val))
ec6fe57c 1080 ASET (font, FONT_SIZE_INDEX, val);
b57d9029
KH
1081 else if (FONT_ENTITY_P (font))
1082 return -1;
ec6fe57c
KH
1083 else
1084 {
1085 double point_size = -1;
1086
4e6a86c6 1087 eassert (FONT_SPEC_P (font));
ec6fe57c
KH
1088 p = f[XLFD_POINT_INDEX];
1089 if (*p == '[')
1090 point_size = parse_matrix (p);
620f13b0 1091 else if (c_isdigit (*p))
ec6fe57c
KH
1092 point_size = atoi (p), point_size /= 10;
1093 if (point_size >= 0)
1094 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
4485a28e
KH
1095 }
1096 }
ec6fe57c 1097
087048cd
KH
1098 val = INTERN_FIELD (XLFD_RESY_INDEX);
1099 if (! NILP (val) && ! INTEGERP (val))
1100 return -1;
1101 ASET (font, FONT_DPI_INDEX, val);
35027d0c
KH
1102 val = INTERN_FIELD (XLFD_SPACING_INDEX);
1103 if (! NILP (val))
ec6fe57c 1104 {
35027d0c
KH
1105 val = font_prop_validate_spacing (QCspacing, val);
1106 if (! INTEGERP (val))
1107 return -1;
1108 ASET (font, FONT_SPACING_INDEX, val);
ec6fe57c 1109 }
ec6fe57c
KH
1110 p = f[XLFD_AVGWIDTH_INDEX];
1111 if (*p == '~')
1112 p++;
087048cd
KH
1113 val = font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p, 0);
1114 if (! NILP (val) && ! INTEGERP (val))
1115 return -1;
1116 ASET (font, FONT_AVGWIDTH_INDEX, val);
4485a28e
KH
1117 }
1118 else
c2f5bfd6 1119 {
a864ef14 1120 bool wild_card_found = 0;
ec6fe57c 1121 Lisp_Object prop[XLFD_LAST_INDEX];
4485a28e 1122
35027d0c
KH
1123 if (FONT_ENTITY_P (font))
1124 return -1;
ec6fe57c 1125 for (j = 0; j < i; j++)
4485a28e 1126 {
ec6fe57c 1127 if (*f[j] == '*')
4485a28e 1128 {
ec6fe57c
KH
1129 if (f[j][1] && f[j][1] != '-')
1130 return -1;
1131 prop[j] = Qnil;
1132 wild_card_found = 1;
1133 }
ec6fe57c 1134 else if (j + 1 < i)
35027d0c 1135 prop[j] = INTERN_FIELD (j);
ec6fe57c 1136 else
2f286d4f 1137 prop[j] = font_intern_prop (f[j], f[i] - f[j], 0);
4485a28e
KH
1138 }
1139 if (! wild_card_found)
c2f5bfd6 1140 return -1;
ec6fe57c 1141 if (font_expand_wildcards (prop, i) < 0)
4485a28e 1142 return -1;
ec6fe57c 1143
35027d0c
KH
1144 ASET (font, FONT_FOUNDRY_INDEX, prop[XLFD_FOUNDRY_INDEX]);
1145 ASET (font, FONT_FAMILY_INDEX, prop[XLFD_FAMILY_INDEX]);
1146 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1147 i <= XLFD_SWIDTH_INDEX; i++, j++)
ec6fe57c 1148 if (! NILP (prop[i]))
35027d0c
KH
1149 {
1150 if ((n = font_style_to_value (j, prop[i], 1)) < 0)
1151 return -1;
1152 ASET (font, j, make_number (n));
1153 }
1154 ASET (font, FONT_ADSTYLE_INDEX, prop[XLFD_ADSTYLE_INDEX]);
ec6fe57c
KH
1155 val = prop[XLFD_REGISTRY_INDEX];
1156 if (NILP (val))
c2f5bfd6 1157 {
ec6fe57c
KH
1158 val = prop[XLFD_ENCODING_INDEX];
1159 if (! NILP (val))
35027d0c 1160 val = concat2 (build_string ("*-"), SYMBOL_NAME (val));
4485a28e 1161 }
ec6fe57c 1162 else if (NILP (prop[XLFD_ENCODING_INDEX]))
35027d0c 1163 val = concat2 (SYMBOL_NAME (val), build_string ("-*"));
4485a28e 1164 else
35027d0c
KH
1165 val = concat3 (SYMBOL_NAME (val), build_string ("-"),
1166 SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
ec6fe57c 1167 if (! NILP (val))
35027d0c 1168 ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
ec6fe57c
KH
1169
1170 if (INTEGERP (prop[XLFD_PIXEL_INDEX]))
1171 ASET (font, FONT_SIZE_INDEX, prop[XLFD_PIXEL_INDEX]);
1172 else if (INTEGERP (prop[XLFD_POINT_INDEX]))
4485a28e 1173 {
ec6fe57c 1174 double point_size = XINT (prop[XLFD_POINT_INDEX]);
c2f5bfd6 1175
ec6fe57c
KH
1176 ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
1177 }
c2f5bfd6 1178
35027d0c
KH
1179 if (INTEGERP (prop[XLFD_RESX_INDEX]))
1180 ASET (font, FONT_DPI_INDEX, prop[XLFD_RESY_INDEX]);
1181 if (! NILP (prop[XLFD_SPACING_INDEX]))
1182 {
1183 val = font_prop_validate_spacing (QCspacing,
1184 prop[XLFD_SPACING_INDEX]);
1185 if (! INTEGERP (val))
1186 return -1;
1187 ASET (font, FONT_SPACING_INDEX, val);
1188 }
ec6fe57c 1189 if (INTEGERP (prop[XLFD_AVGWIDTH_INDEX]))
35027d0c 1190 ASET (font, FONT_AVGWIDTH_INDEX, prop[XLFD_AVGWIDTH_INDEX]);
c2f5bfd6
KH
1191 }
1192
ec6fe57c 1193 return 0;
c2f5bfd6
KH
1194}
1195
1196/* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES
1197 length), and return the name length. If FONT_SIZE_INDEX of FONT is
1198 0, use PIXEL_SIZE instead. */
1199
d923b542 1200ptrdiff_t
971de7fb 1201font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
c2f5bfd6 1202{
e663c700 1203 char *p;
00dc3ead 1204 const char *f[XLFD_REGISTRY_INDEX + 1];
c2f5bfd6 1205 Lisp_Object val;
c21721cc 1206 int i, j, len;
c2f5bfd6 1207
4e6a86c6 1208 eassert (FONTP (font));
c2f5bfd6
KH
1209
1210 for (i = FONT_FOUNDRY_INDEX, j = XLFD_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX;
1211 i++, j++)
1212 {
1213 if (i == FONT_ADSTYLE_INDEX)
1214 j = XLFD_ADSTYLE_INDEX;
1215 else if (i == FONT_REGISTRY_INDEX)
1216 j = XLFD_REGISTRY_INDEX;
1217 val = AREF (font, i);
1218 if (NILP (val))
1bb1d99b
KH
1219 {
1220 if (j == XLFD_REGISTRY_INDEX)
c21721cc 1221 f[j] = "*-*";
1bb1d99b 1222 else
c21721cc 1223 f[j] = "*";
1bb1d99b 1224 }
c2f5bfd6
KH
1225 else
1226 {
1227 if (SYMBOLP (val))
1228 val = SYMBOL_NAME (val);
1bb1d99b 1229 if (j == XLFD_REGISTRY_INDEX
51b59d79 1230 && ! strchr (SSDATA (val), '-'))
1bb1d99b
KH
1231 {
1232 /* Change "jisx0208*" and "jisx0208" to "jisx0208*-*". */
c21721cc
PE
1233 ptrdiff_t alloc = SBYTES (val) + 4;
1234 if (nbytes <= alloc)
1235 return -1;
1236 f[j] = p = alloca (alloc);
1237 sprintf (p, "%s%s-*", SDATA (val),
31ff141c 1238 &"*"[SDATA (val)[SBYTES (val) - 1] == '*']);
1bb1d99b
KH
1239 }
1240 else
c21721cc 1241 f[j] = SSDATA (val);
c2f5bfd6
KH
1242 }
1243 }
1244
1245 for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX;
1246 i++, j++)
1247 {
35027d0c 1248 val = font_style_symbolic (font, i, 0);
c2f5bfd6 1249 if (NILP (val))
c21721cc 1250 f[j] = "*";
c2f5bfd6
KH
1251 else
1252 {
e1bf05c1
KH
1253 int c, k, l;
1254 ptrdiff_t alloc;
1255
35027d0c 1256 val = SYMBOL_NAME (val);
e1bf05c1
KH
1257 alloc = SBYTES (val) + 1;
1258 if (nbytes <= alloc)
1259 return -1;
00dc3ead 1260 f[j] = p = alloca (alloc);
e1bf05c1
KH
1261 /* Copy the name while excluding '-', '?', ',', and '"'. */
1262 for (k = l = 0; k < alloc; k++)
1263 {
1264 c = SREF (val, k);
1265 if (c != '-' && c != '?' && c != ',' && c != '"')
00dc3ead 1266 p[l++] = c;
e1bf05c1 1267 }
c2f5bfd6
KH
1268 }
1269 }
1270
1271 val = AREF (font, FONT_SIZE_INDEX);
4e6a86c6 1272 eassert (NUMBERP (val) || NILP (val));
c2f5bfd6
KH
1273 if (INTEGERP (val))
1274 {
c21721cc
PE
1275 EMACS_INT v = XINT (val);
1276 if (v <= 0)
1277 v = pixel_size;
1278 if (v > 0)
81aefea4 1279 {
c21721cc
PE
1280 f[XLFD_PIXEL_INDEX] = p =
1281 alloca (sizeof "-*" + INT_STRLEN_BOUND (EMACS_INT));
1282 sprintf (p, "%"pI"d-*", v);
81aefea4
SM
1283 }
1284 else
c21721cc 1285 f[XLFD_PIXEL_INDEX] = "*-*";
c2f5bfd6
KH
1286 }
1287 else if (FLOATP (val))
1288 {
c21721cc
PE
1289 double v = XFLOAT_DATA (val) * 10;
1290 f[XLFD_PIXEL_INDEX] = p = alloca (sizeof "*-" + 1 + DBL_MAX_10_EXP + 1);
1291 sprintf (p, "*-%.0f", v);
c2f5bfd6
KH
1292 }
1293 else
c21721cc 1294 f[XLFD_PIXEL_INDEX] = "*-*";
ec6fe57c 1295
35027d0c 1296 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
c2f5bfd6 1297 {
c21721cc
PE
1298 EMACS_INT v = XINT (AREF (font, FONT_DPI_INDEX));
1299 f[XLFD_RESX_INDEX] = p =
1300 alloca (sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT));
1301 sprintf (p, "%"pI"d-%"pI"d", v, v);
c2f5bfd6
KH
1302 }
1303 else
c21721cc 1304 f[XLFD_RESX_INDEX] = "*-*";
35027d0c 1305 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
ec6fe57c 1306 {
c21721cc 1307 EMACS_INT spacing = XINT (AREF (font, FONT_SPACING_INDEX));
ec6fe57c 1308
35027d0c
KH
1309 f[XLFD_SPACING_INDEX] = (spacing <= FONT_SPACING_PROPORTIONAL ? "p"
1310 : spacing <= FONT_SPACING_DUAL ? "d"
1311 : spacing <= FONT_SPACING_MONO ? "m"
1312 : "c");
ec6fe57c 1313 }
35027d0c 1314 else
c21721cc 1315 f[XLFD_SPACING_INDEX] = "*";
35027d0c
KH
1316 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1317 {
c21721cc
PE
1318 f[XLFD_AVGWIDTH_INDEX] = p = alloca (INT_BUFSIZE_BOUND (EMACS_INT));
1319 sprintf (p, "%"pI"d", XINT (AREF (font, FONT_AVGWIDTH_INDEX)));
35027d0c
KH
1320 }
1321 else
c21721cc 1322 f[XLFD_AVGWIDTH_INDEX] = "*";
8666506e
PE
1323 len = snprintf (name, nbytes, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
1324 f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
1325 f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
1326 f[XLFD_SWIDTH_INDEX], f[XLFD_ADSTYLE_INDEX],
1327 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
1328 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
1329 f[XLFD_REGISTRY_INDEX]);
1330 return len < nbytes ? len : -1;
c2f5bfd6
KH
1331}
1332
8c102d5b
CY
1333/* Parse NAME (null terminated) and store information in FONT
1334 (font-spec or font-entity). NAME is supplied in either the
1335 Fontconfig or GTK font name format. If NAME is successfully
1336 parsed, return 0. Otherwise return -1.
1337
1338 The fontconfig format is
1339
1340 FAMILY[-SIZE][:PROP1[=VAL1][:PROP2[=VAL2]...]]
1341
1342 The GTK format is
1343
1344 FAMILY [PROPS...] [SIZE]
1345
1346 This function tries to guess which format it is. */
ef18374f 1347
2f7c71a1 1348static int
984e7f30 1349font_parse_fcname (char *name, ptrdiff_t len, Lisp_Object font)
ef18374f 1350{
8c102d5b
CY
1351 char *p, *q;
1352 char *size_beg = NULL, *size_end = NULL;
1353 char *props_beg = NULL, *family_end = NULL;
ef18374f 1354
ec6fe57c
KH
1355 if (len == 0)
1356 return -1;
8c102d5b
CY
1357
1358 for (p = name; *p; p++)
ef18374f 1359 {
8c102d5b
CY
1360 if (*p == '\\' && p[1])
1361 p++;
1362 else if (*p == ':')
ef18374f 1363 {
59facb78 1364 props_beg = family_end = p;
8c102d5b
CY
1365 break;
1366 }
1367 else if (*p == '-')
1368 {
a864ef14 1369 bool decimal = 0, size_found = 1;
8c102d5b 1370 for (q = p + 1; *q && *q != ':'; q++)
620f13b0 1371 if (! c_isdigit (*q))
8c102d5b 1372 {
b1868a1a
CY
1373 if (*q != '.' || decimal)
1374 {
1375 size_found = 0;
1376 break;
1377 }
1378 decimal = 1;
8c102d5b
CY
1379 }
1380 if (size_found)
1381 {
1382 family_end = p;
1383 size_beg = p + 1;
1384 size_end = q;
1385 break;
1386 }
ef18374f 1387 }
ef18374f 1388 }
9331887d 1389
8c102d5b
CY
1390 if (family_end)
1391 {
637fa988
JD
1392 Lisp_Object extra_props = Qnil;
1393
8c102d5b
CY
1394 /* A fontconfig name with size and/or property data. */
1395 if (family_end > name)
1396 {
1397 Lisp_Object family;
1398 family = font_intern_prop (name, family_end - name, 1);
1399 ASET (font, FONT_FAMILY_INDEX, family);
1400 }
1401 if (size_beg)
1402 {
1403 double point_size = strtod (size_beg, &size_end);
1404 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1405 if (*size_end == ':' && size_end[1])
59facb78 1406 props_beg = size_end;
8c102d5b
CY
1407 }
1408 if (props_beg)
1409 {
d26424c5 1410 /* Now parse ":KEY=VAL" patterns. */
59facb78 1411 Lisp_Object val;
8c102d5b 1412
59facb78 1413 for (p = props_beg; *p; p = q)
8c102d5b 1414 {
8c102d5b 1415 for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
8c102d5b
CY
1416 if (*q != '=')
1417 {
1418 /* Must be an enumerated value. */
b5b8c9e5 1419 ptrdiff_t word_len;
59facb78
CY
1420 p = p + 1;
1421 word_len = q - p;
8c102d5b 1422 val = font_intern_prop (p, q - p, 1);
9277a69d 1423
4ec88040
AS
1424#define PROP_MATCH(STR) (word_len == strlen (STR) \
1425 && memcmp (p, STR, strlen (STR)) == 0)
1426
1427 if (PROP_MATCH ("light")
1428 || PROP_MATCH ("medium")
1429 || PROP_MATCH ("demibold")
1430 || PROP_MATCH ("bold")
1431 || PROP_MATCH ("black"))
8c102d5b 1432 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
4ec88040
AS
1433 else if (PROP_MATCH ("roman")
1434 || PROP_MATCH ("italic")
1435 || PROP_MATCH ("oblique"))
8c102d5b 1436 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
4ec88040 1437 else if (PROP_MATCH ("charcell"))
8c102d5b
CY
1438 ASET (font, FONT_SPACING_INDEX,
1439 make_number (FONT_SPACING_CHARCELL));
4ec88040 1440 else if (PROP_MATCH ("mono"))
8c102d5b
CY
1441 ASET (font, FONT_SPACING_INDEX,
1442 make_number (FONT_SPACING_MONO));
4ec88040 1443 else if (PROP_MATCH ("proportional"))
8c102d5b
CY
1444 ASET (font, FONT_SPACING_INDEX,
1445 make_number (FONT_SPACING_PROPORTIONAL));
9277a69d 1446#undef PROP_MATCH
8c102d5b 1447 }
59facb78 1448 else
8c102d5b 1449 {
59facb78 1450 /* KEY=VAL pairs */
8c102d5b 1451 Lisp_Object key;
59facb78 1452 int prop;
51c01100 1453
59facb78 1454 if (q - p == 10 && memcmp (p + 1, "pixelsize", 9) == 0)
8c102d5b
CY
1455 prop = FONT_SIZE_INDEX;
1456 else
1457 {
1458 key = font_intern_prop (p, q - p, 1);
1459 prop = get_font_prop_index (key);
1460 }
77989187 1461
8c102d5b
CY
1462 p = q + 1;
1463 for (q = p; *q && *q != ':'; q++);
90c00b01 1464 val = font_intern_prop (p, q - p, 0);
77989187 1465
d26424c5
KH
1466 if (prop >= FONT_FOUNDRY_INDEX
1467 && prop < FONT_EXTRA_INDEX)
637fa988 1468 ASET (font, prop, font_prop_validate (prop, Qnil, val));
ce75f06e 1469 else
637fa988
JD
1470 {
1471 extra_props = nconc2 (extra_props,
6c6f1994 1472 list1 (Fcons (key, val)));
637fa988 1473 }
8c102d5b 1474 }
d26424c5 1475 p = q;
8c102d5b 1476 }
8c102d5b 1477 }
637fa988
JD
1478
1479 if (! NILP (extra_props))
1480 {
1481 struct font_driver_list *driver_list = font_driver_list;
1482 for ( ; driver_list; driver_list = driver_list->next)
1483 if (driver_list->driver->filter_properties)
1484 (*driver_list->driver->filter_properties) (font, extra_props);
1485 }
ce75f06e 1486
8c102d5b
CY
1487 }
1488 else
ef18374f 1489 {
8c102d5b
CY
1490 /* Either a fontconfig-style name with no size and property
1491 data, or a GTK-style name. */
6608a7d8
CY
1492 Lisp_Object weight = Qnil, slant = Qnil;
1493 Lisp_Object width = Qnil, size = Qnil;
1494 char *word_start;
b5b8c9e5 1495 ptrdiff_t word_len;
6608a7d8
CY
1496
1497 /* Scan backwards from the end, looking for a size. */
1498 for (p = name + len - 1; p >= name; p--)
620f13b0 1499 if (!c_isdigit (*p))
6608a7d8
CY
1500 break;
1501
1502 if ((p < name + len - 1) && ((p + 1 == name) || *p == ' '))
1503 /* Found a font size. */
1504 size = make_float (strtod (p + 1, NULL));
1505 else
1506 p = name + len;
ef18374f 1507
6608a7d8
CY
1508 /* Now P points to the termination of the string, sans size.
1509 Scan backwards, looking for font properties. */
1510 for (; p > name; p = q)
ef18374f 1511 {
6608a7d8 1512 for (q = p - 1; q >= name; q--)
9331887d 1513 {
6608a7d8
CY
1514 if (q > name && *(q-1) == '\\')
1515 --q; /* Skip quoting backslashes. */
1516 else if (*q == ' ')
1517 break;
027a33c0 1518 }
8c102d5b 1519
6608a7d8
CY
1520 word_start = q + 1;
1521 word_len = p - word_start;
8c102d5b 1522
4ec88040
AS
1523#define PROP_MATCH(STR) \
1524 (word_len == strlen (STR) \
1525 && memcmp (word_start, STR, strlen (STR)) == 0)
1526#define PROP_SAVE(VAR, STR) \
1527 (VAR = NILP (VAR) ? font_intern_prop (STR, strlen (STR), 1) : VAR)
1528
1529 if (PROP_MATCH ("Ultra-Light"))
1530 PROP_SAVE (weight, "ultra-light");
1531 else if (PROP_MATCH ("Light"))
1532 PROP_SAVE (weight, "light");
1533 else if (PROP_MATCH ("Book"))
1534 PROP_SAVE (weight, "book");
1535 else if (PROP_MATCH ("Medium"))
1536 PROP_SAVE (weight, "medium");
1537 else if (PROP_MATCH ("Semi-Bold"))
1538 PROP_SAVE (weight, "semi-bold");
1539 else if (PROP_MATCH ("Bold"))
1540 PROP_SAVE (weight, "bold");
1541 else if (PROP_MATCH ("Italic"))
1542 PROP_SAVE (slant, "italic");
1543 else if (PROP_MATCH ("Oblique"))
1544 PROP_SAVE (slant, "oblique");
1545 else if (PROP_MATCH ("Semi-Condensed"))
1546 PROP_SAVE (width, "semi-condensed");
1547 else if (PROP_MATCH ("Condensed"))
1548 PROP_SAVE (width, "condensed");
6608a7d8
CY
1549 /* An unknown word must be part of the font name. */
1550 else
fe69a722 1551 {
6608a7d8
CY
1552 family_end = p;
1553 break;
fe69a722 1554 }
ef18374f 1555 }
8c102d5b 1556#undef PROP_MATCH
372fb76b 1557#undef PROP_SAVE
9ba6fd41 1558
8c102d5b 1559 if (family_end)
6608a7d8
CY
1560 ASET (font, FONT_FAMILY_INDEX,
1561 font_intern_prop (name, family_end - name, 1));
1562 if (!NILP (size))
1563 ASET (font, FONT_SIZE_INDEX, size);
1564 if (!NILP (weight))
1565 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, weight);
1566 if (!NILP (slant))
1567 FONT_SET_STYLE (font, FONT_SLANT_INDEX, slant);
1568 if (!NILP (width))
1569 FONT_SET_STYLE (font, FONT_WIDTH_INDEX, width);
8c102d5b 1570 }
17ab8f5d 1571
9331887d 1572 return 0;
ef18374f
KH
1573}
1574
1575/* Store fontconfig's font name of FONT (font-spec or font-entity) in
1576 NAME (NBYTES length), and return the name length. If
1577 FONT_SIZE_INDEX of FONT is 0, use PIXEL_SIZE instead. */
1578
1579int
09d93395 1580font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
ef18374f 1581{
b1868a1a 1582 Lisp_Object family, foundry;
c21721cc 1583 Lisp_Object val;
ec6fe57c 1584 int point_size;
b5b8c9e5 1585 int i;
ef18374f 1586 char *p;
c21721cc 1587 char *lim;
a9262bb8 1588 Lisp_Object styles[3];
675e2c69 1589 const char *style_names[3] = { "weight", "slant", "width" };
ef18374f 1590
b1868a1a
CY
1591 family = AREF (font, FONT_FAMILY_INDEX);
1592 if (! NILP (family))
1593 {
1594 if (SYMBOLP (family))
c21721cc 1595 family = SYMBOL_NAME (family);
b1868a1a
CY
1596 else
1597 family = Qnil;
1598 }
ec6fe57c
KH
1599
1600 val = AREF (font, FONT_SIZE_INDEX);
1601 if (INTEGERP (val))
ef18374f 1602 {
ec6fe57c
KH
1603 if (XINT (val) != 0)
1604 pixel_size = XINT (val);
1605 point_size = -1;
ef18374f 1606 }
3ddb0639 1607 else
ef18374f 1608 {
4e6a86c6 1609 eassert (FLOATP (val));
ec6fe57c
KH
1610 pixel_size = -1;
1611 point_size = (int) XFLOAT_DATA (val);
ef18374f 1612 }
ec6fe57c 1613
b1868a1a
CY
1614 foundry = AREF (font, FONT_FOUNDRY_INDEX);
1615 if (! NILP (foundry))
1616 {
1617 if (SYMBOLP (foundry))
c21721cc 1618 foundry = SYMBOL_NAME (foundry);
b1868a1a
CY
1619 else
1620 foundry = Qnil;
1621 }
ec6fe57c 1622
35027d0c 1623 for (i = 0; i < 3; i++)
c21721cc 1624 styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
35027d0c 1625
ef18374f 1626 p = name;
c21721cc 1627 lim = name + nbytes;
b1868a1a 1628 if (! NILP (family))
8666506e
PE
1629 {
1630 int len = snprintf (p, lim - p, "%s", SSDATA (family));
1631 if (! (0 <= len && len < lim - p))
1632 return -1;
1633 p += len;
1634 }
ec6fe57c 1635 if (point_size > 0)
8666506e 1636 {
31ff141c 1637 int len = snprintf (p, lim - p, &"-%d"[p == name], point_size);
8666506e
PE
1638 if (! (0 <= len && len < lim - p))
1639 return -1;
1640 p += len;
1641 }
ef18374f 1642 else if (pixel_size > 0)
8666506e
PE
1643 {
1644 int len = snprintf (p, lim - p, ":pixelsize=%d", pixel_size);
1645 if (! (0 <= len && len < lim - p))
1646 return -1;
1647 p += len;
1648 }
35027d0c 1649 if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
8666506e
PE
1650 {
1651 int len = snprintf (p, lim - p, ":foundry=%s",
1652 SSDATA (SYMBOL_NAME (AREF (font,
1653 FONT_FOUNDRY_INDEX))));
1654 if (! (0 <= len && len < lim - p))
1655 return -1;
1656 p += len;
1657 }
a9262bb8 1658 for (i = 0; i < 3; i++)
35027d0c 1659 if (! NILP (styles[i]))
8666506e
PE
1660 {
1661 int len = snprintf (p, lim - p, ":%s=%s", style_names[i],
1662 SSDATA (SYMBOL_NAME (styles[i])));
1663 if (! (0 <= len && len < lim - p))
1664 return -1;
1665 p += len;
1666 }
1667
35027d0c 1668 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
8666506e
PE
1669 {
1670 int len = snprintf (p, lim - p, ":dpi=%"pI"d",
1671 XINT (AREF (font, FONT_DPI_INDEX)));
1672 if (! (0 <= len && len < lim - p))
1673 return -1;
1674 p += len;
1675 }
1676
35027d0c 1677 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
8666506e
PE
1678 {
1679 int len = snprintf (p, lim - p, ":spacing=%"pI"d",
1680 XINT (AREF (font, FONT_SPACING_INDEX)));
1681 if (! (0 <= len && len < lim - p))
1682 return -1;
1683 p += len;
1684 }
1685
35027d0c 1686 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
8666506e
PE
1687 {
1688 int len = snprintf (p, lim - p,
1689 (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0
1690 ? ":scalable=true"
1691 : ":scalable=false"));
1692 if (! (0 <= len && len < lim - p))
1693 return -1;
1694 p += len;
1695 }
1696
1697 return (p - name);
ef18374f
KH
1698}
1699
1700/* Parse NAME (null terminated) and store information in FONT
1701 (font-spec or font-entity). If NAME is successfully parsed, return
35027d0c 1702 0. Otherwise return -1. */
ef18374f
KH
1703
1704static int
984e7f30 1705font_parse_name (char *name, ptrdiff_t namelen, Lisp_Object font)
ef18374f 1706{
8966b757 1707 if (name[0] == '-' || strchr (name, '*') || strchr (name, '?'))
984e7f30
DA
1708 return font_parse_xlfd (name, namelen, font);
1709 return font_parse_fcname (name, namelen, font);
ef18374f
KH
1710}
1711
35027d0c
KH
1712
1713/* Merge FAMILY and REGISTRY into FONT_SPEC. FAMILY may have the form
1714 "FAMILY-FOUNDRY". REGISTRY may not contain charset-encoding
1715 part. */
45eb10fb 1716
c2f5bfd6 1717void
971de7fb 1718font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Object font_spec)
c2f5bfd6 1719{
35027d0c
KH
1720 int len;
1721 char *p0, *p1;
1722
d0ab1ebe
KH
1723 if (! NILP (family)
1724 && NILP (AREF (font_spec, FONT_FAMILY_INDEX)))
c2f5bfd6 1725 {
35027d0c
KH
1726 CHECK_STRING (family);
1727 len = SBYTES (family);
51b59d79 1728 p0 = SSDATA (family);
8966b757 1729 p1 = strchr (p0, '-');
35027d0c 1730 if (p1)
c2f5bfd6 1731 {
9903d1e6 1732 if ((*p0 != '*' && p1 - p0 > 0)
d0ab1ebe 1733 && NILP (AREF (font_spec, FONT_FOUNDRY_INDEX)))
2f286d4f 1734 Ffont_put (font_spec, QCfoundry, font_intern_prop (p0, p1 - p0, 1));
35027d0c
KH
1735 p1++;
1736 len -= p1 - p0;
2f286d4f 1737 Ffont_put (font_spec, QCfamily, font_intern_prop (p1, len, 1));
c2f5bfd6 1738 }
35027d0c
KH
1739 else
1740 ASET (font_spec, FONT_FAMILY_INDEX, Fintern (family, Qnil));
c2f5bfd6 1741 }
35027d0c 1742 if (! NILP (registry))
c2f5bfd6 1743 {
35027d0c
KH
1744 /* Convert "XXX" and "XXX*" to "XXX*-*". */
1745 CHECK_STRING (registry);
1746 len = SBYTES (registry);
51b59d79 1747 p0 = SSDATA (registry);
8966b757 1748 p1 = strchr (p0, '-');
35027d0c 1749 if (! p1)
c2f5bfd6 1750 {
35027d0c
KH
1751 if (SDATA (registry)[len - 1] == '*')
1752 registry = concat2 (registry, build_string ("-*"));
1753 else
1754 registry = concat2 (registry, build_string ("*-*"));
c2f5bfd6 1755 }
35027d0c
KH
1756 registry = Fdowncase (registry);
1757 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
c2f5bfd6
KH
1758 }
1759}
1760
45eb10fb 1761\f
35027d0c
KH
1762/* This part (through the next ^L) is still experimental and not
1763 tested much. We may drastically change codes. */
10d16101 1764
266fee4f 1765/* OTF handler. */
10d16101 1766
6a3dadd2
KH
1767#if 0
1768
e950d6f1
KH
1769#define LGSTRING_HEADER_SIZE 6
1770#define LGSTRING_GLYPH_SIZE 8
1771
1772static int
1dae0f0a 1773check_gstring (Lisp_Object gstring)
e950d6f1
KH
1774{
1775 Lisp_Object val;
d311d28c
PE
1776 ptrdiff_t i;
1777 int j;
e950d6f1
KH
1778
1779 CHECK_VECTOR (gstring);
1780 val = AREF (gstring, 0);
1781 CHECK_VECTOR (val);
1782 if (ASIZE (val) < LGSTRING_HEADER_SIZE)
1783 goto err;
1784 CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
f9ffa1ea
SM
1785 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING)))
1786 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING));
1787 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING)))
1788 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING));
1789 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH)))
1790 CHECK_NATNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH));
1791 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1792 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
1793 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1794 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
e950d6f1 1795
071132a9 1796 for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
e950d6f1
KH
1797 {
1798 val = LGSTRING_GLYPH (gstring, i);
1799 CHECK_VECTOR (val);
1800 if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
1801 goto err;
f9ffa1ea 1802 if (NILP (AREF (val, LGLYPH_IX_CHAR)))
e950d6f1 1803 break;
f9ffa1ea
SM
1804 CHECK_NATNUM (AREF (val, LGLYPH_IX_FROM));
1805 CHECK_NATNUM (AREF (val, LGLYPH_IX_TO));
1806 CHECK_CHARACTER (AREF (val, LGLYPH_IX_CHAR));
1807 if (!NILP (AREF (val, LGLYPH_IX_CODE)))
1808 CHECK_NATNUM (AREF (val, LGLYPH_IX_CODE));
1809 if (!NILP (AREF (val, LGLYPH_IX_WIDTH)))
1810 CHECK_NATNUM (AREF (val, LGLYPH_IX_WIDTH));
1811 if (!NILP (AREF (val, LGLYPH_IX_ADJUSTMENT)))
e950d6f1 1812 {
f9ffa1ea 1813 val = AREF (val, LGLYPH_IX_ADJUSTMENT);
e950d6f1
KH
1814 CHECK_VECTOR (val);
1815 if (ASIZE (val) < 3)
1816 goto err;
1817 for (j = 0; j < 3; j++)
1818 CHECK_NUMBER (AREF (val, j));
1819 }
1820 }
1821 return i;
1822 err:
1823 error ("Invalid glyph-string format");
1824 return -1;
1825}
1826
cf385d93 1827static void
1dae0f0a 1828check_otf_features (Lisp_Object otf_features)
cf385d93 1829{
35027d0c 1830 Lisp_Object val;
cf385d93
KH
1831
1832 CHECK_CONS (otf_features);
1833 CHECK_SYMBOL (XCAR (otf_features));
1834 otf_features = XCDR (otf_features);
1835 CHECK_CONS (otf_features);
1836 CHECK_SYMBOL (XCAR (otf_features));
1837 otf_features = XCDR (otf_features);
7d7bbefd 1838 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
cf385d93 1839 {
34348bd4 1840 CHECK_SYMBOL (XCAR (val));
cf385d93 1841 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
e6c3da20
EZ
1842 error ("Invalid OTF GSUB feature: %s",
1843 SDATA (SYMBOL_NAME (XCAR (val))));
cf385d93
KH
1844 }
1845 otf_features = XCDR (otf_features);
7d7bbefd 1846 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
cf385d93 1847 {
34348bd4 1848 CHECK_SYMBOL (XCAR (val));
cf385d93 1849 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
e6c3da20
EZ
1850 error ("Invalid OTF GPOS feature: %s",
1851 SDATA (SYMBOL_NAME (XCAR (val))));
cf385d93
KH
1852 }
1853}
1854
c2f5bfd6
KH
1855#ifdef HAVE_LIBOTF
1856#include <otf.h>
1857
733fd013 1858Lisp_Object otf_list;
c2f5bfd6
KH
1859
1860static Lisp_Object
1dae0f0a 1861otf_tag_symbol (OTF_Tag tag)
c2f5bfd6
KH
1862{
1863 char name[5];
1864
1865 OTF_tag_name (tag, name);
1866 return Fintern (make_unibyte_string (name, 4), Qnil);
1867}
1868
1869static OTF *
1dae0f0a 1870otf_open (Lisp_Object file)
c2f5bfd6 1871{
35027d0c 1872 Lisp_Object val = Fassoc (file, otf_list);
733fd013
KH
1873 OTF *otf;
1874
1875 if (! NILP (val))
2b30549c 1876 otf = XSAVE_POINTER (XCDR (val), 0);
733fd013 1877 else
c2f5bfd6 1878 {
51b59d79 1879 otf = STRINGP (file) ? OTF_open (SSDATA (file)) : NULL;
1396ac86 1880 val = make_save_ptr (otf);
35027d0c 1881 otf_list = Fcons (Fcons (file, val), otf_list);
c2f5bfd6 1882 }
733fd013 1883 return otf;
c2f5bfd6
KH
1884}
1885
1886
1887/* Return a list describing which scripts/languages FONT supports by
1888 which GSUB/GPOS features of OpenType tables. See the comment of
51c01100 1889 (struct font_driver).otf_capability. */
c2f5bfd6
KH
1890
1891Lisp_Object
1dae0f0a 1892font_otf_capability (struct font *font)
c2f5bfd6
KH
1893{
1894 OTF *otf;
1895 Lisp_Object capability = Fcons (Qnil, Qnil);
1896 int i;
1897
35027d0c 1898 otf = otf_open (font->props[FONT_FILE_INDEX]);
c2f5bfd6
KH
1899 if (! otf)
1900 return Qnil;
1901 for (i = 0; i < 2; i++)
1902 {
1903 OTF_GSUB_GPOS *gsub_gpos;
1904 Lisp_Object script_list = Qnil;
1905 int j;
1906
1907 if (OTF_get_features (otf, i == 0) < 0)
1908 continue;
1909 gsub_gpos = i == 0 ? otf->gsub : otf->gpos;
1910 for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--)
1911 {
1912 OTF_Script *script = gsub_gpos->ScriptList.Script + j;
1913 Lisp_Object langsys_list = Qnil;
1914 Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag);
1915 int k;
1916
1917 for (k = script->LangSysCount; k >= 0; k--)
1918 {
1919 OTF_LangSys *langsys;
1920 Lisp_Object feature_list = Qnil;
1921 Lisp_Object langsys_tag;
1922 int l;
1923
e80e09b4 1924 if (k == script->LangSysCount)
c2f5bfd6
KH
1925 {
1926 langsys = &script->DefaultLangSys;
1927 langsys_tag = Qnil;
1928 }
1929 else
1930 {
1931 langsys = script->LangSys + k;
1932 langsys_tag
1933 = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
1934 }
e80e09b4 1935 for (l = langsys->FeatureCount - 1; l >= 0; l--)
c2f5bfd6
KH
1936 {
1937 OTF_Feature *feature
1938 = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
1939 Lisp_Object feature_tag
1940 = otf_tag_symbol (feature->FeatureTag);
1941
1942 feature_list = Fcons (feature_tag, feature_list);
1943 }
1944 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
1945 langsys_list);
1946 }
1947 script_list = Fcons (Fcons (script_tag, langsys_list),
1948 script_list);
1949 }
1950
1951 if (i == 0)
1952 XSETCAR (capability, script_list);
1953 else
1954 XSETCDR (capability, script_list);
1955 }
1956
1957 return capability;
1958}
1959
733fd013
KH
1960/* Parse OTF features in SPEC and write a proper features spec string
1961 in FEATURES for the call of OTF_drive_gsub/gpos (of libotf). It is
1962 assured that the sufficient memory has already allocated for
1963 FEATURES. */
1964
e80e09b4 1965static void
1dae0f0a 1966generate_otf_features (Lisp_Object spec, char *features)
c2f5bfd6
KH
1967{
1968 Lisp_Object val;
35027d0c 1969 char *p;
a864ef14 1970 bool asterisk;
c2f5bfd6 1971
733fd013 1972 p = features;
e80e09b4 1973 *p = '\0';
c2f5bfd6
KH
1974 for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
1975 {
1976 val = XCAR (spec);
e80e09b4
KH
1977 CHECK_SYMBOL (val);
1978 if (p > features)
733fd013 1979 *p++ = ',';
c2f5bfd6
KH
1980 if (SREF (SYMBOL_NAME (val), 0) == '*')
1981 {
1982 asterisk = 1;
e80e09b4 1983 *p++ = '*';
c2f5bfd6
KH
1984 }
1985 else if (! asterisk)
e80e09b4
KH
1986 {
1987 val = SYMBOL_NAME (val);
c21721cc 1988 p += esprintf (p, "%s", SDATA (val));
e80e09b4 1989 }
c2f5bfd6 1990 else
e80e09b4
KH
1991 {
1992 val = SYMBOL_NAME (val);
c21721cc 1993 p += esprintf (p, "~%s", SDATA (val));
e80e09b4 1994 }
c2f5bfd6 1995 }
e80e09b4
KH
1996 if (CONSP (spec))
1997 error ("OTF spec too long");
1998}
1999
733fd013 2000Lisp_Object
1dae0f0a 2001font_otf_DeviceTable (OTF_DeviceTable *device_table)
733fd013
KH
2002{
2003 int len = device_table->StartSize - device_table->EndSize + 1;
2004
2005 return Fcons (make_number (len),
2006 make_unibyte_string (device_table->DeltaValue, len));
2007}
2008
2009Lisp_Object
1dae0f0a 2010font_otf_ValueRecord (int value_format, OTF_ValueRecord *value_record)
733fd013
KH
2011{
2012 Lisp_Object val = Fmake_vector (make_number (8), Qnil);
2013
2014 if (value_format & OTF_XPlacement)
43c0454d 2015 ASET (val, 0, make_number (value_record->XPlacement));
733fd013 2016 if (value_format & OTF_YPlacement)
43c0454d 2017 ASET (val, 1, make_number (value_record->YPlacement));
733fd013 2018 if (value_format & OTF_XAdvance)
43c0454d 2019 ASET (val, 2, make_number (value_record->XAdvance));
733fd013 2020 if (value_format & OTF_YAdvance)
43c0454d 2021 ASET (val, 3, make_number (value_record->YAdvance));
733fd013
KH
2022 if (value_format & OTF_XPlaDevice)
2023 ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
2024 if (value_format & OTF_YPlaDevice)
2025 ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
2026 if (value_format & OTF_XAdvDevice)
2027 ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
2028 if (value_format & OTF_YAdvDevice)
2029 ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
2030 return val;
2031}
2032
2033Lisp_Object
1dae0f0a 2034font_otf_Anchor (OTF_Anchor *anchor)
733fd013
KH
2035{
2036 Lisp_Object val;
2037
2038 val = Fmake_vector (make_number (anchor->AnchorFormat + 1), Qnil);
2039 ASET (val, 0, make_number (anchor->XCoordinate));
2040 ASET (val, 1, make_number (anchor->YCoordinate));
2041 if (anchor->AnchorFormat == 2)
2042 ASET (val, 2, make_number (anchor->f.f1.AnchorPoint));
2043 else
2044 {
2045 ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
2046 ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
2047 }
2048 return val;
2049}
c2f5bfd6 2050#endif /* HAVE_LIBOTF */
6a3dadd2 2051#endif /* 0 */
c2f5bfd6 2052
c2f5bfd6 2053\f
266fee4f 2054/* Font sorting. */
c2f5bfd6 2055
55e41770 2056static double
971de7fb 2057font_rescale_ratio (Lisp_Object font_entity)
55e41770
KH
2058{
2059 Lisp_Object tail, elt;
2060 Lisp_Object name = Qnil;
2061
2062 for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail))
2063 {
2064 elt = XCAR (tail);
2065 if (FLOATP (XCDR (elt)))
2066 {
2067 if (STRINGP (XCAR (elt)))
2068 {
2069 if (NILP (name))
2070 name = Ffont_xlfd_name (font_entity, Qnil);
2071 if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
2072 return XFLOAT_DATA (XCDR (elt));
2073 }
2074 else if (FONT_SPEC_P (XCAR (elt)))
2075 {
2076 if (font_match_p (XCAR (elt), font_entity))
2077 return XFLOAT_DATA (XCDR (elt));
2078 }
2079 }
2080 }
2081 return 1.0;
2082}
2083
c2f5bfd6
KH
2084/* We sort fonts by scoring each of them against a specified
2085 font-spec. The score value is 32 bit (`unsigned'), and the smaller
2086 the value is, the closer the font is to the font-spec.
2087
56dd2d86 2088 The lowest 2 bits of the score are used for driver type. The font
4007dd1c 2089 available by the most preferred font driver is 0.
35027d0c 2090
56dd2d86 2091 The 4 7-bit fields in the higher 28 bits are used for numeric properties
c2f5bfd6
KH
2092 WEIGHT, SLANT, WIDTH, and SIZE. */
2093
2094/* How many bits to shift to store the difference value of each font
56dd2d86 2095 property in a score. Note that floats for FONT_TYPE_INDEX and
35027d0c 2096 FONT_REGISTRY_INDEX are not used. */
c2f5bfd6
KH
2097static int sort_shift_bits[FONT_SIZE_INDEX + 1];
2098
9331887d
KH
2099/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
2100 The return value indicates how different ENTITY is compared with
51c13510 2101 SPEC_PROP. */
c2f5bfd6
KH
2102
2103static unsigned
971de7fb 2104font_score (Lisp_Object entity, Lisp_Object *spec_prop)
c2f5bfd6
KH
2105{
2106 unsigned score = 0;
2107 int i;
c2f5bfd6 2108
35027d0c
KH
2109 /* Score three style numeric fields. Maximum difference is 127. */
2110 for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
2111 if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
2112 {
790771b1
PE
2113 EMACS_INT diff = ((XINT (AREF (entity, i)) >> 8)
2114 - (XINT (spec_prop[i]) >> 8));
71376d4b 2115 score |= min (eabs (diff), 127) << sort_shift_bits[i];
35027d0c
KH
2116 }
2117
2118 /* Score the size. Maximum difference is 127. */
2119 i = FONT_SIZE_INDEX;
55e41770
KH
2120 if (! NILP (spec_prop[FONT_SIZE_INDEX])
2121 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
35027d0c
KH
2122 {
2123 /* We use the higher 6-bit for the actual size difference. The
2124 lowest bit is set if the DPI is different. */
b79e8648
PE
2125 EMACS_INT diff;
2126 EMACS_INT pixel_size = XINT (spec_prop[FONT_SIZE_INDEX]);
35027d0c 2127
55e41770
KH
2128 if (CONSP (Vface_font_rescale_alist))
2129 pixel_size *= font_rescale_ratio (entity);
71376d4b 2130 diff = eabs (pixel_size - XINT (AREF (entity, FONT_SIZE_INDEX))) << 1;
35027d0c
KH
2131 if (! NILP (spec_prop[FONT_DPI_INDEX])
2132 && ! EQ (spec_prop[FONT_DPI_INDEX], AREF (entity, FONT_DPI_INDEX)))
2133 diff |= 1;
c0a6070d
KH
2134 if (! NILP (spec_prop[FONT_AVGWIDTH_INDEX])
2135 && ! EQ (spec_prop[FONT_AVGWIDTH_INDEX], AREF (entity, FONT_AVGWIDTH_INDEX)))
2136 diff |= 1;
35027d0c 2137 score |= min (diff, 127) << sort_shift_bits[FONT_SIZE_INDEX];
c2f5bfd6
KH
2138 }
2139
2140 return score;
2141}
2142
2143
72d36834
KH
2144/* Concatenate all elements of LIST into one vector. LIST is a list
2145 of font-entity vectors. */
c2f5bfd6 2146
72d36834
KH
2147static Lisp_Object
2148font_vconcat_entity_vectors (Lisp_Object list)
c2f5bfd6 2149{
72d36834 2150 int nargs = XINT (Flength (list));
663e2b3f 2151 Lisp_Object *args = alloca (word_size * nargs);
72d36834
KH
2152 int i;
2153
2154 for (i = 0; i < nargs; i++, list = XCDR (list))
2155 args[i] = XCAR (list);
2156 return Fvconcat (nargs, args);
c2f5bfd6
KH
2157}
2158
2159
2160/* The structure for elements being sorted by qsort. */
2161struct font_sort_data
2162{
2163 unsigned score;
72d36834 2164 int font_driver_preference;
c2f5bfd6
KH
2165 Lisp_Object entity;
2166};
2167
2168
72d36834
KH
2169/* The comparison function for qsort. */
2170
2171static int
971de7fb 2172font_compare (const void *d1, const void *d2)
72d36834
KH
2173{
2174 const struct font_sort_data *data1 = d1;
2175 const struct font_sort_data *data2 = d2;
2176
2177 if (data1->score < data2->score)
2178 return -1;
2179 else if (data1->score > data2->score)
2180 return 1;
2181 return (data1->font_driver_preference - data2->font_driver_preference);
2182}
2183
2184
2185/* Sort each font-entity vector in LIST by closeness to font-spec PREFER.
c2f5bfd6 2186 If PREFER specifies a point-size, calculate the corresponding
9331887d 2187 pixel-size from QCdpi property of PREFER or from the Y-resolution
7181ea6a 2188 of FRAME before sorting.
35027d0c 2189
c9477f01
KH
2190 If BEST-ONLY is nonzero, return the best matching entity (that
2191 supports the character BEST-ONLY if BEST-ONLY is positive, or any
72d36834
KH
2192 if BEST-ONLY is negative). Otherwise, return the sorted result as
2193 a single vector of font-entities.
c9477f01 2194
72d36834
KH
2195 This function does no optimization for the case that the total
2196 number of elements is 1. The caller should avoid calling this in
2197 such a case. */
c2f5bfd6
KH
2198
2199static Lisp_Object
fdb396e2
DA
2200font_sort_entities (Lisp_Object list, Lisp_Object prefer,
2201 struct frame *f, int best_only)
c2f5bfd6 2202{
9331887d 2203 Lisp_Object prefer_prop[FONT_SPEC_MAX];
72d36834 2204 int len, maxlen, i;
c2f5bfd6 2205 struct font_sort_data *data;
35027d0c 2206 unsigned best_score;
72d36834 2207 Lisp_Object best_entity;
5ad03b97 2208 Lisp_Object tail, vec IF_LINT (= Qnil);
c2f5bfd6
KH
2209 USE_SAFE_ALLOCA;
2210
9903d1e6 2211 for (i = FONT_WEIGHT_INDEX; i <= FONT_AVGWIDTH_INDEX; i++)
9331887d 2212 prefer_prop[i] = AREF (prefer, i);
9331887d
KH
2213 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2214 prefer_prop[FONT_SIZE_INDEX]
fdb396e2 2215 = make_number (font_pixel_size (f, prefer));
9331887d 2216
72d36834
KH
2217 if (NILP (XCDR (list)))
2218 {
2219 /* What we have to take care of is this single vector. */
2220 vec = XCAR (list);
2221 maxlen = ASIZE (vec);
2222 }
2223 else if (best_only)
2224 {
2225 /* We don't have to perform sort, so there's no need of creating
2226 a single vector. But, we must find the length of the longest
2227 vector. */
2228 maxlen = 0;
2229 for (tail = list; CONSP (tail); tail = XCDR (tail))
2230 if (maxlen < ASIZE (XCAR (tail)))
2231 maxlen = ASIZE (XCAR (tail));
2232 }
2233 else
2234 {
2235 /* We have to create a single vector to sort it. */
2236 vec = font_vconcat_entity_vectors (list);
2237 maxlen = ASIZE (vec);
2238 }
2239
98c6f1e3 2240 data = SAFE_ALLOCA (maxlen * sizeof *data);
c9477f01
KH
2241 best_score = 0xFFFFFFFF;
2242 best_entity = Qnil;
72d36834
KH
2243
2244 for (tail = list; CONSP (tail); tail = XCDR (tail))
c2f5bfd6 2245 {
72d36834
KH
2246 int font_driver_preference = 0;
2247 Lisp_Object current_font_driver;
ce75f06e 2248
72d36834
KH
2249 if (best_only)
2250 vec = XCAR (tail);
2251 len = ASIZE (vec);
2252
2253 /* We are sure that the length of VEC > 0. */
2254 current_font_driver = AREF (AREF (vec, 0), FONT_TYPE_INDEX);
2255 /* Score the elements. */
2256 for (i = 0; i < len; i++)
35027d0c 2257 {
72d36834
KH
2258 data[i].entity = AREF (vec, i);
2259 data[i].score
2260 = ((best_only <= 0 || font_has_char (f, data[i].entity, best_only)
2261 > 0)
2262 ? font_score (data[i].entity, prefer_prop)
2263 : 0xFFFFFFFF);
2264 if (best_only && best_score > data[i].score)
2265 {
2266 best_score = data[i].score;
2267 best_entity = data[i].entity;
2268 if (best_score == 0)
2269 break;
2270 }
2271 if (! EQ (current_font_driver, AREF (AREF (vec, i), FONT_TYPE_INDEX)))
2272 {
2273 current_font_driver = AREF (AREF (vec, i), FONT_TYPE_INDEX);
2274 font_driver_preference++;
2275 }
2276 data[i].font_driver_preference = font_driver_preference;
35027d0c 2277 }
72d36834
KH
2278
2279 /* Sort if necessary. */
2280 if (! best_only)
2281 {
2282 qsort (data, len, sizeof *data, font_compare);
2283 for (i = 0; i < len; i++)
2284 ASET (vec, i, data[i].entity);
2285 break;
2286 }
2287 else
2288 vec = best_entity;
c2f5bfd6 2289 }
72d36834 2290
c2f5bfd6
KH
2291 SAFE_FREE ();
2292
652b9560 2293 FONT_ADD_LOG ("sort-by", prefer, vec);
c2f5bfd6
KH
2294 return vec;
2295}
2296
2297\f
2298/* API of Font Service Layer. */
2299
45eb10fb
KH
2300/* Reflect ORDER (see the variable font_sort_order in xfaces.c) to
2301 sort_shift_bits. Finternal_set_font_selection_order calls this
2302 function with font_sort_order after setting up it. */
2303
c2f5bfd6 2304void
971de7fb 2305font_update_sort_order (int *order)
c2f5bfd6 2306{
35027d0c 2307 int i, shift_bits;
c2f5bfd6 2308
943b7eea 2309 for (i = 0, shift_bits = 23; i < 4; i++, shift_bits -= 7)
c2f5bfd6
KH
2310 {
2311 int xlfd_idx = order[i];
2312
2313 if (xlfd_idx == XLFD_WEIGHT_INDEX)
2314 sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits;
2315 else if (xlfd_idx == XLFD_SLANT_INDEX)
2316 sort_shift_bits[FONT_SLANT_INDEX] = shift_bits;
2317 else if (xlfd_idx == XLFD_SWIDTH_INDEX)
2318 sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits;
2319 else
2320 sort_shift_bits[FONT_SIZE_INDEX] = shift_bits;
2321 }
2322}
2323
a864ef14
PE
2324static bool
2325font_check_otf_features (Lisp_Object script, Lisp_Object langsys,
2326 Lisp_Object features, Lisp_Object table)
51c13510
KH
2327{
2328 Lisp_Object val;
a864ef14 2329 bool negative;
51c13510
KH
2330
2331 table = assq_no_quit (script, table);
2332 if (NILP (table))
2333 return 0;
2334 table = XCDR (table);
2335 if (! NILP (langsys))
2336 {
2337 table = assq_no_quit (langsys, table);
2338 if (NILP (table))
2339 return 0;
2340 }
2341 else
2342 {
2343 val = assq_no_quit (Qnil, table);
2344 if (NILP (val))
2345 table = XCAR (table);
2346 else
2347 table = val;
2348 }
2349 table = XCDR (table);
2350 for (negative = 0; CONSP (features); features = XCDR (features))
2351 {
2352 if (NILP (XCAR (features)))
c423ecca
KH
2353 {
2354 negative = 1;
2355 continue;
2356 }
51c13510
KH
2357 if (NILP (Fmemq (XCAR (features), table)) != negative)
2358 return 0;
2359 }
2360 return 1;
2361}
2362
2363/* Check if OTF_CAPABILITY satisfies SPEC (otf-spec). */
2364
a864ef14 2365static bool
3cba9369 2366font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
51c13510
KH
2367{
2368 Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
2369
2370 script = XCAR (spec);
2371 spec = XCDR (spec);
2372 if (! NILP (spec))
2373 {
2374 langsys = XCAR (spec);
2375 spec = XCDR (spec);
2376 if (! NILP (spec))
2377 {
2378 gsub = XCAR (spec);
2379 spec = XCDR (spec);
2380 if (! NILP (spec))
2381 gpos = XCAR (spec);
2382 }
2383 }
2384
2385 if (! NILP (gsub) && ! font_check_otf_features (script, langsys, gsub,
2386 XCAR (otf_capability)))
2387 return 0;
2388 if (! NILP (gpos) && ! font_check_otf_features (script, langsys, gpos,
2389 XCDR (otf_capability)))
2390 return 0;
2391 return 1;
2392}
2393
45eb10fb 2394
51c13510
KH
2395
2396/* Check if FONT (font-entity or font-object) matches with the font
2397 specification SPEC. */
45eb10fb 2398
a864ef14 2399bool
971de7fb 2400font_match_p (Lisp_Object spec, Lisp_Object font)
ef18374f 2401{
51c13510
KH
2402 Lisp_Object prop[FONT_SPEC_MAX], *props;
2403 Lisp_Object extra, font_extra;
ef18374f
KH
2404 int i;
2405
51c13510
KH
2406 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
2407 if (! NILP (AREF (spec, i))
2408 && ! NILP (AREF (font, i))
2409 && ! EQ (AREF (spec, i), AREF (font, i)))
2410 return 0;
2411 props = XFONT_SPEC (spec)->props;
2412 if (FLOATP (props[FONT_SIZE_INDEX]))
2413 {
2414 for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
2415 prop[i] = AREF (spec, i);
2416 prop[FONT_SIZE_INDEX]
2417 = make_number (font_pixel_size (XFRAME (selected_frame), spec));
2418 props = prop;
2419 }
2420
2421 if (font_score (font, props) > 0)
2422 return 0;
2423 extra = AREF (spec, FONT_EXTRA_INDEX);
2424 font_extra = AREF (font, FONT_EXTRA_INDEX);
2425 for (; CONSP (extra); extra = XCDR (extra))
35027d0c 2426 {
51c13510
KH
2427 Lisp_Object key = XCAR (XCAR (extra));
2428 Lisp_Object val = XCDR (XCAR (extra)), val2;
2429
2430 if (EQ (key, QClang))
2431 {
2432 val2 = assq_no_quit (key, font_extra);
2433 if (NILP (val2))
2434 return 0;
2435 val2 = XCDR (val2);
2436 if (CONSP (val))
2437 {
2438 if (! CONSP (val2))
2439 return 0;
2440 while (CONSP (val))
2441 if (NILP (Fmemq (val, val2)))
2442 return 0;
2443 }
2444 else
2445 if (CONSP (val2)
2446 ? NILP (Fmemq (val, XCDR (val2)))
2447 : ! EQ (val, val2))
2448 return 0;
2449 }
2450 else if (EQ (key, QCscript))
2451 {
2452 val2 = assq_no_quit (val, Vscript_representative_chars);
5bdd4dd2
KH
2453 if (CONSP (val2))
2454 {
2455 val2 = XCDR (val2);
2456 if (CONSP (val2))
2457 {
2458 /* All characters in the list must be supported. */
2459 for (; CONSP (val2); val2 = XCDR (val2))
2460 {
d311d28c 2461 if (! CHARACTERP (XCAR (val2)))
5bdd4dd2
KH
2462 continue;
2463 if (font_encode_char (font, XFASTINT (XCAR (val2)))
2464 == FONT_INVALID_CODE)
2465 return 0;
2466 }
2467 }
2468 else if (VECTORP (val2))
2469 {
2470 /* At most one character in the vector must be supported. */
2471 for (i = 0; i < ASIZE (val2); i++)
2472 {
d311d28c 2473 if (! CHARACTERP (AREF (val2, i)))
5bdd4dd2
KH
2474 continue;
2475 if (font_encode_char (font, XFASTINT (AREF (val2, i)))
2476 != FONT_INVALID_CODE)
f5485732 2477 break;
5bdd4dd2
KH
2478 }
2479 if (i == ASIZE (val2))
2480 return 0;
2481 }
2482 }
51c13510
KH
2483 }
2484 else if (EQ (key, QCotf))
2485 {
2486 struct font *fontp;
2487
2488 if (! FONT_OBJECT_P (font))
2489 return 0;
2490 fontp = XFONT_OBJECT (font);
2491 if (! fontp->driver->otf_capability)
2492 return 0;
2493 val2 = fontp->driver->otf_capability (fontp);
2494 if (NILP (val2) || ! font_check_otf (val, val2))
2495 return 0;
2496 }
35027d0c
KH
2497 }
2498
51c13510 2499 return 1;
ef18374f 2500}
ca4da08a 2501\f
819e81df 2502
ca4da08a
KH
2503/* Font cache
2504
2505 Each font backend has the callback function get_cache, and it
2506 returns a cons cell of which cdr part can be freely used for
2507 caching fonts. The cons cell may be shared by multiple frames
2508 and/or multiple font drivers. So, we arrange the cdr part as this:
2509
2510 ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...)
2511
2512 where DRIVER-TYPE is a symbol such as `x', `xft', etc., NUM-FRAMES
2513 is a number frames sharing this cache, and FONT-CACHE-DATA is a
8c1c7611 2514 cons (FONT-SPEC . [FONT-ENTITY ...]). */
ca4da08a 2515
a10c8269
DA
2516static void font_prepare_cache (struct frame *, struct font_driver *);
2517static void font_finish_cache (struct frame *, struct font_driver *);
2518static Lisp_Object font_get_cache (struct frame *, struct font_driver *);
2519static void font_clear_cache (struct frame *, Lisp_Object,
f57e2426 2520 struct font_driver *);
ca4da08a
KH
2521
2522static void
a10c8269 2523font_prepare_cache (struct frame *f, struct font_driver *driver)
ca4da08a
KH
2524{
2525 Lisp_Object cache, val;
2526
2527 cache = driver->get_cache (f);
2528 val = XCDR (cache);
2529 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2530 val = XCDR (val);
2531 if (NILP (val))
2532 {
6c6f1994 2533 val = list2 (driver->type, make_number (1));
ca4da08a
KH
2534 XSETCDR (cache, Fcons (val, XCDR (cache)));
2535 }
2536 else
2537 {
2538 val = XCDR (XCAR (val));
2539 XSETCAR (val, make_number (XINT (XCAR (val)) + 1));
2540 }
2541}
2542
43c0454d 2543
ca4da08a 2544static void
a10c8269 2545font_finish_cache (struct frame *f, struct font_driver *driver)
ca4da08a
KH
2546{
2547 Lisp_Object cache, val, tmp;
2548
2549
2550 cache = driver->get_cache (f);
2551 val = XCDR (cache);
2552 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2553 cache = val, val = XCDR (val);
4e6a86c6 2554 eassert (! NILP (val));
ca4da08a 2555 tmp = XCDR (XCAR (val));
43c0454d 2556 XSETCAR (tmp, make_number (XINT (XCAR (tmp)) - 1));
ca4da08a
KH
2557 if (XINT (XCAR (tmp)) == 0)
2558 {
2559 font_clear_cache (f, XCAR (val), driver);
2560 XSETCDR (cache, XCDR (val));
2561 }
ca4da08a
KH
2562}
2563
43c0454d 2564
ca4da08a 2565static Lisp_Object
a10c8269 2566font_get_cache (struct frame *f, struct font_driver *driver)
ca4da08a
KH
2567{
2568 Lisp_Object val = driver->get_cache (f);
2569 Lisp_Object type = driver->type;
2570
4e6a86c6 2571 eassert (CONSP (val));
ca4da08a 2572 for (val = XCDR (val); ! EQ (XCAR (XCAR (val)), type); val = XCDR (val));
4e6a86c6 2573 eassert (CONSP (val));
ca4da08a
KH
2574 /* VAL = ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...) */
2575 val = XCDR (XCAR (val));
2576 return val;
2577}
2578
43c0454d 2579
ca4da08a 2580static void
a10c8269 2581font_clear_cache (struct frame *f, Lisp_Object cache, struct font_driver *driver)
ca4da08a
KH
2582{
2583 Lisp_Object tail, elt;
8c1c7611
DA
2584 Lisp_Object entity;
2585 ptrdiff_t i;
51c01100 2586
ca4da08a
KH
2587 /* CACHE = (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) */
2588 for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
2589 {
2590 elt = XCAR (tail);
8c1c7611 2591 /* elt should have the form (FONT-SPEC . [FONT-ENTITY ...]) */
6136b72f 2592 if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
ca4da08a 2593 {
8c1c7611
DA
2594 elt = XCDR (elt);
2595 eassert (VECTORP (elt));
2596 for (i = 0; i < ASIZE (elt); i++)
ca4da08a 2597 {
8c1c7611 2598 entity = AREF (elt, i);
ca4da08a 2599
6136b72f
CY
2600 if (FONT_ENTITY_P (entity)
2601 && EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
ca4da08a
KH
2602 {
2603 Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
2604
2605 for (; CONSP (objlist); objlist = XCDR (objlist))
2606 {
2607 Lisp_Object val = XCAR (objlist);
35027d0c 2608 struct font *font = XFONT_OBJECT (val);
ca4da08a 2609
5e634ec9
KH
2610 if (! NILP (AREF (val, FONT_TYPE_INDEX)))
2611 {
4e6a86c6 2612 eassert (font && driver == font->driver);
78e0b35c 2613 driver->close (font);
5e634ec9 2614 }
ca4da08a
KH
2615 }
2616 if (driver->free_entity)
2617 driver->free_entity (entity);
2618 }
2619 }
2620 }
2621 }
2622 XSETCDR (cache, Qnil);
2623}
2624\f
2625
c2f5bfd6
KH
2626static Lisp_Object scratch_font_spec, scratch_font_prefer;
2627
7d56b2dd 2628/* Check each font-entity in VEC, and return a list of font-entities
56dd2d86 2629 that satisfy these conditions:
7d56b2dd
KH
2630 (1) matches with SPEC and SIZE if SPEC is not nil, and
2631 (2) doesn't match with any regexps in Vface_ignored_fonts (if non-nil).
2632*/
2633
7b81e2d0 2634static Lisp_Object
971de7fb 2635font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
35027d0c 2636{
d0ab1ebe 2637 Lisp_Object entity, val;
35027d0c 2638 enum font_property_index prop;
72d36834 2639 int i;
45eb10fb 2640
72d36834 2641 for (val = Qnil, i = ASIZE (vec) - 1; i >= 0; i--)
35027d0c 2642 {
72d36834 2643 entity = AREF (vec, i);
7d56b2dd
KH
2644 if (! NILP (Vface_ignored_fonts))
2645 {
2646 char name[256];
d923b542 2647 ptrdiff_t namelen;
7d56b2dd
KH
2648 Lisp_Object tail, regexp;
2649
d923b542
DA
2650 namelen = font_unparse_xlfd (entity, 0, name, 256);
2651 if (namelen >= 0)
7d56b2dd
KH
2652 {
2653 for (tail = Vface_ignored_fonts; CONSP (tail); tail = XCDR (tail))
2654 {
2655 regexp = XCAR (tail);
2656 if (STRINGP (regexp)
d923b542
DA
2657 && fast_c_string_match_ignore_case (regexp, name,
2658 namelen) >= 0)
7d56b2dd
KH
2659 break;
2660 }
2661 if (CONSP (tail))
2662 continue;
2663 }
2664 }
2665 if (NILP (spec))
2666 {
2667 val = Fcons (entity, val);
2668 continue;
2669 }
35027d0c
KH
2670 for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
2671 if (INTEGERP (AREF (spec, prop))
2672 && ((XINT (AREF (spec, prop)) >> 8)
2673 != (XINT (AREF (entity, prop)) >> 8)))
2674 prop = FONT_SPEC_MAX;
7181ea6a 2675 if (prop < FONT_SPEC_MAX
35027d0c
KH
2676 && size
2677 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
2678 {
2679 int diff = XINT (AREF (entity, FONT_SIZE_INDEX)) - size;
c2f5bfd6 2680
71376d4b 2681 if (eabs (diff) > FONT_PIXEL_SIZE_QUANTUM)
35027d0c
KH
2682 prop = FONT_SPEC_MAX;
2683 }
7181ea6a
KH
2684 if (prop < FONT_SPEC_MAX
2685 && INTEGERP (AREF (spec, FONT_DPI_INDEX))
2686 && INTEGERP (AREF (entity, FONT_DPI_INDEX))
c576d6dc 2687 && XINT (AREF (entity, FONT_DPI_INDEX)) != 0
7181ea6a
KH
2688 && ! EQ (AREF (spec, FONT_DPI_INDEX), AREF (entity, FONT_DPI_INDEX)))
2689 prop = FONT_SPEC_MAX;
2690 if (prop < FONT_SPEC_MAX
2691 && INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
2692 && INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
c576d6dc 2693 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) != 0
7181ea6a
KH
2694 && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
2695 AREF (entity, FONT_AVGWIDTH_INDEX)))
2696 prop = FONT_SPEC_MAX;
35027d0c 2697 if (prop < FONT_SPEC_MAX)
d0ab1ebe 2698 val = Fcons (entity, val);
35027d0c 2699 }
72d36834 2700 return (Fvconcat (1, &val));
35027d0c
KH
2701}
2702
2703
72d36834 2704/* Return a list of vectors of font-entities matching with SPEC on
ce75f06e
CY
2705 FRAME. Each elements in the list is a vector of entities from the
2706 same font-driver. */
35027d0c
KH
2707
2708Lisp_Object
fdb396e2 2709font_list_entities (struct frame *f, Lisp_Object spec)
c2f5bfd6 2710{
c2f5bfd6 2711 struct font_driver_list *driver_list = f->font_driver_list;
4007dd1c 2712 Lisp_Object ftype, val;
72d36834 2713 Lisp_Object list = Qnil;
35027d0c 2714 int size;
a864ef14 2715 bool need_filtering = 0;
c2f5bfd6
KH
2716 int i;
2717
4e6a86c6 2718 eassert (FONT_SPEC_P (spec));
c2f5bfd6 2719
35027d0c
KH
2720 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
2721 size = XINT (AREF (spec, FONT_SIZE_INDEX));
2722 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2723 size = font_pixel_size (f, spec);
2724 else
2725 size = 0;
2726
c2f5bfd6 2727 ftype = AREF (spec, FONT_TYPE_INDEX);
4007dd1c 2728 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
35027d0c 2729 ASET (scratch_font_spec, i, AREF (spec, i));
4007dd1c 2730 for (i = FONT_WEIGHT_INDEX; i < FONT_EXTRA_INDEX; i++)
56201685
PE
2731 if (i != FONT_SPACING_INDEX)
2732 {
2733 ASET (scratch_font_spec, i, Qnil);
2734 if (! NILP (AREF (spec, i)))
2735 need_filtering = 1;
2736 }
aa50ca2f 2737 ASET (scratch_font_spec, FONT_SPACING_INDEX, AREF (spec, FONT_SPACING_INDEX));
35027d0c
KH
2738 ASET (scratch_font_spec, FONT_EXTRA_INDEX, AREF (spec, FONT_EXTRA_INDEX));
2739
a378aa9d 2740 for (; driver_list; driver_list = driver_list->next)
417a1b10
KH
2741 if (driver_list->on
2742 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
c2f5bfd6 2743 {
ca4da08a 2744 Lisp_Object cache = font_get_cache (f, driver_list->driver);
c2f5bfd6 2745
e4c93315 2746 ASET (scratch_font_spec, FONT_TYPE_INDEX, driver_list->driver->type);
4007dd1c
KH
2747 val = assoc_no_quit (scratch_font_spec, XCDR (cache));
2748 if (CONSP (val))
2749 val = XCDR (val);
2750 else
c2f5bfd6 2751 {
fdb396e2 2752 val = driver_list->driver->list (f, scratch_font_spec);
af1a69f4
DA
2753 if (!NILP (val))
2754 {
2755 Lisp_Object copy = copy_font_spec (scratch_font_spec);
2756
2757 val = Fvconcat (1, &val);
2758 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2759 XSETCDR (cache, Fcons (Fcons (copy, val), XCDR (cache)));
2760 }
c2f5bfd6 2761 }
af1a69f4 2762 if (VECTORP (val) && ASIZE (val) > 0
7d56b2dd
KH
2763 && (need_filtering
2764 || ! NILP (Vface_ignored_fonts)))
2765 val = font_delete_unmatched (val, need_filtering ? spec : Qnil, size);
af1a69f4 2766 if (VECTORP (val) && ASIZE (val) > 0)
72d36834 2767 list = Fcons (val, list);
c2f5bfd6 2768 }
35027d0c 2769
72d36834
KH
2770 list = Fnreverse (list);
2771 FONT_ADD_LOG ("list", spec, list);
2772 return list;
c2f5bfd6
KH
2773}
2774
45eb10fb 2775
35027d0c
KH
2776/* Return a font entity matching with SPEC on FRAME. ATTRS, if non
2777 nil, is an array of face's attributes, which specifies preferred
2778 font-related attributes. */
45eb10fb 2779
e950d6f1 2780static Lisp_Object
a10c8269 2781font_matching_entity (struct frame *f, Lisp_Object *attrs, Lisp_Object spec)
e950d6f1 2782{
e950d6f1
KH
2783 struct font_driver_list *driver_list = f->font_driver_list;
2784 Lisp_Object ftype, size, entity;
92470028 2785 Lisp_Object work = copy_font_spec (spec);
e950d6f1
KH
2786
2787 ftype = AREF (spec, FONT_TYPE_INDEX);
2788 size = AREF (spec, FONT_SIZE_INDEX);
819ab95f 2789
8d0e382e
AR
2790 if (FLOATP (size))
2791 ASET (work, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
819ab95f
KH
2792 FONT_SET_STYLE (work, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2793 FONT_SET_STYLE (work, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2794 FONT_SET_STYLE (work, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
2795
e950d6f1
KH
2796 entity = Qnil;
2797 for (; driver_list; driver_list = driver_list->next)
2798 if (driver_list->on
2799 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2800 {
ca4da08a 2801 Lisp_Object cache = font_get_cache (f, driver_list->driver);
e950d6f1 2802
819ab95f
KH
2803 ASET (work, FONT_TYPE_INDEX, driver_list->driver->type);
2804 entity = assoc_no_quit (work, XCDR (cache));
7cee5d63 2805 if (CONSP (entity))
e950d6f1
KH
2806 entity = XCDR (entity);
2807 else
2808 {
fdb396e2 2809 entity = driver_list->driver->match (f, work);
af1a69f4
DA
2810 if (!NILP (entity))
2811 {
2812 Lisp_Object copy = copy_font_spec (work);
2813 Lisp_Object match = Fvector (1, &entity);
2814
2815 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2816 XSETCDR (cache, Fcons (Fcons (copy, match), XCDR (cache)));
2817 }
e950d6f1
KH
2818 }
2819 if (! NILP (entity))
2820 break;
2821 }
652b9560 2822 FONT_ADD_LOG ("match", work, entity);
e950d6f1
KH
2823 return entity;
2824}
2825
45eb10fb
KH
2826
2827/* Open a font of ENTITY and PIXEL_SIZE on frame F, and return the
2828 opened font object. */
2829
c2f5bfd6 2830static Lisp_Object
a10c8269 2831font_open_entity (struct frame *f, Lisp_Object entity, int pixel_size)
c2f5bfd6
KH
2832{
2833 struct font_driver_list *driver_list;
43c0454d 2834 Lisp_Object objlist, size, val, font_object;
c2f5bfd6 2835 struct font *font;
8bd722db 2836 int min_width, height, psize;
c2f5bfd6 2837
4e6a86c6 2838 eassert (FONT_ENTITY_P (entity));
c2f5bfd6 2839 size = AREF (entity, FONT_SIZE_INDEX);
c2f5bfd6 2840 if (XINT (size) != 0)
7e70a152 2841 pixel_size = XINT (size);
c2f5bfd6 2842
35027d0c
KH
2843 val = AREF (entity, FONT_TYPE_INDEX);
2844 for (driver_list = f->font_driver_list;
2845 driver_list && ! EQ (driver_list->driver->type, val);
2846 driver_list = driver_list->next);
2847 if (! driver_list)
2848 return Qnil;
c2f5bfd6 2849
d0cf45b7
JD
2850 for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
2851 objlist = XCDR (objlist))
2852 {
2853 Lisp_Object fn = XCAR (objlist);
2854 if (! NILP (AREF (fn, FONT_TYPE_INDEX))
2855 && XFONT_OBJECT (fn)->pixel_size == pixel_size)
2856 {
2857 if (driver_list->driver->cached_font_ok == NULL
2858 || driver_list->driver->cached_font_ok (f, fn, entity))
2859 return fn;
2860 }
2861 }
2862
8bd722db
KH
2863 /* We always open a font of manageable size; i.e non-zero average
2864 width and height. */
2865 for (psize = pixel_size; ; psize++)
2866 {
2867 font_object = driver_list->driver->open (f, entity, psize);
2868 if (NILP (font_object))
2869 return Qnil;
2870 font = XFONT_OBJECT (font_object);
2871 if (font->average_width > 0 && font->height > 0)
2872 break;
2873 }
2874 ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
652b9560 2875 FONT_ADD_LOG ("open", entity, font_object);
35027d0c
KH
2876 ASET (entity, FONT_OBJLIST_INDEX,
2877 Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
35027d0c
KH
2878
2879 font = XFONT_OBJECT (font_object);
2880 min_width = (font->min_width ? font->min_width
2881 : font->average_width ? font->average_width
2882 : font->space_width ? font->space_width
2883 : 1);
d26424c5 2884 height = (font->height ? font->height : 1);
819e81df 2885#ifdef HAVE_WINDOW_SYSTEM
aad3612f
DA
2886 FRAME_DISPLAY_INFO (f)->n_fonts++;
2887 if (FRAME_DISPLAY_INFO (f)->n_fonts == 1)
43c0454d 2888 {
35027d0c 2889 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
d26424c5 2890 FRAME_SMALLEST_FONT_HEIGHT (f) = height;
bd0443bb 2891 f->fonts_changed = 1;
35027d0c
KH
2892 }
2893 else
2894 {
2895 if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
bd0443bb 2896 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, f->fonts_changed = 1;
d26424c5 2897 if (FRAME_SMALLEST_FONT_HEIGHT (f) > height)
bd0443bb 2898 FRAME_SMALLEST_FONT_HEIGHT (f) = height, f->fonts_changed = 1;
43c0454d 2899 }
819e81df 2900#endif
43c0454d
KH
2901
2902 return font_object;
c2f5bfd6
KH
2903}
2904
45eb10fb 2905
5035fbc1 2906/* Close FONT_OBJECT that is opened on frame F. */
45eb10fb 2907
5035fbc1
DA
2908static void
2909font_close_object (struct frame *f, Lisp_Object font_object)
c2f5bfd6 2910{
35027d0c 2911 struct font *font = XFONT_OBJECT (font_object);
c2f5bfd6 2912
5e634ec9
KH
2913 if (NILP (AREF (font_object, FONT_TYPE_INDEX)))
2914 /* Already closed. */
2915 return;
652b9560 2916 FONT_ADD_LOG ("close", font_object, Qnil);
78e0b35c 2917 font->driver->close (font);
819e81df 2918#ifdef HAVE_WINDOW_SYSTEM
5035fbc1
DA
2919 eassert (FRAME_DISPLAY_INFO (f)->n_fonts);
2920 FRAME_DISPLAY_INFO (f)->n_fonts--;
819e81df 2921#endif
c2f5bfd6
KH
2922}
2923
45eb10fb 2924
1701724c
KH
2925/* Return 1 if FONT on F has a glyph for character C, 0 if not, -1 if
2926 FONT is a font-entity and it must be opened to check. */
45eb10fb 2927
c2f5bfd6 2928int
a10c8269 2929font_has_char (struct frame *f, Lisp_Object font, int c)
c2f5bfd6 2930{
1b834a8d 2931 struct font *fontp;
c2f5bfd6 2932
1b834a8d
KH
2933 if (FONT_ENTITY_P (font))
2934 {
2935 Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
2936 struct font_driver_list *driver_list;
2937
2938 for (driver_list = f->font_driver_list;
2939 driver_list && ! EQ (driver_list->driver->type, type);
2940 driver_list = driver_list->next);
2941 if (! driver_list)
2942 return 0;
2943 if (! driver_list->driver->has_char)
2944 return -1;
2945 return driver_list->driver->has_char (font, c);
2946 }
2947
4e6a86c6 2948 eassert (FONT_OBJECT_P (font));
35027d0c 2949 fontp = XFONT_OBJECT (font);
1b834a8d
KH
2950 if (fontp->driver->has_char)
2951 {
35027d0c 2952 int result = fontp->driver->has_char (font, c);
1b834a8d
KH
2953
2954 if (result >= 0)
2955 return result;
2956 }
2957 return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
c2f5bfd6
KH
2958}
2959
45eb10fb
KH
2960
2961/* Return the glyph ID of FONT_OBJECT for character C. */
2962
2f7c71a1 2963static unsigned
971de7fb 2964font_encode_char (Lisp_Object font_object, int c)
c2f5bfd6 2965{
35027d0c 2966 struct font *font;
c2f5bfd6 2967
4e6a86c6 2968 eassert (FONT_OBJECT_P (font_object));
35027d0c 2969 font = XFONT_OBJECT (font_object);
c2f5bfd6
KH
2970 return font->driver->encode_char (font, c);
2971}
2972
45eb10fb
KH
2973
2974/* Return the name of FONT_OBJECT. */
2975
ef18374f 2976Lisp_Object
971de7fb 2977font_get_name (Lisp_Object font_object)
c2f5bfd6 2978{
4e6a86c6 2979 eassert (FONT_OBJECT_P (font_object));
35027d0c 2980 return AREF (font_object, FONT_NAME_INDEX);
ef18374f
KH
2981}
2982
45eb10fb 2983
05802645
CY
2984/* Create a new font spec from FONT_NAME, and return it. If FONT_NAME
2985 could not be parsed by font_parse_name, return Qnil. */
2986
35027d0c 2987Lisp_Object
971de7fb 2988font_spec_from_name (Lisp_Object font_name)
35027d0c 2989{
05802645 2990 Lisp_Object spec = Ffont_spec (0, NULL);
35027d0c 2991
05802645 2992 CHECK_STRING (font_name);
984e7f30 2993 if (font_parse_name (SSDATA (font_name), SBYTES (font_name), spec) == -1)
05802645
CY
2994 return Qnil;
2995 font_put_extra (spec, QCname, font_name);
42707278 2996 font_put_extra (spec, QCuser_spec, font_name);
05802645 2997 return spec;
35027d0c
KH
2998}
2999
45eb10fb 3000
35027d0c 3001void
971de7fb 3002font_clear_prop (Lisp_Object *attrs, enum font_property_index prop)
35027d0c
KH
3003{
3004 Lisp_Object font = attrs[LFACE_FONT_INDEX];
45eb10fb 3005
35027d0c
KH
3006 if (! FONTP (font))
3007 return;
42707278 3008
483670b5
KH
3009 if (! NILP (Ffont_get (font, QCname)))
3010 {
92470028 3011 font = copy_font_spec (font);
483670b5
KH
3012 font_put_extra (font, QCname, Qnil);
3013 }
3014
35027d0c 3015 if (NILP (AREF (font, prop))
e234927a
CY
3016 && prop != FONT_FAMILY_INDEX
3017 && prop != FONT_FOUNDRY_INDEX
3018 && prop != FONT_WIDTH_INDEX
4007dd1c 3019 && prop != FONT_SIZE_INDEX)
35027d0c 3020 return;
483670b5 3021 if (EQ (font, attrs[LFACE_FONT_INDEX]))
92470028 3022 font = copy_font_spec (font);
35027d0c 3023 ASET (font, prop, Qnil);
4007dd1c 3024 if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
35027d0c 3025 {
4007dd1c 3026 if (prop == FONT_FAMILY_INDEX)
962e8aa9
CY
3027 {
3028 ASET (font, FONT_FOUNDRY_INDEX, Qnil);
3029 /* If we are setting the font family, we must also clear
3030 FONT_WIDTH_INDEX to avoid rejecting families that lack
3031 support for some widths. */
3032 ASET (font, FONT_WIDTH_INDEX, Qnil);
3033 }
35027d0c 3034 ASET (font, FONT_ADSTYLE_INDEX, Qnil);
4007dd1c 3035 ASET (font, FONT_REGISTRY_INDEX, Qnil);
35027d0c
KH
3036 ASET (font, FONT_SIZE_INDEX, Qnil);
3037 ASET (font, FONT_DPI_INDEX, Qnil);
3038 ASET (font, FONT_SPACING_INDEX, Qnil);
3039 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3040 }
3041 else if (prop == FONT_SIZE_INDEX)
3042 {
3043 ASET (font, FONT_DPI_INDEX, Qnil);
3044 ASET (font, FONT_SPACING_INDEX, Qnil);
3045 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
3046 }
e234927a
CY
3047 else if (prop == FONT_WIDTH_INDEX)
3048 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
35027d0c
KH
3049 attrs[LFACE_FONT_INDEX] = font;
3050}
3051
56dd2d86
EZ
3052/* Select a font from ENTITIES (list of font-entity vectors) that
3053 supports C and is the best match for ATTRS and PIXEL_SIZE. */
988a7ddb
KH
3054
3055static Lisp_Object
fdb396e2
DA
3056font_select_entity (struct frame *f, Lisp_Object entities,
3057 Lisp_Object *attrs, int pixel_size, int c)
988a7ddb
KH
3058{
3059 Lisp_Object font_entity;
3060 Lisp_Object prefer;
a864ef14 3061 int i;
988a7ddb 3062
72d36834
KH
3063 if (NILP (XCDR (entities))
3064 && ASIZE (XCAR (entities)) == 1)
988a7ddb 3065 {
72d36834 3066 font_entity = AREF (XCAR (entities), 0);
a864ef14 3067 if (c < 0 || font_has_char (f, font_entity, c) > 0)
988a7ddb
KH
3068 return font_entity;
3069 return Qnil;
3070 }
3071
3072 /* Sort fonts by properties specified in ATTRS. */
3073 prefer = scratch_font_prefer;
3074
3075 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3076 ASET (prefer, i, Qnil);
3077 if (FONTP (attrs[LFACE_FONT_INDEX]))
3078 {
3079 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3080
3081 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
3082 ASET (prefer, i, AREF (face_font, i));
3083 }
3084 if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
3085 FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
3086 if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
3087 FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
3088 if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
3089 FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
3090 ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
988a7ddb 3091
fdb396e2 3092 return font_sort_entities (entities, prefer, f, c);
988a7ddb
KH
3093}
3094
56dd2d86
EZ
3095/* Return a font-entity that satisfies SPEC and is the best match for
3096 face's font related attributes in ATTRS. C, if not negative, is a
1701724c 3097 character that the entity must support. */
c2f5bfd6
KH
3098
3099Lisp_Object
a10c8269 3100font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int c)
c2f5bfd6 3101{
4007dd1c 3102 Lisp_Object work;
fdb396e2 3103 Lisp_Object entities, val;
78834453 3104 Lisp_Object foundry[3], *family, registry[3], adstyle[3];
1d1e1245 3105 int pixel_size;
72d36834 3106 int i, j, k, l;
d311d28c 3107 USE_SAFE_ALLOCA;
d0a47776
KH
3108
3109 registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
3110 if (NILP (registry[0]))
3111 {
edfda783 3112 registry[0] = DEFAULT_ENCODING;
d0a47776 3113 registry[1] = Qascii_0;
9730daca 3114 registry[2] = zero_vector;
d0a47776
KH
3115 }
3116 else
9730daca 3117 registry[1] = zero_vector;
c2f5bfd6 3118
4007dd1c 3119 if (c >= 0 && ! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
fe5ddfbc 3120 {
35027d0c 3121 struct charset *encoding, *repertory;
1701724c 3122
4007dd1c
KH
3123 if (font_registry_charsets (AREF (spec, FONT_REGISTRY_INDEX),
3124 &encoding, &repertory) < 0)
35027d0c 3125 return Qnil;
72d36834
KH
3126 if (repertory
3127 && ENCODE_CHAR (repertory, c) == CHARSET_INVALID_CODE (repertory))
3128 return Qnil;
35027d0c
KH
3129 else if (c > encoding->max_char)
3130 return Qnil;
c2f5bfd6
KH
3131 }
3132
92470028 3133 work = copy_font_spec (spec);
227f12fa 3134 ASET (work, FONT_TYPE_INDEX, AREF (spec, FONT_TYPE_INDEX));
1d1e1245 3135 pixel_size = font_pixel_size (f, spec);
dbc05432 3136 if (pixel_size == 0 && INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
1d1e1245
KH
3137 {
3138 double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3139
42143acd 3140 pixel_size = POINT_TO_PIXEL (pt / 10, FRAME_RES_Y (f));
8bd722db
KH
3141 if (pixel_size < 1)
3142 pixel_size = 1;
1d1e1245 3143 }
4007dd1c
KH
3144 ASET (work, FONT_SIZE_INDEX, Qnil);
3145 foundry[0] = AREF (work, FONT_FOUNDRY_INDEX);
3146 if (! NILP (foundry[0]))
9730daca 3147 foundry[1] = zero_vector;
4007dd1c
KH
3148 else if (STRINGP (attrs[LFACE_FOUNDRY_INDEX]))
3149 {
071132a9 3150 val = attrs[LFACE_FOUNDRY_INDEX];
51b59d79 3151 foundry[0] = font_intern_prop (SSDATA (val), SBYTES (val), 1);
4007dd1c 3152 foundry[1] = Qnil;
9730daca 3153 foundry[2] = zero_vector;
4007dd1c
KH
3154 }
3155 else
9730daca 3156 foundry[0] = Qnil, foundry[1] = zero_vector;
4007dd1c 3157
22459668
KH
3158 adstyle[0] = AREF (work, FONT_ADSTYLE_INDEX);
3159 if (! NILP (adstyle[0]))
9730daca 3160 adstyle[1] = zero_vector;
22459668
KH
3161 else if (FONTP (attrs[LFACE_FONT_INDEX]))
3162 {
3163 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3164
3165 if (! NILP (AREF (face_font, FONT_ADSTYLE_INDEX)))
3166 {
3167 adstyle[0] = AREF (face_font, FONT_ADSTYLE_INDEX);
3168 adstyle[1] = Qnil;
9730daca 3169 adstyle[2] = zero_vector;
22459668
KH
3170 }
3171 else
9730daca 3172 adstyle[0] = Qnil, adstyle[1] = zero_vector;
22459668
KH
3173 }
3174 else
9730daca 3175 adstyle[0] = Qnil, adstyle[1] = zero_vector;
22459668
KH
3176
3177
4007dd1c
KH
3178 val = AREF (work, FONT_FAMILY_INDEX);
3179 if (NILP (val) && STRINGP (attrs[LFACE_FAMILY_INDEX]))
071132a9
KH
3180 {
3181 val = attrs[LFACE_FAMILY_INDEX];
51b59d79 3182 val = font_intern_prop (SSDATA (val), SBYTES (val), 1);
071132a9 3183 }
4007dd1c
KH
3184 if (NILP (val))
3185 {
3186 family = alloca ((sizeof family[0]) * 2);
3187 family[0] = Qnil;
9730daca 3188 family[1] = zero_vector; /* terminator. */
4007dd1c
KH
3189 }
3190 else
3191 {
3192 Lisp_Object alters
b6e64c41 3193 = Fassoc_string (val, Vface_alternative_font_family_alist, Qt);
4007dd1c
KH
3194
3195 if (! NILP (alters))
3196 {
d311d28c
PE
3197 EMACS_INT alterslen = XFASTINT (Flength (alters));
3198 SAFE_ALLOCA_LISP (family, alterslen + 2);
4007dd1c
KH
3199 for (i = 0; CONSP (alters); i++, alters = XCDR (alters))
3200 family[i] = XCAR (alters);
3201 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3202 family[i++] = Qnil;
9730daca 3203 family[i] = zero_vector;
4007dd1c
KH
3204 }
3205 else
3206 {
3207 family = alloca ((sizeof family[0]) * 3);
3208 i = 0;
3209 family[i++] = val;
3210 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3211 family[i++] = Qnil;
9730daca 3212 family[i] = zero_vector;
4007dd1c
KH
3213 }
3214 }
3215
d0a47776 3216 for (i = 0; SYMBOLP (family[i]); i++)
4007dd1c 3217 {
d0a47776
KH
3218 ASET (work, FONT_FAMILY_INDEX, family[i]);
3219 for (j = 0; SYMBOLP (foundry[j]); j++)
4007dd1c 3220 {
d0a47776
KH
3221 ASET (work, FONT_FOUNDRY_INDEX, foundry[j]);
3222 for (k = 0; SYMBOLP (registry[k]); k++)
3223 {
904a2e0e 3224 ASET (work, FONT_REGISTRY_INDEX, registry[k]);
22459668
KH
3225 for (l = 0; SYMBOLP (adstyle[l]); l++)
3226 {
3227 ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
fdb396e2 3228 entities = font_list_entities (f, work);
72d36834 3229 if (! NILP (entities))
988a7ddb 3230 {
fdb396e2 3231 val = font_select_entity (f, entities,
988a7ddb
KH
3232 attrs, pixel_size, c);
3233 if (! NILP (val))
e8374b39
DA
3234 {
3235 SAFE_FREE ();
3236 return val;
3237 }
988a7ddb 3238 }
22459668 3239 }
d0a47776 3240 }
4007dd1c 3241 }
4007dd1c 3242 }
d311d28c
PE
3243
3244 SAFE_FREE ();
d0a47776 3245 return Qnil;
1701724c 3246}
45eb10fb
KH
3247
3248
c2f5bfd6 3249Lisp_Object
a10c8269 3250font_open_for_lface (struct frame *f, Lisp_Object entity, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3251{
9331887d 3252 int size;
c2f5bfd6 3253
4007dd1c
KH
3254 if (INTEGERP (AREF (entity, FONT_SIZE_INDEX))
3255 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
3256 size = XINT (AREF (entity, FONT_SIZE_INDEX));
733fd013
KH
3257 else
3258 {
7e70a152
KH
3259 if (FONT_SPEC_P (spec) && ! NILP (AREF (spec, FONT_SIZE_INDEX)))
3260 size = font_pixel_size (f, spec);
50b0cd29
CY
3261 else
3262 {
7e70a152
KH
3263 double pt;
3264 if (INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
3265 pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
3266 else
3267 {
3268 struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
3269 Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
3270 eassert (INTEGERP (height));
3271 pt = XINT (height);
3272 }
733fd013 3273
7e70a152 3274 pt /= 10;
42143acd 3275 size = POINT_TO_PIXEL (pt, FRAME_RES_Y (f));
ed96cde8 3276#ifdef HAVE_NS
7e70a152
KH
3277 if (size == 0)
3278 {
3279 Lisp_Object ffsize = get_frame_param (f, Qfontsize);
42143acd
DA
3280 size = (NUMBERP (ffsize)
3281 ? POINT_TO_PIXEL (XINT (ffsize), FRAME_RES_Y (f)) : 0);
7e70a152 3282 }
ed96cde8 3283#endif
7e70a152
KH
3284 }
3285 size *= font_rescale_ratio (entity);
733fd013 3286 }
7e70a152 3287
c2f5bfd6
KH
3288 return font_open_entity (f, entity, size);
3289}
3290
45eb10fb 3291
56dd2d86
EZ
3292/* Find a font that satisfies SPEC and is the best match for
3293 face's attributes in ATTRS on FRAME, and return the opened
35027d0c 3294 font-object. */
45eb10fb 3295
35027d0c 3296Lisp_Object
a10c8269 3297font_load_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec)
c2f5bfd6 3298{
637fa988 3299 Lisp_Object entity, name;
ef18374f 3300
908567ef 3301 entity = font_find_for_lface (f, attrs, spec, -1);
35027d0c 3302 if (NILP (entity))
ef18374f 3303 {
35027d0c 3304 /* No font is listed for SPEC, but each font-backend may have
56dd2d86 3305 different criteria about "font matching". So, try it. */
35027d0c
KH
3306 entity = font_matching_entity (f, attrs, spec);
3307 if (NILP (entity))
3308 return Qnil;
c2f5bfd6 3309 }
537b04b9 3310 /* Don't lose the original name that was put in initially. We need
637fa988
JD
3311 it to re-apply the font when font parameters (like hinting or dpi) have
3312 changed. */
3313 entity = font_open_for_lface (f, entity, attrs, spec);
8096a0ff
YM
3314 if (!NILP (entity))
3315 {
42707278
JD
3316 name = Ffont_get (spec, QCuser_spec);
3317 if (STRINGP (name)) font_put_extra (entity, QCuser_spec, name);
8096a0ff 3318 }
637fa988 3319 return entity;
c2f5bfd6
KH
3320}
3321
45eb10fb
KH
3322
3323/* Make FACE on frame F ready to use the font opened for FACE. */
3324
c2f5bfd6 3325void
a10c8269 3326font_prepare_for_face (struct frame *f, struct face *face)
c2f5bfd6 3327{
35027d0c
KH
3328 if (face->font->driver->prepare_face)
3329 face->font->driver->prepare_face (f, face);
c2f5bfd6
KH
3330}
3331
45eb10fb
KH
3332
3333/* Make FACE on frame F stop using the font opened for FACE. */
3334
c2f5bfd6 3335void
a10c8269 3336font_done_for_face (struct frame *f, struct face *face)
c2f5bfd6 3337{
35027d0c
KH
3338 if (face->font->driver->done_face)
3339 face->font->driver->done_face (f, face);
c2f5bfd6
KH
3340 face->extra = NULL;
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{
4007dd1c
KH
5064 sort_shift_bits[FONT_TYPE_INDEX] = 0;
5065 sort_shift_bits[FONT_SLANT_INDEX] = 2;
5066 sort_shift_bits[FONT_WEIGHT_INDEX] = 9;
5067 sort_shift_bits[FONT_SIZE_INDEX] = 16;
5068 sort_shift_bits[FONT_WIDTH_INDEX] = 23;
5069 /* Note that the other elements in sort_shift_bits are not used. */
c2f5bfd6 5070
1701724c
KH
5071 staticpro (&font_charset_alist);
5072 font_charset_alist = Qnil;
5073
e0708580 5074 DEFSYM (Qopentype, "opentype");
c2f5bfd6 5075
9e1bb909 5076 DEFSYM (Qascii_0, "ascii-0");
1bb1d99b
KH
5077 DEFSYM (Qiso8859_1, "iso8859-1");
5078 DEFSYM (Qiso10646_1, "iso10646-1");
5079 DEFSYM (Qunicode_bmp, "unicode-bmp");
cf96c5c2 5080 DEFSYM (Qunicode_sip, "unicode-sip");
1bb1d99b 5081
071132a9
KH
5082 DEFSYM (QCf, "Cf");
5083
c2f5bfd6 5084 DEFSYM (QCotf, ":otf");
35027d0c 5085 DEFSYM (QClang, ":lang");
c2f5bfd6 5086 DEFSYM (QCscript, ":script");
4c496d0d 5087 DEFSYM (QCantialias, ":antialias");
c2f5bfd6
KH
5088
5089 DEFSYM (QCfoundry, ":foundry");
5090 DEFSYM (QCadstyle, ":adstyle");
5091 DEFSYM (QCregistry, ":registry");
9331887d
KH
5092 DEFSYM (QCspacing, ":spacing");
5093 DEFSYM (QCdpi, ":dpi");
ec6fe57c 5094 DEFSYM (QCscalable, ":scalable");
35027d0c
KH
5095 DEFSYM (QCavgwidth, ":avgwidth");
5096 DEFSYM (QCfont_entity, ":font-entity");
5097 DEFSYM (QCfc_unknown_spec, ":fc-unknown-spec");
c2f5bfd6 5098
ec6fe57c
KH
5099 DEFSYM (Qc, "c");
5100 DEFSYM (Qm, "m");
5101 DEFSYM (Qp, "p");
5102 DEFSYM (Qd, "d");
5103
cf702558
CY
5104 DEFSYM (Qja, "ja");
5105 DEFSYM (Qko, "ko");
5106
42707278
JD
5107 DEFSYM (QCuser_spec, "user-spec");
5108
c2f5bfd6
KH
5109 staticpro (&scratch_font_spec);
5110 scratch_font_spec = Ffont_spec (0, NULL);
5111 staticpro (&scratch_font_prefer);
5112 scratch_font_prefer = Ffont_spec (0, NULL);
5113
d0818984
KH
5114 staticpro (&Vfont_log_deferred);
5115 Vfont_log_deferred = Fmake_vector (make_number (3), Qnil);
5116
6a3dadd2 5117#if 0
733fd013
KH
5118#ifdef HAVE_LIBOTF
5119 staticpro (&otf_list);
5120 otf_list = Qnil;
6a3dadd2
KH
5121#endif /* HAVE_LIBOTF */
5122#endif /* 0 */
733fd013 5123
c2f5bfd6
KH
5124 defsubr (&Sfontp);
5125 defsubr (&Sfont_spec);
5126 defsubr (&Sfont_get);
51cf11be 5127#ifdef HAVE_WINDOW_SYSTEM
b1868a1a 5128 defsubr (&Sfont_face_attributes);
51cf11be 5129#endif
c2f5bfd6
KH
5130 defsubr (&Sfont_put);
5131 defsubr (&Slist_fonts);
35027d0c 5132 defsubr (&Sfont_family_list);
c2f5bfd6
KH
5133 defsubr (&Sfind_font);
5134 defsubr (&Sfont_xlfd_name);
5135 defsubr (&Sclear_font_cache);
071132a9 5136 defsubr (&Sfont_shape_gstring);
78a2f9cd 5137 defsubr (&Sfont_variation_glyphs);
6a3dadd2 5138#if 0
733fd013 5139 defsubr (&Sfont_drive_otf);
e80e09b4 5140 defsubr (&Sfont_otf_alternates);
6a3dadd2 5141#endif /* 0 */
c2f5bfd6
KH
5142
5143#ifdef FONT_DEBUG
5144 defsubr (&Sopen_font);
5145 defsubr (&Sclose_font);
5146 defsubr (&Squery_font);
a7840ffb 5147 defsubr (&Sfont_get_glyphs);
ec6fe57c 5148 defsubr (&Sfont_match_p);
10d16101 5149 defsubr (&Sfont_at);
c2f5bfd6
KH
5150#if 0
5151 defsubr (&Sdraw_string);
5152#endif
8c1c7611 5153 defsubr (&Sframe_font_cache);
c2f5bfd6 5154#endif /* FONT_DEBUG */
a266686a 5155#ifdef HAVE_WINDOW_SYSTEM
72606e45 5156 defsubr (&Sfont_info);
a266686a 5157#endif
c2f5bfd6 5158
29208e82 5159 DEFVAR_LISP ("font-encoding-alist", Vfont_encoding_alist,
819e81df
KH
5160 doc: /*
5161Alist of fontname patterns vs the corresponding encoding and repertory info.
5162Each element looks like (REGEXP . (ENCODING . REPERTORY)),
5163where ENCODING is a charset or a char-table,
5164and REPERTORY is a charset, a char-table, or nil.
5165
027a33c0 5166If ENCODING and REPERTORY are the same, the element can have the form
819e81df
KH
5167\(REGEXP . ENCODING).
5168
5169ENCODING is for converting a character to a glyph code of the font.
5170If ENCODING is a charset, encoding a character by the charset gives
5171the corresponding glyph code. If ENCODING is a char-table, looking up
5172the table by a character gives the corresponding glyph code.
5173
5174REPERTORY specifies a repertory of characters supported by the font.
91af3942 5175If REPERTORY is a charset, all characters belonging to the charset are
819e81df 5176supported. If REPERTORY is a char-table, all characters who have a
027a33c0 5177non-nil value in the table are supported. If REPERTORY is nil, Emacs
819e81df
KH
5178gets the repertory information by an opened font and ENCODING. */);
5179 Vfont_encoding_alist = Qnil;
5180
933ac235
SM
5181 /* FIXME: These 3 vars are not quite what they appear: setq on them
5182 won't have any effect other than disconnect them from the style
5183 table used by the font display code. So we make them read-only,
5184 to avoid this confusing situation. */
5185
29208e82 5186 DEFVAR_LISP_NOPRO ("font-weight-table", Vfont_weight_table,
d0ab1ebe
KH
5187 doc: /* Vector of valid font weight values.
5188Each element has the form:
5189 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
17ab8f5d 5190NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */);
d0ab1ebe 5191 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
933ac235 5192 XSYMBOL (intern_c_string ("font-weight-table"))->constant = 1;
d0ab1ebe 5193
29208e82 5194 DEFVAR_LISP_NOPRO ("font-slant-table", Vfont_slant_table,
d0ab1ebe 5195 doc: /* Vector of font slant symbols vs the corresponding numeric values.
17ab8f5d 5196See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5197 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
933ac235 5198 XSYMBOL (intern_c_string ("font-slant-table"))->constant = 1;
d0ab1ebe 5199
29208e82 5200 DEFVAR_LISP_NOPRO ("font-width-table", Vfont_width_table,
d0ab1ebe 5201 doc: /* Alist of font width symbols vs the corresponding numeric values.
17ab8f5d 5202See `font-weight-table' for the format of the vector. */);
d0ab1ebe 5203 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
933ac235 5204 XSYMBOL (intern_c_string ("font-width-table"))->constant = 1;
d0ab1ebe
KH
5205
5206 staticpro (&font_style_table);
25721f5b 5207 font_style_table = make_uninit_vector (3);
d0ab1ebe
KH
5208 ASET (font_style_table, 0, Vfont_weight_table);
5209 ASET (font_style_table, 1, Vfont_slant_table);
5210 ASET (font_style_table, 2, Vfont_width_table);
5211
29208e82 5212 DEFVAR_LISP ("font-log", Vfont_log, doc: /*
d0ab1ebe
KH
5213*Logging list of font related actions and results.
5214The value t means to suppress the logging.
5215The initial value is set to nil if the environment variable
5216EMACS_FONT_LOG is set. Otherwise, it is set to t. */);
5217 Vfont_log = Qnil;
5218
819e81df 5219#ifdef HAVE_WINDOW_SYSTEM
c2f5bfd6 5220#ifdef HAVE_FREETYPE
35027d0c 5221 syms_of_ftfont ();
c2f5bfd6 5222#ifdef HAVE_X_WINDOWS
35027d0c
KH
5223 syms_of_xfont ();
5224 syms_of_ftxfont ();
c2f5bfd6 5225#ifdef HAVE_XFT
35027d0c 5226 syms_of_xftfont ();
c2f5bfd6
KH
5227#endif /* HAVE_XFT */
5228#endif /* HAVE_X_WINDOWS */
5229#else /* not HAVE_FREETYPE */
5230#ifdef HAVE_X_WINDOWS
35027d0c 5231 syms_of_xfont ();
c2f5bfd6
KH
5232#endif /* HAVE_X_WINDOWS */
5233#endif /* not HAVE_FREETYPE */
5234#ifdef HAVE_BDFFONT
35027d0c 5235 syms_of_bdffont ();
c2f5bfd6 5236#endif /* HAVE_BDFFONT */
0fda9b75 5237#ifdef HAVE_NTGUI
35027d0c 5238 syms_of_w32font ();
0fda9b75 5239#endif /* HAVE_NTGUI */
819e81df 5240#endif /* HAVE_WINDOW_SYSTEM */
c2f5bfd6 5241}
885b7d09 5242
652b9560 5243void
971de7fb 5244init_font (void)
652b9560
KH
5245{
5246 Vfont_log = egetenv ("EMACS_FONT_LOG") ? Qnil : Qt;
5247}