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