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