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