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