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