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