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