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