Add lisp/face-remap.el and associated documentation
[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);
548 if (spacing == 'P' || spacing == 'P')
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 {
9331887d
KH
1409 if (memcmp (p0 + 1, "pixelsize=", 10) == 0)
1410 prop = FONT_SIZE_INDEX;
1411 else
1412 {
35027d0c
KH
1413 key = font_intern_prop (p0, p1 - p0);
1414 prop = get_font_prop_index (key);
9331887d
KH
1415 }
1416 p0 = p1 + 1;
1417 for (p1 = p0; *p1 && *p1 != ':'; p1++);
35027d0c 1418 val = font_intern_prop (p0, p1 - p0);
ec6fe57c 1419 if (! NILP (val))
9331887d 1420 {
35027d0c
KH
1421 if (prop >= FONT_FOUNDRY_INDEX && prop < FONT_EXTRA_INDEX)
1422 ASET (font, prop, font_prop_validate (prop, Qnil, val));
1423 else if (prop >= 0)
1424 Ffont_put (font, key, val);
ec6fe57c 1425 else
35027d0c
KH
1426 bcopy (p0 - 1, copy, p1 - p0 + 1);
1427 copy += p1 - p0 + 1;
ef18374f
KH
1428 }
1429 }
1430 p0 = p1;
1431 }
35027d0c
KH
1432 if (name != copy)
1433 font_put_extra (font, QCfc_unknown_spec,
1434 make_unibyte_string (name, copy - name));
9ba6fd41 1435
9331887d 1436 return 0;
ef18374f
KH
1437}
1438
1439/* Store fontconfig's font name of FONT (font-spec or font-entity) in
1440 NAME (NBYTES length), and return the name length. If
1441 FONT_SIZE_INDEX of FONT is 0, use PIXEL_SIZE instead. */
1442
1443int
1444font_unparse_fcname (font, pixel_size, name, nbytes)
1445 Lisp_Object font;
1446 int pixel_size;
1447 char *name;
1448 int nbytes;
1449{
35027d0c 1450 Lisp_Object tail, val;
ec6fe57c 1451 int point_size;
d0ab1ebe 1452 int dpi;
ec6fe57c 1453 int i, len = 1;
ef18374f 1454 char *p;
a9262bb8 1455 Lisp_Object styles[3];
417a1b10 1456 char *style_names[3] = { "weight", "slant", "width" };
35027d0c 1457 char work[256];
ef18374f 1458
ec6fe57c 1459 val = AREF (font, FONT_FAMILY_INDEX);
35027d0c
KH
1460 if (STRINGP (val))
1461 len += SBYTES (val);
ec6fe57c
KH
1462
1463 val = AREF (font, FONT_SIZE_INDEX);
1464 if (INTEGERP (val))
ef18374f 1465 {
ec6fe57c
KH
1466 if (XINT (val) != 0)
1467 pixel_size = XINT (val);
1468 point_size = -1;
1469 len += 21; /* for ":pixelsize=NUM" */
ef18374f 1470 }
ec6fe57c 1471 else if (FLOATP (val))
ef18374f 1472 {
ec6fe57c
KH
1473 pixel_size = -1;
1474 point_size = (int) XFLOAT_DATA (val);
1475 len += 11; /* for "-NUM" */
ef18374f 1476 }
ec6fe57c
KH
1477
1478 val = AREF (font, FONT_FOUNDRY_INDEX);
35027d0c 1479 if (STRINGP (val))
ef18374f 1480 /* ":foundry=NAME" */
35027d0c 1481 len += 9 + SBYTES (val);
ec6fe57c 1482
35027d0c 1483 for (i = 0; i < 3; i++)
a9262bb8 1484 {
35027d0c
KH
1485 styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
1486 if (! NILP (styles[i]))
1487 len += sprintf (work, ":%s=%s", style_names[i],
1488 SDATA (SYMBOL_NAME (styles[i])));
ec6fe57c 1489 }
35027d0c
KH
1490
1491 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
1492 len += sprintf (work, ":dpi=%d", dpi);
1493 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
1494 len += strlen (":spacing=100");
1495 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1496 len += strlen (":scalable=false"); /* or ":scalable=true" */
1497 for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
ec6fe57c 1498 {
35027d0c
KH
1499 Lisp_Object key = XCAR (XCAR (tail)), val = XCDR (XCAR (tail));
1500
1501 len += SBYTES (SYMBOL_NAME (key)) + 1; /* for :KEY= */
1502 if (STRINGP (val))
1503 len += SBYTES (val);
1504 else if (INTEGERP (val))
1505 len += sprintf (work, "%d", XINT (val));
1506 else if (SYMBOLP (val))
1507 len += (NILP (val) ? 5 : 4); /* for "false" or "true" */
ec6fe57c
KH
1508 }
1509
ef18374f
KH
1510 if (len > nbytes)
1511 return -1;
1512 p = name;
1513 if (! NILP (AREF (font, FONT_FAMILY_INDEX)))
35027d0c 1514 p += sprintf(p, "%s", SDATA (SYMBOL_NAME (AREF (font, FONT_FAMILY_INDEX))));
ec6fe57c
KH
1515 if (point_size > 0)
1516 {
1517 if (p == name)
1518 p += sprintf (p, "%d", point_size);
1519 else
1520 p += sprintf (p, "-%d", point_size);
1521 }
ef18374f
KH
1522 else if (pixel_size > 0)
1523 p += sprintf (p, ":pixelsize=%d", pixel_size);
35027d0c 1524 if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
a9262bb8
KH
1525 p += sprintf (p, ":foundry=%s",
1526 SDATA (SYMBOL_NAME (AREF (font, FONT_FOUNDRY_INDEX))));
1527 for (i = 0; i < 3; i++)
35027d0c 1528 if (! NILP (styles[i]))
a9262bb8 1529 p += sprintf (p, ":%s=%s", style_names[i],
35027d0c
KH
1530 SDATA (SYMBOL_NAME (styles[i])));
1531 if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
1532 p += sprintf (p, ":dpi=%d", XINT (AREF (font, FONT_DPI_INDEX)));
1533 if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
1534 p += sprintf (p, ":spacing=%d", XINT (AREF (font, FONT_SPACING_INDEX)));
1535 if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
1536 {
1537 if (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0)
1538 p += sprintf (p, ":scalable=true");
1539 else
1540 p += sprintf (p, ":scalable=false");
1541 }
ef18374f
KH
1542 return (p - name);
1543}
1544
1545/* Parse NAME (null terminated) and store information in FONT
1546 (font-spec or font-entity). If NAME is successfully parsed, return
35027d0c 1547 0. Otherwise return -1. */
ef18374f
KH
1548
1549static int
ec6fe57c 1550font_parse_name (name, font)
ef18374f
KH
1551 char *name;
1552 Lisp_Object font;
ef18374f
KH
1553{
1554 if (name[0] == '-' || index (name, '*'))
e950d6f1 1555 return font_parse_xlfd (name, font);
ec6fe57c 1556 return font_parse_fcname (name, font);
ef18374f
KH
1557}
1558
35027d0c
KH
1559
1560/* Merge FAMILY and REGISTRY into FONT_SPEC. FAMILY may have the form
1561 "FAMILY-FOUNDRY". REGISTRY may not contain charset-encoding
1562 part. */
45eb10fb 1563
c2f5bfd6 1564void
35027d0c
KH
1565font_parse_family_registry (family, registry, font_spec)
1566 Lisp_Object family, registry, font_spec;
c2f5bfd6 1567{
35027d0c
KH
1568 int len;
1569 char *p0, *p1;
1570
d0ab1ebe
KH
1571 if (! NILP (family)
1572 && NILP (AREF (font_spec, FONT_FAMILY_INDEX)))
c2f5bfd6 1573 {
35027d0c
KH
1574 CHECK_STRING (family);
1575 len = SBYTES (family);
1576 p0 = (char *) SDATA (family);
1577 p1 = index (p0, '-');
1578 if (p1)
c2f5bfd6 1579 {
d0ab1ebe
KH
1580 if ((*p0 != '*' || p1 - p0 > 1)
1581 && NILP (AREF (font_spec, FONT_FOUNDRY_INDEX)))
aa50ca2f 1582 Ffont_put (font_spec, QCfoundry, font_intern_prop (p0, p1 - p0));
35027d0c
KH
1583 p1++;
1584 len -= p1 - p0;
aa50ca2f 1585 Ffont_put (font_spec, QCfamily, font_intern_prop (p1, len));
c2f5bfd6 1586 }
35027d0c
KH
1587 else
1588 ASET (font_spec, FONT_FAMILY_INDEX, Fintern (family, Qnil));
c2f5bfd6 1589 }
35027d0c 1590 if (! NILP (registry))
c2f5bfd6 1591 {
35027d0c
KH
1592 /* Convert "XXX" and "XXX*" to "XXX*-*". */
1593 CHECK_STRING (registry);
1594 len = SBYTES (registry);
1595 p0 = (char *) SDATA (registry);
1596 p1 = index (p0, '-');
1597 if (! p1)
c2f5bfd6 1598 {
35027d0c
KH
1599 if (SDATA (registry)[len - 1] == '*')
1600 registry = concat2 (registry, build_string ("-*"));
1601 else
1602 registry = concat2 (registry, build_string ("*-*"));
c2f5bfd6 1603 }
35027d0c
KH
1604 registry = Fdowncase (registry);
1605 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
c2f5bfd6
KH
1606 }
1607}
1608
45eb10fb 1609\f
35027d0c
KH
1610/* This part (through the next ^L) is still experimental and not
1611 tested much. We may drastically change codes. */
10d16101 1612
45eb10fb 1613/* OTF handler */
10d16101 1614
6a3dadd2
KH
1615#if 0
1616
e950d6f1
KH
1617#define LGSTRING_HEADER_SIZE 6
1618#define LGSTRING_GLYPH_SIZE 8
1619
1620static int
1621check_gstring (gstring)
1622 Lisp_Object gstring;
1623{
1624 Lisp_Object val;
1625 int i, j;
1626
1627 CHECK_VECTOR (gstring);
1628 val = AREF (gstring, 0);
1629 CHECK_VECTOR (val);
1630 if (ASIZE (val) < LGSTRING_HEADER_SIZE)
1631 goto err;
1632 CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
f9ffa1ea
SM
1633 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING)))
1634 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING));
1635 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING)))
1636 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING));
1637 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH)))
1638 CHECK_NATNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH));
1639 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1640 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
1641 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
1642 CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
e950d6f1
KH
1643
1644 for (i = 0; i < LGSTRING_LENGTH (gstring); i++)
1645 {
1646 val = LGSTRING_GLYPH (gstring, i);
1647 CHECK_VECTOR (val);
1648 if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
1649 goto err;
f9ffa1ea 1650 if (NILP (AREF (val, LGLYPH_IX_CHAR)))
e950d6f1 1651 break;
f9ffa1ea
SM
1652 CHECK_NATNUM (AREF (val, LGLYPH_IX_FROM));
1653 CHECK_NATNUM (AREF (val, LGLYPH_IX_TO));
1654 CHECK_CHARACTER (AREF (val, LGLYPH_IX_CHAR));
1655 if (!NILP (AREF (val, LGLYPH_IX_CODE)))
1656 CHECK_NATNUM (AREF (val, LGLYPH_IX_CODE));
1657 if (!NILP (AREF (val, LGLYPH_IX_WIDTH)))
1658 CHECK_NATNUM (AREF (val, LGLYPH_IX_WIDTH));
1659 if (!NILP (AREF (val, LGLYPH_IX_ADJUSTMENT)))
e950d6f1 1660 {
f9ffa1ea 1661 val = AREF (val, LGLYPH_IX_ADJUSTMENT);
e950d6f1
KH
1662 CHECK_VECTOR (val);
1663 if (ASIZE (val) < 3)
1664 goto err;
1665 for (j = 0; j < 3; j++)
1666 CHECK_NUMBER (AREF (val, j));
1667 }
1668 }
1669 return i;
1670 err:
1671 error ("Invalid glyph-string format");
1672 return -1;
1673}
1674
cf385d93
KH
1675static void
1676check_otf_features (otf_features)
1677 Lisp_Object otf_features;
1678{
35027d0c 1679 Lisp_Object val;
cf385d93
KH
1680
1681 CHECK_CONS (otf_features);
1682 CHECK_SYMBOL (XCAR (otf_features));
1683 otf_features = XCDR (otf_features);
1684 CHECK_CONS (otf_features);
1685 CHECK_SYMBOL (XCAR (otf_features));
1686 otf_features = XCDR (otf_features);
1687 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
1688 {
1689 CHECK_SYMBOL (Fcar (val));
1690 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1691 error ("Invalid OTF GSUB feature: %s", SYMBOL_NAME (XCAR (val)));
1692 }
1693 otf_features = XCDR (otf_features);
1694 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
1695 {
1696 CHECK_SYMBOL (Fcar (val));
1697 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1698 error ("Invalid OTF GPOS feature: %s", SYMBOL_NAME (XCAR (val)));
1699 }
1700}
1701
c2f5bfd6
KH
1702#ifdef HAVE_LIBOTF
1703#include <otf.h>
1704
733fd013 1705Lisp_Object otf_list;
c2f5bfd6
KH
1706
1707static Lisp_Object
1708otf_tag_symbol (tag)
1709 OTF_Tag tag;
1710{
1711 char name[5];
1712
1713 OTF_tag_name (tag, name);
1714 return Fintern (make_unibyte_string (name, 4), Qnil);
1715}
1716
1717static OTF *
35027d0c
KH
1718otf_open (file)
1719 Lisp_Object file;
c2f5bfd6 1720{
35027d0c 1721 Lisp_Object val = Fassoc (file, otf_list);
733fd013
KH
1722 OTF *otf;
1723
1724 if (! NILP (val))
1725 otf = XSAVE_VALUE (XCDR (val))->pointer;
1726 else
c2f5bfd6 1727 {
35027d0c 1728 otf = STRINGP (file) ? OTF_open ((char *) SDATA (file)) : NULL;
733fd013 1729 val = make_save_value (otf, 0);
35027d0c 1730 otf_list = Fcons (Fcons (file, val), otf_list);
c2f5bfd6 1731 }
733fd013 1732 return otf;
c2f5bfd6
KH
1733}
1734
1735
1736/* Return a list describing which scripts/languages FONT supports by
1737 which GSUB/GPOS features of OpenType tables. See the comment of
51c01100 1738 (struct font_driver).otf_capability. */
c2f5bfd6
KH
1739
1740Lisp_Object
1741font_otf_capability (font)
1742 struct font *font;
1743{
1744 OTF *otf;
1745 Lisp_Object capability = Fcons (Qnil, Qnil);
1746 int i;
1747
35027d0c 1748 otf = otf_open (font->props[FONT_FILE_INDEX]);
c2f5bfd6
KH
1749 if (! otf)
1750 return Qnil;
1751 for (i = 0; i < 2; i++)
1752 {
1753 OTF_GSUB_GPOS *gsub_gpos;
1754 Lisp_Object script_list = Qnil;
1755 int j;
1756
1757 if (OTF_get_features (otf, i == 0) < 0)
1758 continue;
1759 gsub_gpos = i == 0 ? otf->gsub : otf->gpos;
1760 for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--)
1761 {
1762 OTF_Script *script = gsub_gpos->ScriptList.Script + j;
1763 Lisp_Object langsys_list = Qnil;
1764 Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag);
1765 int k;
1766
1767 for (k = script->LangSysCount; k >= 0; k--)
1768 {
1769 OTF_LangSys *langsys;
1770 Lisp_Object feature_list = Qnil;
1771 Lisp_Object langsys_tag;
1772 int l;
1773
e80e09b4 1774 if (k == script->LangSysCount)
c2f5bfd6
KH
1775 {
1776 langsys = &script->DefaultLangSys;
1777 langsys_tag = Qnil;
1778 }
1779 else
1780 {
1781 langsys = script->LangSys + k;
1782 langsys_tag
1783 = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
1784 }
e80e09b4 1785 for (l = langsys->FeatureCount - 1; l >= 0; l--)
c2f5bfd6
KH
1786 {
1787 OTF_Feature *feature
1788 = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
1789 Lisp_Object feature_tag
1790 = otf_tag_symbol (feature->FeatureTag);
1791
1792 feature_list = Fcons (feature_tag, feature_list);
1793 }
1794 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
1795 langsys_list);
1796 }
1797 script_list = Fcons (Fcons (script_tag, langsys_list),
1798 script_list);
1799 }
1800
1801 if (i == 0)
1802 XSETCAR (capability, script_list);
1803 else
1804 XSETCDR (capability, script_list);
1805 }
1806
1807 return capability;
1808}
1809
733fd013
KH
1810/* Parse OTF features in SPEC and write a proper features spec string
1811 in FEATURES for the call of OTF_drive_gsub/gpos (of libotf). It is
1812 assured that the sufficient memory has already allocated for
1813 FEATURES. */
1814
e80e09b4 1815static void
733fd013 1816generate_otf_features (spec, features)
c2f5bfd6 1817 Lisp_Object spec;
733fd013 1818 char *features;
c2f5bfd6
KH
1819{
1820 Lisp_Object val;
35027d0c 1821 char *p;
c2f5bfd6
KH
1822 int asterisk;
1823
733fd013 1824 p = features;
e80e09b4 1825 *p = '\0';
c2f5bfd6
KH
1826 for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
1827 {
1828 val = XCAR (spec);
e80e09b4
KH
1829 CHECK_SYMBOL (val);
1830 if (p > features)
733fd013 1831 *p++ = ',';
c2f5bfd6
KH
1832 if (SREF (SYMBOL_NAME (val), 0) == '*')
1833 {
1834 asterisk = 1;
e80e09b4 1835 *p++ = '*';
c2f5bfd6
KH
1836 }
1837 else if (! asterisk)
e80e09b4
KH
1838 {
1839 val = SYMBOL_NAME (val);
e80e09b4
KH
1840 p += sprintf (p, "%s", SDATA (val));
1841 }
c2f5bfd6 1842 else
e80e09b4
KH
1843 {
1844 val = SYMBOL_NAME (val);
e80e09b4
KH
1845 p += sprintf (p, "~%s", SDATA (val));
1846 }
c2f5bfd6 1847 }
e80e09b4
KH
1848 if (CONSP (spec))
1849 error ("OTF spec too long");
1850}
1851
733fd013
KH
1852Lisp_Object
1853font_otf_DeviceTable (device_table)
1854 OTF_DeviceTable *device_table;
1855{
1856 int len = device_table->StartSize - device_table->EndSize + 1;
1857
1858 return Fcons (make_number (len),
1859 make_unibyte_string (device_table->DeltaValue, len));
1860}
1861
1862Lisp_Object
1863font_otf_ValueRecord (value_format, value_record)
1864 int value_format;
1865 OTF_ValueRecord *value_record;
1866{
1867 Lisp_Object val = Fmake_vector (make_number (8), Qnil);
1868
1869 if (value_format & OTF_XPlacement)
43c0454d 1870 ASET (val, 0, make_number (value_record->XPlacement));
733fd013 1871 if (value_format & OTF_YPlacement)
43c0454d 1872 ASET (val, 1, make_number (value_record->YPlacement));
733fd013 1873 if (value_format & OTF_XAdvance)
43c0454d 1874 ASET (val, 2, make_number (value_record->XAdvance));
733fd013 1875 if (value_format & OTF_YAdvance)
43c0454d 1876 ASET (val, 3, make_number (value_record->YAdvance));
733fd013
KH
1877 if (value_format & OTF_XPlaDevice)
1878 ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
1879 if (value_format & OTF_YPlaDevice)
1880 ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
1881 if (value_format & OTF_XAdvDevice)
1882 ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
1883 if (value_format & OTF_YAdvDevice)
1884 ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
1885 return val;
1886}
1887
1888Lisp_Object
1889font_otf_Anchor (anchor)
1890 OTF_Anchor *anchor;
1891{
1892 Lisp_Object val;
1893
1894 val = Fmake_vector (make_number (anchor->AnchorFormat + 1), Qnil);
1895 ASET (val, 0, make_number (anchor->XCoordinate));
1896 ASET (val, 1, make_number (anchor->YCoordinate));
1897 if (anchor->AnchorFormat == 2)
1898 ASET (val, 2, make_number (anchor->f.f1.AnchorPoint));
1899 else
1900 {
1901 ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
1902 ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
1903 }
1904 return val;
1905}
c2f5bfd6 1906#endif /* HAVE_LIBOTF */
6a3dadd2 1907#endif /* 0 */
c2f5bfd6 1908
e80e09b4
KH
1909/* G-string (glyph string) handler */
1910
1911/* G-string is a vector of the form [HEADER GLYPH ...].
1912 See the docstring of `font-make-gstring' for more detail. */
c2f5bfd6
KH
1913
1914struct font *
1701724c 1915font_prepare_composition (cmp, f)
c2f5bfd6 1916 struct composition *cmp;
1701724c 1917 FRAME_PTR f;
c2f5bfd6
KH
1918{
1919 Lisp_Object gstring
1920 = AREF (XHASH_TABLE (composition_hash_table)->key_and_value,
1921 cmp->hash_index * 2);
c2f5bfd6 1922
35027d0c 1923 cmp->font = XFONT_OBJECT (LGSTRING_FONT (gstring));
1701724c
KH
1924 cmp->glyph_len = LGSTRING_LENGTH (gstring);
1925 cmp->pixel_width = LGSTRING_WIDTH (gstring);
1926 cmp->lbearing = LGSTRING_LBEARING (gstring);
1927 cmp->rbearing = LGSTRING_RBEARING (gstring);
1928 cmp->ascent = LGSTRING_ASCENT (gstring);
1929 cmp->descent = LGSTRING_DESCENT (gstring);
1930 cmp->width = cmp->pixel_width / FRAME_COLUMN_WIDTH (f);
1931 if (cmp->width == 0)
1932 cmp->width = 1;
c2f5bfd6 1933
1701724c 1934 return cmp->font;
c2f5bfd6
KH
1935}
1936
c2f5bfd6
KH
1937\f
1938/* Font sorting */
1939
35027d0c 1940static unsigned font_score P_ ((Lisp_Object, Lisp_Object *, Lisp_Object));
c2f5bfd6
KH
1941static int font_compare P_ ((const void *, const void *));
1942static Lisp_Object font_sort_entites P_ ((Lisp_Object, Lisp_Object,
35027d0c
KH
1943 Lisp_Object, Lisp_Object,
1944 int));
c2f5bfd6
KH
1945
1946/* We sort fonts by scoring each of them against a specified
1947 font-spec. The score value is 32 bit (`unsigned'), and the smaller
1948 the value is, the closer the font is to the font-spec.
1949
35027d0c
KH
1950 The highest 2 bits of the score is used for FAMILY. The exact
1951 match is 0, match with one of face-font-family-alternatives is
1952 nonzero.
1953
1954 The next 2 bits of the score is used for the atomic properties
1955 FOUNDRY and ADSTYLE respectively.
c2f5bfd6 1956
35027d0c 1957 Each 7-bit in the lower 28 bits are used for numeric properties
c2f5bfd6
KH
1958 WEIGHT, SLANT, WIDTH, and SIZE. */
1959
1960/* How many bits to shift to store the difference value of each font
35027d0c
KH
1961 property in a score. Note that flots for FONT_TYPE_INDEX and
1962 FONT_REGISTRY_INDEX are not used. */
c2f5bfd6
KH
1963static int sort_shift_bits[FONT_SIZE_INDEX + 1];
1964
9331887d
KH
1965/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
1966 The return value indicates how different ENTITY is compared with
35027d0c
KH
1967 SPEC_PROP.
1968
1969 ALTERNATE_FAMILIES, if non-nil, is a pre-calculated list of
1970 alternate family names for AREF (SPEC_PROP, FONT_FAMILY_INDEX). */
c2f5bfd6
KH
1971
1972static unsigned
35027d0c 1973font_score (entity, spec_prop, alternate_families)
9331887d 1974 Lisp_Object entity, *spec_prop;
35027d0c 1975 Lisp_Object alternate_families;
c2f5bfd6
KH
1976{
1977 unsigned score = 0;
1978 int i;
c2f5bfd6 1979
35027d0c
KH
1980 /* Score three atomic fields. Maximum difference is 1 (family is 3). */
1981 for (i = FONT_FOUNDRY_INDEX; i <= FONT_ADSTYLE_INDEX; i++)
1982 if (i != FONT_REGISTRY_INDEX
1983 && ! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
1984 {
1985 Lisp_Object entity_str = SYMBOL_NAME (AREF (entity, i));
1986 Lisp_Object spec_str = SYMBOL_NAME (spec_prop[i]);
9ba6fd41 1987
72606e45 1988 if (xstrcasecmp (SDATA (spec_str), SDATA (entity_str)))
35027d0c
KH
1989 {
1990 if (i == FONT_FAMILY_INDEX && CONSP (alternate_families))
1991 {
1992 int j;
1993
1994 for (j = 1; CONSP (alternate_families);
027a33c0 1995 j++, alternate_families = XCDR (alternate_families))
35027d0c
KH
1996 {
1997 spec_str = XCAR (alternate_families);
72606e45 1998 if (xstrcasecmp (SDATA (spec_str), SDATA (entity_str)) == 0)
35027d0c 1999 break;
35027d0c
KH
2000 }
2001 if (j > 3)
2002 j = 3;
2003 score |= j << sort_shift_bits[i];
2004 }
2005 else
2006 score |= 1 << sort_shift_bits[i];
2007 }
2008 }
c2f5bfd6 2009
35027d0c
KH
2010 /* Score three style numeric fields. Maximum difference is 127. */
2011 for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
2012 if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
2013 {
2014 int diff = (XINT (AREF (entity, i)) >> 8) - (XINT (spec_prop[i]) >> 8);
2015
2016 if (diff < 0)
2017 diff = - diff;
2018 /* This is to prefer the exact symbol style. */
2019 diff++;
2020 score |= min (diff, 127) << sort_shift_bits[i];
2021 }
2022
2023 /* Score the size. Maximum difference is 127. */
2024 i = FONT_SIZE_INDEX;
2025 if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i])
2026 && XINT (AREF (entity, i)) > 0)
2027 {
2028 /* We use the higher 6-bit for the actual size difference. The
2029 lowest bit is set if the DPI is different. */
2030 int diff = XINT (spec_prop[i]) - XINT (AREF (entity, i));
2031
2032 if (diff < 0)
2033 diff = - diff;
d0ab1ebe 2034 diff <<= 1;
35027d0c
KH
2035 if (! NILP (spec_prop[FONT_DPI_INDEX])
2036 && ! EQ (spec_prop[FONT_DPI_INDEX], AREF (entity, FONT_DPI_INDEX)))
2037 diff |= 1;
2038 score |= min (diff, 127) << sort_shift_bits[FONT_SIZE_INDEX];
c2f5bfd6
KH
2039 }
2040
2041 return score;
2042}
2043
2044
2045/* The comparison function for qsort. */
2046
2047static int
2048font_compare (d1, d2)
2049 const void *d1, *d2;
2050{
35027d0c 2051 return (*(unsigned *) d1 - *(unsigned *) d2);
c2f5bfd6
KH
2052}
2053
2054
2055/* The structure for elements being sorted by qsort. */
2056struct font_sort_data
2057{
2058 unsigned score;
2059 Lisp_Object entity;
2060};
2061
2062
2063/* Sort font-entities in vector VEC by closeness to font-spec PREFER.
2064 If PREFER specifies a point-size, calculate the corresponding
9331887d
KH
2065 pixel-size from QCdpi property of PREFER or from the Y-resolution
2066 of FRAME before sorting. If SPEC is not nil, it is a font-spec to
35027d0c
KH
2067 get the font-entities in VEC.
2068
2069 If BEST-ONLY is nonzero, return the best matching entity. Otherwise,
2070 return the sorted VEC. */
c2f5bfd6
KH
2071
2072static Lisp_Object
35027d0c 2073font_sort_entites (vec, prefer, frame, spec, best_only)
c2f5bfd6 2074 Lisp_Object vec, prefer, frame, spec;
35027d0c 2075 int best_only;
c2f5bfd6 2076{
9331887d 2077 Lisp_Object prefer_prop[FONT_SPEC_MAX];
c2f5bfd6
KH
2078 int len, i;
2079 struct font_sort_data *data;
35027d0c
KH
2080 Lisp_Object alternate_families = Qnil;
2081 unsigned best_score;
2082 Lisp_Object best_entity;
c2f5bfd6
KH
2083 USE_SAFE_ALLOCA;
2084
2085 len = ASIZE (vec);
2086 if (len <= 1)
35027d0c 2087 return best_only ? AREF (vec, 0) : vec;
c2f5bfd6 2088
35027d0c 2089 for (i = FONT_FOUNDRY_INDEX; i <= FONT_DPI_INDEX; i++)
9331887d 2090 prefer_prop[i] = AREF (prefer, i);
c2f5bfd6
KH
2091
2092 if (! NILP (spec))
2093 {
35027d0c
KH
2094 /* A font driver may return a font that has a property value
2095 different from the value specified in SPEC if the driver
2096 thinks they are the same. That happens, for instance, such a
2097 generic family name as "serif" is specified. So, to ignore
2098 such a difference, for all properties specified in SPEC, set
2099 the corresponding properties in PREFER_PROP to nil. */
2100 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
9331887d 2101 if (! NILP (AREF (spec, i)))
35027d0c 2102 prefer_prop[i] = Qnil;
c2f5bfd6
KH
2103 }
2104
9331887d
KH
2105 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2106 prefer_prop[FONT_SIZE_INDEX]
2107 = make_number (font_pixel_size (XFRAME (frame), prefer));
35027d0c
KH
2108 if (! NILP (prefer_prop[FONT_FAMILY_INDEX]))
2109 {
2110 alternate_families
2111 = Fassoc_string (prefer_prop[FONT_FAMILY_INDEX],
2112 Vface_alternative_font_family_alist, Qt);
2113 if (CONSP (alternate_families))
2114 alternate_families = XCDR (alternate_families);
2115 }
9331887d 2116
c2f5bfd6
KH
2117 /* Scoring and sorting. */
2118 SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * len);
35027d0c
KH
2119 best_score = 0xFFFFFFFF;
2120 best_entity = Qnil;
c2f5bfd6
KH
2121 for (i = 0; i < len; i++)
2122 {
2123 data[i].entity = AREF (vec, i);
35027d0c
KH
2124 data[i].score = font_score (data[i].entity, prefer_prop,
2125 alternate_families);
2126 if (best_only && best_score > data[i].score)
2127 {
2128 best_score = data[i].score;
2129 best_entity = data[i].entity;
2130 if (best_score == 0)
2131 break;
2132 }
c2f5bfd6 2133 }
35027d0c
KH
2134 if (NILP (best_entity))
2135 {
2136 qsort (data, len, sizeof *data, font_compare);
2137 for (i = 0; i < len; i++)
2138 ASET (vec, i, data[i].entity);
2139 }
2140 else
2141 vec = best_entity;
c2f5bfd6
KH
2142 SAFE_FREE ();
2143
d0ab1ebe 2144 font_add_log ("sort-by", prefer, vec);
c2f5bfd6
KH
2145 return vec;
2146}
2147
2148\f
2149/* API of Font Service Layer. */
2150
45eb10fb
KH
2151/* Reflect ORDER (see the variable font_sort_order in xfaces.c) to
2152 sort_shift_bits. Finternal_set_font_selection_order calls this
2153 function with font_sort_order after setting up it. */
2154
c2f5bfd6
KH
2155void
2156font_update_sort_order (order)
2157 int *order;
2158{
35027d0c 2159 int i, shift_bits;
c2f5bfd6 2160
35027d0c 2161 for (i = 0, shift_bits = 21; i < 4; i++, shift_bits -= 7)
c2f5bfd6
KH
2162 {
2163 int xlfd_idx = order[i];
2164
2165 if (xlfd_idx == XLFD_WEIGHT_INDEX)
2166 sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits;
2167 else if (xlfd_idx == XLFD_SLANT_INDEX)
2168 sort_shift_bits[FONT_SLANT_INDEX] = shift_bits;
2169 else if (xlfd_idx == XLFD_SWIDTH_INDEX)
2170 sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits;
2171 else
2172 sort_shift_bits[FONT_SIZE_INDEX] = shift_bits;
2173 }
2174}
2175
45eb10fb 2176
45eb10fb
KH
2177/* Check if ENTITY matches with the font specification SPEC. */
2178
ef18374f
KH
2179int
2180font_match_p (spec, entity)
2181 Lisp_Object spec, entity;
2182{
35027d0c
KH
2183 Lisp_Object prefer_prop[FONT_SPEC_MAX];
2184 Lisp_Object alternate_families = Qnil;
ef18374f
KH
2185 int i;
2186
35027d0c
KH
2187 for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++)
2188 prefer_prop[i] = AREF (spec, i);
2189 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2190 prefer_prop[FONT_SIZE_INDEX]
2191 = make_number (font_pixel_size (XFRAME (selected_frame), spec));
2192 if (! NILP (prefer_prop[FONT_FAMILY_INDEX]))
2193 {
2194 alternate_families
2195 = Fassoc_string (prefer_prop[FONT_FAMILY_INDEX],
2196 Vface_alternative_font_family_alist, Qt);
2197 if (CONSP (alternate_families))
2198 alternate_families = XCDR (alternate_families);
2199 }
2200
2201 return (font_score (entity, prefer_prop, alternate_families) == 0);
ef18374f
KH
2202}
2203
45eb10fb 2204
35027d0c 2205/* CHeck a lispy font object corresponding to FONT. */
45eb10fb 2206
35027d0c
KH
2207int
2208font_check_object (font)
c2f5bfd6
KH
2209 struct font *font;
2210{
2211 Lisp_Object tail, elt;
2212
35027d0c 2213 for (tail = font->props[FONT_OBJLIST_INDEX]; CONSP (tail);
c2f5bfd6
KH
2214 tail = XCDR (tail))
2215 {
2216 elt = XCAR (tail);
35027d0c
KH
2217 if (font == XFONT_OBJECT (elt))
2218 return 1;
c2f5bfd6 2219 }
35027d0c 2220 return 0;
c2f5bfd6
KH
2221}
2222
ca4da08a 2223\f
819e81df 2224
ca4da08a
KH
2225/* Font cache
2226
2227 Each font backend has the callback function get_cache, and it
2228 returns a cons cell of which cdr part can be freely used for
2229 caching fonts. The cons cell may be shared by multiple frames
2230 and/or multiple font drivers. So, we arrange the cdr part as this:
2231
2232 ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...)
2233
2234 where DRIVER-TYPE is a symbol such as `x', `xft', etc., NUM-FRAMES
2235 is a number frames sharing this cache, and FONT-CACHE-DATA is a
2236 cons (FONT-SPEC FONT-ENTITY ...). */
2237
2238static void font_prepare_cache P_ ((FRAME_PTR, struct font_driver *));
2239static void font_finish_cache P_ ((FRAME_PTR, struct font_driver *));
2240static Lisp_Object font_get_cache P_ ((FRAME_PTR, struct font_driver *));
2241static void font_clear_cache P_ ((FRAME_PTR, Lisp_Object,
2242 struct font_driver *));
2243
2244static void
2245font_prepare_cache (f, driver)
2246 FRAME_PTR f;
2247 struct font_driver *driver;
2248{
2249 Lisp_Object cache, val;
2250
2251 cache = driver->get_cache (f);
2252 val = XCDR (cache);
2253 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2254 val = XCDR (val);
2255 if (NILP (val))
2256 {
2257 val = Fcons (driver->type, Fcons (make_number (1), Qnil));
2258 XSETCDR (cache, Fcons (val, XCDR (cache)));
2259 }
2260 else
2261 {
2262 val = XCDR (XCAR (val));
2263 XSETCAR (val, make_number (XINT (XCAR (val)) + 1));
2264 }
2265}
2266
43c0454d 2267
ca4da08a
KH
2268static void
2269font_finish_cache (f, driver)
2270 FRAME_PTR f;
2271 struct font_driver *driver;
2272{
2273 Lisp_Object cache, val, tmp;
2274
2275
2276 cache = driver->get_cache (f);
2277 val = XCDR (cache);
2278 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2279 cache = val, val = XCDR (val);
d0ab1ebe 2280 font_assert (! NILP (val));
ca4da08a 2281 tmp = XCDR (XCAR (val));
43c0454d 2282 XSETCAR (tmp, make_number (XINT (XCAR (tmp)) - 1));
ca4da08a
KH
2283 if (XINT (XCAR (tmp)) == 0)
2284 {
2285 font_clear_cache (f, XCAR (val), driver);
2286 XSETCDR (cache, XCDR (val));
2287 }
ca4da08a
KH
2288}
2289
43c0454d 2290
ca4da08a
KH
2291static Lisp_Object
2292font_get_cache (f, driver)
2293 FRAME_PTR f;
2294 struct font_driver *driver;
2295{
2296 Lisp_Object val = driver->get_cache (f);
2297 Lisp_Object type = driver->type;
2298
d0ab1ebe 2299 font_assert (CONSP (val));
ca4da08a 2300 for (val = XCDR (val); ! EQ (XCAR (XCAR (val)), type); val = XCDR (val));
d0ab1ebe 2301 font_assert (CONSP (val));
ca4da08a
KH
2302 /* VAL = ((DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) ...) */
2303 val = XCDR (XCAR (val));
2304 return val;
2305}
2306
43c0454d
KH
2307static int num_fonts;
2308
ca4da08a
KH
2309static void
2310font_clear_cache (f, cache, driver)
2311 FRAME_PTR f;
2312 Lisp_Object cache;
2313 struct font_driver *driver;
2314{
2315 Lisp_Object tail, elt;
51c01100 2316
ca4da08a
KH
2317 /* CACHE = (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) */
2318 for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
2319 {
2320 elt = XCAR (tail);
be9442ad 2321 if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)) && VECTORP (XCDR (elt)))
ca4da08a
KH
2322 {
2323 Lisp_Object vec = XCDR (elt);
2324 int i;
2325
2326 for (i = 0; i < ASIZE (vec); i++)
2327 {
2328 Lisp_Object entity = AREF (vec, i);
2329
2330 if (EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
2331 {
2332 Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
2333
2334 for (; CONSP (objlist); objlist = XCDR (objlist))
2335 {
2336 Lisp_Object val = XCAR (objlist);
35027d0c 2337 struct font *font = XFONT_OBJECT (val);
ca4da08a 2338
d0ab1ebe 2339 font_assert (font && driver == font->driver);
ca4da08a 2340 driver->close (f, font);
43c0454d 2341 num_fonts--;
ca4da08a
KH
2342 }
2343 if (driver->free_entity)
2344 driver->free_entity (entity);
2345 }
2346 }
2347 }
2348 }
2349 XSETCDR (cache, Qnil);
2350}
2351\f
2352
c2f5bfd6
KH
2353static Lisp_Object scratch_font_spec, scratch_font_prefer;
2354
35027d0c
KH
2355Lisp_Object
2356font_delete_unmatched (list, spec, size)
2357 Lisp_Object list, spec;
2358 int size;
2359{
d0ab1ebe 2360 Lisp_Object entity, val;
35027d0c 2361 enum font_property_index prop;
45eb10fb 2362
d0ab1ebe 2363 for (val = Qnil; CONSP (list); list = XCDR (list))
35027d0c 2364 {
d0ab1ebe 2365 entity = XCAR (list);
35027d0c
KH
2366 for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
2367 if (INTEGERP (AREF (spec, prop))
2368 && ((XINT (AREF (spec, prop)) >> 8)
2369 != (XINT (AREF (entity, prop)) >> 8)))
2370 prop = FONT_SPEC_MAX;
2371 if (prop++ <= FONT_SIZE_INDEX
2372 && size
2373 && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
2374 {
2375 int diff = XINT (AREF (entity, FONT_SIZE_INDEX)) - size;
c2f5bfd6 2376
35027d0c
KH
2377 if (diff != 0
2378 && (diff < 0 ? -diff > FONT_PIXEL_SIZE_QUANTUM
2379 : diff > FONT_PIXEL_SIZE_QUANTUM))
2380 prop = FONT_SPEC_MAX;
2381 }
35027d0c 2382 if (prop < FONT_SPEC_MAX)
d0ab1ebe 2383 val = Fcons (entity, val);
35027d0c 2384 }
d0ab1ebe 2385 return val;
35027d0c
KH
2386}
2387
2388
2389/* Return a vector of font-entities matching with SPEC on FRAME. */
2390
2391Lisp_Object
c2f5bfd6
KH
2392font_list_entities (frame, spec)
2393 Lisp_Object frame, spec;
2394{
2395 FRAME_PTR f = XFRAME (frame);
2396 struct font_driver_list *driver_list = f->font_driver_list;
d0ab1ebe 2397 Lisp_Object ftype, family, alternate_familes, val;
35027d0c
KH
2398 Lisp_Object *vec;
2399 int size;
2400 int need_filtering = 0;
2401 int n_family = 1;
c2f5bfd6
KH
2402 int i;
2403
d0ab1ebe 2404 font_assert (FONT_SPEC_P (spec));
c2f5bfd6
KH
2405
2406 family = AREF (spec, FONT_FAMILY_INDEX);
2407 if (NILP (family))
2408 alternate_familes = Qnil;
2409 else
2410 {
027a33c0 2411 alternate_familes = Fassoc_string (family,
35027d0c
KH
2412 Vface_alternative_font_family_alist,
2413 Qt);
c2f5bfd6
KH
2414 if (! NILP (alternate_familes))
2415 alternate_familes = XCDR (alternate_familes);
35027d0c 2416 n_family += XINT (Flength (alternate_familes));
c2f5bfd6 2417 }
a9262bb8 2418
35027d0c
KH
2419 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
2420 size = XINT (AREF (spec, FONT_SIZE_INDEX));
2421 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2422 size = font_pixel_size (f, spec);
2423 else
2424 size = 0;
2425
c2f5bfd6 2426 ftype = AREF (spec, FONT_TYPE_INDEX);
7cee5d63 2427 for (i = 1; i <= FONT_REGISTRY_INDEX; i++)
35027d0c 2428 ASET (scratch_font_spec, i, AREF (spec, i));
aa50ca2f 2429 for (i = FONT_DPI_INDEX; i < FONT_EXTRA_INDEX; i += 2)
35027d0c
KH
2430 {
2431 ASET (scratch_font_spec, i, Qnil);
2432 if (! NILP (AREF (spec, i)))
2433 need_filtering = 1;
2434 }
aa50ca2f 2435 ASET (scratch_font_spec, FONT_SPACING_INDEX, AREF (spec, FONT_SPACING_INDEX));
35027d0c
KH
2436 ASET (scratch_font_spec, FONT_EXTRA_INDEX, AREF (spec, FONT_EXTRA_INDEX));
2437
2438 vec = alloca (sizeof (Lisp_Object) * num_font_drivers * n_family);
2439 if (! vec)
2440 return null_vector;
51c01100 2441
c2f5bfd6 2442 for (i = 0; driver_list; driver_list = driver_list->next)
417a1b10
KH
2443 if (driver_list->on
2444 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
c2f5bfd6 2445 {
ca4da08a 2446 Lisp_Object cache = font_get_cache (f, driver_list->driver);
c2f5bfd6 2447 Lisp_Object tail = alternate_familes;
c2f5bfd6 2448
e4c93315
KH
2449 ASET (scratch_font_spec, FONT_TYPE_INDEX, driver_list->driver->type);
2450 ASET (scratch_font_spec, FONT_FAMILY_INDEX, family);
c2f5bfd6
KH
2451 while (1)
2452 {
d0ab1ebe 2453 val = assoc_no_quit (scratch_font_spec, XCDR (cache));
7cee5d63 2454 if (CONSP (val))
c2f5bfd6
KH
2455 val = XCDR (val);
2456 else
2457 {
35027d0c
KH
2458 Lisp_Object copy;
2459
2460 val = driver_list->driver->list (frame, scratch_font_spec);
35027d0c 2461 copy = Fcopy_font_spec (scratch_font_spec);
e4c93315 2462 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
35027d0c 2463 XSETCDR (cache, Fcons (Fcons (copy, val), XCDR (cache)));
c2f5bfd6 2464 }
d0ab1ebe
KH
2465 if (! NILP (val) && need_filtering)
2466 val = font_delete_unmatched (val, spec, size);
35027d0c 2467 if (! NILP (val))
c2f5bfd6
KH
2468 {
2469 vec[i++] = val;
2470 break;
2471 }
2472 if (NILP (tail))
2473 break;
35027d0c
KH
2474 ASET (scratch_font_spec, FONT_FAMILY_INDEX,
2475 Fintern (XCAR (tail), Qnil));
c2f5bfd6
KH
2476 tail = XCDR (tail);
2477 }
2478 }
35027d0c 2479
d0ab1ebe
KH
2480 val = (i > 0 ? Fvconcat (i, vec) : null_vector);
2481 font_add_log ("list", spec, val);
2482 return (val);
c2f5bfd6
KH
2483}
2484
45eb10fb 2485
35027d0c
KH
2486/* Return a font entity matching with SPEC on FRAME. ATTRS, if non
2487 nil, is an array of face's attributes, which specifies preferred
2488 font-related attributes. */
45eb10fb 2489
e950d6f1 2490static Lisp_Object
35027d0c
KH
2491font_matching_entity (f, attrs, spec)
2492 FRAME_PTR f;
2493 Lisp_Object *attrs, spec;
e950d6f1 2494{
e950d6f1
KH
2495 struct font_driver_list *driver_list = f->font_driver_list;
2496 Lisp_Object ftype, size, entity;
35027d0c 2497 Lisp_Object frame;
e950d6f1 2498
35027d0c 2499 XSETFRAME (frame, f);
e950d6f1
KH
2500 ftype = AREF (spec, FONT_TYPE_INDEX);
2501 size = AREF (spec, FONT_SIZE_INDEX);
2502 if (FLOATP (size))
2503 ASET (spec, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
2504 entity = Qnil;
2505 for (; driver_list; driver_list = driver_list->next)
2506 if (driver_list->on
2507 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2508 {
ca4da08a 2509 Lisp_Object cache = font_get_cache (f, driver_list->driver);
7cee5d63 2510 Lisp_Object copy;
e950d6f1 2511
e950d6f1 2512 ASET (spec, FONT_TYPE_INDEX, driver_list->driver->type);
35027d0c 2513 entity = assoc_no_quit (spec, XCDR (cache));
7cee5d63 2514 if (CONSP (entity))
e950d6f1
KH
2515 entity = XCDR (entity);
2516 else
2517 {
2518 entity = driver_list->driver->match (frame, spec);
7cee5d63
KH
2519 copy = Fcopy_font_spec (spec);
2520 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2521 XSETCDR (cache, Fcons (Fcons (copy, entity), XCDR (cache)));
e950d6f1
KH
2522 }
2523 if (! NILP (entity))
2524 break;
2525 }
2526 ASET (spec, FONT_TYPE_INDEX, ftype);
2527 ASET (spec, FONT_SIZE_INDEX, size);
d0ab1ebe 2528 font_add_log ("match", spec, entity);
e950d6f1
KH
2529 return entity;
2530}
2531
45eb10fb
KH
2532
2533/* Open a font of ENTITY and PIXEL_SIZE on frame F, and return the
2534 opened font object. */
2535
c2f5bfd6
KH
2536static Lisp_Object
2537font_open_entity (f, entity, pixel_size)
2538 FRAME_PTR f;
2539 Lisp_Object entity;
2540 int pixel_size;
2541{
2542 struct font_driver_list *driver_list;
43c0454d 2543 Lisp_Object objlist, size, val, font_object;
c2f5bfd6 2544 struct font *font;
35027d0c 2545 int min_width;
c2f5bfd6 2546
d0ab1ebe 2547 font_assert (FONT_ENTITY_P (entity));
c2f5bfd6 2548 size = AREF (entity, FONT_SIZE_INDEX);
c2f5bfd6
KH
2549 if (XINT (size) != 0)
2550 pixel_size = XINT (size);
2551
2552 for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
2553 objlist = XCDR (objlist))
35027d0c
KH
2554 if (XFONT_OBJECT (XCAR (objlist))->pixel_size == pixel_size)
2555 return XCAR (objlist);
2556
2557 val = AREF (entity, FONT_TYPE_INDEX);
2558 for (driver_list = f->font_driver_list;
2559 driver_list && ! EQ (driver_list->driver->type, val);
2560 driver_list = driver_list->next);
2561 if (! driver_list)
2562 return Qnil;
c2f5bfd6 2563
35027d0c 2564 font_object = driver_list->driver->open (f, entity, pixel_size);
d0ab1ebe 2565 font_add_log ("open", entity, font_object);
43c0454d 2566 if (NILP (font_object))
35027d0c
KH
2567 return Qnil;
2568 ASET (entity, FONT_OBJLIST_INDEX,
2569 Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
2570 ASET (font_object, FONT_OBJLIST_INDEX, AREF (entity, FONT_OBJLIST_INDEX));
2571 num_fonts++;
2572
2573 font = XFONT_OBJECT (font_object);
2574 min_width = (font->min_width ? font->min_width
2575 : font->average_width ? font->average_width
2576 : font->space_width ? font->space_width
2577 : 1);
819e81df 2578#ifdef HAVE_WINDOW_SYSTEM
35027d0c
KH
2579 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
2580 if (FRAME_X_DISPLAY_INFO (f)->n_fonts == 1)
43c0454d 2581 {
35027d0c
KH
2582 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
2583 FRAME_SMALLEST_FONT_HEIGHT (f) = font->height;
2584 fonts_changed_p = 1;
2585 }
2586 else
2587 {
2588 if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
2589 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, fonts_changed_p = 1;
2590 if (FRAME_SMALLEST_FONT_HEIGHT (f) > font->height)
2591 FRAME_SMALLEST_FONT_HEIGHT (f) = font->height, fonts_changed_p = 1;
43c0454d 2592 }
819e81df 2593#endif
43c0454d
KH
2594
2595 return font_object;
c2f5bfd6
KH
2596}
2597
45eb10fb
KH
2598
2599/* Close FONT_OBJECT that is opened on frame F. */
2600
c2f5bfd6
KH
2601void
2602font_close_object (f, font_object)
2603 FRAME_PTR f;
2604 Lisp_Object font_object;
2605{
35027d0c 2606 struct font *font = XFONT_OBJECT (font_object);
10d16101 2607 Lisp_Object objlist;
c2f5bfd6
KH
2608 Lisp_Object tail, prev = Qnil;
2609
35027d0c 2610 objlist = AREF (font_object, FONT_OBJLIST_INDEX);
c2f5bfd6
KH
2611 for (prev = Qnil, tail = objlist; CONSP (tail);
2612 prev = tail, tail = XCDR (tail))
2613 if (EQ (font_object, XCAR (tail)))
2614 {
d0ab1ebe 2615 font_add_log ("close", font_object, Qnil);
35027d0c 2616 font->driver->close (f, font);
819e81df 2617#ifdef HAVE_WINDOW_SYSTEM
d0ab1ebe 2618 font_assert (FRAME_X_DISPLAY_INFO (f)->n_fonts);
35027d0c 2619 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
819e81df 2620#endif
10d16101 2621 if (NILP (prev))
35027d0c 2622 ASET (font_object, FONT_OBJLIST_INDEX, XCDR (objlist));
10d16101
KH
2623 else
2624 XSETCDR (prev, XCDR (objlist));
43c0454d 2625 num_fonts--;
10d16101 2626 return;
c2f5bfd6 2627 }
10d16101 2628 abort ();
c2f5bfd6
KH
2629}
2630
45eb10fb 2631
1701724c
KH
2632/* Return 1 if FONT on F has a glyph for character C, 0 if not, -1 if
2633 FONT is a font-entity and it must be opened to check. */
45eb10fb 2634
c2f5bfd6 2635int
1b834a8d 2636font_has_char (f, font, c)
c2f5bfd6 2637 FRAME_PTR f;
1b834a8d 2638 Lisp_Object font;
c2f5bfd6
KH
2639 int c;
2640{
1b834a8d 2641 struct font *fontp;
c2f5bfd6 2642
1b834a8d
KH
2643 if (FONT_ENTITY_P (font))
2644 {
2645 Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
2646 struct font_driver_list *driver_list;
2647
2648 for (driver_list = f->font_driver_list;
2649 driver_list && ! EQ (driver_list->driver->type, type);
2650 driver_list = driver_list->next);
2651 if (! driver_list)
2652 return 0;
2653 if (! driver_list->driver->has_char)
2654 return -1;
2655 return driver_list->driver->has_char (font, c);
2656 }
2657
d0ab1ebe 2658 font_assert (FONT_OBJECT_P (font));
35027d0c 2659 fontp = XFONT_OBJECT (font);
1b834a8d
KH
2660 if (fontp->driver->has_char)
2661 {
35027d0c 2662 int result = fontp->driver->has_char (font, c);
1b834a8d
KH
2663
2664 if (result >= 0)
2665 return result;
2666 }
2667 return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
c2f5bfd6
KH
2668}
2669
45eb10fb
KH
2670
2671/* Return the glyph ID of FONT_OBJECT for character C. */
2672
c2f5bfd6
KH
2673unsigned
2674font_encode_char (font_object, c)
2675 Lisp_Object font_object;
2676 int c;
2677{
35027d0c 2678 struct font *font;
c2f5bfd6 2679
d0ab1ebe 2680 font_assert (FONT_OBJECT_P (font_object));
35027d0c 2681 font = XFONT_OBJECT (font_object);
c2f5bfd6
KH
2682 return font->driver->encode_char (font, c);
2683}
2684
45eb10fb
KH
2685
2686/* Return the name of FONT_OBJECT. */
2687
ef18374f 2688Lisp_Object
c2f5bfd6
KH
2689font_get_name (font_object)
2690 Lisp_Object font_object;
2691{
d0ab1ebe 2692 font_assert (FONT_OBJECT_P (font_object));
35027d0c 2693 return AREF (font_object, FONT_NAME_INDEX);
ef18374f
KH
2694}
2695
45eb10fb
KH
2696
2697/* Return the specification of FONT_OBJECT. */
2698
ef18374f
KH
2699Lisp_Object
2700font_get_spec (font_object)
2701 Lisp_Object font_object;
2702{
35027d0c 2703 Lisp_Object spec = font_make_spec ();
ef18374f
KH
2704 int i;
2705
2706 for (i = 0; i < FONT_SIZE_INDEX; i++)
35027d0c
KH
2707 ASET (spec, i, AREF (font_object, i));
2708 ASET (spec, FONT_SIZE_INDEX,
2709 make_number (XFONT_OBJECT (font_object)->pixel_size));
ef18374f 2710 return spec;
c2f5bfd6
KH
2711}
2712
35027d0c
KH
2713Lisp_Object
2714font_spec_from_name (font_name)
2715 Lisp_Object font_name;
2716{
2717 Lisp_Object args[2];
2718
2719 args[0] = QCname;
2720 args[1] = font_name;
2721 return Ffont_spec (2, args);
2722}
2723
45eb10fb 2724
35027d0c
KH
2725void
2726font_clear_prop (attrs, prop)
2727 Lisp_Object *attrs;
2728 enum font_property_index prop;
2729{
2730 Lisp_Object font = attrs[LFACE_FONT_INDEX];
45eb10fb 2731
35027d0c
KH
2732 if (! FONTP (font))
2733 return;
2734 if (NILP (AREF (font, prop))
2735 && prop != FONT_FAMILY_INDEX && prop != FONT_FAMILY_INDEX)
2736 return;
2737 font = Fcopy_font_spec (font);
2738 ASET (font, prop, Qnil);
2739 if (prop == FONT_FAMILY_INDEX)
2740 {
2741 ASET (font, FONT_FOUNDRY_INDEX, Qnil);
2742 ASET (font, FONT_ADSTYLE_INDEX, Qnil);
2743 ASET (font, FONT_SIZE_INDEX, Qnil);
2744 ASET (font, FONT_DPI_INDEX, Qnil);
2745 ASET (font, FONT_SPACING_INDEX, Qnil);
2746 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
2747 }
2748 else if (prop == FONT_SIZE_INDEX)
2749 {
2750 ASET (font, FONT_DPI_INDEX, Qnil);
2751 ASET (font, FONT_SPACING_INDEX, Qnil);
2752 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
2753 }
2754 attrs[LFACE_FONT_INDEX] = font;
2755}
2756
2757void
2758font_update_lface (f, attrs)
2759 FRAME_PTR f;
2760 Lisp_Object *attrs;
c2f5bfd6 2761{
d0ab1ebe 2762 Lisp_Object spec;
35027d0c
KH
2763
2764 spec = attrs[LFACE_FONT_INDEX];
2765 if (! FONT_SPEC_P (spec))
2766 return;
2767
2768 if (! NILP (AREF (spec, FONT_FOUNDRY_INDEX))
2769 || ! NILP (AREF (spec, FONT_FAMILY_INDEX)))
2770 {
2771 Lisp_Object family;
2772
2773 if (NILP (AREF (spec, FONT_FOUNDRY_INDEX)))
2774 family = AREF (spec, FONT_FAMILY_INDEX);
2775 else if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
2776 family = concat2 (SYMBOL_NAME (AREF (spec, FONT_FOUNDRY_INDEX)),
2777 build_string ("-*"));
2778 else
2779 family = concat3 (SYMBOL_NAME (AREF (spec, FONT_FOUNDRY_INDEX)),
2780 build_string ("-"),
2781 SYMBOL_NAME (AREF (spec, FONT_FAMILY_INDEX)));
2782 attrs[LFACE_FAMILY_INDEX] = family;
2783 }
2784 if (! NILP (AREF (spec, FONT_WEIGHT_INDEX)))
2785 attrs[LFACE_WEIGHT_INDEX] = FONT_WEIGHT_FOR_FACE (spec);
2786 if (! NILP (AREF (spec, FONT_SLANT_INDEX)))
2787 attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);;
2788 if (! NILP (AREF (spec, FONT_WIDTH_INDEX)))
2789 attrs[LFACE_SWIDTH_INDEX] = FONT_WIDTH_FOR_FACE (spec);
2790 if (! NILP (AREF (spec, FONT_SIZE_INDEX)))
2791 {
2792 int point;
2793
2794 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
2795 {
2796 Lisp_Object val;
2797 int dpi = f->resy;
2798
2799 val = Ffont_get (spec, QCdpi);
2800 if (! NILP (val))
2801 dpi = XINT (val);
2802 point = PIXEL_TO_POINT (XINT (AREF (spec, FONT_SIZE_INDEX)) * 10,
2803 dpi);
2804 }
2805 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2806 point = XFLOAT_DATA (AREF (spec, FONT_SIZE_INDEX)) * 10;
2807 attrs[LFACE_HEIGHT_INDEX] = make_number (point);
2808 }
c2f5bfd6
KH
2809}
2810
45eb10fb 2811
35027d0c
KH
2812/* Return a font-entity satisfying SPEC and best matching with face's
2813 font related attributes in ATTRS. C, if not negative, is a
1701724c 2814 character that the entity must support. */
c2f5bfd6
KH
2815
2816Lisp_Object
35027d0c 2817font_find_for_lface (f, attrs, spec, c)
c2f5bfd6 2818 FRAME_PTR f;
35027d0c 2819 Lisp_Object *attrs;
c2f5bfd6 2820 Lisp_Object spec;
1701724c 2821 int c;
c2f5bfd6 2822{
35027d0c
KH
2823 Lisp_Object frame, entities, val, props[FONT_REGISTRY_INDEX + 1] ;
2824 Lisp_Object size;
1d1e1245 2825 int pixel_size;
6c8ec042 2826 int i, result;
c2f5bfd6 2827
35027d0c 2828 if (c >= 0)
fe5ddfbc 2829 {
1701724c 2830 Lisp_Object registry = AREF (spec, FONT_REGISTRY_INDEX);
35027d0c 2831 struct charset *encoding, *repertory;
1701724c 2832
35027d0c
KH
2833 if (font_registry_charsets (registry, &encoding, &repertory) < 0)
2834 return Qnil;
2835 if (repertory)
1701724c 2836 {
35027d0c 2837 if (ENCODE_CHAR (repertory, c) == CHARSET_INVALID_CODE (repertory))
1701724c 2838 return Qnil;
35027d0c
KH
2839 /* Any font of this registry support C. So, let's
2840 suppress the further checking. */
2841 c = -1;
1701724c 2842 }
35027d0c
KH
2843 else if (c > encoding->max_char)
2844 return Qnil;
c2f5bfd6
KH
2845 }
2846
35027d0c
KH
2847 XSETFRAME (frame, f);
2848 size = AREF (spec, FONT_SIZE_INDEX);
1d1e1245
KH
2849 pixel_size = font_pixel_size (f, spec);
2850 if (pixel_size == 0)
2851 {
2852 double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
2853
2854 pixel_size = POINT_TO_PIXEL (pt / 10, f->resy);
2855 }
35027d0c
KH
2856 ASET (spec, FONT_SIZE_INDEX, Qnil);
2857 entities = font_list_entities (frame, spec);
2858 ASET (spec, FONT_SIZE_INDEX, size);
fe5ddfbc
KH
2859 if (ASIZE (entities) == 0)
2860 return Qnil;
35027d0c
KH
2861 if (ASIZE (entities) == 1)
2862 {
2863 if (c < 0)
2864 return AREF (entities, 0);
2865 }
2866 else
c2f5bfd6 2867 {
fe5ddfbc 2868 /* Sort fonts by properties specified in LFACE. */
ec6fe57c 2869 Lisp_Object prefer = scratch_font_prefer;
d0ab1ebe 2870
35027d0c
KH
2871 for (i = 0; i < FONT_EXTRA_INDEX; i++)
2872 ASET (prefer, i, AREF (spec, i));
79f105c9
KH
2873 if (FONTP (attrs[LFACE_FONT_INDEX]))
2874 {
2875 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
2876
2877 for (i = 0; i < FONT_EXTRA_INDEX; i++)
2878 if (NILP (AREF (prefer, i)))
2879 ASET (prefer, i, AREF (face_font, i));
2880 }
35027d0c
KH
2881 if (NILP (AREF (prefer, FONT_FAMILY_INDEX)))
2882 font_parse_family_registry (attrs[LFACE_FAMILY_INDEX], Qnil, prefer);
2883 if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
2884 FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2885 if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
2886 FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2887 if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
2888 FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
1d1e1245 2889 ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
35027d0c
KH
2890 ASET (spec, FONT_SIZE_INDEX, Qnil);
2891 entities = font_sort_entites (entities, prefer, frame, spec, c < 0);
2892 ASET (spec, FONT_SIZE_INDEX, size);
c2f5bfd6 2893 }
1701724c 2894 if (c < 0)
35027d0c 2895 return entities;
45eb10fb 2896
35027d0c
KH
2897 for (i = 0; i < ASIZE (entities); i++)
2898 {
2899 int j;
2900
2901 val = AREF (entities, i);
2902 if (i > 0)
2903 {
2904 for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
2905 if (! EQ (AREF (val, j), props[j]))
2906 break;
2907 if (j > FONT_REGISTRY_INDEX)
2908 continue;
2909 }
2910 for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
2911 props[j] = AREF (val, j);
2912 result = font_has_char (f, val, c);
2913 if (result > 0)
2914 return val;
2915 if (result == 0)
2916 return Qnil;
2917 val = font_open_for_lface (f, val, attrs, spec);
2918 if (NILP (val))
2919 continue;
2920 result = font_has_char (f, val, c);
2921 font_close_object (f, val);
2922 if (result > 0)
2923 return AREF (entities, i);
2924 }
1701724c
KH
2925 return Qnil;
2926}
45eb10fb
KH
2927
2928
c2f5bfd6 2929Lisp_Object
35027d0c 2930font_open_for_lface (f, entity, attrs, spec)
c2f5bfd6 2931 FRAME_PTR f;
c2f5bfd6 2932 Lisp_Object entity;
35027d0c 2933 Lisp_Object *attrs;
733fd013 2934 Lisp_Object spec;
c2f5bfd6 2935{
9331887d 2936 int size;
c2f5bfd6 2937
1d1e1245
KH
2938 if (FONT_SPEC_P (spec) && ! NILP (AREF (spec, FONT_SIZE_INDEX)))
2939 size = font_pixel_size (f, spec);
733fd013
KH
2940 else
2941 {
35027d0c 2942 double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
733fd013
KH
2943
2944 pt /= 10;
2945 size = POINT_TO_PIXEL (pt, f->resy);
2946 }
c2f5bfd6
KH
2947 return font_open_entity (f, entity, size);
2948}
2949
45eb10fb 2950
35027d0c
KH
2951/* Find a font satisfying SPEC and best matching with face's
2952 attributes in ATTRS on FRAME, and return the opened
2953 font-object. */
45eb10fb 2954
35027d0c
KH
2955Lisp_Object
2956font_load_for_lface (f, attrs, spec)
c2f5bfd6 2957 FRAME_PTR f;
35027d0c 2958 Lisp_Object *attrs, spec;
c2f5bfd6 2959{
35027d0c 2960 Lisp_Object entity;
ef18374f 2961
35027d0c
KH
2962 entity = font_find_for_lface (f, attrs, spec, -1);
2963 if (NILP (entity))
ef18374f 2964 {
35027d0c
KH
2965 /* No font is listed for SPEC, but each font-backend may have
2966 the different criteria about "font matching". So, try
2967 it. */
2968 entity = font_matching_entity (f, attrs, spec);
2969 if (NILP (entity))
2970 return Qnil;
c2f5bfd6 2971 }
35027d0c 2972 return font_open_for_lface (f, entity, attrs, spec);
c2f5bfd6
KH
2973}
2974
45eb10fb
KH
2975
2976/* Make FACE on frame F ready to use the font opened for FACE. */
2977
c2f5bfd6
KH
2978void
2979font_prepare_for_face (f, face)
2980 FRAME_PTR f;
2981 struct face *face;
2982{
35027d0c
KH
2983 if (face->font->driver->prepare_face)
2984 face->font->driver->prepare_face (f, face);
c2f5bfd6
KH
2985}
2986
45eb10fb
KH
2987
2988/* Make FACE on frame F stop using the font opened for FACE. */
2989
c2f5bfd6
KH
2990void
2991font_done_for_face (f, face)
2992 FRAME_PTR f;
2993 struct face *face;
2994{
35027d0c
KH
2995 if (face->font->driver->done_face)
2996 face->font->driver->done_face (f, face);
c2f5bfd6
KH
2997 face->extra = NULL;
2998}
2999
45eb10fb
KH
3000
3001/* Open a font best matching with NAME on frame F. If no proper font
3002 is found, return Qnil. */
3003
c2f5bfd6
KH
3004Lisp_Object
3005font_open_by_name (f, name)
3006 FRAME_PTR f;
3007 char *name;
3008{
ef18374f 3009 Lisp_Object args[2];
e950d6f1 3010 Lisp_Object spec, prefer, size, entity, entity_list;
c2f5bfd6 3011 Lisp_Object frame;
a9262bb8 3012 int i;
ef18374f 3013 int pixel_size;
c2f5bfd6
KH
3014
3015 XSETFRAME (frame, f);
a9262bb8 3016
ef18374f
KH
3017 args[0] = QCname;
3018 args[1] = make_unibyte_string (name, strlen (name));
3019 spec = Ffont_spec (2, args);
a9262bb8 3020 prefer = scratch_font_prefer;
35027d0c
KH
3021 for (i = 0; i < FONT_SPEC_MAX; i++)
3022 {
3023 ASET (prefer, i, AREF (spec, i));
3024 if (NILP (AREF (prefer, i))
3025 && i >= FONT_WEIGHT_INDEX && i <= FONT_WIDTH_INDEX)
3026 FONT_SET_STYLE (prefer, i, make_number (100));
3027 }
a9262bb8
KH
3028 size = AREF (spec, FONT_SIZE_INDEX);
3029 if (NILP (size))
3030 pixel_size = 0;
35027d0c 3031 else
ef18374f 3032 {
35027d0c
KH
3033 if (INTEGERP (size))
3034 pixel_size = XINT (size);
3035 else /* FLOATP (size) */
3036 {
3037 double pt = XFLOAT_DATA (size);
a9262bb8 3038
35027d0c
KH
3039 pixel_size = POINT_TO_PIXEL (pt, f->resy);
3040 }
3041 if (pixel_size == 0)
3042 ASET (spec, FONT_SIZE_INDEX, Qnil);
ef18374f 3043 }
a9262bb8 3044 if (pixel_size == 0)
ef18374f 3045 {
9331887d 3046 pixel_size = POINT_TO_PIXEL (12.0, f->resy);
a9262bb8 3047 size = make_number (pixel_size);
35027d0c 3048 ASET (prefer, FONT_SIZE_INDEX, size);
ef18374f 3049 }
9331887d
KH
3050 if (NILP (AREF (spec, FONT_REGISTRY_INDEX)))
3051 ASET (spec, FONT_REGISTRY_INDEX, Qiso8859_1);
a9262bb8 3052
e950d6f1
KH
3053 entity_list = Flist_fonts (spec, frame, make_number (1), prefer);
3054 if (NILP (entity_list))
35027d0c 3055 entity = font_matching_entity (f, NULL, spec);
e950d6f1
KH
3056 else
3057 entity = XCAR (entity_list);
3058 return (NILP (entity)
a9262bb8 3059 ? Qnil
e950d6f1 3060 : font_open_entity (f, entity, pixel_size));
c2f5bfd6
KH
3061}
3062
3063
3064/* Register font-driver DRIVER. This function is used in two ways.
3065
417a1b10
KH
3066 The first is with frame F non-NULL. In this case, make DRIVER
3067 available (but not yet activated) on F. All frame creaters
3068 (e.g. Fx_create_frame) must call this function at least once with
3069 an available font-driver.
c2f5bfd6
KH
3070
3071 The second is with frame F NULL. In this case, DRIVER is globally
3072 registered in the variable `font_driver_list'. All font-driver
3073 implementations must call this function in its syms_of_XXXX
3074 (e.g. syms_of_xfont). */
3075
3076void
3077register_font_driver (driver, f)
3078 struct font_driver *driver;
3079 FRAME_PTR f;
3080{
3081 struct font_driver_list *root = f ? f->font_driver_list : font_driver_list;
3082 struct font_driver_list *prev, *list;
3083
3084 if (f && ! driver->draw)
43a1d19b 3085 error ("Unusable font driver for a frame: %s",
c2f5bfd6
KH
3086 SDATA (SYMBOL_NAME (driver->type)));
3087
3088 for (prev = NULL, list = root; list; prev = list, list = list->next)
cf23b845 3089 if (EQ (list->driver->type, driver->type))
c2f5bfd6
KH
3090 error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type)));
3091
3092 list = malloc (sizeof (struct font_driver_list));
417a1b10 3093 list->on = 0;
c2f5bfd6
KH
3094 list->driver = driver;
3095 list->next = NULL;
3096 if (prev)
3097 prev->next = list;
3098 else if (f)
3099 f->font_driver_list = list;
3100 else
3101 font_driver_list = list;
72606e45
KH
3102 if (! f)
3103 num_font_drivers++;
c2f5bfd6
KH
3104}
3105
45eb10fb 3106
c2f5bfd6
KH
3107/* Free font-driver list on frame F. It doesn't free font-drivers
3108 themselves. */
3109
3110void
3111free_font_driver_list (f)
3112 FRAME_PTR f;
3113{
3114 while (f->font_driver_list)
3115 {
3116 struct font_driver_list *next = f->font_driver_list->next;
3117
3118 free (f->font_driver_list);
3119 f->font_driver_list = next;
3120 }
3121}
3122
45eb10fb 3123
f697fff0 3124/* Make the frame F use font backends listed in NEW_DRIVERS (list of
ca4da08a
KH
3125 symbols, e.g. xft, x). If NEW_DRIVERS is t, make F use all
3126 available font drivers. If NEW_DRIVERS is nil, finalize all drivers.
417a1b10 3127
ca4da08a
KH
3128 A caller must free all realized faces if any in advance. The
3129 return value is a list of font backends actually made used on
3130 F. */
e950d6f1
KH
3131
3132Lisp_Object
3133font_update_drivers (f, new_drivers)
417a1b10
KH
3134 FRAME_PTR f;
3135 Lisp_Object new_drivers;
417a1b10
KH
3136{
3137 Lisp_Object active_drivers = Qnil;
417a1b10
KH
3138 struct font_driver_list *list;
3139
f697fff0
KH
3140 for (list = f->font_driver_list; list; list = list->next)
3141 if (list->on)
3142 {
ca4da08a
KH
3143 if (! EQ (new_drivers, Qt)
3144 && NILP (Fmemq (list->driver->type, new_drivers)))
3145 {
3146 if (list->driver->end_for_frame)
3147 list->driver->end_for_frame (f);
3148 font_finish_cache (f, list->driver);
3149 list->on = 0;
3150 }
f697fff0 3151 }
ca4da08a 3152 else
e950d6f1 3153 {
ca4da08a
KH
3154 if (EQ (new_drivers, Qt)
3155 || ! NILP (Fmemq (list->driver->type, new_drivers)))
3156 {
3157 if (! list->driver->start_for_frame
3158 || list->driver->start_for_frame (f) == 0)
3159 {
3160 font_prepare_cache (f, list->driver);
3161 list->on = 1;
3162 active_drivers = nconc2 (active_drivers,
3163 Fcons (list->driver->type, Qnil));
3164 }
3165 }
e950d6f1 3166 }
417a1b10 3167
e950d6f1 3168 return active_drivers;
417a1b10
KH
3169}
3170
f697fff0
KH
3171int
3172font_put_frame_data (f, driver, data)
3173 FRAME_PTR f;
3174 struct font_driver *driver;
3175 void *data;
3176{
3177 struct font_data_list *list, *prev;
3178
3179 for (prev = NULL, list = f->font_data_list; list;
3180 prev = list, list = list->next)
3181 if (list->driver == driver)
3182 break;
3183 if (! data)
3184 {
3185 if (list)
3186 {
3187 if (prev)
3188 prev->next = list->next;
3189 else
3190 f->font_data_list = list->next;
3191 free (list);
3192 }
3193 return 0;
3194 }
3195
3196 if (! list)
3197 {
3198 list = malloc (sizeof (struct font_data_list));
3199 if (! list)
3200 return -1;
3201 list->driver = driver;
3202 list->next = f->font_data_list;
3203 f->font_data_list = list;
3204 }
3205 list->data = data;
3206 return 0;
3207}
3208
3209
3210void *
3211font_get_frame_data (f, driver)
3212 FRAME_PTR f;
3213 struct font_driver *driver;
3214{
3215 struct font_data_list *list;
3216
3217 for (list = f->font_data_list; list; list = list->next)
3218 if (list->driver == driver)
3219 break;
3220 if (! list)
3221 return NULL;
3222 return list->data;
3223}
3224
417a1b10 3225
45eb10fb 3226/* Return the font used to draw character C by FACE at buffer position
e3ee0340
KH
3227 POS in window W. If STRING is non-nil, it is a string containing C
3228 at index POS. If C is negative, get C from the current buffer or
3229 STRING. */
45eb10fb 3230
10d16101 3231Lisp_Object
e3ee0340 3232font_at (c, pos, face, w, string)
10d16101
KH
3233 int c;
3234 EMACS_INT pos;
3235 struct face *face;
3236 struct window *w;
e3ee0340 3237 Lisp_Object string;
10d16101
KH
3238{
3239 FRAME_PTR f;
e3ee0340 3240 int multibyte;
35027d0c 3241 Lisp_Object font_object;
e3ee0340
KH
3242
3243 if (c < 0)
3244 {
3245 if (NILP (string))
3246 {
3247 multibyte = ! NILP (current_buffer->enable_multibyte_characters);
3248 if (multibyte)
3249 {
3250 EMACS_INT pos_byte = CHAR_TO_BYTE (pos);
3251
3252 c = FETCH_CHAR (pos_byte);
3253 }
3254 else
3255 c = FETCH_BYTE (pos);
3256 }
3257 else
3258 {
3259 unsigned char *str;
3260
3261 multibyte = STRING_MULTIBYTE (string);
3262 if (multibyte)
3263 {
3264 EMACS_INT pos_byte = string_char_to_byte (string, pos);
3265
3266 str = SDATA (string) + pos_byte;
3267 c = STRING_CHAR (str, 0);
3268 }
3269 else
3270 c = SDATA (string)[pos];
3271 }
3272 }
10d16101
KH
3273
3274 f = XFRAME (w->frame);
1385a806
KH
3275 if (! FRAME_WINDOW_P (f))
3276 return Qnil;
10d16101
KH
3277 if (! face)
3278 {
e3ee0340 3279 int face_id;
0f8b27ea 3280 EMACS_INT endptr;
e3ee0340
KH
3281
3282 if (STRINGP (string))
3283 face_id = face_at_string_position (w, string, pos, 0, -1, -1, &endptr,
10d16101
KH
3284 DEFAULT_FACE_ID, 0);
3285 else
e3ee0340 3286 face_id = face_at_buffer_position (w, pos, -1, -1, &endptr,
10d16101
KH
3287 pos + 100, 0);
3288 face = FACE_FROM_ID (f, face_id);
3289 }
e3ee0340
KH
3290 if (multibyte)
3291 {
3292 int face_id = FACE_FOR_CHAR (f, face, c, pos, string);
3293 face = FACE_FROM_ID (f, face_id);
3294 }
35027d0c 3295 if (! face->font)
10d16101 3296 return Qnil;
35027d0c 3297
d0ab1ebe 3298 font_assert (font_check_object ((struct font *) face->font));
35027d0c
KH
3299 XSETFONT (font_object, face->font);
3300 return font_object;
3301}
3302
3303
3304/* Check how many characters after POS (at most to LIMIT) can be
3305 displayed by the same font. FACE is the face selected for the
3306 character as POS on frame F. STRING, if not nil, is the string to
3307 check instead of the current buffer.
027a33c0 3308
35027d0c
KH
3309 The return value is the position of the character that is displayed
3310 by the differnt font than that of the character as POS. */
3311
3312EMACS_INT
3313font_range (pos, limit, face, f, string)
3314 EMACS_INT pos, limit;
3315 struct face *face;
3316 FRAME_PTR f;
3317 Lisp_Object string;
3318{
3319 int multibyte;
3320 EMACS_INT pos_byte;
3321 int c;
3322 struct font *font;
3323 int first = 1;
3324
3325 if (NILP (string))
3326 {
3327 multibyte = ! NILP (current_buffer->enable_multibyte_characters);
3328 pos_byte = CHAR_TO_BYTE (pos);
3329 }
3330 else
3331 {
3332 multibyte = STRING_MULTIBYTE (string);
3333 pos_byte = string_char_to_byte (string, pos);
3334 }
3335
3336 if (! multibyte)
3337 /* All unibyte character are displayed by the same font. */
3338 return limit;
3339
3340 while (pos < limit)
3341 {
3342 int face_id;
3343
3344 if (NILP (string))
3345 FETCH_CHAR_ADVANCE_NO_CHECK (c, pos, pos_byte);
3346 else
3347 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, pos, pos_byte);
3348 face_id = FACE_FOR_CHAR (f, face, c, pos, string);
3349 face = FACE_FROM_ID (f, face_id);
3350 if (first)
3351 {
3352 font = face->font;
3353 first = 0;
3354 continue;
3355 }
3356 else if (font != face->font)
3357 {
3358 pos--;
3359 break;
3360 }
3361 }
3362 return pos;
10d16101
KH
3363}
3364
c2f5bfd6
KH
3365\f
3366/* Lisp API */
3367
35027d0c 3368DEFUN ("fontp", Ffontp, Sfontp, 1, 2, 0,
6c8ec042 3369 doc: /* Return t if OBJECT is a font-spec, font-entity, or font-object.
35027d0c
KH
3370Return nil otherwise.
3371Optional 2nd argument EXTRA-TYPE, if non-nil, specifies to check
027a33c0 3372which kind of font it is. It must be one of `font-spec', `font-entity',
35027d0c
KH
3373`font-object'. */)
3374 (object, extra_type)
3375 Lisp_Object object, extra_type;
c2f5bfd6 3376{
35027d0c
KH
3377 if (NILP (extra_type))
3378 return (FONTP (object) ? Qt : Qnil);
3379 if (EQ (extra_type, Qfont_spec))
3380 return (FONT_SPEC_P (object) ? Qt : Qnil);
3381 if (EQ (extra_type, Qfont_entity))
3382 return (FONT_ENTITY_P (object) ? Qt : Qnil);
3383 if (EQ (extra_type, Qfont_object))
3384 return (FONT_OBJECT_P (object) ? Qt : Qnil);
3385 wrong_type_argument (intern ("font-extra-type"), extra_type);
c2f5bfd6
KH
3386}
3387
3388DEFUN ("font-spec", Ffont_spec, Sfont_spec, 0, MANY, 0,
45eb10fb
KH
3389 doc: /* Return a newly created font-spec with arguments as properties.
3390
3391ARGS must come in pairs KEY VALUE of font properties. KEY must be a
3392valid font property name listed below:
3393
3394`:family', `:weight', `:slant', `:width'
3395
3396They are the same as face attributes of the same name. See
51c01100 3397`set-face-attribute'.
45eb10fb
KH
3398
3399`:foundry'
3400
3401VALUE must be a string or a symbol specifying the font foundry, e.g. ``misc''.
3402
3403`:adstyle'
3404
3405VALUE must be a string or a symbol specifying the additional
35027d0c 3406typographic style information of a font, e.g. ``sans''.
45eb10fb
KH
3407
3408`:registry'
3409
3410VALUE must be a string or a symbol specifying the charset registry and
3411encoding of a font, e.g. ``iso8859-1''.
3412
3413`:size'
3414
3415VALUE must be a non-negative integer or a floating point number
35027d0c 3416specifying the font size. It specifies the font size in pixels
f697fff0
KH
3417(if VALUE is an integer), or in points (if VALUE is a float).
3418usage: (font-spec ARGS ...) */)
c2f5bfd6
KH
3419 (nargs, args)
3420 int nargs;
3421 Lisp_Object *args;
3422{
35027d0c 3423 Lisp_Object spec = font_make_spec ();
c2f5bfd6
KH
3424 int i;
3425
3426 for (i = 0; i < nargs; i += 2)
3427 {
c2f5bfd6
KH
3428 Lisp_Object key = args[i], val = args[i + 1];
3429
35027d0c
KH
3430 if (EQ (key, QCname))
3431 {
3432 CHECK_STRING (val);
3433 font_parse_name ((char *) SDATA (val), spec);
3434 font_put_extra (spec, key, val);
3435 }
3436 else if (EQ (key, QCfamily))
3437 {
3438 CHECK_STRING (val);
3439 font_parse_family_registry (val, Qnil, spec);
3440 }
c2f5bfd6 3441 else
4485a28e 3442 {
35027d0c
KH
3443 int idx = get_font_prop_index (key);
3444
3445 if (idx >= 0)
ec6fe57c 3446 {
35027d0c
KH
3447 val = font_prop_validate (idx, Qnil, val);
3448 if (idx < FONT_EXTRA_INDEX)
3449 ASET (spec, idx, val);
3450 else
3451 font_put_extra (spec, key, val);
ec6fe57c 3452 }
35027d0c
KH
3453 else
3454 font_put_extra (spec, key, font_prop_validate (0, key, val));
4485a28e 3455 }
e950d6f1 3456 }
c2f5bfd6
KH
3457 return spec;
3458}
3459
35027d0c
KH
3460DEFUN ("copy-font-spec", Fcopy_font_spec, Scopy_font_spec, 1, 1, 0,
3461 doc: /* Return a copy of FONT as a font-spec. */)
3462 (font)
3463 Lisp_Object font;
3464{
3465 Lisp_Object new_spec, tail, extra;
3466 int i;
3467
3468 CHECK_FONT (font);
3469 new_spec = font_make_spec ();
3470 for (i = 1; i < FONT_EXTRA_INDEX; i++)
3471 ASET (new_spec, i, AREF (font, i));
3472 extra = Qnil;
3473 for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
3474 {
3475 if (! EQ (XCAR (XCAR (tail)), QCfont_entity))
3476 extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
3477 }
3478 ASET (new_spec, FONT_EXTRA_INDEX, extra);
3479 return new_spec;
3480}
3481
3482DEFUN ("merge-font-spec", Fmerge_font_spec, Smerge_font_spec, 2, 2, 0,
3483 doc: /* Merge font-specs FROM and TO, and return a new font-spec.
3484Every specified properties in FROM override the corresponding
3485properties in TO. */)
3486 (from, to)
3487 Lisp_Object from, to;
3488{
3489 Lisp_Object extra, tail;
3490 int i;
3491
3492 CHECK_FONT (from);
3493 CHECK_FONT (to);
3494 to = Fcopy_font_spec (to);
3495 for (i = 0; i < FONT_EXTRA_INDEX; i++)
3496 ASET (to, i, AREF (from, i));
3497 extra = AREF (to, FONT_EXTRA_INDEX);
3498 for (tail = AREF (from, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
3499 if (! EQ (XCAR (XCAR (tail)), Qfont_entity))
3500 {
3501 Lisp_Object slot = assq_no_quit (XCAR (XCAR (tail)), extra);
3502
3503 if (! NILP (slot))
3504 XSETCDR (slot, XCDR (XCAR (tail)));
3505 else
3506 extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
3507 }
3508 ASET (to, FONT_EXTRA_INDEX, extra);
3509 return to;
3510}
c2f5bfd6
KH
3511
3512DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
45eb10fb 3513 doc: /* Return the value of FONT's property KEY.
e950d6f1 3514FONT is a font-spec, a font-entity, or a font-object. */)
45eb10fb
KH
3515 (font, key)
3516 Lisp_Object font, key;
c2f5bfd6 3517{
35027d0c 3518 int idx;
c2f5bfd6 3519
35027d0c
KH
3520 CHECK_FONT (font);
3521 CHECK_SYMBOL (key);
e80e09b4 3522
35027d0c
KH
3523 idx = get_font_prop_index (key);
3524 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
c2f5bfd6 3525 return AREF (font, idx);
35027d0c 3526 return Fcdr (Fassq (key, AREF (font, FONT_EXTRA_INDEX)));
c2f5bfd6
KH
3527}
3528
3529
3530DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
51c01100 3531 doc: /* Set one property of FONT-SPEC: give property PROP value VAL. */)
c2f5bfd6
KH
3532 (font_spec, prop, val)
3533 Lisp_Object font_spec, prop, val;
3534{
35027d0c 3535 int idx;
c2f5bfd6
KH
3536
3537 CHECK_FONT_SPEC (font_spec);
35027d0c
KH
3538 idx = get_font_prop_index (prop);
3539 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
3540 {
3541 if (idx == FONT_FAMILY_INDEX
3542 && STRINGP (val))
3543 font_parse_family_registry (val, Qnil, font_spec);
3544 else
3545 ASET (font_spec, idx, font_prop_validate (idx, Qnil, val));
3546 }
c2f5bfd6 3547 else
35027d0c 3548 font_put_extra (font_spec, prop, font_prop_validate (0, prop, val));
c2f5bfd6
KH
3549 return val;
3550}
3551
3552DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0,
3553 doc: /* List available fonts matching FONT-SPEC on the current frame.
3554Optional 2nd argument FRAME specifies the target frame.
3555Optional 3rd argument NUM, if non-nil, limits the number of returned fonts.
45eb10fb
KH
3556Optional 4th argument PREFER, if non-nil, is a font-spec to
3557control the order of the returned list. Fonts are sorted by
027a33c0 3558how close they are to PREFER. */)
c2f5bfd6
KH
3559 (font_spec, frame, num, prefer)
3560 Lisp_Object font_spec, frame, num, prefer;
3561{
3562 Lisp_Object vec, list, tail;
3563 int n = 0, i, len;
3564
3565 if (NILP (frame))
3566 frame = selected_frame;
3567 CHECK_LIVE_FRAME (frame);
35027d0c 3568 CHECK_FONT_SPEC (font_spec);
c2f5bfd6
KH
3569 if (! NILP (num))
3570 {
3571 CHECK_NUMBER (num);
3572 n = XINT (num);
3573 if (n <= 0)
3574 return Qnil;
3575 }
3576 if (! NILP (prefer))
35027d0c 3577 CHECK_FONT_SPEC (prefer);
c2f5bfd6
KH
3578
3579 vec = font_list_entities (frame, font_spec);
3580 len = ASIZE (vec);
3581 if (len == 0)
3582 return Qnil;
3583 if (len == 1)
3584 return Fcons (AREF (vec, 0), Qnil);
3585
3586 if (! NILP (prefer))
35027d0c 3587 vec = font_sort_entites (vec, prefer, frame, font_spec, 0);
c2f5bfd6
KH
3588
3589 list = tail = Fcons (AREF (vec, 0), Qnil);
3590 if (n == 0 || n > len)
3591 n = len;
3592 for (i = 1; i < n; i++)
3593 {
3594 Lisp_Object val = Fcons (AREF (vec, i), Qnil);
3595
3596 XSETCDR (tail, val);
3597 tail = val;
3598 }
3599 return list;
3600}
3601
35027d0c 3602DEFUN ("font-family-list", Ffont_family_list, Sfont_family_list, 0, 1, 0,
c2f5bfd6 3603 doc: /* List available font families on the current frame.
027a33c0 3604Optional argument FRAME, if non-nil, specifies the target frame. */)
c2f5bfd6
KH
3605 (frame)
3606 Lisp_Object frame;
3607{
3608 FRAME_PTR f;
3609 struct font_driver_list *driver_list;
3610 Lisp_Object list;
3611
3612 if (NILP (frame))
3613 frame = selected_frame;
3614 CHECK_LIVE_FRAME (frame);
3615 f = XFRAME (frame);
3616 list = Qnil;
3617 for (driver_list = f->font_driver_list; driver_list;
3618 driver_list = driver_list->next)
3619 if (driver_list->driver->list_family)
3620 {
3621 Lisp_Object val = driver_list->driver->list_family (frame);
3622
3623 if (NILP (list))
3624 list = val;
3625 else
3626 {
3627 Lisp_Object tail = list;
3628
3629 for (; CONSP (val); val = XCDR (val))
3630 if (NILP (Fmemq (XCAR (val), tail)))
3631 list = Fcons (XCAR (val), list);
3632 }
3633 }
3634 return list;
3635}
3636
3637DEFUN ("find-font", Ffind_font, Sfind_font, 1, 2, 0,
3638 doc: /* Return a font-entity matching with FONT-SPEC on the current frame.
3639Optional 2nd argument FRAME, if non-nil, specifies the target frame. */)
3640 (font_spec, frame)
3641 Lisp_Object font_spec, frame;
3642{
3643 Lisp_Object val = Flist_fonts (font_spec, frame, make_number (1), Qnil);
3644
3645 if (CONSP (val))
3646 val = XCAR (val);
3647 return val;
3648}
3649
d0ab1ebe 3650DEFUN ("font-xlfd-name", Ffont_xlfd_name, Sfont_xlfd_name, 1, 2, 0,
c2f5bfd6
KH
3651 doc: /* Return XLFD name of FONT.
3652FONT is a font-spec, font-entity, or font-object.
d0ab1ebe
KH
3653If the name is too long for XLFD (maximum 255 chars), return nil.
3654If the 2nd optional arg FOLD-WILDCARDS is non-nil,
3655the consecutive wildcards are folded to one. */)
3656 (font, fold_wildcards)
3657 Lisp_Object font, fold_wildcards;
c2f5bfd6
KH
3658{
3659 char name[256];
3660 int pixel_size = 0;
3661
35027d0c
KH
3662 CHECK_FONT (font);
3663
3664 if (FONT_OBJECT_P (font))
c2f5bfd6 3665 {
35027d0c 3666 Lisp_Object font_name = AREF (font, FONT_NAME_INDEX);
c2f5bfd6 3667
35027d0c
KH
3668 if (STRINGP (font_name)
3669 && SDATA (font_name)[0] == '-')
d0ab1ebe
KH
3670 {
3671 if (NILP (fold_wildcards))
3672 return font_name;
3673 strcpy (name, (char *) SDATA (font_name));
3674 goto done;
3675 }
35027d0c 3676 pixel_size = XFONT_OBJECT (font)->pixel_size;
c2f5bfd6 3677 }
c2f5bfd6
KH
3678 if (font_unparse_xlfd (font, pixel_size, name, 256) < 0)
3679 return Qnil;
d0ab1ebe
KH
3680 done:
3681 if (! NILP (fold_wildcards))
3682 {
3683 char *p0 = name, *p1;
3684
3685 while ((p1 = strstr (p0, "-*-*")))
3686 {
3687 strcpy (p1, p1 + 2);
3688 p0 = p1;
3689 }
3690 }
3691
c2f5bfd6
KH
3692 return build_string (name);
3693}
3694
3695DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
3696 doc: /* Clear font cache. */)
3697 ()
3698{
3699 Lisp_Object list, frame;
3700
3701 FOR_EACH_FRAME (list, frame)
3702 {
3703 FRAME_PTR f = XFRAME (frame);
3704 struct font_driver_list *driver_list = f->font_driver_list;
3705
3706 for (; driver_list; driver_list = driver_list->next)
417a1b10
KH
3707 if (driver_list->on)
3708 {
ca4da08a
KH
3709 Lisp_Object cache = driver_list->driver->get_cache (f);
3710 Lisp_Object val;
51c01100 3711
ca4da08a 3712 val = XCDR (cache);
43c0454d
KH
3713 while (! NILP (val)
3714 && ! EQ (XCAR (XCAR (val)), driver_list->driver->type))
ca4da08a 3715 val = XCDR (val);
d0ab1ebe 3716 font_assert (! NILP (val));
ca4da08a
KH
3717 val = XCDR (XCAR (val));
3718 if (XINT (XCAR (val)) == 0)
417a1b10 3719 {
ca4da08a
KH
3720 font_clear_cache (f, XCAR (val), driver_list->driver);
3721 XSETCDR (cache, XCDR (val));
417a1b10 3722 }
417a1b10 3723 }
c2f5bfd6
KH
3724 }
3725
3726 return Qnil;
3727}
3728
68eaeee4 3729/* The following three functions are still experimental. */
45eb10fb 3730
c2f5bfd6 3731DEFUN ("font-make-gstring", Ffont_make_gstring, Sfont_make_gstring, 2, 2, 0,
e80e09b4
KH
3732 doc: /* Return a newly created g-string for FONT-OBJECT with NUM glyphs.
3733FONT-OBJECT may be nil if it is not yet known.
3734
3735G-string is sequence of glyphs of a specific font,
3736and is a vector of this form:
3737 [ HEADER GLYPH ... ]
3738HEADER is a vector of this form:
1701724c 3739 [FONT-OBJECT WIDTH LBEARING RBEARING ASCENT DESCENT]
e80e09b4 3740where
733fd013 3741 FONT-OBJECT is a font-object for all glyphs in the g-string,
027a33c0 3742 WIDTH thru DESCENT are the metrics (in pixels) of the whole G-string.
e80e09b4 3743GLYPH is a vector of this form:
1701724c
KH
3744 [ FROM-IDX TO-IDX C CODE WIDTH LBEARING RBEARING ASCENT DESCENT
3745 [ [X-OFF Y-OFF WADJUST] | nil] ]
e80e09b4
KH
3746where
3747 FROM-IDX and TO-IDX are used internally and should not be touched.
3748 C is the character of the glyph.
3749 CODE is the glyph-code of C in FONT-OBJECT.
027a33c0 3750 WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
e80e09b4 3751 X-OFF and Y-OFF are offests to the base position for the glyph.
e80e09b4 3752 WADJUST is the adjustment to the normal width of the glyph. */)
c2f5bfd6
KH
3753 (font_object, num)
3754 Lisp_Object font_object, num;
3755{
3756 Lisp_Object gstring, g;
3757 int len;
3758 int i;
3759
3760 if (! NILP (font_object))
3761 CHECK_FONT_OBJECT (font_object);
3762 CHECK_NATNUM (num);
3763
3764 len = XINT (num) + 1;
3765 gstring = Fmake_vector (make_number (len), Qnil);
3766 g = Fmake_vector (make_number (6), Qnil);
3767 ASET (g, 0, font_object);
3768 ASET (gstring, 0, g);
3769 for (i = 1; i < len; i++)
1701724c 3770 ASET (gstring, i, Fmake_vector (make_number (10), Qnil));
c2f5bfd6
KH
3771 return gstring;
3772}
3773
3774DEFUN ("font-fill-gstring", Ffont_fill_gstring, Sfont_fill_gstring, 4, 5, 0,
51c01100
JB
3775 doc: /* Fill in glyph-string GSTRING by characters for FONT-OBJECT.
3776START and END specify the region to extract characters.
3777If optional 5rd argument OBJECT is non-nil, it is a buffer or a string from
c2f5bfd6 3778where to extract characters.
027a33c0 3779FONT-OBJECT may be nil if GSTRING already contains one. */)
c2f5bfd6
KH
3780 (gstring, font_object, start, end, object)
3781 Lisp_Object gstring, font_object, start, end, object;
3782{
3783 int len, i, c;
3784 unsigned code;
3785 struct font *font;
3786
3787 CHECK_VECTOR (gstring);
3788 if (NILP (font_object))
10d16101 3789 font_object = LGSTRING_FONT (gstring);
35027d0c 3790 font = XFONT_OBJECT (font_object);
c2f5bfd6
KH
3791
3792 if (STRINGP (object))
3793 {
3794 const unsigned char *p;
3795
3796 CHECK_NATNUM (start);
3797 CHECK_NATNUM (end);
3798 if (XINT (start) > XINT (end)
3799 || XINT (end) > ASIZE (object)
10d16101 3800 || XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
1701724c 3801 args_out_of_range_3 (object, start, end);
c2f5bfd6
KH
3802
3803 len = XINT (end) - XINT (start);
3804 p = SDATA (object) + string_char_to_byte (object, XINT (start));
3805 for (i = 0; i < len; i++)
3806 {
3807 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
2930d117
EZ
3808 /* Shut up GCC warning in comparison with
3809 MOST_POSITIVE_FIXNUM below. */
3810 EMACS_INT cod;
c2f5bfd6
KH
3811
3812 c = STRING_CHAR_ADVANCE (p);
2930d117
EZ
3813 cod = code = font->driver->encode_char (font, c);
3814 if (cod > MOST_POSITIVE_FIXNUM || code == FONT_INVALID_CODE)
40fb53d6 3815 break;
1701724c
KH
3816 LGLYPH_SET_FROM (g, i);
3817 LGLYPH_SET_TO (g, i);
3818 LGLYPH_SET_CHAR (g, c);
3819 LGLYPH_SET_CODE (g, code);
c2f5bfd6
KH
3820 }
3821 }
3822 else
3823 {
3824 int pos, pos_byte;
3825
3826 if (! NILP (object))
3827 Fset_buffer (object);
3828 validate_region (&start, &end);
10d16101 3829 if (XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
c2f5bfd6
KH
3830 args_out_of_range (start, end);
3831 len = XINT (end) - XINT (start);
3832 pos = XINT (start);
3833 pos_byte = CHAR_TO_BYTE (pos);
3834 for (i = 0; i < len; i++)
3835 {
3836 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
2930d117
EZ
3837 /* Shut up GCC warning in comparison with
3838 MOST_POSITIVE_FIXNUM below. */
3839 EMACS_INT cod;
c2f5bfd6
KH
3840
3841 FETCH_CHAR_ADVANCE (c, pos, pos_byte);
2930d117
EZ
3842 cod = code = font->driver->encode_char (font, c);
3843 if (cod > MOST_POSITIVE_FIXNUM || code == FONT_INVALID_CODE)
40fb53d6 3844 break;
1701724c
KH
3845 LGLYPH_SET_FROM (g, i);
3846 LGLYPH_SET_TO (g, i);
3847 LGLYPH_SET_CHAR (g, c);
3848 LGLYPH_SET_CODE (g, code);
c2f5bfd6
KH
3849 }
3850 }
40fb53d6 3851 for (; i < LGSTRING_LENGTH (gstring); i++)
51c01100 3852 LGSTRING_SET_GLYPH (gstring, i, Qnil);
1701724c
KH
3853 return Qnil;
3854}
3855
3856DEFUN ("font-shape-text", Ffont_shape_text, Sfont_shape_text, 3, 4, 0,
3857 doc: /* Shape text between FROM and TO by FONT-OBJECT.
3858If optional 4th argument STRING is non-nil, it is a string to shape,
3859and FROM and TO are indices to the string.
40fb53d6
KH
3860The value is the end position of the text that can be shaped by
3861FONT-OBJECT. */)
1701724c
KH
3862 (from, to, font_object, string)
3863 Lisp_Object from, to, font_object, string;
3864{
3865 struct font *font;
3866 struct font_metrics metrics;
3867 EMACS_INT start, end;
3868 Lisp_Object gstring, n;
35027d0c 3869 int len, i;
1701724c 3870
b876ea91
KH
3871 if (! FONT_OBJECT_P (font_object))
3872 return Qnil;
35027d0c 3873 font = XFONT_OBJECT (font_object);
b876ea91
KH
3874 if (! font->driver->shape)
3875 return Qnil;
3876
1701724c
KH
3877 if (NILP (string))
3878 {
3879 validate_region (&from, &to);
3880 start = XFASTINT (from);
3881 end = XFASTINT (to);
3882 modify_region (current_buffer, start, end, 0);
3883 }
3884 else
3885 {
3886 CHECK_STRING (string);
3887 start = XINT (from);
3888 end = XINT (to);
3889 if (start < 0 || start > end || end > SCHARS (string))
3890 args_out_of_range_3 (string, from, to);
3891 }
3892
40fb53d6
KH
3893 len = end - start;
3894 gstring = Ffont_make_gstring (font_object, make_number (len));
1701724c 3895 Ffont_fill_gstring (gstring, font_object, from, to, string);
51c01100 3896
40fb53d6
KH
3897 /* Try at most three times with larger gstring each time. */
3898 for (i = 0; i < 3; i++)
3899 {
3900 Lisp_Object args[2];
3901
3902 n = font->driver->shape (gstring);
3903 if (INTEGERP (n))
3904 break;
3905 args[0] = gstring;
3906 args[1] = Fmake_vector (make_number (len), Qnil);
3907 gstring = Fvconcat (2, args);
3908 }
3909 if (! INTEGERP (n) || XINT (n) == 0)
1701724c 3910 return Qnil;
40fb53d6
KH
3911 len = XINT (n);
3912
3913 for (i = 0; i < len;)
10d16101 3914 {
1701724c 3915 Lisp_Object gstr;
10d16101 3916 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
1701724c
KH
3917 EMACS_INT this_from = LGLYPH_FROM (g);
3918 EMACS_INT this_to = LGLYPH_TO (g) + 1;
3919 int j, k;
b2937119 3920 int need_composition = 0;
1701724c
KH
3921
3922 metrics.lbearing = LGLYPH_LBEARING (g);
3923 metrics.rbearing = LGLYPH_RBEARING (g);
3924 metrics.ascent = LGLYPH_ASCENT (g);
3925 metrics.descent = LGLYPH_DESCENT (g);
3926 if (NILP (LGLYPH_ADJUSTMENT (g)))
b2937119
KH
3927 {
3928 metrics.width = LGLYPH_WIDTH (g);
f9ffa1ea 3929 if (LGLYPH_CHAR (g) == 0 || metrics.width == 0)
b2937119
KH
3930 need_composition = 1;
3931 }
1701724c
KH
3932 else
3933 {
3934 metrics.width = LGLYPH_WADJUST (g);
3935 metrics.lbearing += LGLYPH_XOFF (g);
3936 metrics.rbearing += LGLYPH_XOFF (g);
3937 metrics.ascent -= LGLYPH_YOFF (g);
3938 metrics.descent += LGLYPH_YOFF (g);
b2937119 3939 need_composition = 1;
1701724c 3940 }
40fb53d6 3941 for (j = i + 1; j < len; j++)
1701724c
KH
3942 {
3943 int x;
3944
3945 g = LGSTRING_GLYPH (gstring, j);
3946 if (this_from != LGLYPH_FROM (g))
3947 break;
b2937119 3948 need_composition = 1;
1701724c
KH
3949 x = metrics.width + LGLYPH_LBEARING (g) + LGLYPH_XOFF (g);
3950 if (metrics.lbearing > x)
3951 metrics.lbearing = x;
3952 x = metrics.width + LGLYPH_RBEARING (g) + LGLYPH_XOFF (g);
3953 if (metrics.rbearing < x)
3954 metrics.rbearing = x;
3955 x = LGLYPH_ASCENT (g) - LGLYPH_YOFF (g);
3956 if (metrics.ascent < x)
3957 metrics.ascent = x;
3958 x = LGLYPH_DESCENT (g) - LGLYPH_YOFF (g);
3959 if (metrics.descent < x)
3960 metrics.descent = x;
3961 if (NILP (LGLYPH_ADJUSTMENT (g)))
3962 metrics.width += LGLYPH_WIDTH (g);
3963 else
3964 metrics.width += LGLYPH_WADJUST (g);
3965 }
10d16101 3966
b2937119
KH
3967 if (need_composition)
3968 {
3969 gstr = Ffont_make_gstring (font_object, make_number (j - i));
3970 LGSTRING_SET_WIDTH (gstr, metrics.width);
3971 LGSTRING_SET_LBEARING (gstr, metrics.lbearing);
3972 LGSTRING_SET_RBEARING (gstr, metrics.rbearing);
3973 LGSTRING_SET_ASCENT (gstr, metrics.ascent);
3974 LGSTRING_SET_DESCENT (gstr, metrics.descent);
3975 for (k = i; i < j; i++)
e8912e41
KH
3976 {
3977 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
3978
3979 LGLYPH_SET_FROM (g, LGLYPH_FROM (g) - this_from);
95d0a340 3980 LGLYPH_SET_TO (g, LGLYPH_TO (g) - this_from);
e8912e41
KH
3981 LGSTRING_SET_GLYPH (gstr, i - k, LGSTRING_GLYPH (gstring, i));
3982 }
b2937119
KH
3983 from = make_number (start + this_from);
3984 to = make_number (start + this_to);
3985 if (NILP (string))
3986 Fcompose_region_internal (from, to, gstr, Qnil);
3987 else
3988 Fcompose_string_internal (string, from, to, gstr, Qnil);
3989 }
1701724c 3990 else
b2937119 3991 i = j;
10d16101 3992 }
1701724c 3993
14065d35 3994 return to;
c2f5bfd6
KH
3995}
3996
6a3dadd2
KH
3997#if 0
3998
733fd013
KH
3999DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
4000 doc: /* Apply OpenType features on glyph-string GSTRING-IN.
51c01100 4001OTF-FEATURES specifies which features to apply in this format:
733fd013 4002 (SCRIPT LANGSYS GSUB GPOS)
e80e09b4
KH
4003where
4004 SCRIPT is a symbol specifying a script tag of OpenType,
4005 LANGSYS is a symbol specifying a langsys tag of OpenType,
733fd013 4006 GSUB and GPOS, if non-nil, are lists of symbols specifying feature tags.
e80e09b4
KH
4007
4008If LANGYS is nil, the default langsys is selected.
4009
51c01100
JB
4010The features are applied in the order they appear in the list. The
4011symbol `*' means to apply all available features not present in this
733fd013
KH
4012list, and the remaining features are ignored. For instance, (vatu
4013pstf * haln) is to apply vatu and pstf in this order, then to apply
4014all available features other than vatu, pstf, and haln.
e80e09b4
KH
4015
4016The features are applied to the glyphs in the range FROM and TO of
733fd013 4017the glyph-string GSTRING-IN.
e80e09b4 4018
51c01100 4019If some feature is actually applicable, the resulting glyphs are
e80e09b4
KH
4020produced in the glyph-string GSTRING-OUT from the index INDEX. In
4021this case, the value is the number of produced glyphs.
4022
4023If no feature is applicable, no glyph is produced in GSTRING-OUT, and
4024the value is 0.
4025
51c01100 4026If GSTRING-OUT is too short to hold produced glyphs, no glyphs are
e80e09b4
KH
4027produced in GSTRING-OUT, and the value is nil.
4028
4029See the documentation of `font-make-gstring' for the format of
4030glyph-string. */)
733fd013
KH
4031 (otf_features, gstring_in, from, to, gstring_out, index)
4032 Lisp_Object otf_features, gstring_in, from, to, gstring_out, index;
e80e09b4
KH
4033{
4034 Lisp_Object font_object = LGSTRING_FONT (gstring_in);
733fd013
KH
4035 Lisp_Object val;
4036 struct font *font;
e80e09b4
KH
4037 int len, num;
4038
733fd013 4039 check_otf_features (otf_features);
35027d0c
KH
4040 CHECK_FONT_OBJECT (font_object);
4041 font = XFONT_OBJECT (font_object);
733fd013 4042 if (! font->driver->otf_drive)
e80e09b4
KH
4043 error ("Font backend %s can't drive OpenType GSUB table",
4044 SDATA (SYMBOL_NAME (font->driver->type)));
733fd013
KH
4045 CHECK_CONS (otf_features);
4046 CHECK_SYMBOL (XCAR (otf_features));
4047 val = XCDR (otf_features);
4048 CHECK_SYMBOL (XCAR (val));
4049 val = XCDR (otf_features);
4050 if (! NILP (val))
4051 CHECK_CONS (val);
e80e09b4
KH
4052 len = check_gstring (gstring_in);
4053 CHECK_VECTOR (gstring_out);
4054 CHECK_NATNUM (from);
4055 CHECK_NATNUM (to);
4056 CHECK_NATNUM (index);
4057
4058 if (XINT (from) >= XINT (to) || XINT (to) > len)
4059 args_out_of_range_3 (from, to, make_number (len));
4060 if (XINT (index) >= ASIZE (gstring_out))
4061 args_out_of_range (index, make_number (ASIZE (gstring_out)));
733fd013
KH
4062 num = font->driver->otf_drive (font, otf_features,
4063 gstring_in, XINT (from), XINT (to),
4064 gstring_out, XINT (index), 0);
e80e09b4
KH
4065 if (num < 0)
4066 return Qnil;
4067 return make_number (num);
4068}
4069
e80e09b4
KH
4070DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
4071 3, 3, 0,
4072 doc: /* Return a list of alternate glyphs of CHARACTER in FONT-OBJECT.
51c01100 4073OTF-FEATURES specifies which features of the font FONT-OBJECT to apply
e80e09b4
KH
4074in this format:
4075 (SCRIPT LANGSYS FEATURE ...)
027a33c0 4076See the documentation of `font-drive-otf' for more detail.
e80e09b4
KH
4077
4078The value is a list of cons cells of the format (GLYPH-ID . CHARACTER),
4079where GLYPH-ID is a glyph index of the font, and CHARACTER is a
4080character code corresponding to the glyph or nil if there's no
4081corresponding character. */)
733fd013
KH
4082 (font_object, character, otf_features)
4083 Lisp_Object font_object, character, otf_features;
e80e09b4
KH
4084{
4085 struct font *font;
4086 Lisp_Object gstring_in, gstring_out, g;
4087 Lisp_Object alternates;
4088 int i, num;
4089
4090 CHECK_FONT_GET_OBJECT (font_object, font);
733fd013 4091 if (! font->driver->otf_drive)
e950d6f1
KH
4092 error ("Font backend %s can't drive OpenType GSUB table",
4093 SDATA (SYMBOL_NAME (font->driver->type)));
e80e09b4 4094 CHECK_CHARACTER (character);
733fd013 4095 CHECK_CONS (otf_features);
e80e09b4
KH
4096
4097 gstring_in = Ffont_make_gstring (font_object, make_number (1));
4098 g = LGSTRING_GLYPH (gstring_in, 0);
f9ffa1ea 4099 LGLYPH_SET_CHAR (g, XINT (character));
e80e09b4 4100 gstring_out = Ffont_make_gstring (font_object, make_number (10));
733fd013
KH
4101 while ((num = font->driver->otf_drive (font, otf_features, gstring_in, 0, 1,
4102 gstring_out, 0, 1)) < 0)
e80e09b4
KH
4103 gstring_out = Ffont_make_gstring (font_object,
4104 make_number (ASIZE (gstring_out) * 2));
4105 alternates = Qnil;
4106 for (i = 0; i < num; i++)
4107 {
4108 Lisp_Object g = LGSTRING_GLYPH (gstring_out, i);
f9ffa1ea
SM
4109 int c = LGLYPH_CHAR (g);
4110 unsigned code = LGLYPH_CODE (g);
e80e09b4
KH
4111
4112 alternates = Fcons (Fcons (make_number (code),
4113 c > 0 ? make_number (c) : Qnil),
4114 alternates);
4115 }
4116 return Fnreverse (alternates);
4117}
6a3dadd2 4118#endif /* 0 */
c2f5bfd6
KH
4119
4120#ifdef FONT_DEBUG
4121
4122DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0,
4123 doc: /* Open FONT-ENTITY. */)
4124 (font_entity, size, frame)
4125 Lisp_Object font_entity;
4126 Lisp_Object size;
4127 Lisp_Object frame;
4128{
4129 int isize;
4130
4131 CHECK_FONT_ENTITY (font_entity);
c2f5bfd6
KH
4132 if (NILP (frame))
4133 frame = selected_frame;
4134 CHECK_LIVE_FRAME (frame);
51c01100 4135
35027d0c
KH
4136 if (NILP (size))
4137 isize = XINT (AREF (font_entity, FONT_SIZE_INDEX));
4138 else
4139 {
4140 CHECK_NUMBER_OR_FLOAT (size);
4141 if (FLOATP (size))
4142 isize = POINT_TO_PIXEL (- isize, XFRAME (frame)->resy);
4143 else
4144 isize = XINT (size);
4145 if (isize == 0)
4146 isize = 120;
4147 }
c2f5bfd6
KH
4148 return font_open_entity (XFRAME (frame), font_entity, isize);
4149}
4150
4151DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0,
4152 doc: /* Close FONT-OBJECT. */)
4153 (font_object, frame)
4154 Lisp_Object font_object, frame;
4155{
4156 CHECK_FONT_OBJECT (font_object);
4157 if (NILP (frame))
4158 frame = selected_frame;
4159 CHECK_LIVE_FRAME (frame);
4160 font_close_object (XFRAME (frame), font_object);
4161 return Qnil;
4162}
4163
4164DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
e80e09b4
KH
4165 doc: /* Return information about FONT-OBJECT.
4166The value is a vector:
4167 [ NAME FILENAME PIXEL-SIZE SIZE ASCENT DESCENT SPACE-WIDTH AVERAGE-WIDTH
e0708580 4168 CAPABILITY ]
e80e09b4
KH
4169
4170NAME is a string of the font name (or nil if the font backend doesn't
4171provide a name).
4172
4173FILENAME is a string of the font file (or nil if the font backend
4174doesn't provide a file name).
4175
4176PIXEL-SIZE is a pixel size by which the font is opened.
4177
027a33c0 4178SIZE is a maximum advance width of the font in pixels.
e80e09b4
KH
4179
4180ASCENT, DESCENT, SPACE-WIDTH, AVERAGE-WIDTH are metrics of the font in
027a33c0 4181pixels.
e80e09b4 4182
e0708580
KH
4183CAPABILITY is a list whose first element is a symbol representing the
4184font format \(x, opentype, truetype, type1, pcf, or bdf) and the
027a33c0 4185remaining elements describe the details of the font capability.
e0708580
KH
4186
4187If the font is OpenType font, the form of the list is
4188 \(opentype GSUB GPOS)
4189where GSUB shows which "GSUB" features the font supports, and GPOS
4190shows which "GPOS" features the font supports. Both GSUB and GPOS are
4191lists of the format:
4192 \((SCRIPT (LANGSYS FEATURE ...) ...) ...)
4193
4194If the font is not OpenType font, currently the length of the form is
4195one.
e80e09b4
KH
4196
4197SCRIPT is a symbol representing OpenType script tag.
4198
4199LANGSYS is a symbol representing OpenType langsys tag, or nil
4200representing the default langsys.
4201
51c01100 4202FEATURE is a symbol representing OpenType feature tag.
e80e09b4 4203
51c01100 4204If the font is not OpenType font, CAPABILITY is nil. */)
c2f5bfd6
KH
4205 (font_object)
4206 Lisp_Object font_object;
4207{
4208 struct font *font;
4209 Lisp_Object val;
4210
4211 CHECK_FONT_GET_OBJECT (font_object, font);
4212
4213 val = Fmake_vector (make_number (9), Qnil);
35027d0c
KH
4214 ASET (val, 0, AREF (font_object, FONT_NAME_INDEX));
4215 ASET (val, 1, AREF (font_object, FONT_FILE_INDEX));
c2f5bfd6 4216 ASET (val, 2, make_number (font->pixel_size));
35027d0c 4217 ASET (val, 3, make_number (font->max_width));
c2f5bfd6
KH
4218 ASET (val, 4, make_number (font->ascent));
4219 ASET (val, 5, make_number (font->descent));
35027d0c
KH
4220 ASET (val, 6, make_number (font->space_width));
4221 ASET (val, 7, make_number (font->average_width));
c2f5bfd6 4222 if (font->driver->otf_capability)
e0708580 4223 ASET (val, 8, Fcons (Qopentype, font->driver->otf_capability (font)));
c2f5bfd6
KH
4224 return val;
4225}
4226
4227DEFUN ("get-font-glyphs", Fget_font_glyphs, Sget_font_glyphs, 2, 2, 0,
4228 doc: /* Return a vector of glyphs of FONT-OBJECT for drawing STRING.
4229Each element is a vector [GLYPH-CODE LBEARING RBEARING WIDTH ASCENT DESCENT]. */)
4230 (font_object, string)
4231 Lisp_Object font_object, string;
4232{
4233 struct font *font;
4234 int i, len;
4235 Lisp_Object vec;
4236
4237 CHECK_FONT_GET_OBJECT (font_object, font);
4238 CHECK_STRING (string);
4239 len = SCHARS (string);
4240 vec = Fmake_vector (make_number (len), Qnil);
4241 for (i = 0; i < len; i++)
4242 {
4243 Lisp_Object ch = Faref (string, make_number (i));
4244 Lisp_Object val;
4245 int c = XINT (ch);
4246 unsigned code;
2930d117 4247 EMACS_INT cod;
c2f5bfd6
KH
4248 struct font_metrics metrics;
4249
2930d117 4250 cod = code = font->driver->encode_char (font, c);
c2f5bfd6
KH
4251 if (code == FONT_INVALID_CODE)
4252 continue;
4253 val = Fmake_vector (make_number (6), Qnil);
2930d117 4254 if (cod <= MOST_POSITIVE_FIXNUM)
c2f5bfd6
KH
4255 ASET (val, 0, make_number (code));
4256 else
4257 ASET (val, 0, Fcons (make_number (code >> 16),
4258 make_number (code & 0xFFFF)));
51c01100 4259 font->driver->text_extents (font, &code, 1, &metrics);
c2f5bfd6
KH
4260 ASET (val, 1, make_number (metrics.lbearing));
4261 ASET (val, 2, make_number (metrics.rbearing));
4262 ASET (val, 3, make_number (metrics.width));
4263 ASET (val, 4, make_number (metrics.ascent));
4264 ASET (val, 5, make_number (metrics.descent));
4265 ASET (vec, i, val);
4266 }
4267 return vec;
4268}
4269
ec6fe57c 4270DEFUN ("font-match-p", Ffont_match_p, Sfont_match_p, 2, 2, 0,
67b5d7de 4271 doc: /* Return t if and only if font-spec SPEC matches with FONT.
ec6fe57c
KH
4272FONT is a font-spec, font-entity, or font-object. */)
4273 (spec, font)
4274 Lisp_Object spec, font;
4275{
4276 CHECK_FONT_SPEC (spec);
35027d0c 4277 CHECK_FONT (font);
ec6fe57c
KH
4278
4279 return (font_match_p (spec, font) ? Qt : Qnil);
4280}
4281
1701724c 4282DEFUN ("font-at", Ffont_at, Sfont_at, 1, 3, 0,
51c01100 4283 doc: /* Return a font-object for displaying a character at POSITION.
10d16101
KH
4284Optional second arg WINDOW, if non-nil, is a window displaying
4285the current buffer. It defaults to the currently selected window. */)
1701724c
KH
4286 (position, window, string)
4287 Lisp_Object position, window, string;
10d16101
KH
4288{
4289 struct window *w;
e3ee0340 4290 EMACS_INT pos;
10d16101 4291
1701724c
KH
4292 if (NILP (string))
4293 {
4294 CHECK_NUMBER_COERCE_MARKER (position);
4295 pos = XINT (position);
4296 if (pos < BEGV || pos >= ZV)
4297 args_out_of_range_3 (position, make_number (BEGV), make_number (ZV));
1701724c
KH
4298 }
4299 else
4300 {
1701724c
KH
4301 CHECK_NUMBER (position);
4302 CHECK_STRING (string);
4303 pos = XINT (position);
4304 if (pos < 0 || pos >= SCHARS (string))
4305 args_out_of_range (string, position);
1701724c 4306 }
10d16101
KH
4307 if (NILP (window))
4308 window = selected_window;
4309 CHECK_LIVE_WINDOW (window);
40fb53d6 4310 w = XWINDOW (window);
10d16101 4311
40fb53d6 4312 return font_at (-1, pos, NULL, w, string);
10d16101
KH
4313}
4314
c2f5bfd6
KH
4315#if 0
4316DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
4317 doc: /* Draw STRING by FONT-OBJECT on the top left corner of the current frame.
4318The value is a number of glyphs drawn.
4319Type C-l to recover what previously shown. */)
4320 (font_object, string)
4321 Lisp_Object font_object, string;
4322{
4323 Lisp_Object frame = selected_frame;
4324 FRAME_PTR f = XFRAME (frame);
4325 struct font *font;
4326 struct face *face;
4327 int i, len, width;
4328 unsigned *code;
4329
4330 CHECK_FONT_GET_OBJECT (font_object, font);
4331 CHECK_STRING (string);
4332 len = SCHARS (string);
4333 code = alloca (sizeof (unsigned) * len);
4334 for (i = 0; i < len; i++)
4335 {
4336 Lisp_Object ch = Faref (string, make_number (i));
4337 Lisp_Object val;
4338 int c = XINT (ch);
4339
4340 code[i] = font->driver->encode_char (font, c);
4341 if (code[i] == FONT_INVALID_CODE)
4342 break;
4343 }
4344 face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
4345 face->fontp = font;
4346 if (font->driver->prepare_face)
4347 font->driver->prepare_face (f, face);
4348 width = font->driver->text_extents (font, code, i, NULL);
4349 len = font->driver->draw_text (f, face, 0, font->ascent, code, i, width);
4350 if (font->driver->done_face)
4351 font->driver->done_face (f, face);
4352 face->fontp = NULL;
4353 return make_number (len);
4354}
4355#endif
4356
4357#endif /* FONT_DEBUG */
4358
a266686a
KH
4359#ifdef HAVE_WINDOW_SYSTEM
4360
72606e45
KH
4361DEFUN ("font-info", Ffont_info, Sfont_info, 1, 2, 0,
4362 doc: /* Return information about a font named NAME on frame FRAME.
4363If FRAME is omitted or nil, use the selected frame.
4364The returned value is a vector of OPENED-NAME, FULL-NAME, CHARSET, SIZE,
4365 HEIGHT, BASELINE-OFFSET, RELATIVE-COMPOSE, and DEFAULT-ASCENT,
4366where
4367 OPENED-NAME is the name used for opening the font,
4368 FULL-NAME is the full name of the font,
4369 SIZE is the maximum bound width of the font,
4370 HEIGHT is the height of the font,
4371 BASELINE-OFFSET is the upward offset pixels from ASCII baseline,
4372 RELATIVE-COMPOSE and DEFAULT-ASCENT are the numbers controlling
4373 how to compose characters.
4374If the named font is not yet loaded, return nil. */)
4375 (name, frame)
4376 Lisp_Object name, frame;
4377{
4378 FRAME_PTR f;
4379 struct font *font;
4380 Lisp_Object info;
4381 Lisp_Object font_object;
4382
4383 (*check_window_system_func) ();
4384
4385 if (! FONTP (name))
4386 CHECK_STRING (name);
4387 if (NILP (frame))
4388 frame = selected_frame;
4389 CHECK_LIVE_FRAME (frame);
4390 f = XFRAME (frame);
4391
4392 if (STRINGP (name))
4393 {
4394 int fontset = fs_query_fontset (name, 0);
4395
4396 if (fontset >= 0)
4397 name = fontset_ascii (fontset);
4398 font_object = font_open_by_name (f, (char *) SDATA (name));
4399 }
4400 else if (FONT_OBJECT_P (name))
4401 font_object = name;
4402 else if (FONT_ENTITY_P (name))
4403 font_object = font_open_entity (f, name, 0);
4404 else
4405 {
4406 struct face *face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
4407 Lisp_Object entity = font_matching_entity (f, face->lface, name);
4408
4409 font_object = ! NILP (entity) ? font_open_entity (f, entity, 0) : Qnil;
4410 }
4411 if (NILP (font_object))
4412 return Qnil;
4413 font = XFONT_OBJECT (font_object);
4414
4415 info = Fmake_vector (make_number (7), Qnil);
4416 XVECTOR (info)->contents[0] = AREF (font_object, FONT_NAME_INDEX);
4417 XVECTOR (info)->contents[1] = AREF (font_object, FONT_NAME_INDEX);
4418 XVECTOR (info)->contents[2] = make_number (font->pixel_size);
4419 XVECTOR (info)->contents[3] = make_number (font->height);
4420 XVECTOR (info)->contents[4] = make_number (font->baseline_offset);
4421 XVECTOR (info)->contents[5] = make_number (font->relative_compose);
4422 XVECTOR (info)->contents[6] = make_number (font->default_ascent);
4423
4424#if 0
4425 /* As font_object is still in FONT_OBJLIST of the entity, we can't
4426 close it now. Perhaps, we should manage font-objects
4427 by `reference-count'. */
4428 font_close_object (f, font_object);
4429#endif
4430 return info;
4431}
a266686a 4432#endif
72606e45 4433
c2f5bfd6 4434\f
d0ab1ebe
KH
4435#define BUILD_STYLE_TABLE(TBL) \
4436 build_style_table ((TBL), sizeof TBL / sizeof (struct table_entry))
4437
4438static Lisp_Object
4439build_style_table (entry, nelement)
4440 struct table_entry *entry;
4441 int nelement;
4442{
4443 int i, j;
4444 Lisp_Object table, elt;
4445
4446 table = Fmake_vector (make_number (nelement), Qnil);
4447 for (i = 0; i < nelement; i++)
4448 {
4449 for (j = 0; entry[i].names[j]; j++);
4450 elt = Fmake_vector (make_number (j + 1), Qnil);
4451 ASET (elt, 0, make_number (entry[i].numeric));
4452 for (j = 0; entry[i].names[j]; j++)
4453 ASET (elt, j + 1, intern (entry[i].names[j]));
4454 ASET (table, i, elt);
4455 }
4456 return table;
4457}
4458
4459static Lisp_Object Vfont_log;
4460static int font_log_env_checked;
4461
4462void
4463font_add_log (action, arg, result)
4464 char *action;
4465 Lisp_Object arg, result;
4466{
4467 Lisp_Object tail, val;
4468 int i;
4469
4470 if (! font_log_env_checked)
4471 {
4472 Vfont_log = egetenv ("EMACS_FONT_LOG") ? Qnil : Qt;
4473 font_log_env_checked = 1;
4474 }
4475 if (EQ (Vfont_log, Qt))
4476 return;
4477 if (FONTP (arg))
4478 arg = Ffont_xlfd_name (arg, Qt);
4479 if (FONTP (result))
4480 result = Ffont_xlfd_name (result, Qt);
4481 else if (CONSP (result))
4482 {
4483 result = Fcopy_sequence (result);
4484 for (tail = result; CONSP (tail); tail = XCDR (tail))
4485 {
4486 val = XCAR (tail);
4487 if (FONTP (val))
4488 val = Ffont_xlfd_name (val, Qt);
4489 XSETCAR (tail, val);
4490 }
4491 }
4492 else if (VECTORP (result))
4493 {
4494 result = Fcopy_sequence (result);
4495 for (i = 0; i < ASIZE (result); i++)
4496 {
4497 val = AREF (result, i);
4498 if (FONTP (val))
4499 val = Ffont_xlfd_name (val, Qt);
4500 ASET (result, i, val);
4501 }
4502 }
4503 Vfont_log = Fcons (list3 (intern (action), arg, result), Vfont_log);
4504}
4505
c2f5bfd6
KH
4506extern void syms_of_ftfont P_ (());
4507extern void syms_of_xfont P_ (());
4508extern void syms_of_xftfont P_ (());
4509extern void syms_of_ftxfont P_ (());
4510extern void syms_of_bdffont P_ (());
4511extern void syms_of_w32font P_ (());
4512extern void syms_of_atmfont P_ (());
4513
4514void
4515syms_of_font ()
4516{
4517 sort_shift_bits[FONT_SLANT_INDEX] = 0;
4518 sort_shift_bits[FONT_WEIGHT_INDEX] = 7;
4519 sort_shift_bits[FONT_SIZE_INDEX] = 14;
4520 sort_shift_bits[FONT_WIDTH_INDEX] = 21;
4521 sort_shift_bits[FONT_ADSTYLE_INDEX] = 28;
4522 sort_shift_bits[FONT_FOUNDRY_INDEX] = 29;
4523 sort_shift_bits[FONT_FAMILY_INDEX] = 30;
35027d0c
KH
4524 /* Note that sort_shift_bits[FONT_SORT_TYPE] and
4525 sort_shift_bits[FONT_SORT_REGISTRY] are never used. */
c2f5bfd6 4526
1701724c
KH
4527 staticpro (&font_charset_alist);
4528 font_charset_alist = Qnil;
4529
35027d0c
KH
4530 DEFSYM (Qfont_spec, "font-spec");
4531 DEFSYM (Qfont_entity, "font-entity");
4532 DEFSYM (Qfont_object, "font-object");
4533
e0708580 4534 DEFSYM (Qopentype, "opentype");
c2f5bfd6 4535
1bb1d99b
KH
4536 DEFSYM (Qiso8859_1, "iso8859-1");
4537 DEFSYM (Qiso10646_1, "iso10646-1");
4538 DEFSYM (Qunicode_bmp, "unicode-bmp");
cf96c5c2 4539 DEFSYM (Qunicode_sip, "unicode-sip");
1bb1d99b 4540
c2f5bfd6 4541 DEFSYM (QCotf, ":otf");
35027d0c 4542 DEFSYM (QClang, ":lang");
c2f5bfd6 4543 DEFSYM (QCscript, ":script");
4c496d0d 4544 DEFSYM (QCantialias, ":antialias");
c2f5bfd6
KH
4545
4546 DEFSYM (QCfoundry, ":foundry");
4547 DEFSYM (QCadstyle, ":adstyle");
4548 DEFSYM (QCregistry, ":registry");
9331887d
KH
4549 DEFSYM (QCspacing, ":spacing");
4550 DEFSYM (QCdpi, ":dpi");
ec6fe57c 4551 DEFSYM (QCscalable, ":scalable");
35027d0c
KH
4552 DEFSYM (QCavgwidth, ":avgwidth");
4553 DEFSYM (QCfont_entity, ":font-entity");
4554 DEFSYM (QCfc_unknown_spec, ":fc-unknown-spec");
c2f5bfd6 4555
ec6fe57c
KH
4556 DEFSYM (Qc, "c");
4557 DEFSYM (Qm, "m");
4558 DEFSYM (Qp, "p");
4559 DEFSYM (Qd, "d");
4560
c2f5bfd6
KH
4561 staticpro (&null_vector);
4562 null_vector = Fmake_vector (make_number (0), Qnil);
4563
4564 staticpro (&scratch_font_spec);
4565 scratch_font_spec = Ffont_spec (0, NULL);
4566 staticpro (&scratch_font_prefer);
4567 scratch_font_prefer = Ffont_spec (0, NULL);
4568
6a3dadd2 4569#if 0
733fd013
KH
4570#ifdef HAVE_LIBOTF
4571 staticpro (&otf_list);
4572 otf_list = Qnil;
6a3dadd2
KH
4573#endif /* HAVE_LIBOTF */
4574#endif /* 0 */
733fd013 4575
c2f5bfd6
KH
4576 defsubr (&Sfontp);
4577 defsubr (&Sfont_spec);
4578 defsubr (&Sfont_get);
4579 defsubr (&Sfont_put);
4580 defsubr (&Slist_fonts);
35027d0c 4581 defsubr (&Sfont_family_list);
c2f5bfd6
KH
4582 defsubr (&Sfind_font);
4583 defsubr (&Sfont_xlfd_name);
4584 defsubr (&Sclear_font_cache);
c2f5bfd6
KH
4585 defsubr (&Sfont_make_gstring);
4586 defsubr (&Sfont_fill_gstring);
1701724c 4587 defsubr (&Sfont_shape_text);
6a3dadd2 4588#if 0
733fd013 4589 defsubr (&Sfont_drive_otf);
e80e09b4 4590 defsubr (&Sfont_otf_alternates);
6a3dadd2 4591#endif /* 0 */
c2f5bfd6
KH
4592
4593#ifdef FONT_DEBUG
4594 defsubr (&Sopen_font);
4595 defsubr (&Sclose_font);
4596 defsubr (&Squery_font);
4597 defsubr (&Sget_font_glyphs);
ec6fe57c 4598 defsubr (&Sfont_match_p);
10d16101 4599 defsubr (&Sfont_at);
c2f5bfd6
KH
4600#if 0
4601 defsubr (&Sdraw_string);
4602#endif
4603#endif /* FONT_DEBUG */
a266686a 4604#ifdef HAVE_WINDOW_SYSTEM
72606e45 4605 defsubr (&Sfont_info);
a266686a 4606#endif
c2f5bfd6 4607
819e81df
KH
4608 DEFVAR_LISP ("font-encoding-alist", &Vfont_encoding_alist,
4609 doc: /*
4610Alist of fontname patterns vs the corresponding encoding and repertory info.
4611Each element looks like (REGEXP . (ENCODING . REPERTORY)),
4612where ENCODING is a charset or a char-table,
4613and REPERTORY is a charset, a char-table, or nil.
4614
027a33c0 4615If ENCODING and REPERTORY are the same, the element can have the form
819e81df
KH
4616\(REGEXP . ENCODING).
4617
4618ENCODING is for converting a character to a glyph code of the font.
4619If ENCODING is a charset, encoding a character by the charset gives
4620the corresponding glyph code. If ENCODING is a char-table, looking up
4621the table by a character gives the corresponding glyph code.
4622
4623REPERTORY specifies a repertory of characters supported by the font.
4624If REPERTORY is a charset, all characters beloging to the charset are
4625supported. If REPERTORY is a char-table, all characters who have a
027a33c0 4626non-nil value in the table are supported. If REPERTORY is nil, Emacs
819e81df
KH
4627gets the repertory information by an opened font and ENCODING. */);
4628 Vfont_encoding_alist = Qnil;
4629
d0ab1ebe
KH
4630 DEFVAR_LISP_NOPRO ("font-weight-table", &Vfont_weight_table,
4631 doc: /* Vector of valid font weight values.
4632Each element has the form:
4633 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
4634NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symobls. */);
4635 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
4636
4637 DEFVAR_LISP_NOPRO ("font-slant-table", &Vfont_slant_table,
4638 doc: /* Vector of font slant symbols vs the corresponding numeric values.
4639See `font-weight_table' for the format of the vector. */);
4640 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
4641
4642 DEFVAR_LISP_NOPRO ("font-width-table", &Vfont_width_table,
4643 doc: /* Alist of font width symbols vs the corresponding numeric values.
4644See `font-weight_table' for the format of the vector. */);
4645 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
4646
4647 staticpro (&font_style_table);
4648 font_style_table = Fmake_vector (make_number (3), Qnil);
4649 ASET (font_style_table, 0, Vfont_weight_table);
4650 ASET (font_style_table, 1, Vfont_slant_table);
4651 ASET (font_style_table, 2, Vfont_width_table);
4652
4653 DEFVAR_LISP ("font-log", &Vfont_log, doc: /*
4654*Logging list of font related actions and results.
4655The value t means to suppress the logging.
4656The initial value is set to nil if the environment variable
4657EMACS_FONT_LOG is set. Otherwise, it is set to t. */);
4658 Vfont_log = Qnil;
4659
819e81df 4660#ifdef HAVE_WINDOW_SYSTEM
c2f5bfd6 4661#ifdef HAVE_FREETYPE
35027d0c 4662 syms_of_ftfont ();
c2f5bfd6 4663#ifdef HAVE_X_WINDOWS
35027d0c
KH
4664 syms_of_xfont ();
4665 syms_of_ftxfont ();
c2f5bfd6 4666#ifdef HAVE_XFT
35027d0c 4667 syms_of_xftfont ();
c2f5bfd6
KH
4668#endif /* HAVE_XFT */
4669#endif /* HAVE_X_WINDOWS */
4670#else /* not HAVE_FREETYPE */
4671#ifdef HAVE_X_WINDOWS
35027d0c 4672 syms_of_xfont ();
c2f5bfd6
KH
4673#endif /* HAVE_X_WINDOWS */
4674#endif /* not HAVE_FREETYPE */
4675#ifdef HAVE_BDFFONT
35027d0c 4676 syms_of_bdffont ();
c2f5bfd6
KH
4677#endif /* HAVE_BDFFONT */
4678#ifdef WINDOWSNT
35027d0c 4679 syms_of_w32font ();
c2f5bfd6
KH
4680#endif /* WINDOWSNT */
4681#ifdef MAC_OS
35027d0c 4682 syms_of_atmfont ();
c2f5bfd6 4683#endif /* MAC_OS */
819e81df 4684#endif /* HAVE_WINDOW_SYSTEM */
c2f5bfd6 4685}
885b7d09
MB
4686
4687/* arch-tag: 74c9475d-5976-4c93-a327-942ae3072846
4688 (do not change this comment) */