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