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