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