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