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