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