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