This source file includes following definitions.
- valid_font_driver
- font_make_spec
- font_make_entity
- font_make_object
- font_build_object
- font_intern_prop
- font_pixel_size
- font_style_to_value
- font_style_symbolic
- find_font_encoding
- font_registry_charsets
- font_prop_validate_symbol
- font_prop_validate_style
- font_prop_validate_non_neg
- font_prop_validate_spacing
- font_prop_validate_otf
- get_font_prop_index
- font_prop_validate
- font_put_extra
- parse_matrix
- font_expand_wildcards
- font_parse_xlfd_1
- font_parse_xlfd
- font_unparse_xlfd
- font_parse_fcname
- font_unparse_fcname
- font_parse_name
- font_parse_family_registry
- font_rescale_ratio
- font_score
- font_vconcat_entity_vectors
- font_compare
- font_sort_entities
- font_update_sort_order
- font_check_otf_features
- font_check_otf
- font_match_p
- font_prepare_cache
- font_finish_cache
- font_get_cache
- font_clear_cache
- font_is_ignored
- font_delete_unmatched
- font_list_entities
- font_matching_entity
- font_open_entity
- font_close_object
- font_has_char
- font_encode_char
- font_get_name
- font_spec_from_name
- font_clear_prop
- font_select_entity
- font_find_for_lface
- font_open_for_lface
- font_load_for_lface
- font_prepare_for_face
- font_done_for_face
- font_open_by_spec
- font_open_by_name
- register_font_driver
- free_font_driver_list
- font_update_drivers
- fset_font_data
- font_put_frame_data
- font_get_frame_data
- font_filter_properties
- font_at
- codepoint_is_emoji_eligible
- font_range
- copy_font_spec
- merge_font_spec
- DEFUN
- clear_font_cache
- DEFUN
- font_fill_lglyph_metrics
- check_gstring
- check_otf_features
- otf_tag_symbol
- otf_open
- font_otf_capability
- generate_otf_features
- font_otf_DeviceTable
- font_otf_ValueRecord
- font_otf_Anchor
- DEFUN
- DEFUN
- build_style_table
- font_add_log
- font_deferred_log
- font_drop_xrender_surfaces
- syms_of_font
- init_font
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #include <config.h>
24 #include <float.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <c-ctype.h>
29
30 #include "lisp.h"
31 #include "character.h"
32 #include "buffer.h"
33 #include "frame.h"
34 #include "window.h"
35 #include "dispextern.h"
36 #include "charset.h"
37 #include "composite.h"
38 #include "fontset.h"
39 #include "font.h"
40 #include "termhooks.h"
41 #include "pdumper.h"
42
43 #ifdef HAVE_WINDOW_SYSTEM
44 #include TERM_HEADER
45 #endif
46
47 #define DEFAULT_ENCODING Qiso8859_1
48
49
50 static Lisp_Object font_style_table;
51
52
53
54
55 struct table_entry
56 {
57 int numeric;
58
59
60 const char *names[6];
61 };
62
63
64
65
66
67
68
69 static const struct table_entry weight_table[] =
70 {
71 { 0, { "thin" }},
72 { 40, { "ultra-light", "ultralight", "extra-light", "extralight" }},
73 { 50, { "light" }},
74 { 55, { "semi-light", "semilight", "demilight" }},
75 { 80, { "regular", "normal", "unspecified", "book" }},
76 { 100, { "medium" }},
77 { 180, { "semi-bold", "semibold", "demibold", "demi-bold", "demi" }},
78 { 200, { "bold" }},
79 { 205, { "extra-bold", "extrabold", "ultra-bold", "ultrabold" }},
80 { 210, { "black", "heavy" }},
81 { 250, { "ultra-heavy", "ultraheavy" }}
82 };
83
84
85
86
87 static const struct table_entry slant_table[] =
88 {
89 { 0, { "reverse-oblique", "ro" }},
90 { 10, { "reverse-italic", "ri" }},
91 { 100, { "normal", "r", "unspecified" }},
92 { 200, { "italic" ,"i", "ot" }},
93 { 210, { "oblique", "o" }}
94 };
95
96
97
98
99 static const struct table_entry width_table[] =
100 {
101 { 50, { "ultra-condensed", "ultracondensed" }},
102 { 63, { "extra-condensed", "extracondensed" }},
103 { 75, { "condensed", "compressed", "narrow" }},
104 { 87, { "semi-condensed", "semicondensed", "demicondensed" }},
105 { 100, { "normal", "medium", "regular", "unspecified" }},
106 { 113, { "semi-expanded", "semiexpanded", "demiexpanded" }},
107 { 125, { "expanded" }},
108 { 150, { "extra-expanded", "extraexpanded" }},
109 { 200, { "ultra-expanded", "ultraexpanded", "wide" }}
110 };
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 static Lisp_Object font_charset_alist;
129
130
131
132
133 static struct font_driver_list *font_driver_list;
134
135 #ifdef ENABLE_CHECKING
136
137
138
139 bool
140 valid_font_driver (struct font_driver const *drv)
141 {
142 Lisp_Object tail, frame;
143 struct font_driver_list *fdl;
144
145 for (fdl = font_driver_list; fdl; fdl = fdl->next)
146 if (fdl->driver == drv)
147 return true;
148 FOR_EACH_FRAME (tail, frame)
149 for (fdl = XFRAME (frame)->font_driver_list; fdl; fdl = fdl->next)
150 if (fdl->driver == drv)
151 return true;
152 return false;
153 }
154
155 #endif
156
157
158
159 static Lisp_Object
160 font_make_spec (void)
161 {
162 Lisp_Object font_spec;
163 struct font_spec *spec
164 = ((struct font_spec *)
165 allocate_pseudovector (VECSIZE (struct font_spec),
166 FONT_SPEC_MAX, FONT_SPEC_MAX, PVEC_FONT));
167 XSETFONT (font_spec, spec);
168 return font_spec;
169 }
170
171 Lisp_Object
172 font_make_entity (void)
173 {
174 Lisp_Object font_entity;
175 struct font_entity *entity
176 = ((struct font_entity *)
177 allocate_pseudovector (VECSIZE (struct font_entity),
178 FONT_ENTITY_MAX, FONT_ENTITY_MAX, PVEC_FONT));
179 XSETFONT (font_entity, entity);
180 return font_entity;
181 }
182
183
184
185
186 Lisp_Object
187 font_make_object (int size, Lisp_Object entity, int pixelsize)
188 {
189 Lisp_Object font_object;
190 struct font *font
191 = (struct font *) allocate_pseudovector (size, FONT_OBJECT_MAX,
192 FONT_OBJECT_MAX, PVEC_FONT);
193 int i;
194
195
196 eassert (font->max_width = 1024 * 1024 * 1024);
197
198
199
200 font->driver = NULL;
201 XSETFONT (font_object, font);
202
203 if (! NILP (entity))
204 {
205 for (i = 1; i < FONT_SPEC_MAX; i++)
206 font->props[i] = AREF (entity, i);
207 if (! NILP (AREF (entity, FONT_EXTRA_INDEX)))
208 font->props[FONT_EXTRA_INDEX]
209 = Fcopy_alist (AREF (entity, FONT_EXTRA_INDEX));
210 }
211 if (size > 0)
212 font->props[FONT_SIZE_INDEX] = make_fixnum (pixelsize);
213 return font_object;
214 }
215
216 #if defined (HAVE_XFT) || defined (HAVE_FREETYPE) || defined (HAVE_NS)
217
218 static int font_unparse_fcname (Lisp_Object, int, char *, int);
219
220
221
222
223 Lisp_Object
224 font_build_object (int vectorsize, Lisp_Object type,
225 Lisp_Object entity, double pixelsize)
226 {
227 int len;
228 char name[256];
229 Lisp_Object font_object = font_make_object (vectorsize, entity, pixelsize);
230
231 ASET (font_object, FONT_TYPE_INDEX, type);
232 len = font_unparse_xlfd (entity, pixelsize, name, sizeof name);
233 if (len > 0)
234 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
235 len = font_unparse_fcname (entity, pixelsize, name, sizeof name);
236 if (len > 0)
237 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
238 else
239 ASET (font_object, FONT_FULLNAME_INDEX,
240 AREF (font_object, FONT_NAME_INDEX));
241 return font_object;
242 }
243
244 #endif
245
246 static int font_pixel_size (struct frame *f, Lisp_Object);
247 static Lisp_Object font_open_entity (struct frame *, Lisp_Object, int);
248 static Lisp_Object font_matching_entity (struct frame *, Lisp_Object *,
249 Lisp_Object);
250 static unsigned font_encode_char (Lisp_Object, int);
251
252
253 static int num_font_drivers;
254
255
256
257
258
259
260
261 Lisp_Object
262 font_intern_prop (const char *str, ptrdiff_t len, bool force_symbol)
263 {
264 ptrdiff_t i, nbytes, nchars;
265 Lisp_Object tem, name, obarray;
266
267 if (len == 1 && *str == '*')
268 return Qnil;
269 if (!force_symbol && 0 < len && '0' <= *str && *str <= '9')
270 {
271 for (i = 1; i < len; i++)
272 if (! ('0' <= str[i] && str[i] <= '9'))
273 break;
274 if (i == len)
275 {
276 i = 0;
277 for (EMACS_INT n = 0;
278 (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; )
279 {
280 if (i == len)
281 return make_fixnum (n);
282 if (INT_MULTIPLY_WRAPV (n, 10, &n))
283 break;
284 }
285
286 xsignal1 (Qoverflow_error, make_string (str, len));
287 }
288 }
289
290
291 obarray = check_obarray (Vobarray);
292 parse_str_as_multibyte ((unsigned char *) str, len, &nchars, &nbytes);
293 tem = oblookup (obarray, str,
294 (len == nchars || len != nbytes) ? len : nchars, len);
295 if (SYMBOLP (tem))
296 return tem;
297 name = make_specified_string (str, nchars, len,
298 len != nchars && len == nbytes);
299 return intern_driver (name, obarray, tem);
300 }
301
302
303
304 static int
305 font_pixel_size (struct frame *f, Lisp_Object spec)
306 {
307 #ifdef HAVE_WINDOW_SYSTEM
308 Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
309 double point_size;
310 int dpi, pixel_size;
311 Lisp_Object val;
312
313 if (FIXNUMP (size))
314 return XFIXNUM (size);
315 if (NILP (size))
316 return 0;
317 if (FRAME_WINDOW_P (f))
318 {
319 eassert (FLOATP (size));
320 point_size = XFLOAT_DATA (size);
321 val = AREF (spec, FONT_DPI_INDEX);
322 if (FIXNUMP (val))
323 dpi = XFIXNUM (val);
324 else
325 dpi = FRAME_RES_Y (f);
326 pixel_size = POINT_TO_PIXEL (point_size, dpi);
327 return pixel_size;
328 }
329 #endif
330 return 1;
331 }
332
333
334
335
336
337
338
339
340
341 int
342 font_style_to_value (enum font_property_index prop, Lisp_Object val,
343 bool noerror)
344 {
345 Lisp_Object table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
346 int len;
347
348 CHECK_VECTOR (table);
349 len = ASIZE (table);
350
351 if (SYMBOLP (val))
352 {
353 int i, j;
354 char *s;
355 Lisp_Object elt;
356
357
358 for (i = 0; i < len; i++)
359 {
360 CHECK_VECTOR (AREF (table, i));
361 for (j = 1; j < ASIZE (AREF (table, i)); j++)
362 if (EQ (val, AREF (AREF (table, i), j)))
363 {
364 CHECK_FIXNUM (AREF (AREF (table, i), 0));
365 return ((XFIXNUM (AREF (AREF (table, i), 0)) << 8)
366 | (i << 4) | (j - 1));
367 }
368 }
369
370 s = SSDATA (SYMBOL_NAME (val));
371 for (i = 0; i < len; i++)
372 for (j = 1; j < ASIZE (AREF (table, i)); j++)
373 {
374 elt = AREF (AREF (table, i), j);
375 if (xstrcasecmp (s, SSDATA (SYMBOL_NAME (elt))) == 0)
376 {
377 CHECK_FIXNUM (AREF (AREF (table, i), 0));
378 return ((XFIXNUM (AREF (AREF (table, i), 0)) << 8)
379 | (i << 4) | (j - 1));
380 }
381 }
382 if (! noerror)
383 return -1;
384 eassert (len < 255);
385 elt = make_vector (2, make_fixnum (100));
386 ASET (elt, 1, val);
387 ASET (font_style_table, prop - FONT_WEIGHT_INDEX,
388 CALLN (Fvconcat, table, make_vector (1, elt)));
389 return (100 << 8) | (i << 4);
390 }
391 else
392 {
393 int i, last_n;
394 EMACS_INT numeric = XFIXNUM (val);
395
396 for (i = 0, last_n = -1; i < len; i++)
397 {
398 int n;
399
400 CHECK_VECTOR (AREF (table, i));
401 CHECK_FIXNUM (AREF (AREF (table, i), 0));
402 n = XFIXNUM (AREF (AREF (table, i), 0));
403 if (numeric == n)
404 return (n << 8) | (i << 4);
405 if (numeric < n)
406 {
407 if (! noerror)
408 return -1;
409 return ((i == 0 || n - numeric < numeric - last_n)
410 ? (n << 8) | (i << 4): (last_n << 8 | ((i - 1) << 4)));
411 }
412 last_n = n;
413 }
414 if (! noerror)
415 return -1;
416 return ((last_n << 8) | ((i - 1) << 4));
417 }
418 }
419
420 Lisp_Object
421 font_style_symbolic (Lisp_Object font, enum font_property_index prop,
422 bool for_face)
423 {
424 Lisp_Object val = AREF (font, prop);
425 Lisp_Object table, elt;
426 int i;
427
428 if (NILP (val))
429 return Qnil;
430 table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
431 CHECK_VECTOR (table);
432 i = XFIXNUM (val) & 0xFF;
433 eassert (((i >> 4) & 0xF) < ASIZE (table));
434 elt = AREF (table, ((i >> 4) & 0xF));
435 CHECK_VECTOR (elt);
436 eassert ((i & 0xF) + 1 < ASIZE (elt));
437 elt = (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));
438 CHECK_SYMBOL (elt);
439 return elt;
440 }
441
442
443
444
445
446 Lisp_Object
447 find_font_encoding (Lisp_Object fontname)
448 {
449 Lisp_Object tail, elt;
450
451 for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
452 {
453 elt = XCAR (tail);
454 if (CONSP (elt)
455 && STRINGP (XCAR (elt))
456 && fast_string_match_ignore_case (XCAR (elt), fontname) >= 0
457 && (SYMBOLP (XCDR (elt))
458 ? CHARSETP (XCDR (elt))
459 : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
460 return (XCDR (elt));
461 }
462 return Qnil;
463 }
464
465
466
467
468
469 int
470 font_registry_charsets (Lisp_Object registry, struct charset **encoding, struct charset **repertory)
471 {
472 Lisp_Object val;
473 int encoding_id, repertory_id;
474
475 val = Fassoc_string (registry, font_charset_alist, Qt);
476 if (! NILP (val))
477 {
478 val = XCDR (val);
479 if (NILP (val))
480 return -1;
481 encoding_id = XFIXNUM (XCAR (val));
482 repertory_id = XFIXNUM (XCDR (val));
483 }
484 else
485 {
486 val = find_font_encoding (SYMBOL_NAME (registry));
487 if (SYMBOLP (val) && CHARSETP (val))
488 {
489 encoding_id = repertory_id = XFIXNUM (CHARSET_SYMBOL_ID (val));
490 }
491 else if (CONSP (val))
492 {
493 if (! CHARSETP (XCAR (val)))
494 goto invalid_entry;
495 encoding_id = XFIXNUM (CHARSET_SYMBOL_ID (XCAR (val)));
496 if (NILP (XCDR (val)))
497 repertory_id = -1;
498 else
499 {
500 if (! CHARSETP (XCDR (val)))
501 goto invalid_entry;
502 repertory_id = XFIXNUM (CHARSET_SYMBOL_ID (XCDR (val)));
503 }
504 }
505 else
506 goto invalid_entry;
507 val = Fcons (make_fixnum (encoding_id), make_fixnum (repertory_id));
508 font_charset_alist
509 = nconc2 (font_charset_alist, list1 (Fcons (registry, val)));
510 }
511
512 if (encoding)
513 *encoding = CHARSET_FROM_ID (encoding_id);
514 if (repertory)
515 *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
516 return 0;
517
518 invalid_entry:
519 font_charset_alist
520 = nconc2 (font_charset_alist, list1 (Fcons (registry, Qnil)));
521 return -1;
522 }
523
524
525
526
527
528 static Lisp_Object font_prop_validate (int, Lisp_Object, Lisp_Object);
529 static Lisp_Object font_prop_validate_symbol (Lisp_Object, Lisp_Object);
530 static Lisp_Object font_prop_validate_style (Lisp_Object, Lisp_Object);
531 static Lisp_Object font_prop_validate_non_neg (Lisp_Object, Lisp_Object);
532 static Lisp_Object font_prop_validate_spacing (Lisp_Object, Lisp_Object);
533 static int get_font_prop_index (Lisp_Object);
534
535 static Lisp_Object
536 font_prop_validate_symbol (Lisp_Object prop, Lisp_Object val)
537 {
538 if (STRINGP (val))
539 val = Fintern (val, Qnil);
540 if (! SYMBOLP (val))
541 val = Qerror;
542 else if (EQ (prop, QCregistry))
543 val = Fintern (Fdowncase (SYMBOL_NAME (val)), Qnil);
544 return val;
545 }
546
547
548 static Lisp_Object
549 font_prop_validate_style (Lisp_Object style, Lisp_Object val)
550 {
551 enum font_property_index prop = (EQ (style, QCweight) ? FONT_WEIGHT_INDEX
552 : EQ (style, QCslant) ? FONT_SLANT_INDEX
553 : FONT_WIDTH_INDEX);
554 if (FIXNUMP (val))
555 {
556 EMACS_INT n = XFIXNUM (val);
557 CHECK_VECTOR (AREF (font_style_table, prop - FONT_WEIGHT_INDEX));
558 if (((n >> 4) & 0xF)
559 >= ASIZE (AREF (font_style_table, prop - FONT_WEIGHT_INDEX)))
560 val = Qerror;
561 else
562 {
563 Lisp_Object elt = AREF (AREF (font_style_table, prop - FONT_WEIGHT_INDEX), (n >> 4) & 0xF);
564
565 CHECK_VECTOR (elt);
566 if ((n & 0xF) + 1 >= ASIZE (elt))
567 val = Qerror;
568 else
569 {
570 CHECK_FIXNUM (AREF (elt, 0));
571 if (XFIXNUM (AREF (elt, 0)) != (n >> 8))
572 val = Qerror;
573 }
574 }
575 }
576 else if (SYMBOLP (val))
577 {
578 int n = font_style_to_value (prop, val, 0);
579
580 val = n >= 0 ? make_fixnum (n) : Qerror;
581 }
582 else
583 val = Qerror;
584 return val;
585 }
586
587 static Lisp_Object
588 font_prop_validate_non_neg (Lisp_Object prop, Lisp_Object val)
589 {
590 return (FIXNATP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0)
591 ? val : Qerror);
592 }
593
594 static Lisp_Object
595 font_prop_validate_spacing (Lisp_Object prop, Lisp_Object val)
596 {
597 if (NILP (val) || (FIXNATP (val) && XFIXNUM (val) <= FONT_SPACING_CHARCELL))
598 return val;
599 if (SYMBOLP (val) && SBYTES (SYMBOL_NAME (val)) == 1)
600 {
601 char spacing = SDATA (SYMBOL_NAME (val))[0];
602
603 if (spacing == 'c' || spacing == 'C')
604 return make_fixnum (FONT_SPACING_CHARCELL);
605 if (spacing == 'm' || spacing == 'M')
606 return make_fixnum (FONT_SPACING_MONO);
607 if (spacing == 'p' || spacing == 'P')
608 return make_fixnum (FONT_SPACING_PROPORTIONAL);
609 if (spacing == 'd' || spacing == 'D')
610 return make_fixnum (FONT_SPACING_DUAL);
611 }
612 return Qerror;
613 }
614
615 static Lisp_Object
616 font_prop_validate_otf (Lisp_Object prop, Lisp_Object val)
617 {
618 Lisp_Object tail, tmp;
619 int i;
620
621
622
623
624 if (! CONSP (val))
625 return Qerror;
626 if (! SYMBOLP (XCAR (val)))
627 return Qerror;
628 tail = XCDR (val);
629 if (NILP (tail))
630 return val;
631 if (! CONSP (tail) || ! SYMBOLP (XCAR (val)))
632 return Qerror;
633 for (i = 0; i < 2; i++)
634 {
635 tail = XCDR (tail);
636 if (NILP (tail))
637 return val;
638 if (! CONSP (tail))
639 return Qerror;
640 for (tmp = XCAR (tail); CONSP (tmp); tmp = XCDR (tmp))
641 if (! SYMBOLP (XCAR (tmp)))
642 return Qerror;
643 if (! NILP (tmp))
644 return Qerror;
645 }
646 return val;
647 }
648
649
650
651 static const struct
652 {
653
654 int key;
655
656
657
658 Lisp_Object (*validator) (Lisp_Object prop, Lisp_Object val);
659 } font_property_table[] =
660 { { SYMBOL_INDEX (QCtype), font_prop_validate_symbol },
661 { SYMBOL_INDEX (QCfoundry), font_prop_validate_symbol },
662 { SYMBOL_INDEX (QCfamily), font_prop_validate_symbol },
663 { SYMBOL_INDEX (QCadstyle), font_prop_validate_symbol },
664 { SYMBOL_INDEX (QCregistry), font_prop_validate_symbol },
665 { SYMBOL_INDEX (QCweight), font_prop_validate_style },
666 { SYMBOL_INDEX (QCslant), font_prop_validate_style },
667 { SYMBOL_INDEX (QCwidth), font_prop_validate_style },
668 { SYMBOL_INDEX (QCsize), font_prop_validate_non_neg },
669 { SYMBOL_INDEX (QCdpi), font_prop_validate_non_neg },
670 { SYMBOL_INDEX (QCspacing), font_prop_validate_spacing },
671 { SYMBOL_INDEX (QCavgwidth), font_prop_validate_non_neg },
672
673
674 { SYMBOL_INDEX (QClang), font_prop_validate_symbol },
675 { SYMBOL_INDEX (QCscript), font_prop_validate_symbol },
676 { SYMBOL_INDEX (QCotf), font_prop_validate_otf }
677 };
678
679
680
681
682 static int
683 get_font_prop_index (Lisp_Object key)
684 {
685 int i;
686
687 for (i = 0; i < ARRAYELTS (font_property_table); i++)
688 if (EQ (key, builtin_lisp_symbol (font_property_table[i].key)))
689 return i;
690 return -1;
691 }
692
693
694
695
696
697 static Lisp_Object
698 font_prop_validate (int idx, Lisp_Object prop, Lisp_Object val)
699 {
700 Lisp_Object validated;
701
702 if (NILP (val))
703 return val;
704 if (NILP (prop))
705 prop = builtin_lisp_symbol (font_property_table[idx].key);
706 else
707 {
708 idx = get_font_prop_index (prop);
709 if (idx < 0)
710 return val;
711 }
712 validated = (font_property_table[idx].validator) (prop, val);
713 if (EQ (validated, Qerror))
714 signal_error ("invalid font property", Fcons (prop, val));
715 return validated;
716 }
717
718
719
720
721
722
723
724 Lisp_Object
725 font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
726 {
727 Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
728 Lisp_Object slot = (NILP (extra) ? Qnil : assq_no_quit (prop, extra));
729
730 if (NILP (slot))
731 {
732 Lisp_Object prev = Qnil;
733
734 if (BASE_EQ (val, Qunbound))
735 return val;
736 while (CONSP (extra)
737 && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
738 prev = extra, extra = XCDR (extra);
739
740 if (NILP (prev))
741 ASET (font, FONT_EXTRA_INDEX, Fcons (Fcons (prop, val), extra));
742 else
743 XSETCDR (prev, Fcons (Fcons (prop, val), extra));
744
745 return val;
746 }
747 XSETCDR (slot, val);
748 if (BASE_EQ (val, Qunbound))
749 ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
750 return val;
751 }
752
753
754
755
756 static int parse_matrix (const char *);
757 static int font_expand_wildcards (Lisp_Object *, int);
758 static int font_parse_name (char *, ptrdiff_t, Lisp_Object);
759
760
761 enum xlfd_field_index
762 {
763 XLFD_FOUNDRY_INDEX,
764 XLFD_FAMILY_INDEX,
765 XLFD_WEIGHT_INDEX,
766 XLFD_SLANT_INDEX,
767 XLFD_SWIDTH_INDEX,
768 XLFD_ADSTYLE_INDEX,
769 XLFD_PIXEL_INDEX,
770 XLFD_POINT_INDEX,
771 XLFD_RESX_INDEX,
772 XLFD_RESY_INDEX,
773 XLFD_SPACING_INDEX,
774 XLFD_AVGWIDTH_INDEX,
775 XLFD_REGISTRY_INDEX,
776 XLFD_ENCODING_INDEX,
777 XLFD_LAST_INDEX
778 };
779
780
781 enum xlfd_field_mask
782 {
783 XLFD_FOUNDRY_MASK = 0x0001,
784 XLFD_FAMILY_MASK = 0x0002,
785 XLFD_WEIGHT_MASK = 0x0004,
786 XLFD_SLANT_MASK = 0x0008,
787 XLFD_SWIDTH_MASK = 0x0010,
788 XLFD_ADSTYLE_MASK = 0x0020,
789 XLFD_PIXEL_MASK = 0x0040,
790 XLFD_POINT_MASK = 0x0080,
791 XLFD_RESX_MASK = 0x0100,
792 XLFD_RESY_MASK = 0x0200,
793 XLFD_SPACING_MASK = 0x0400,
794 XLFD_AVGWIDTH_MASK = 0x0800,
795 XLFD_REGISTRY_MASK = 0x1000,
796 XLFD_ENCODING_MASK = 0x2000
797 };
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814 static int
815 parse_matrix (const char *p)
816 {
817 double matrix[4];
818 char *end;
819 int i;
820
821 for (i = 0, p++; i < 4 && *p && *p != ']'; i++)
822 {
823 if (*p == '~')
824 matrix[i] = - strtod (p + 1, &end);
825 else
826 matrix[i] = strtod (p, &end);
827 p = end;
828 }
829 return (i == 4 ? (int) matrix[3] : -1);
830 }
831
832
833
834
835
836 static int
837 font_expand_wildcards (Lisp_Object *field, int n)
838 {
839
840 Lisp_Object tmp[XLFD_LAST_INDEX];
841
842
843 struct {
844
845 int from;
846
847 int to;
848
849 int mask;
850 } range[XLFD_LAST_INDEX];
851 int i, j;
852 int range_from, range_to;
853 unsigned range_mask;
854
855 #define XLFD_SYMBOL_MASK (XLFD_FOUNDRY_MASK | XLFD_FAMILY_MASK \
856 | XLFD_ADSTYLE_MASK | XLFD_REGISTRY_MASK)
857 #define XLFD_NULL_MASK (XLFD_FOUNDRY_MASK | XLFD_ADSTYLE_MASK)
858 #define XLFD_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \
859 | XLFD_AVGWIDTH_MASK)
860 #define XLFD_REGENC_MASK (XLFD_REGISTRY_MASK | XLFD_ENCODING_MASK)
861
862
863
864
865 for (i = 0, range_mask = 0; i <= 14 - n; i++)
866 range_mask = (range_mask << 1) | 1;
867
868
869
870 for (i = 0, range_from = 0, range_to = 14 - n; i < n;
871 i++, range_from++, range_to++, range_mask <<= 1)
872 {
873 Lisp_Object val = field[i];
874
875 tmp[i] = val;
876 if (NILP (val))
877 {
878
879 range[i].from = range_from;
880 range[i].to = range_to;
881 range[i].mask = range_mask;
882 }
883 else
884 {
885
886
887 int from, to;
888 unsigned mask;
889
890 if (FIXNUMP (val))
891 {
892 EMACS_INT numeric = XFIXNUM (val);
893
894 if (i + 1 == n)
895 from = to = XLFD_ENCODING_INDEX,
896 mask = XLFD_ENCODING_MASK;
897 else if (numeric == 0)
898 from = XLFD_PIXEL_INDEX, to = XLFD_AVGWIDTH_INDEX,
899 mask = XLFD_PIXEL_MASK | XLFD_LARGENUM_MASK;
900 else if (numeric <= 48)
901 from = to = XLFD_PIXEL_INDEX,
902 mask = XLFD_PIXEL_MASK;
903 else
904 from = XLFD_POINT_INDEX, to = XLFD_AVGWIDTH_INDEX,
905 mask = XLFD_LARGENUM_MASK;
906 }
907 else if (SBYTES (SYMBOL_NAME (val)) == 0)
908 from = XLFD_FOUNDRY_INDEX, to = XLFD_ADSTYLE_INDEX,
909 mask = XLFD_NULL_MASK;
910 else if (i == 0)
911 from = to = XLFD_FOUNDRY_INDEX, mask = XLFD_FOUNDRY_MASK;
912 else if (i + 1 == n)
913 {
914 Lisp_Object name = SYMBOL_NAME (val);
915
916 if (SDATA (name)[SBYTES (name) - 1] == '*')
917 from = XLFD_REGISTRY_INDEX, to = XLFD_ENCODING_INDEX,
918 mask = XLFD_REGENC_MASK;
919 else
920 from = to = XLFD_ENCODING_INDEX,
921 mask = XLFD_ENCODING_MASK;
922 }
923 else if (range_from <= XLFD_WEIGHT_INDEX
924 && range_to >= XLFD_WEIGHT_INDEX
925 && FONT_WEIGHT_NAME_NUMERIC (val) >= 0)
926 from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK;
927 else if (range_from <= XLFD_SLANT_INDEX
928 && range_to >= XLFD_SLANT_INDEX
929 && FONT_SLANT_NAME_NUMERIC (val) >= 0)
930 from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK;
931 else if (range_from <= XLFD_SWIDTH_INDEX
932 && range_to >= XLFD_SWIDTH_INDEX
933 && FONT_WIDTH_NAME_NUMERIC (val) >= 0)
934 from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK;
935 else
936 {
937 if (EQ (val, Qc) || EQ (val, Qm) || EQ (val, Qp) || EQ (val, Qd))
938 from = to = XLFD_SPACING_INDEX, mask = XLFD_SPACING_MASK;
939 else
940 from = XLFD_FOUNDRY_INDEX, to = XLFD_ENCODING_INDEX,
941 mask = XLFD_SYMBOL_MASK;
942 }
943
944
945 mask &= range_mask;
946 while (from < range_from)
947 mask &= ~(1 << from++);
948 while (from < 14 && ! (mask & (1 << from)))
949 from++;
950 while (to > range_to)
951 mask &= ~(1 << to--);
952 while (to >= 0 && ! (mask & (1 << to)))
953 to--;
954 if (from > to)
955 return -1;
956 range[i].from = from;
957 range[i].to = to;
958 range[i].mask = mask;
959
960 if (from > range_from || to < range_to)
961 {
962
963
964
965
966 range_from = from;
967
968 for (j = i - 1, from--, to--; j >= 0; j--, from--, to--)
969 {
970
971 if (! NILP (tmp[j]) && range[j].from < from)
972 {
973 while (range[j].from < from)
974 range[j].mask &= ~(1 << range[j].from++);
975 while (from < 14 && ! (range[j].mask & (1 << from)))
976 from++;
977 range[j].from = from;
978 }
979 else
980 from = range[j].from;
981 if (range[j].to > to)
982 {
983 while (range[j].to > to)
984 range[j].mask &= ~(1 << range[j].to--);
985 while (to >= 0 && ! (range[j].mask & (1 << to)))
986 to--;
987 range[j].to = to;
988 }
989 else
990 to = range[j].to;
991 if (from > to)
992 return -1;
993 }
994 }
995 }
996 }
997
998
999 for (i = j = 0; i < n ; i++)
1000 {
1001 if (j < range[i].from)
1002 {
1003 if (i == 0 || ! NILP (tmp[i - 1]))
1004
1005 return -1;
1006 memclear (field + j, (range[i].from - j) * word_size);
1007 j = range[i].from;
1008 }
1009 field[j++] = tmp[i];
1010 }
1011 if (! NILP (tmp[n - 1]) && j < XLFD_REGISTRY_INDEX)
1012 return -1;
1013 memclear (field + j, (XLFD_LAST_INDEX - j) * word_size);
1014 if (FIXNUMP (field[XLFD_ENCODING_INDEX]))
1015 field[XLFD_ENCODING_INDEX]
1016 = Fintern (Fnumber_to_string (field[XLFD_ENCODING_INDEX]), Qnil);
1017 return 0;
1018 }
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 static int
1037 font_parse_xlfd_1 (char *name, ptrdiff_t len, Lisp_Object font, int segments)
1038 {
1039 int i, j, n;
1040 char *f[XLFD_LAST_INDEX + 1];
1041 Lisp_Object val;
1042 char *p;
1043
1044 if (len > 255 || !len)
1045
1046 return -1;
1047
1048
1049 if (name[0] == '*' && (len == 1 || name[1] == '-'))
1050 i = 1, f[XLFD_FOUNDRY_INDEX] = name;
1051 else
1052 i = 0;
1053
1054
1055 for (p = name + i; *p; p++)
1056 if (*p == '-')
1057 {
1058
1059
1060
1061 if (segments > XLFD_LAST_INDEX && i == XLFD_WEIGHT_INDEX)
1062 segments--;
1063 else {
1064 f[i++] = p + 1;
1065 if (i == XLFD_LAST_INDEX)
1066 break;
1067 }
1068 }
1069 f[i] = name + len;
1070
1071 #define INTERN_FIELD(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 0)
1072 #define INTERN_FIELD_SYM(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N], 1)
1073
1074 if (i == XLFD_LAST_INDEX)
1075 {
1076
1077 int pixel_size;
1078
1079 ASET (font, FONT_FOUNDRY_INDEX, INTERN_FIELD_SYM (XLFD_FOUNDRY_INDEX));
1080 ASET (font, FONT_FAMILY_INDEX, INTERN_FIELD_SYM (XLFD_FAMILY_INDEX));
1081 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1082 i <= XLFD_SWIDTH_INDEX; i++, j++)
1083 {
1084 val = INTERN_FIELD_SYM (i);
1085 if (! NILP (val))
1086 {
1087 if ((n = font_style_to_value (j, INTERN_FIELD_SYM (i), 0)) < 0)
1088 return -1;
1089 ASET (font, j, make_fixnum (n));
1090 }
1091 }
1092 ASET (font, FONT_ADSTYLE_INDEX, INTERN_FIELD_SYM (XLFD_ADSTYLE_INDEX));
1093 if (strcmp (f[XLFD_REGISTRY_INDEX], "*-*") == 0)
1094 ASET (font, FONT_REGISTRY_INDEX, Qnil);
1095 else
1096 ASET (font, FONT_REGISTRY_INDEX,
1097 font_intern_prop (f[XLFD_REGISTRY_INDEX],
1098 f[XLFD_LAST_INDEX] - f[XLFD_REGISTRY_INDEX],
1099 1));
1100 p = f[XLFD_PIXEL_INDEX];
1101 if (*p == '[' && (pixel_size = parse_matrix (p)) >= 0)
1102 ASET (font, FONT_SIZE_INDEX, make_fixnum (pixel_size));
1103 else
1104 {
1105 val = INTERN_FIELD (XLFD_PIXEL_INDEX);
1106 if (FIXNUMP (val))
1107 ASET (font, FONT_SIZE_INDEX, val);
1108 else if (FONT_ENTITY_P (font))
1109 return -1;
1110 else
1111 {
1112 double point_size = -1;
1113
1114 eassert (FONT_SPEC_P (font));
1115 p = f[XLFD_POINT_INDEX];
1116 if (*p == '[')
1117 point_size = parse_matrix (p);
1118 else if (c_isdigit (*p))
1119 point_size = atoi (p), point_size /= 10;
1120 if (point_size >= 0)
1121 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1122 }
1123 }
1124
1125 val = INTERN_FIELD (XLFD_RESY_INDEX);
1126 if (! NILP (val) && ! FIXNUMP (val))
1127 return -1;
1128 ASET (font, FONT_DPI_INDEX, val);
1129 val = INTERN_FIELD (XLFD_SPACING_INDEX);
1130 if (! NILP (val))
1131 {
1132 val = font_prop_validate_spacing (QCspacing, val);
1133 if (! FIXNUMP (val))
1134 return -1;
1135 ASET (font, FONT_SPACING_INDEX, val);
1136 }
1137 p = f[XLFD_AVGWIDTH_INDEX];
1138 if (*p == '~')
1139 p++;
1140 val = font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p, 0);
1141 if (! NILP (val) && ! FIXNUMP (val))
1142 return -1;
1143 ASET (font, FONT_AVGWIDTH_INDEX, val);
1144 }
1145 else
1146 {
1147 bool wild_card_found = 0;
1148 Lisp_Object prop[XLFD_LAST_INDEX];
1149
1150 if (FONT_ENTITY_P (font))
1151 return -1;
1152 for (j = 0; j < i; j++)
1153 {
1154 if (*f[j] == '*')
1155 {
1156 if (f[j][1] && f[j][1] != '-')
1157 return -1;
1158 prop[j] = Qnil;
1159 wild_card_found = 1;
1160 }
1161 else if (j + 1 < i)
1162 prop[j] = INTERN_FIELD (j);
1163 else
1164 prop[j] = font_intern_prop (f[j], f[i] - f[j], 0);
1165 }
1166 if (! wild_card_found)
1167 return -1;
1168 if (font_expand_wildcards (prop, i) < 0)
1169 return -1;
1170
1171 ASET (font, FONT_FOUNDRY_INDEX, prop[XLFD_FOUNDRY_INDEX]);
1172 ASET (font, FONT_FAMILY_INDEX, prop[XLFD_FAMILY_INDEX]);
1173 for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
1174 i <= XLFD_SWIDTH_INDEX; i++, j++)
1175 if (! NILP (prop[i]))
1176 {
1177 if ((n = font_style_to_value (j, prop[i], 1)) < 0)
1178 return -1;
1179 ASET (font, j, make_fixnum (n));
1180 }
1181 ASET (font, FONT_ADSTYLE_INDEX, prop[XLFD_ADSTYLE_INDEX]);
1182 val = prop[XLFD_REGISTRY_INDEX];
1183 if (NILP (val))
1184 {
1185 val = prop[XLFD_ENCODING_INDEX];
1186 if (! NILP (val))
1187 {
1188 AUTO_STRING (star_dash, "*-");
1189 val = concat2 (star_dash, SYMBOL_NAME (val));
1190 }
1191 }
1192 else if (NILP (prop[XLFD_ENCODING_INDEX]))
1193 {
1194 AUTO_STRING (dash_star, "-*");
1195 val = concat2 (SYMBOL_NAME (val), dash_star);
1196 }
1197 else
1198 {
1199 AUTO_STRING (dash, "-");
1200 val = concat3 (SYMBOL_NAME (val), dash,
1201 SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
1202 }
1203 if (! NILP (val))
1204 ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
1205
1206 if (FIXNUMP (prop[XLFD_PIXEL_INDEX]))
1207 ASET (font, FONT_SIZE_INDEX, prop[XLFD_PIXEL_INDEX]);
1208 else if (FIXNUMP (prop[XLFD_POINT_INDEX]))
1209 {
1210 double point_size = XFIXNUM (prop[XLFD_POINT_INDEX]);
1211
1212 ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
1213 }
1214
1215 if (FIXNUMP (prop[XLFD_RESX_INDEX]))
1216 ASET (font, FONT_DPI_INDEX, prop[XLFD_RESY_INDEX]);
1217 if (! NILP (prop[XLFD_SPACING_INDEX]))
1218 {
1219 val = font_prop_validate_spacing (QCspacing,
1220 prop[XLFD_SPACING_INDEX]);
1221 if (! FIXNUMP (val))
1222 return -1;
1223 ASET (font, FONT_SPACING_INDEX, val);
1224 }
1225 if (FIXNUMP (prop[XLFD_AVGWIDTH_INDEX]))
1226 ASET (font, FONT_AVGWIDTH_INDEX, prop[XLFD_AVGWIDTH_INDEX]);
1227 }
1228
1229 return 0;
1230 }
1231
1232 int
1233 font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
1234 {
1235 int found = font_parse_xlfd_1 (name, len, font, -1);
1236 if (found > -1)
1237 return found;
1238
1239 int segments = 0;
1240
1241 for (char *p = name; *p; p++)
1242 if (*p == '-')
1243 segments++;
1244
1245
1246
1247 if (segments > XLFD_LAST_INDEX)
1248 return font_parse_xlfd_1 (name, len, font, segments);
1249 else
1250 return -1;
1251 }
1252
1253
1254
1255
1256
1257
1258 ptrdiff_t
1259 font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
1260 {
1261 char *p;
1262 const char *f[XLFD_REGISTRY_INDEX + 1];
1263 Lisp_Object val;
1264 int i, j, len;
1265
1266 eassert (FONTP (font));
1267
1268 for (i = FONT_FOUNDRY_INDEX, j = XLFD_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX;
1269 i++, j++)
1270 {
1271 if (i == FONT_ADSTYLE_INDEX)
1272 j = XLFD_ADSTYLE_INDEX;
1273 else if (i == FONT_REGISTRY_INDEX)
1274 j = XLFD_REGISTRY_INDEX;
1275 val = AREF (font, i);
1276 if (NILP (val))
1277 {
1278 if (j == XLFD_REGISTRY_INDEX)
1279 f[j] = "*-*";
1280 else
1281 f[j] = "*";
1282 }
1283 else
1284 {
1285 if (SYMBOLP (val))
1286 val = SYMBOL_NAME (val);
1287 if (j == XLFD_REGISTRY_INDEX
1288 && ! strchr (SSDATA (val), '-'))
1289 {
1290
1291 ptrdiff_t alloc = SBYTES (val) + 4;
1292 if (nbytes <= alloc)
1293 return -1;
1294 f[j] = p = alloca (alloc);
1295 sprintf (p, "%s%s-*", SDATA (val),
1296 &"*"[SDATA (val)[SBYTES (val) - 1] == '*']);
1297 }
1298 else
1299 f[j] = SSDATA (val);
1300 }
1301 }
1302
1303 for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX;
1304 i++, j++)
1305 {
1306 val = font_style_symbolic (font, i, 0);
1307 if (NILP (val))
1308 f[j] = "*";
1309 else
1310 {
1311 int c, k, l;
1312 ptrdiff_t alloc;
1313
1314 val = SYMBOL_NAME (val);
1315 alloc = SBYTES (val) + 1;
1316 if (nbytes <= alloc)
1317 return -1;
1318 f[j] = p = alloca (alloc);
1319
1320 for (k = l = 0; k < alloc; k++)
1321 {
1322 c = SREF (val, k);
1323 if (c != '-' && c != '?' && c != ',' && c != '"')
1324 p[l++] = c;
1325 }
1326 }
1327 }
1328
1329 val = AREF (font, FONT_SIZE_INDEX);
1330 eassert (NUMBERP (val) || NILP (val));
1331 char font_size_index_buf[sizeof "-*"
1332 + max (INT_STRLEN_BOUND (EMACS_INT),
1333 1 + DBL_MAX_10_EXP + 1)];
1334 if (INTEGERP (val))
1335 {
1336 intmax_t v;
1337 if (! (integer_to_intmax (val, &v) && 0 < v))
1338 v = pixel_size;
1339 if (v > 0)
1340 {
1341 f[XLFD_PIXEL_INDEX] = p = font_size_index_buf;
1342 sprintf (p, "%"PRIdMAX"-*", v);
1343 }
1344 else
1345 f[XLFD_PIXEL_INDEX] = "*-*";
1346 }
1347 else if (FLOATP (val))
1348 {
1349 double v = XFLOAT_DATA (val) * 10;
1350 f[XLFD_PIXEL_INDEX] = p = font_size_index_buf;
1351 sprintf (p, "*-%.0f", v);
1352 }
1353 else
1354 f[XLFD_PIXEL_INDEX] = "*-*";
1355
1356 char dpi_index_buf[sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT)];
1357 if (FIXNUMP (AREF (font, FONT_DPI_INDEX)))
1358 {
1359 EMACS_INT v = XFIXNUM (AREF (font, FONT_DPI_INDEX));
1360 f[XLFD_RESX_INDEX] = p = dpi_index_buf;
1361 sprintf (p, "%"pI"d-%"pI"d", v, v);
1362 }
1363 else
1364 f[XLFD_RESX_INDEX] = "*-*";
1365
1366 if (FIXNUMP (AREF (font, FONT_SPACING_INDEX)))
1367 {
1368 EMACS_INT spacing = XFIXNUM (AREF (font, FONT_SPACING_INDEX));
1369
1370 f[XLFD_SPACING_INDEX] = (spacing <= FONT_SPACING_PROPORTIONAL ? "p"
1371 : spacing <= FONT_SPACING_DUAL ? "d"
1372 : spacing <= FONT_SPACING_MONO ? "m"
1373 : "c");
1374 }
1375 else
1376 f[XLFD_SPACING_INDEX] = "*";
1377
1378 char avgwidth_index_buf[INT_BUFSIZE_BOUND (EMACS_INT)];
1379 if (FIXNUMP (AREF (font, FONT_AVGWIDTH_INDEX)))
1380 {
1381 f[XLFD_AVGWIDTH_INDEX] = p = avgwidth_index_buf;
1382 sprintf (p, "%"pI"d", XFIXNUM (AREF (font, FONT_AVGWIDTH_INDEX)));
1383 }
1384 else
1385 f[XLFD_AVGWIDTH_INDEX] = "*";
1386
1387 len = snprintf (name, nbytes, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
1388 f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
1389 f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
1390 f[XLFD_SWIDTH_INDEX], f[XLFD_ADSTYLE_INDEX],
1391 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
1392 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
1393 f[XLFD_REGISTRY_INDEX]);
1394 return len < nbytes ? len : -1;
1395 }
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412 static int
1413 font_parse_fcname (char *name, ptrdiff_t len, Lisp_Object font)
1414 {
1415 char *p, *q;
1416 char *size_beg = NULL, *size_end = NULL;
1417 char *props_beg = NULL, *family_end = NULL;
1418
1419 if (len == 0)
1420 return -1;
1421
1422 for (p = name; *p; p++)
1423 {
1424 if (*p == '\\' && p[1])
1425 p++;
1426 else if (*p == ':')
1427 {
1428 props_beg = family_end = p;
1429 break;
1430 }
1431 else if (*p == '-')
1432 {
1433 bool decimal = 0, size_found = 1;
1434 for (q = p + 1; *q && *q != ':'; q++)
1435 if (! c_isdigit (*q))
1436 {
1437 if (*q != '.' || decimal)
1438 {
1439 size_found = 0;
1440 break;
1441 }
1442 decimal = 1;
1443 }
1444 if (size_found)
1445 {
1446 family_end = p;
1447 size_beg = p + 1;
1448 size_end = q;
1449 break;
1450 }
1451 }
1452 }
1453
1454 if (family_end)
1455 {
1456 Lisp_Object extra_props = Qnil;
1457
1458
1459 if (family_end > name)
1460 {
1461 Lisp_Object family;
1462 family = font_intern_prop (name, family_end - name, 1);
1463 ASET (font, FONT_FAMILY_INDEX, family);
1464 }
1465 if (size_beg)
1466 {
1467 double point_size = strtod (size_beg, &size_end);
1468 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1469 if (*size_end == ':' && size_end[1])
1470 props_beg = size_end;
1471 }
1472 if (props_beg)
1473 {
1474
1475 Lisp_Object val;
1476
1477 for (p = props_beg; *p; p = q)
1478 {
1479 for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
1480 if (*q != '=')
1481 {
1482
1483 ptrdiff_t word_len;
1484 p = p + 1;
1485 word_len = q - p;
1486 val = font_intern_prop (p, q - p, 1);
1487
1488 #define PROP_MATCH(STR) (word_len == strlen (STR) \
1489 && memcmp (p, STR, strlen (STR)) == 0)
1490
1491 if (PROP_MATCH ("thin")
1492 || PROP_MATCH ("ultra-light")
1493 || PROP_MATCH ("light")
1494 || PROP_MATCH ("semi-light")
1495 || PROP_MATCH ("book")
1496 || PROP_MATCH ("medium")
1497 || PROP_MATCH ("normal")
1498 || PROP_MATCH ("semibold")
1499 || PROP_MATCH ("demibold")
1500 || PROP_MATCH ("bold")
1501 || PROP_MATCH ("ultra-bold")
1502 || PROP_MATCH ("black")
1503 || PROP_MATCH ("heavy")
1504 || PROP_MATCH ("ultra-heavy"))
1505 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
1506 else if (PROP_MATCH ("roman")
1507 || PROP_MATCH ("italic")
1508 || PROP_MATCH ("oblique"))
1509 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
1510 else if (PROP_MATCH ("charcell"))
1511 ASET (font, FONT_SPACING_INDEX,
1512 make_fixnum (FONT_SPACING_CHARCELL));
1513 else if (PROP_MATCH ("mono"))
1514 ASET (font, FONT_SPACING_INDEX,
1515 make_fixnum (FONT_SPACING_MONO));
1516 else if (PROP_MATCH ("proportional"))
1517 ASET (font, FONT_SPACING_INDEX,
1518 make_fixnum (FONT_SPACING_PROPORTIONAL));
1519 #undef PROP_MATCH
1520 }
1521 else
1522 {
1523
1524 Lisp_Object key UNINIT;
1525 int prop;
1526
1527 if (q - p == 10 && memcmp (p + 1, "pixelsize", 9) == 0)
1528 prop = FONT_SIZE_INDEX;
1529 else
1530 {
1531 key = font_intern_prop (p, q - p, 1);
1532 prop = get_font_prop_index (key);
1533 }
1534
1535 p = q + 1;
1536 for (q = p; *q && *q != ':'; q++);
1537 val = font_intern_prop (p, q - p, 0);
1538
1539 if (prop >= FONT_FOUNDRY_INDEX
1540 && prop < FONT_EXTRA_INDEX)
1541 ASET (font, prop, font_prop_validate (prop, Qnil, val));
1542 else
1543 {
1544 extra_props = nconc2 (extra_props,
1545 list1 (Fcons (key, val)));
1546 }
1547 }
1548 p = q;
1549 }
1550 }
1551
1552 if (! NILP (extra_props))
1553 {
1554 struct font_driver_list *driver_list = font_driver_list;
1555 for ( ; driver_list; driver_list = driver_list->next)
1556 if (driver_list->driver->filter_properties)
1557 (*driver_list->driver->filter_properties) (font, extra_props);
1558 }
1559
1560 }
1561 else
1562 {
1563
1564
1565 Lisp_Object weight = Qnil, slant = Qnil;
1566 Lisp_Object width = Qnil, size = Qnil;
1567 char *word_start;
1568 ptrdiff_t word_len;
1569
1570
1571 for (p = name + len - 1; p >= name; p--)
1572 if (!c_isdigit (*p))
1573 break;
1574
1575 if ((p < name + len - 1) && ((p + 1 == name) || *p == ' '))
1576
1577 size = make_float (strtod (p + 1, NULL));
1578 else
1579 p = name + len;
1580
1581
1582
1583 for (; p > name; p = q)
1584 {
1585 for (q = p - 1; q >= name; q--)
1586 {
1587 if (q > name && *(q-1) == '\\')
1588 --q;
1589 else if (*q == ' ')
1590 break;
1591 }
1592
1593 word_start = q + 1;
1594 word_len = p - word_start;
1595
1596 #define PROP_MATCH(STR) \
1597 (word_len == strlen (STR) \
1598 && memcmp (word_start, STR, strlen (STR)) == 0)
1599 #define PROP_SAVE(VAR, STR) \
1600 (VAR = NILP (VAR) ? font_intern_prop (STR, strlen (STR), 1) : VAR)
1601
1602 if (PROP_MATCH ("Ultra-Light"))
1603 PROP_SAVE (weight, "ultra-light");
1604 else if (PROP_MATCH ("Light"))
1605 PROP_SAVE (weight, "light");
1606 else if (PROP_MATCH ("Book"))
1607 PROP_SAVE (weight, "book");
1608 else if (PROP_MATCH ("Medium"))
1609 PROP_SAVE (weight, "medium");
1610 else if (PROP_MATCH ("Semi-Bold"))
1611 PROP_SAVE (weight, "semi-bold");
1612 else if (PROP_MATCH ("Bold"))
1613 PROP_SAVE (weight, "bold");
1614 else if (PROP_MATCH ("Italic"))
1615 PROP_SAVE (slant, "italic");
1616 else if (PROP_MATCH ("Oblique"))
1617 PROP_SAVE (slant, "oblique");
1618 else if (PROP_MATCH ("Semi-Condensed"))
1619 PROP_SAVE (width, "semi-condensed");
1620 else if (PROP_MATCH ("Condensed"))
1621 PROP_SAVE (width, "condensed");
1622
1623 else
1624 {
1625 family_end = p;
1626 break;
1627 }
1628 }
1629 #undef PROP_MATCH
1630 #undef PROP_SAVE
1631
1632 if (family_end)
1633 ASET (font, FONT_FAMILY_INDEX,
1634 font_intern_prop (name, family_end - name, 1));
1635 if (!NILP (size))
1636 ASET (font, FONT_SIZE_INDEX, size);
1637 if (!NILP (weight))
1638 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, weight);
1639 if (!NILP (slant))
1640 FONT_SET_STYLE (font, FONT_SLANT_INDEX, slant);
1641 if (!NILP (width))
1642 FONT_SET_STYLE (font, FONT_WIDTH_INDEX, width);
1643 }
1644
1645 return 0;
1646 }
1647
1648 #if defined HAVE_XFT || defined HAVE_FREETYPE || defined HAVE_NS
1649
1650
1651
1652
1653
1654
1655 static int
1656 font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
1657 {
1658 Lisp_Object family, foundry;
1659 Lisp_Object val;
1660 int point_size;
1661 int i;
1662 char *p;
1663 char *lim;
1664 Lisp_Object styles[3];
1665 const char *style_names[3] = { "weight", "slant", "width" };
1666
1667 family = AREF (font, FONT_FAMILY_INDEX);
1668 if (! NILP (family))
1669 {
1670 if (SYMBOLP (family))
1671 family = SYMBOL_NAME (family);
1672 else
1673 family = Qnil;
1674 }
1675
1676 val = AREF (font, FONT_SIZE_INDEX);
1677 if (FIXNUMP (val))
1678 {
1679 if (XFIXNUM (val) != 0)
1680 pixel_size = XFIXNUM (val);
1681 point_size = -1;
1682 }
1683 else
1684 {
1685 eassert (FLOATP (val));
1686 pixel_size = -1;
1687 point_size = (int) XFLOAT_DATA (val);
1688 }
1689
1690 foundry = AREF (font, FONT_FOUNDRY_INDEX);
1691 if (! NILP (foundry))
1692 {
1693 if (SYMBOLP (foundry))
1694 foundry = SYMBOL_NAME (foundry);
1695 else
1696 foundry = Qnil;
1697 }
1698
1699 for (i = 0; i < 3; i++)
1700 styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
1701
1702 p = name;
1703 lim = name + nbytes;
1704 if (! NILP (family))
1705 {
1706 int len = snprintf (p, lim - p, "%s", SSDATA (family));
1707 if (! (0 <= len && len < lim - p))
1708 return -1;
1709 p += len;
1710 }
1711 if (point_size > 0)
1712 {
1713 int len = snprintf (p, lim - p, &"-%d"[p == name], point_size);
1714 if (! (0 <= len && len < lim - p))
1715 return -1;
1716 p += len;
1717 }
1718 else if (pixel_size > 0)
1719 {
1720 int len = snprintf (p, lim - p, ":pixelsize=%d", pixel_size);
1721 if (! (0 <= len && len < lim - p))
1722 return -1;
1723 p += len;
1724 }
1725 if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
1726 {
1727 int len = snprintf (p, lim - p, ":foundry=%s",
1728 SSDATA (SYMBOL_NAME (AREF (font,
1729 FONT_FOUNDRY_INDEX))));
1730 if (! (0 <= len && len < lim - p))
1731 return -1;
1732 p += len;
1733 }
1734 for (i = 0; i < 3; i++)
1735 if (! NILP (styles[i]))
1736 {
1737 int len = snprintf (p, lim - p, ":%s=%s", style_names[i],
1738 SSDATA (SYMBOL_NAME (styles[i])));
1739 if (! (0 <= len && len < lim - p))
1740 return -1;
1741 p += len;
1742 }
1743
1744 if (FIXNUMP (AREF (font, FONT_DPI_INDEX)))
1745 {
1746 int len = snprintf (p, lim - p, ":dpi=%"pI"d",
1747 XFIXNUM (AREF (font, FONT_DPI_INDEX)));
1748 if (! (0 <= len && len < lim - p))
1749 return -1;
1750 p += len;
1751 }
1752
1753 if (FIXNUMP (AREF (font, FONT_SPACING_INDEX)))
1754 {
1755 int len = snprintf (p, lim - p, ":spacing=%"pI"d",
1756 XFIXNUM (AREF (font, FONT_SPACING_INDEX)));
1757 if (! (0 <= len && len < lim - p))
1758 return -1;
1759 p += len;
1760 }
1761
1762 if (FIXNUMP (AREF (font, FONT_AVGWIDTH_INDEX)))
1763 {
1764 int len = snprintf (p, lim - p,
1765 (XFIXNUM (AREF (font, FONT_AVGWIDTH_INDEX)) == 0
1766 ? ":scalable=true"
1767 : ":scalable=false"));
1768 if (! (0 <= len && len < lim - p))
1769 return -1;
1770 p += len;
1771 }
1772
1773 return (p - name);
1774 }
1775
1776 #endif
1777
1778
1779
1780
1781
1782 static int
1783 font_parse_name (char *name, ptrdiff_t namelen, Lisp_Object font)
1784 {
1785 if (name[0] == '-' || strchr (name, '*') || strchr (name, '?'))
1786 return font_parse_xlfd (name, namelen, font);
1787 return font_parse_fcname (name, namelen, font);
1788 }
1789
1790
1791
1792
1793
1794
1795 void
1796 font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Object font_spec)
1797 {
1798 ptrdiff_t len;
1799 char *p0, *p1;
1800
1801 if (! NILP (family)
1802 && NILP (AREF (font_spec, FONT_FAMILY_INDEX)))
1803 {
1804 CHECK_STRING (family);
1805 len = SBYTES (family);
1806 p0 = SSDATA (family);
1807 p1 = strchr (p0, '-');
1808 if (p1)
1809 {
1810 if ((*p0 != '*' && p1 - p0 > 0)
1811 && NILP (AREF (font_spec, FONT_FOUNDRY_INDEX)))
1812 Ffont_put (font_spec, QCfoundry, font_intern_prop (p0, p1 - p0, 1));
1813 p1++;
1814 len -= p1 - p0;
1815 Ffont_put (font_spec, QCfamily, font_intern_prop (p1, len, 1));
1816 }
1817 else
1818 ASET (font_spec, FONT_FAMILY_INDEX, Fintern (family, Qnil));
1819 }
1820 if (! NILP (registry))
1821 {
1822
1823 CHECK_STRING (registry);
1824 len = SBYTES (registry);
1825 p0 = SSDATA (registry);
1826 p1 = strchr (p0, '-');
1827 if (! p1)
1828 {
1829 bool asterisk = len && p0[len - 1] == '*';
1830 AUTO_STRING_WITH_LEN (extra, &"*-*"[asterisk], 3 - asterisk);
1831 registry = concat2 (registry, extra);
1832 }
1833 registry = Fdowncase (registry);
1834 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
1835 }
1836 }
1837
1838
1839
1840
1841 static double
1842 font_rescale_ratio (Lisp_Object font_entity)
1843 {
1844 Lisp_Object tail, elt;
1845 Lisp_Object name = Qnil;
1846
1847 for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail))
1848 {
1849 elt = XCAR (tail);
1850 if (FLOATP (XCDR (elt)))
1851 {
1852 if (STRINGP (XCAR (elt)))
1853 {
1854 if (NILP (name))
1855 name = Ffont_xlfd_name (font_entity, Qnil);
1856 if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
1857 return XFLOAT_DATA (XCDR (elt));
1858 }
1859 else if (FONT_SPEC_P (XCAR (elt)))
1860 {
1861 if (font_match_p (XCAR (elt), font_entity))
1862 return XFLOAT_DATA (XCDR (elt));
1863 }
1864 }
1865 }
1866 return 1.0;
1867 }
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882 static int sort_shift_bits[FONT_SIZE_INDEX + 1];
1883
1884
1885
1886
1887
1888 static unsigned
1889 font_score (Lisp_Object entity, Lisp_Object *spec_prop)
1890 {
1891 unsigned score = 0;
1892 int i;
1893
1894
1895 for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
1896 if (! NILP (spec_prop[i])
1897 && ! EQ (AREF (entity, i), spec_prop[i])
1898 && FIXNUMP (AREF (entity, i)))
1899 {
1900 EMACS_INT diff = ((XFIXNUM (AREF (entity, i)) >> 8)
1901 - (XFIXNUM (spec_prop[i]) >> 8));
1902 score |= min (eabs (diff), 127) << sort_shift_bits[i];
1903 }
1904
1905
1906 if (! NILP (spec_prop[FONT_SIZE_INDEX])
1907 && XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) > 0)
1908 {
1909
1910
1911 EMACS_INT diff;
1912 EMACS_INT pixel_size = XFIXNUM (spec_prop[FONT_SIZE_INDEX]);
1913 EMACS_INT entity_size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
1914
1915 if (CONSP (Vface_font_rescale_alist))
1916 pixel_size *= font_rescale_ratio (entity);
1917 if (pixel_size * 2 < entity_size || entity_size * 2 < pixel_size)
1918
1919 return 0xFFFFFFFF;
1920 diff = eabs (pixel_size - entity_size) << 1;
1921 if (! NILP (spec_prop[FONT_DPI_INDEX])
1922 && ! EQ (spec_prop[FONT_DPI_INDEX], AREF (entity, FONT_DPI_INDEX)))
1923 diff |= 1;
1924 if (! NILP (spec_prop[FONT_AVGWIDTH_INDEX])
1925 && ! EQ (spec_prop[FONT_AVGWIDTH_INDEX], AREF (entity, FONT_AVGWIDTH_INDEX)))
1926 diff |= 1;
1927 score |= min (diff, 127) << sort_shift_bits[FONT_SIZE_INDEX];
1928 }
1929
1930 return score;
1931 }
1932
1933
1934
1935
1936
1937 static Lisp_Object
1938 font_vconcat_entity_vectors (Lisp_Object list)
1939 {
1940 ptrdiff_t nargs = list_length (list);
1941 Lisp_Object *args;
1942 USE_SAFE_ALLOCA;
1943 SAFE_ALLOCA_LISP (args, nargs);
1944
1945 for (ptrdiff_t i = 0; i < nargs; i++, list = XCDR (list))
1946 args[i] = XCAR (list);
1947 Lisp_Object result = Fvconcat (nargs, args);
1948 SAFE_FREE ();
1949 return result;
1950 }
1951
1952
1953
1954 struct font_sort_data
1955 {
1956 unsigned score;
1957 int font_driver_preference;
1958 Lisp_Object entity;
1959 };
1960
1961
1962
1963
1964 static int
1965 font_compare (const void *d1, const void *d2)
1966 {
1967 const struct font_sort_data *data1 = d1;
1968 const struct font_sort_data *data2 = d2;
1969
1970 if (data1->score < data2->score)
1971 return -1;
1972 else if (data1->score > data2->score)
1973 return 1;
1974 return (data1->font_driver_preference - data2->font_driver_preference);
1975 }
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992 static Lisp_Object
1993 font_sort_entities (Lisp_Object list, Lisp_Object prefer,
1994 struct frame *f, int best_only)
1995 {
1996 Lisp_Object prefer_prop[FONT_SPEC_MAX];
1997 int len, maxlen, i;
1998 struct font_sort_data *data;
1999 unsigned best_score;
2000 Lisp_Object best_entity;
2001 Lisp_Object tail;
2002 Lisp_Object vec UNINIT;
2003 USE_SAFE_ALLOCA;
2004
2005 for (i = FONT_WEIGHT_INDEX; i <= FONT_AVGWIDTH_INDEX; i++)
2006 prefer_prop[i] = AREF (prefer, i);
2007 if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
2008 prefer_prop[FONT_SIZE_INDEX]
2009 = make_fixnum (font_pixel_size (f, prefer));
2010
2011 if (NILP (XCDR (list)))
2012 {
2013
2014 vec = XCAR (list);
2015 maxlen = ASIZE (vec);
2016 }
2017 else if (best_only)
2018 {
2019
2020
2021
2022 maxlen = 0;
2023 for (tail = list; CONSP (tail); tail = XCDR (tail))
2024 if (maxlen < ASIZE (XCAR (tail)))
2025 maxlen = ASIZE (XCAR (tail));
2026 }
2027 else
2028 {
2029
2030 vec = font_vconcat_entity_vectors (list);
2031 maxlen = ASIZE (vec);
2032 }
2033
2034 data = SAFE_ALLOCA (maxlen * sizeof *data);
2035 best_score = 0xFFFFFFFF;
2036 best_entity = Qnil;
2037
2038 for (tail = list; CONSP (tail); tail = XCDR (tail))
2039 {
2040 int font_driver_preference = 0;
2041 Lisp_Object current_font_driver;
2042
2043 if (best_only)
2044 vec = XCAR (tail);
2045 len = ASIZE (vec);
2046
2047
2048 current_font_driver = AREF (AREF (vec, 0), FONT_TYPE_INDEX);
2049
2050 for (i = 0; i < len; i++)
2051 {
2052 data[i].entity = AREF (vec, i);
2053 data[i].score
2054 = ((best_only <= 0 || font_has_char (f, data[i].entity, best_only)
2055 > 0)
2056 ? font_score (data[i].entity, prefer_prop)
2057 : 0xFFFFFFFF);
2058 if (best_only && best_score > data[i].score)
2059 {
2060 best_score = data[i].score;
2061 best_entity = data[i].entity;
2062 if (best_score == 0)
2063 break;
2064 }
2065 if (! EQ (current_font_driver, AREF (AREF (vec, i), FONT_TYPE_INDEX)))
2066 {
2067 current_font_driver = AREF (AREF (vec, i), FONT_TYPE_INDEX);
2068 font_driver_preference++;
2069 }
2070 data[i].font_driver_preference = font_driver_preference;
2071 }
2072
2073
2074 if (! best_only)
2075 {
2076 qsort (data, len, sizeof *data, font_compare);
2077 for (i = 0; i < len; i++)
2078 ASET (vec, i, data[i].entity);
2079 break;
2080 }
2081 else
2082 vec = best_entity;
2083 }
2084
2085 SAFE_FREE ();
2086
2087 FONT_ADD_LOG ("sort-by", prefer, vec);
2088 return vec;
2089 }
2090
2091
2092
2093
2094
2095
2096
2097
2098 void
2099 font_update_sort_order (int *order)
2100 {
2101 int i, shift_bits;
2102
2103 for (i = 0, shift_bits = 23; i < 4; i++, shift_bits -= 7)
2104 {
2105 int xlfd_idx = order[i];
2106
2107 if (xlfd_idx == XLFD_WEIGHT_INDEX)
2108 sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits;
2109 else if (xlfd_idx == XLFD_SLANT_INDEX)
2110 sort_shift_bits[FONT_SLANT_INDEX] = shift_bits;
2111 else if (xlfd_idx == XLFD_SWIDTH_INDEX)
2112 sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits;
2113 else
2114 sort_shift_bits[FONT_SIZE_INDEX] = shift_bits;
2115 }
2116 }
2117
2118 static bool
2119 font_check_otf_features (Lisp_Object script, Lisp_Object langsys,
2120 Lisp_Object features, Lisp_Object table)
2121 {
2122 Lisp_Object val;
2123 bool negative;
2124
2125 table = assq_no_quit (script, table);
2126 if (NILP (table))
2127 return 0;
2128 table = XCDR (table);
2129 if (! NILP (langsys))
2130 {
2131 table = assq_no_quit (langsys, table);
2132 if (NILP (table))
2133 return 0;
2134 }
2135 else
2136 {
2137 val = assq_no_quit (Qnil, table);
2138 if (NILP (val))
2139 table = XCAR (table);
2140 else
2141 table = val;
2142 }
2143 table = XCDR (table);
2144 for (negative = 0; CONSP (features); features = XCDR (features))
2145 {
2146 if (NILP (XCAR (features)))
2147 {
2148 negative = 1;
2149 continue;
2150 }
2151 if (NILP (Fmemq (XCAR (features), table)) != negative)
2152 return 0;
2153 }
2154 return 1;
2155 }
2156
2157
2158
2159 static bool
2160 font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
2161 {
2162 Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
2163
2164 script = XCAR (spec);
2165 spec = XCDR (spec);
2166 if (! NILP (spec))
2167 {
2168 langsys = XCAR (spec);
2169 spec = XCDR (spec);
2170 if (! NILP (spec))
2171 {
2172 gsub = XCAR (spec);
2173 spec = XCDR (spec);
2174 if (! NILP (spec))
2175 gpos = XCAR (spec);
2176 }
2177 }
2178
2179 if (! NILP (gsub) && ! font_check_otf_features (script, langsys, gsub,
2180 XCAR (otf_capability)))
2181 return 0;
2182 if (! NILP (gpos) && ! font_check_otf_features (script, langsys, gpos,
2183 XCDR (otf_capability)))
2184 return 0;
2185 return 1;
2186 }
2187
2188
2189
2190
2191
2192
2193 bool
2194 font_match_p (Lisp_Object spec, Lisp_Object font)
2195 {
2196 Lisp_Object prop[FONT_SPEC_MAX], *props;
2197 Lisp_Object extra, font_extra;
2198 int i;
2199
2200 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
2201 if (! NILP (AREF (spec, i))
2202 && ! NILP (AREF (font, i))
2203 && ! EQ (AREF (spec, i), AREF (font, i)))
2204 return 0;
2205 props = XFONT_SPEC (spec)->props;
2206 if (FLOATP (props[FONT_SIZE_INDEX]))
2207 {
2208 for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
2209 prop[i] = AREF (spec, i);
2210 prop[FONT_SIZE_INDEX]
2211 = make_fixnum (font_pixel_size (XFRAME (selected_frame), spec));
2212 props = prop;
2213 }
2214
2215 if (font_score (font, props) > 0)
2216 return 0;
2217 extra = AREF (spec, FONT_EXTRA_INDEX);
2218 font_extra = AREF (font, FONT_EXTRA_INDEX);
2219 for (; CONSP (extra); extra = XCDR (extra))
2220 {
2221 Lisp_Object key = XCAR (XCAR (extra));
2222 Lisp_Object val = XCDR (XCAR (extra)), val2;
2223
2224 if (EQ (key, QClang))
2225 {
2226 val2 = assq_no_quit (key, font_extra);
2227 if (NILP (val2))
2228 return 0;
2229 val2 = XCDR (val2);
2230 if (CONSP (val))
2231 {
2232 if (! CONSP (val2))
2233 return 0;
2234 while (CONSP (val))
2235 if (NILP (Fmemq (val, val2)))
2236 return 0;
2237 }
2238 else
2239 if (CONSP (val2)
2240 ? NILP (Fmemq (val, XCDR (val2)))
2241 : ! EQ (val, val2))
2242 return 0;
2243 }
2244 else if (EQ (key, QCscript))
2245 {
2246 val2 = assq_no_quit (val, Vscript_representative_chars);
2247 if (CONSP (val2))
2248 {
2249 val2 = XCDR (val2);
2250 if (CONSP (val2))
2251 {
2252
2253 for (; CONSP (val2); val2 = XCDR (val2))
2254 {
2255 if (! CHARACTERP (XCAR (val2)))
2256 continue;
2257 if (font_encode_char (font, XFIXNAT (XCAR (val2)))
2258 == FONT_INVALID_CODE)
2259 return 0;
2260 }
2261 }
2262 else if (VECTORP (val2))
2263 {
2264
2265 for (i = 0; i < ASIZE (val2); i++)
2266 {
2267 if (! CHARACTERP (AREF (val2, i)))
2268 continue;
2269 if (font_encode_char (font, XFIXNAT (AREF (val2, i)))
2270 != FONT_INVALID_CODE)
2271 break;
2272 }
2273 if (i == ASIZE (val2))
2274 return 0;
2275 }
2276 }
2277 }
2278 else if (EQ (key, QCotf))
2279 {
2280 struct font *fontp;
2281
2282 if (! FONT_OBJECT_P (font))
2283 return 0;
2284 fontp = XFONT_OBJECT (font);
2285 if (! fontp->driver->otf_capability)
2286 return 0;
2287 val2 = fontp->driver->otf_capability (fontp);
2288 if (NILP (val2) || ! font_check_otf (val, val2))
2289 return 0;
2290 }
2291 }
2292
2293 return 1;
2294 }
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310 static void font_clear_cache (struct frame *, Lisp_Object,
2311 struct font_driver const *);
2312
2313 static void
2314 font_prepare_cache (struct frame *f, struct font_driver const *driver)
2315 {
2316 Lisp_Object cache, val;
2317
2318 cache = driver->get_cache (f);
2319 val = XCDR (cache);
2320 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2321 val = XCDR (val);
2322 if (NILP (val))
2323 {
2324 val = list2 (driver->type, make_fixnum (1));
2325 XSETCDR (cache, Fcons (val, XCDR (cache)));
2326 }
2327 else
2328 {
2329 val = XCDR (XCAR (val));
2330 XSETCAR (val, make_fixnum (XFIXNUM (XCAR (val)) + 1));
2331 }
2332 }
2333
2334
2335 static void
2336 font_finish_cache (struct frame *f, struct font_driver const *driver)
2337 {
2338 Lisp_Object cache, val, tmp;
2339
2340
2341 cache = driver->get_cache (f);
2342 val = XCDR (cache);
2343 while (CONSP (val) && ! EQ (XCAR (XCAR (val)), driver->type))
2344 cache = val, val = XCDR (val);
2345 eassert (! NILP (val));
2346 tmp = XCDR (XCAR (val));
2347 XSETCAR (tmp, make_fixnum (XFIXNUM (XCAR (tmp)) - 1));
2348 if (XFIXNUM (XCAR (tmp)) == 0)
2349 {
2350 font_clear_cache (f, XCAR (val), driver);
2351 XSETCDR (cache, XCDR (val));
2352 }
2353 }
2354
2355
2356 static Lisp_Object
2357 font_get_cache (struct frame *f, struct font_driver const *driver)
2358 {
2359 Lisp_Object val = driver->get_cache (f);
2360 Lisp_Object type = driver->type;
2361
2362 eassert (CONSP (val));
2363 for (val = XCDR (val); ! EQ (XCAR (XCAR (val)), type); val = XCDR (val));
2364 eassert (CONSP (val));
2365
2366 val = XCDR (XCAR (val));
2367 return val;
2368 }
2369
2370
2371 static void
2372 font_clear_cache (struct frame *f, Lisp_Object cache,
2373 struct font_driver const *driver)
2374 {
2375 Lisp_Object tail, elt;
2376 Lisp_Object entity;
2377 ptrdiff_t i;
2378
2379
2380 for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
2381 {
2382 elt = XCAR (tail);
2383
2384 if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
2385 {
2386 elt = XCDR (elt);
2387 eassert (VECTORP (elt));
2388 for (i = 0; i < ASIZE (elt); i++)
2389 {
2390 entity = AREF (elt, i);
2391
2392 if (FONT_ENTITY_P (entity)
2393 && EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
2394 {
2395 Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
2396
2397 for (; CONSP (objlist); objlist = XCDR (objlist))
2398 {
2399 Lisp_Object val = XCAR (objlist);
2400 struct font *font = XFONT_OBJECT (val);
2401
2402 if (! NILP (AREF (val, FONT_TYPE_INDEX)))
2403 {
2404 eassert (font && driver == font->driver);
2405
2406
2407
2408
2409 composition_gstring_cache_clear_font (val);
2410 driver->close_font (font);
2411 }
2412 }
2413 if (driver->free_entity)
2414 driver->free_entity (entity);
2415 }
2416 }
2417 }
2418 }
2419 XSETCDR (cache, Qnil);
2420 }
2421
2422
2423
2424
2425
2426
2427 bool
2428 font_is_ignored (const char *name, ptrdiff_t namelen)
2429 {
2430 Lisp_Object tail = Vface_ignored_fonts;
2431 Lisp_Object regexp;
2432
2433 FOR_EACH_TAIL_SAFE (tail)
2434 {
2435 regexp = XCAR (tail);
2436 if (STRINGP (regexp)
2437 && fast_c_string_match_ignore_case (regexp, name,
2438 namelen) >= 0)
2439 return true;
2440 }
2441 return false;
2442 }
2443 static Lisp_Object scratch_font_spec, scratch_font_prefer;
2444
2445
2446
2447
2448
2449
2450
2451 static Lisp_Object
2452 font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
2453 {
2454 Lisp_Object entity, val;
2455 enum font_property_index prop;
2456 ptrdiff_t i;
2457
2458 for (val = Qnil, i = ASIZE (vec) - 1; i >= 0; i--)
2459 {
2460 entity = AREF (vec, i);
2461 if (! NILP (Vface_ignored_fonts))
2462 {
2463 char name[256];
2464 ptrdiff_t namelen;
2465 namelen = font_unparse_xlfd (entity, 0, name, 256);
2466 if (namelen >= 0)
2467 if (font_is_ignored (name, namelen))
2468 continue;
2469 }
2470 if (NILP (spec))
2471 {
2472 val = Fcons (entity, val);
2473 continue;
2474 }
2475 for (prop = FONT_WEIGHT_INDEX; prop < FONT_SIZE_INDEX; prop++)
2476 {
2477 if (FIXNUMP (AREF (spec, prop)))
2478 {
2479 if (!FIXNUMP (AREF (entity, prop)))
2480 prop = FONT_SPEC_MAX;
2481 else
2482 {
2483 int required = XFIXNUM (AREF (spec, prop)) >> 8;
2484 int candidate = XFIXNUM (AREF (entity, prop)) >> 8;
2485
2486 if (candidate != required
2487 #ifdef HAVE_NTGUI
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498 && (prop != FONT_WEIGHT_INDEX
2499 || eabs (candidate - required) > 100)
2500 #endif
2501 )
2502 prop = FONT_SPEC_MAX;
2503 }
2504 }
2505 }
2506 if (prop < FONT_SPEC_MAX
2507 && size
2508 && XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) > 0)
2509 {
2510 int diff = XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) - size;
2511
2512 if (eabs (diff) > FONT_PIXEL_SIZE_QUANTUM)
2513 prop = FONT_SPEC_MAX;
2514 }
2515 if (prop < FONT_SPEC_MAX
2516 && FIXNUMP (AREF (spec, FONT_DPI_INDEX))
2517 && FIXNUMP (AREF (entity, FONT_DPI_INDEX))
2518 && XFIXNUM (AREF (entity, FONT_DPI_INDEX)) != 0
2519 && ! EQ (AREF (spec, FONT_DPI_INDEX), AREF (entity, FONT_DPI_INDEX)))
2520 prop = FONT_SPEC_MAX;
2521 if (prop < FONT_SPEC_MAX
2522 && FIXNUMP (AREF (spec, FONT_AVGWIDTH_INDEX))
2523 && FIXNUMP (AREF (entity, FONT_AVGWIDTH_INDEX))
2524 && XFIXNUM (AREF (entity, FONT_AVGWIDTH_INDEX)) != 0
2525 && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
2526 AREF (entity, FONT_AVGWIDTH_INDEX)))
2527 prop = FONT_SPEC_MAX;
2528 if (prop < FONT_SPEC_MAX)
2529 val = Fcons (entity, val);
2530 }
2531 return (Fvconcat (1, &val));
2532 }
2533
2534
2535
2536
2537
2538
2539 Lisp_Object
2540 font_list_entities (struct frame *f, Lisp_Object spec)
2541 {
2542 struct font_driver_list *driver_list = f->font_driver_list;
2543 Lisp_Object ftype, val;
2544 Lisp_Object list = Qnil;
2545 int size;
2546 bool need_filtering = 0;
2547 int i;
2548
2549 eassert (FONT_SPEC_P (spec));
2550
2551 if (FIXNUMP (AREF (spec, FONT_SIZE_INDEX)))
2552 size = XFIXNUM (AREF (spec, FONT_SIZE_INDEX));
2553 else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
2554 size = font_pixel_size (f, spec);
2555 else
2556 size = 0;
2557
2558 ftype = AREF (spec, FONT_TYPE_INDEX);
2559 for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
2560 ASET (scratch_font_spec, i, AREF (spec, i));
2561 for (i = FONT_WEIGHT_INDEX; i < FONT_EXTRA_INDEX; i++)
2562 if (i != FONT_SPACING_INDEX)
2563 {
2564 ASET (scratch_font_spec, i, Qnil);
2565 if (! NILP (AREF (spec, i)))
2566 need_filtering = 1;
2567 }
2568 ASET (scratch_font_spec, FONT_SPACING_INDEX, AREF (spec, FONT_SPACING_INDEX));
2569 ASET (scratch_font_spec, FONT_EXTRA_INDEX, AREF (spec, FONT_EXTRA_INDEX));
2570
2571 for (; driver_list; driver_list = driver_list->next)
2572 if (driver_list->on
2573 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2574 {
2575 Lisp_Object cache = font_get_cache (f, driver_list->driver);
2576
2577 ASET (scratch_font_spec, FONT_TYPE_INDEX, driver_list->driver->type);
2578 val = assoc_no_quit (scratch_font_spec, XCDR (cache));
2579 if (CONSP (val))
2580 val = XCDR (val);
2581 else
2582 {
2583 Lisp_Object copy;
2584
2585 val = (driver_list->driver->list) (f, scratch_font_spec);
2586
2587
2588
2589
2590
2591 if (NILP (val))
2592 val = zero_vector;
2593 else
2594 val = Fvconcat (1, &val);
2595 copy = copy_font_spec (scratch_font_spec);
2596 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2597 XSETCDR (cache, Fcons (Fcons (copy, val), XCDR (cache)));
2598 }
2599 if (ASIZE (val) > 0
2600 && (need_filtering
2601 || ! NILP (Vface_ignored_fonts)))
2602 val = font_delete_unmatched (val, need_filtering ? spec : Qnil, size);
2603 if (ASIZE (val) > 0)
2604 {
2605 list = Fcons (val, list);
2606
2607
2608 if (query_all_font_backends == false)
2609 break;
2610 }
2611 }
2612
2613 list = Fnreverse (list);
2614 FONT_ADD_LOG ("list", spec, list);
2615 return list;
2616 }
2617
2618
2619
2620
2621
2622
2623 static Lisp_Object
2624 font_matching_entity (struct frame *f, Lisp_Object *attrs, Lisp_Object spec)
2625 {
2626 struct font_driver_list *driver_list = f->font_driver_list;
2627 Lisp_Object ftype, size, entity;
2628 Lisp_Object work = copy_font_spec (spec);
2629
2630 ftype = AREF (spec, FONT_TYPE_INDEX);
2631 size = AREF (spec, FONT_SIZE_INDEX);
2632
2633 if (FLOATP (size))
2634 ASET (work, FONT_SIZE_INDEX, make_fixnum (font_pixel_size (f, spec)));
2635 FONT_SET_STYLE (work, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2636 FONT_SET_STYLE (work, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2637 FONT_SET_STYLE (work, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
2638
2639 entity = Qnil;
2640 for (; driver_list; driver_list = driver_list->next)
2641 if (driver_list->on
2642 && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
2643 {
2644 Lisp_Object cache = font_get_cache (f, driver_list->driver);
2645
2646 ASET (work, FONT_TYPE_INDEX, driver_list->driver->type);
2647 entity = assoc_no_quit (work, XCDR (cache));
2648 if (CONSP (entity))
2649 entity = AREF (XCDR (entity), 0);
2650 else
2651 {
2652 entity = driver_list->driver->match (f, work);
2653 if (!NILP (entity))
2654 {
2655 Lisp_Object copy = copy_font_spec (work);
2656 Lisp_Object match = Fvector (1, &entity);
2657
2658 ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
2659 XSETCDR (cache, Fcons (Fcons (copy, match), XCDR (cache)));
2660 }
2661 }
2662 if (! NILP (entity))
2663 break;
2664 }
2665 FONT_ADD_LOG ("match", work, entity);
2666 return entity;
2667 }
2668
2669
2670
2671
2672
2673 static Lisp_Object
2674 font_open_entity (struct frame *f, Lisp_Object entity, int pixel_size)
2675 {
2676 struct font_driver_list *driver_list;
2677 Lisp_Object objlist, size, val, font_object;
2678 struct font *font;
2679 int height, psize;
2680
2681 eassert (FONT_ENTITY_P (entity));
2682 size = AREF (entity, FONT_SIZE_INDEX);
2683 if (XFIXNUM (size) != 0)
2684 pixel_size = XFIXNUM (size);
2685
2686 val = AREF (entity, FONT_TYPE_INDEX);
2687 for (driver_list = f->font_driver_list;
2688 driver_list && ! EQ (driver_list->driver->type, val);
2689 driver_list = driver_list->next);
2690 if (! driver_list)
2691 return Qnil;
2692
2693 for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
2694 objlist = XCDR (objlist))
2695 {
2696 Lisp_Object fn = XCAR (objlist);
2697 if (! NILP (AREF (fn, FONT_TYPE_INDEX))
2698 && XFONT_OBJECT (fn)->pixel_size == pixel_size)
2699 {
2700 if (driver_list->driver->cached_font_ok == NULL
2701 || driver_list->driver->cached_font_ok (f, fn, entity))
2702 return fn;
2703 }
2704 }
2705
2706
2707
2708 for (psize = pixel_size; ; psize++)
2709 {
2710 font_object = driver_list->driver->open_font (f, entity, psize);
2711 if (NILP (font_object))
2712 return Qnil;
2713 font = XFONT_OBJECT (font_object);
2714 if (font->average_width > 0 && font->height > 0)
2715 break;
2716
2717 if (psize > pixel_size + 15)
2718 return Qnil;
2719 }
2720 ASET (font_object, FONT_SIZE_INDEX, make_fixnum (pixel_size));
2721 FONT_ADD_LOG ("open", entity, font_object);
2722 ASET (entity, FONT_OBJLIST_INDEX,
2723 Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
2724
2725 font = XFONT_OBJECT (font_object);
2726 #ifdef HAVE_WINDOW_SYSTEM
2727 int min_width = (font->min_width ? font->min_width
2728 : font->average_width ? font->average_width
2729 : font->space_width ? font->space_width
2730 : 1);
2731 #endif
2732
2733 int font_ascent, font_descent;
2734 get_font_ascent_descent (font, &font_ascent, &font_descent);
2735 height = font_ascent + font_descent;
2736 if (height <= 0)
2737 height = 1;
2738 #ifdef HAVE_WINDOW_SYSTEM
2739 FRAME_DISPLAY_INFO (f)->n_fonts++;
2740 if (FRAME_DISPLAY_INFO (f)->n_fonts == 1)
2741 {
2742 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
2743 FRAME_SMALLEST_FONT_HEIGHT (f) = height;
2744 f->fonts_changed = 1;
2745 }
2746 else
2747 {
2748 if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
2749 FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, f->fonts_changed = 1;
2750 if (FRAME_SMALLEST_FONT_HEIGHT (f) > height)
2751 FRAME_SMALLEST_FONT_HEIGHT (f) = height, f->fonts_changed = 1;
2752 }
2753 #endif
2754
2755 return font_object;
2756 }
2757
2758
2759
2760
2761 static void
2762 font_close_object (struct frame *f, Lisp_Object font_object)
2763 {
2764 struct font *font = XFONT_OBJECT (font_object);
2765
2766 if (NILP (AREF (font_object, FONT_TYPE_INDEX)))
2767
2768 return;
2769 FONT_ADD_LOG ("close", font_object, Qnil);
2770 font->driver->close_font (font);
2771 #ifdef HAVE_WINDOW_SYSTEM
2772 eassert (FRAME_DISPLAY_INFO (f)->n_fonts);
2773 FRAME_DISPLAY_INFO (f)->n_fonts--;
2774 #endif
2775 }
2776
2777
2778
2779
2780
2781 int
2782 font_has_char (struct frame *f, Lisp_Object font, int c)
2783 {
2784 struct font *fontp;
2785
2786 if (FONT_ENTITY_P (font))
2787 {
2788 Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
2789 struct font_driver_list *driver_list;
2790
2791 for (driver_list = f->font_driver_list;
2792 driver_list && ! EQ (driver_list->driver->type, type);
2793 driver_list = driver_list->next);
2794 if (! driver_list)
2795 return 0;
2796 if (! driver_list->driver->has_char)
2797 return -1;
2798 return driver_list->driver->has_char (font, c);
2799 }
2800
2801 eassert (FONT_OBJECT_P (font));
2802 fontp = XFONT_OBJECT (font);
2803 if (fontp->driver->has_char)
2804 {
2805 int result = fontp->driver->has_char (font, c);
2806
2807 if (result >= 0)
2808 return result;
2809 }
2810 return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
2811 }
2812
2813
2814
2815
2816 static unsigned
2817 font_encode_char (Lisp_Object font_object, int c)
2818 {
2819 struct font *font;
2820
2821 eassert (FONT_OBJECT_P (font_object));
2822 font = XFONT_OBJECT (font_object);
2823 return font->driver->encode_char (font, c);
2824 }
2825
2826
2827
2828
2829 Lisp_Object
2830 font_get_name (Lisp_Object font_object)
2831 {
2832 eassert (FONT_OBJECT_P (font_object));
2833 return AREF (font_object, FONT_NAME_INDEX);
2834 }
2835
2836
2837
2838
2839
2840 Lisp_Object
2841 font_spec_from_name (Lisp_Object font_name)
2842 {
2843 Lisp_Object spec = Ffont_spec (0, NULL);
2844
2845 CHECK_STRING (font_name);
2846 if (font_parse_name (SSDATA (font_name), SBYTES (font_name), spec) == -1)
2847 return Qnil;
2848 font_put_extra (spec, QCname, font_name);
2849 font_put_extra (spec, QCuser_spec, font_name);
2850 return spec;
2851 }
2852
2853
2854 void
2855 font_clear_prop (Lisp_Object *attrs, enum font_property_index prop)
2856 {
2857 Lisp_Object font = attrs[LFACE_FONT_INDEX];
2858
2859 if (! FONTP (font))
2860 return;
2861
2862 if (! NILP (Ffont_get (font, QCname)))
2863 {
2864 font = copy_font_spec (font);
2865 font_put_extra (font, QCname, Qunbound);
2866 }
2867
2868 if (NILP (AREF (font, prop))
2869 && prop != FONT_FAMILY_INDEX
2870 && prop != FONT_FOUNDRY_INDEX
2871 && prop != FONT_WIDTH_INDEX
2872 && prop != FONT_SIZE_INDEX)
2873 return;
2874 if (EQ (font, attrs[LFACE_FONT_INDEX]))
2875 font = copy_font_spec (font);
2876 ASET (font, prop, Qnil);
2877 if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
2878 {
2879 if (prop == FONT_FAMILY_INDEX)
2880 {
2881 ASET (font, FONT_FOUNDRY_INDEX, Qnil);
2882
2883
2884
2885 ASET (font, FONT_WIDTH_INDEX, Qnil);
2886 }
2887 ASET (font, FONT_ADSTYLE_INDEX, Qnil);
2888 ASET (font, FONT_REGISTRY_INDEX, Qnil);
2889 ASET (font, FONT_SIZE_INDEX, Qnil);
2890 ASET (font, FONT_DPI_INDEX, Qnil);
2891 ASET (font, FONT_SPACING_INDEX, Qnil);
2892 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
2893 }
2894 else if (prop == FONT_SIZE_INDEX)
2895 {
2896 ASET (font, FONT_DPI_INDEX, Qnil);
2897 ASET (font, FONT_SPACING_INDEX, Qnil);
2898 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
2899 }
2900 else if (prop == FONT_WIDTH_INDEX)
2901 ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
2902 attrs[LFACE_FONT_INDEX] = font;
2903 }
2904
2905
2906
2907
2908
2909 static Lisp_Object
2910 font_select_entity (struct frame *f, Lisp_Object entities,
2911 Lisp_Object *attrs, int pixel_size, int c)
2912 {
2913 Lisp_Object font_entity;
2914 Lisp_Object prefer;
2915 int i;
2916
2917
2918 if (NILP (XCDR (entities))
2919 && ASIZE (XCAR (entities)) == 1)
2920 {
2921 font_entity = AREF (XCAR (entities), 0);
2922 if (c < 0 || font_has_char (f, font_entity, c) > 0)
2923 return font_entity;
2924 return Qnil;
2925 }
2926
2927
2928
2929
2930
2931 prefer = scratch_font_prefer;
2932
2933 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
2934 ASET (prefer, i, Qnil);
2935 if (FONTP (attrs[LFACE_FONT_INDEX]))
2936 {
2937 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
2938
2939 for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
2940 ASET (prefer, i, AREF (face_font, i));
2941 }
2942 if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
2943 FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
2944 if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
2945 FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
2946 if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
2947 FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
2948 ASET (prefer, FONT_SIZE_INDEX, make_fixnum (pixel_size));
2949
2950 return font_sort_entities (entities, prefer, f, c);
2951 }
2952
2953
2954
2955
2956
2957 Lisp_Object
2958 font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int c)
2959 {
2960 Lisp_Object work;
2961 Lisp_Object entities, val;
2962 Lisp_Object foundry[3], *family, registry[3], adstyle[3];
2963 int pixel_size;
2964 int i, j, k, l;
2965 USE_SAFE_ALLOCA;
2966
2967
2968
2969 registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
2970 if (NILP (registry[0]))
2971 {
2972 registry[0] = DEFAULT_ENCODING;
2973 registry[1] = Qascii_0;
2974 registry[2] = zero_vector;
2975 }
2976 else
2977 registry[1] = zero_vector;
2978
2979 if (c >= 0 && ! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
2980 {
2981 struct charset *encoding, *repertory;
2982
2983 if (font_registry_charsets (AREF (spec, FONT_REGISTRY_INDEX),
2984 &encoding, &repertory) < 0)
2985 return Qnil;
2986 if (repertory
2987 && ENCODE_CHAR (repertory, c) == CHARSET_INVALID_CODE (repertory))
2988 return Qnil;
2989 else if (c > encoding->max_char)
2990 return Qnil;
2991 }
2992
2993 work = copy_font_spec (spec);
2994 ASET (work, FONT_TYPE_INDEX, AREF (spec, FONT_TYPE_INDEX));
2995 pixel_size = font_pixel_size (f, spec);
2996 if (pixel_size == 0 && FIXNUMP (attrs[LFACE_HEIGHT_INDEX]))
2997 {
2998 double pt = XFIXNUM (attrs[LFACE_HEIGHT_INDEX]);
2999
3000 pixel_size = POINT_TO_PIXEL (pt / 10, FRAME_RES_Y (f));
3001 if (pixel_size < 1)
3002 pixel_size = 1;
3003 }
3004 ASET (work, FONT_SIZE_INDEX, Qnil);
3005
3006
3007
3008 foundry[0] = AREF (work, FONT_FOUNDRY_INDEX);
3009 if (! NILP (foundry[0]))
3010 foundry[1] = zero_vector;
3011 else if (STRINGP (attrs[LFACE_FOUNDRY_INDEX]))
3012 {
3013 val = attrs[LFACE_FOUNDRY_INDEX];
3014 foundry[0] = font_intern_prop (SSDATA (val), SBYTES (val), 1);
3015 foundry[1] = Qnil;
3016 foundry[2] = zero_vector;
3017 }
3018 else
3019 foundry[0] = Qnil, foundry[1] = zero_vector;
3020
3021
3022
3023 adstyle[0] = AREF (work, FONT_ADSTYLE_INDEX);
3024 if (! NILP (adstyle[0]))
3025 adstyle[1] = zero_vector;
3026 else if (FONTP (attrs[LFACE_FONT_INDEX]))
3027 {
3028 Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
3029
3030 if (! NILP (AREF (face_font, FONT_ADSTYLE_INDEX)))
3031 {
3032 adstyle[0] = AREF (face_font, FONT_ADSTYLE_INDEX);
3033 adstyle[1] = Qnil;
3034 adstyle[2] = zero_vector;
3035 }
3036 else
3037 adstyle[0] = Qnil, adstyle[1] = zero_vector;
3038 }
3039 else
3040 adstyle[0] = Qnil, adstyle[1] = zero_vector;
3041
3042
3043
3044
3045 val = AREF (work, FONT_FAMILY_INDEX);
3046 if (NILP (val) && STRINGP (attrs[LFACE_FAMILY_INDEX]))
3047 {
3048 val = attrs[LFACE_FAMILY_INDEX];
3049 val = font_intern_prop (SSDATA (val), SBYTES (val), 1);
3050 }
3051 Lisp_Object familybuf[3];
3052 if (NILP (val))
3053 {
3054 family = familybuf;
3055 family[0] = Qnil;
3056 family[1] = zero_vector;
3057 }
3058 else
3059 {
3060 Lisp_Object alters
3061 = Fassoc_string (val, Vface_alternative_font_family_alist, Qt);
3062
3063 if (! NILP (alters))
3064 {
3065 EMACS_INT alterslen = list_length (alters);
3066 SAFE_ALLOCA_LISP (family, alterslen + 2);
3067 for (i = 0; CONSP (alters); i++, alters = XCDR (alters))
3068 family[i] = XCAR (alters);
3069 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3070 family[i++] = Qnil;
3071 family[i] = zero_vector;
3072 }
3073 else
3074 {
3075 family = familybuf;
3076 i = 0;
3077 family[i++] = val;
3078 if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
3079 family[i++] = Qnil;
3080 family[i] = zero_vector;
3081 }
3082 }
3083
3084
3085
3086 for (i = 0; SYMBOLP (family[i]); i++)
3087 {
3088 ASET (work, FONT_FAMILY_INDEX, family[i]);
3089 for (j = 0; SYMBOLP (foundry[j]); j++)
3090 {
3091 ASET (work, FONT_FOUNDRY_INDEX, foundry[j]);
3092 for (k = 0; SYMBOLP (registry[k]); k++)
3093 {
3094 ASET (work, FONT_REGISTRY_INDEX, registry[k]);
3095 for (l = 0; SYMBOLP (adstyle[l]); l++)
3096 {
3097 ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
3098
3099 entities = font_list_entities (f, work);
3100 if (! NILP (entities))
3101 {
3102
3103
3104 val = font_select_entity (f, entities,
3105 attrs, pixel_size, c);
3106 if (! NILP (val))
3107 {
3108 SAFE_FREE ();
3109 return val;
3110 }
3111 }
3112 }
3113 }
3114 }
3115 }
3116
3117 SAFE_FREE ();
3118 return Qnil;
3119 }
3120
3121
3122 Lisp_Object
3123 font_open_for_lface (struct frame *f, Lisp_Object entity, Lisp_Object *attrs, Lisp_Object spec)
3124 {
3125 int size;
3126
3127 if (FIXNUMP (AREF (entity, FONT_SIZE_INDEX))
3128 && XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) > 0)
3129 size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
3130 else
3131 {
3132 if (FONT_SPEC_P (spec) && ! NILP (AREF (spec, FONT_SIZE_INDEX)))
3133 size = font_pixel_size (f, spec);
3134 else
3135 {
3136 double pt;
3137 if (FIXNUMP (attrs[LFACE_HEIGHT_INDEX]))
3138 pt = XFIXNUM (attrs[LFACE_HEIGHT_INDEX]);
3139 else
3140 {
3141
3142 if (FRAME_FACE_CACHE (f)->used == 0)
3143 recompute_basic_faces (f);
3144
3145 struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
3146 Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
3147 eassert (FIXNUMP (height));
3148 pt = XFIXNUM (height);
3149 }
3150
3151 pt /= 10;
3152 size = POINT_TO_PIXEL (pt, FRAME_RES_Y (f));
3153 #ifdef HAVE_NS
3154 if (size == 0)
3155 {
3156 Lisp_Object ffsize = get_frame_param (f, Qfontsize);
3157 size = (NUMBERP (ffsize)
3158 ? POINT_TO_PIXEL (XFLOATINT (ffsize), FRAME_RES_Y (f))
3159 : 0);
3160 }
3161 #endif
3162 }
3163 size *= font_rescale_ratio (entity);
3164 }
3165
3166 return font_open_entity (f, entity, size);
3167 }
3168
3169
3170
3171
3172
3173
3174 Lisp_Object
3175 font_load_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec)
3176 {
3177 Lisp_Object entity, name;
3178
3179 entity = font_find_for_lface (f, attrs, spec, -1);
3180 if (NILP (entity))
3181 {
3182
3183
3184 entity = font_matching_entity (f, attrs, spec);
3185
3186
3187
3188
3189 if (NILP (entity))
3190 {
3191 name = Ffont_get (spec, QCuser_spec);
3192 if (STRINGP (name))
3193 {
3194 char *p = SSDATA (name), *q = strrchr (p, '-');
3195
3196 if (q != NULL && c_isdigit (q[1]))
3197 {
3198 char *tail;
3199 double font_size = strtod (q + 1, &tail);
3200
3201 if (font_size > 0 && tail != q + 1)
3202 {
3203 Lisp_Object lsize = Ffont_get (spec, QCsize);
3204
3205 if ((FLOATP (lsize) && XFLOAT_DATA (lsize) == font_size)
3206 || (FIXNUMP (lsize) && XFIXNUM (lsize) == font_size))
3207 {
3208 ASET (spec, FONT_FAMILY_INDEX,
3209 font_intern_prop (p, tail - p, 1));
3210 ASET (spec, FONT_SIZE_INDEX, Qnil);
3211 entity = font_matching_entity (f, attrs, spec);
3212 }
3213 }
3214 }
3215 }
3216 }
3217 if (NILP (entity))
3218 return Qnil;
3219 }
3220
3221
3222
3223 entity = font_open_for_lface (f, entity, attrs, spec);
3224 if (!NILP (entity))
3225 {
3226 name = Ffont_get (spec, QCuser_spec);
3227 if (STRINGP (name)) font_put_extra (entity, QCuser_spec, name);
3228 }
3229 return entity;
3230 }
3231
3232
3233
3234
3235 void
3236 font_prepare_for_face (struct frame *f, struct face *face)
3237 {
3238 if (face->font->driver->prepare_face)
3239 face->font->driver->prepare_face (f, face);
3240 }
3241
3242
3243
3244
3245 void
3246 font_done_for_face (struct frame *f, struct face *face)
3247 {
3248 if (face->font->driver->done_face)
3249 face->font->driver->done_face (f, face);
3250 }
3251
3252
3253
3254
3255
3256 Lisp_Object
3257 font_open_by_spec (struct frame *f, Lisp_Object spec)
3258 {
3259 Lisp_Object attrs[LFACE_VECTOR_SIZE];
3260
3261
3262
3263 attrs[LFACE_FAMILY_INDEX] = attrs[LFACE_FOUNDRY_INDEX] = Qnil;
3264 attrs[LFACE_SWIDTH_INDEX] = attrs[LFACE_WEIGHT_INDEX]
3265 = attrs[LFACE_SLANT_INDEX] = Qnormal;
3266 #ifndef HAVE_NS
3267 attrs[LFACE_HEIGHT_INDEX] = make_fixnum (120);
3268 #else
3269 attrs[LFACE_HEIGHT_INDEX] = make_fixnum (0);
3270 #endif
3271 attrs[LFACE_FONT_INDEX] = Qnil;
3272
3273 return font_load_for_lface (f, attrs, spec);
3274 }
3275
3276
3277
3278
3279
3280 Lisp_Object
3281 font_open_by_name (struct frame *f, Lisp_Object name)
3282 {
3283 Lisp_Object spec = CALLN (Ffont_spec, QCname, name);
3284 Lisp_Object ret = font_open_by_spec (f, spec);
3285
3286 if (!NILP (ret))
3287 font_put_extra (ret, QCuser_spec, name);
3288
3289 return ret;
3290 }
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305 void
3306 register_font_driver (struct font_driver const *driver, struct frame *f)
3307 {
3308 struct font_driver_list *root = f ? f->font_driver_list : font_driver_list;
3309 struct font_driver_list *prev, *list;
3310
3311 #ifdef HAVE_WINDOW_SYSTEM
3312 if (f && ! driver->draw)
3313 error ("Unusable font driver for a frame: %s",
3314 SDATA (SYMBOL_NAME (driver->type)));
3315 #endif
3316
3317 for (prev = NULL, list = root; list; prev = list, list = list->next)
3318 if (EQ (list->driver->type, driver->type))
3319 error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type)));
3320
3321 list = xmalloc (sizeof *list);
3322 list->on = 0;
3323 list->driver = driver;
3324 list->next = NULL;
3325 if (prev)
3326 prev->next = list;
3327 else if (f)
3328 f->font_driver_list = list;
3329 else
3330 font_driver_list = list;
3331 if (! f)
3332 num_font_drivers++;
3333 }
3334
3335 void
3336 free_font_driver_list (struct frame *f)
3337 {
3338 struct font_driver_list *list, *next;
3339
3340 for (list = f->font_driver_list; list; list = next)
3341 {
3342 next = list->next;
3343 xfree (list);
3344 }
3345 f->font_driver_list = NULL;
3346 }
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360 Lisp_Object
3361 font_update_drivers (struct frame *f, Lisp_Object new_drivers)
3362 {
3363 Lisp_Object active_drivers = Qnil, default_drivers = Qnil;
3364 struct font_driver_list *list;
3365
3366
3367
3368 Lisp_Object all_drivers = Qnil;
3369 for (list = f->font_driver_list; list; list = list->next)
3370 all_drivers = Fcons (list->driver->type, all_drivers);
3371 for (Lisp_Object rest = all_drivers; CONSP (rest); rest = XCDR (rest))
3372 {
3373 Lisp_Object superseded_by
3374 = Fget (XCAR (rest), Qfont_driver_superseded_by);
3375
3376 if (NILP (superseded_by)
3377 || NILP (Fmemq (superseded_by, all_drivers)))
3378 default_drivers = Fcons (XCAR (rest), default_drivers);
3379 }
3380
3381 if (EQ (new_drivers, Qt))
3382 new_drivers = default_drivers;
3383
3384
3385
3386 for (list = f->font_driver_list; list; list = list->next)
3387 {
3388 struct font_driver const *driver = list->driver;
3389 if ((! NILP (Fmemq (driver->type, new_drivers))) != list->on)
3390 {
3391 if (list->on)
3392 {
3393 if (driver->end_for_frame)
3394 driver->end_for_frame (f);
3395 font_finish_cache (f, driver);
3396 list->on = 0;
3397 }
3398 else
3399 {
3400 if (! driver->start_for_frame
3401 || driver->start_for_frame (f) == 0)
3402 {
3403 font_prepare_cache (f, driver);
3404 list->on = 1;
3405 }
3406 }
3407 }
3408 }
3409
3410 if (NILP (new_drivers))
3411 return Qnil;
3412 else
3413 {
3414
3415 struct font_driver_list **list_table, **next;
3416 Lisp_Object tail;
3417 int i;
3418 USE_SAFE_ALLOCA;
3419
3420 SAFE_NALLOCA (list_table, 1, num_font_drivers + 1);
3421 for (i = 0, tail = new_drivers; ! NILP (tail); tail = XCDR (tail))
3422 {
3423 for (list = f->font_driver_list; list; list = list->next)
3424 if (list->on && EQ (list->driver->type, XCAR (tail)))
3425 break;
3426 if (list)
3427 list_table[i++] = list;
3428 }
3429 for (list = f->font_driver_list; list; list = list->next)
3430 if (! list->on)
3431 list_table[i++] = list;
3432 list_table[i] = NULL;
3433
3434 next = &f->font_driver_list;
3435 for (i = 0; list_table[i]; i++)
3436 {
3437 *next = list_table[i];
3438 next = &(*next)->next;
3439 }
3440 *next = NULL;
3441 SAFE_FREE ();
3442
3443 if (! f->font_driver_list->on)
3444 {
3445
3446
3447 for (list = f->font_driver_list; list; list = list->next)
3448 {
3449 struct font_driver const *driver = list->driver;
3450 eassert (! list->on);
3451 if (NILP (Fmemq (driver->type, default_drivers)))
3452 continue;
3453 if (! driver->start_for_frame
3454 || driver->start_for_frame (f) == 0)
3455 {
3456 font_prepare_cache (f, driver);
3457 list->on = 1;
3458 }
3459 }
3460 }
3461 }
3462
3463 for (list = f->font_driver_list; list; list = list->next)
3464 if (list->on)
3465 active_drivers = nconc2 (active_drivers, list1 (list->driver->type));
3466 return active_drivers;
3467 }
3468
3469 #if (defined HAVE_XFT || defined HAVE_FREETYPE) && !defined USE_CAIRO
3470
3471 static void
3472 fset_font_data (struct frame *f, Lisp_Object val)
3473 {
3474 f->font_data = val;
3475 }
3476
3477 void
3478 font_put_frame_data (struct frame *f, Lisp_Object driver, void *data)
3479 {
3480 Lisp_Object val = assq_no_quit (driver, f->font_data);
3481
3482 if (!data)
3483 fset_font_data (f, Fdelq (val, f->font_data));
3484 else
3485 {
3486 if (NILP (val))
3487 fset_font_data (f, Fcons (Fcons (driver, make_mint_ptr (data)),
3488 f->font_data));
3489 else
3490 XSETCDR (val, make_mint_ptr (data));
3491 }
3492 }
3493
3494 void *
3495 font_get_frame_data (struct frame *f, Lisp_Object driver)
3496 {
3497 Lisp_Object val = assq_no_quit (driver, f->font_data);
3498
3499 return NILP (val) ? NULL : xmint_pointer (XCDR (val));
3500 }
3501
3502 #endif
3503
3504
3505
3506
3507
3508
3509 void
3510 font_filter_properties (Lisp_Object font,
3511 Lisp_Object alist,
3512 const char *const boolean_properties[],
3513 const char *const non_boolean_properties[])
3514 {
3515 Lisp_Object it;
3516 int i;
3517
3518
3519 for (i = 0; boolean_properties[i] != NULL; ++i)
3520 for (it = alist; ! NILP (it); it = XCDR (it))
3521 {
3522 Lisp_Object key = XCAR (XCAR (it));
3523 Lisp_Object val = XCDR (XCAR (it));
3524 char *keystr = SSDATA (SYMBOL_NAME (key));
3525
3526 if (strcmp (boolean_properties[i], keystr) == 0)
3527 {
3528 const char *str = FIXNUMP (val) ? (XFIXNUM (val) ? "true" : "false")
3529 : SYMBOLP (val) ? SSDATA (SYMBOL_NAME (val))
3530 : "true";
3531
3532 if (strcmp ("false", str) == 0 || strcmp ("False", str) == 0
3533 || strcmp ("FALSE", str) == 0 || strcmp ("FcFalse", str) == 0
3534 || strcmp ("off", str) == 0 || strcmp ("OFF", str) == 0
3535 || strcmp ("Off", str) == 0)
3536 val = Qnil;
3537 else
3538 val = Qt;
3539
3540 Ffont_put (font, key, val);
3541 }
3542 }
3543
3544 for (i = 0; non_boolean_properties[i] != NULL; ++i)
3545 for (it = alist; ! NILP (it); it = XCDR (it))
3546 {
3547 Lisp_Object key = XCAR (XCAR (it));
3548 Lisp_Object val = XCDR (XCAR (it));
3549 char *keystr = SSDATA (SYMBOL_NAME (key));
3550 if (strcmp (non_boolean_properties[i], keystr) == 0)
3551 Ffont_put (font, key, val);
3552 }
3553 }
3554
3555
3556
3557
3558
3559
3560
3561 static Lisp_Object
3562 font_at (int c, ptrdiff_t pos, struct face *face, struct window *w,
3563 Lisp_Object string)
3564 {
3565 struct frame *f;
3566 bool multibyte;
3567 Lisp_Object font_object;
3568
3569 multibyte = (NILP (string)
3570 ? ! NILP (BVAR (current_buffer, enable_multibyte_characters))
3571 : STRING_MULTIBYTE (string));
3572 if (c < 0)
3573 {
3574 if (NILP (string))
3575 {
3576 if (multibyte)
3577 {
3578 ptrdiff_t pos_byte = CHAR_TO_BYTE (pos);
3579
3580 c = FETCH_CHAR (pos_byte);
3581 }
3582 else
3583 c = FETCH_BYTE (pos);
3584 }
3585 else
3586 {
3587 unsigned char *str;
3588
3589 multibyte = STRING_MULTIBYTE (string);
3590 if (multibyte)
3591 {
3592 ptrdiff_t pos_byte = string_char_to_byte (string, pos);
3593
3594 str = SDATA (string) + pos_byte;
3595 c = STRING_CHAR (str);
3596 }
3597 else
3598 c = SDATA (string)[pos];
3599 }
3600 }
3601
3602 f = XFRAME (w->frame);
3603 if (! FRAME_WINDOW_P (f))
3604 return Qnil;
3605 if (! face)
3606 {
3607 int face_id;
3608 ptrdiff_t endptr;
3609
3610 if (STRINGP (string))
3611 face_id = face_at_string_position (w, string, pos, 0, &endptr,
3612 DEFAULT_FACE_ID, false, 0);
3613 else
3614 face_id = face_at_buffer_position (w, pos, &endptr,
3615 pos + 100, false, -1, 0);
3616 face = FACE_FROM_ID (f, face_id);
3617 }
3618 if (multibyte)
3619 {
3620 int face_id = FACE_FOR_CHAR (f, face, c, pos, string);
3621 face = FACE_FROM_ID (f, face_id);
3622 }
3623 if (! face->font)
3624 return Qnil;
3625
3626 XSETFONT (font_object, face->font);
3627 return font_object;
3628 }
3629
3630
3631 #ifdef HAVE_WINDOW_SYSTEM
3632
3633
3634
3635
3636
3637 static bool
3638 codepoint_is_emoji_eligible (int ch)
3639 {
3640 if (EQ (CHAR_TABLE_REF (Vchar_script_table, ch), Qemoji))
3641 return true;
3642
3643 if (! NILP (Fmemq (make_fixnum (ch),
3644 Vauto_composition_emoji_eligible_codepoints)))
3645 return true;
3646
3647 return false;
3648 }
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664 Lisp_Object
3665 font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit,
3666 struct window *w, struct face *face, Lisp_Object string,
3667 int ch)
3668 {
3669 ptrdiff_t ignore;
3670 int c;
3671 Lisp_Object font_object = Qnil;
3672 struct frame *f = XFRAME (w->frame);
3673
3674 if (!face)
3675 {
3676 int face_id;
3677
3678 if (NILP (string))
3679 face_id = face_at_buffer_position (w, pos, &ignore, *limit,
3680 false, -1, 0);
3681 else
3682 {
3683 face_id =
3684 NILP (Vface_remapping_alist)
3685 ? DEFAULT_FACE_ID
3686 : lookup_basic_face (w, f, DEFAULT_FACE_ID);
3687
3688 face_id = face_at_string_position (w, string, pos, 0, &ignore,
3689 face_id, false, 0);
3690 }
3691 face = FACE_FROM_ID (f, face_id);
3692 }
3693
3694
3695
3696
3697 if (codepoint_is_emoji_eligible (ch))
3698 {
3699 Lisp_Object val = assq_no_quit (Qemoji, Vscript_representative_chars);
3700 if (CONSP (val))
3701 {
3702 val = XCDR (val);
3703 if (CONSP (val))
3704 val = XCAR (val);
3705 else if (VECTORP (val))
3706 val = AREF (val, 0);
3707 font_object = font_for_char (face, XFIXNAT (val), pos, string);
3708 }
3709 }
3710
3711 while (pos < *limit)
3712 {
3713 c = (NILP (string)
3714 ? fetch_char_advance_no_check (&pos, &pos_byte)
3715 : fetch_string_char_advance_no_check (string, &pos, &pos_byte));
3716 Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, c);
3717 if (FIXNUMP (category)
3718 && (XFIXNUM (category) == UNICODE_CATEGORY_Cf
3719 || CHAR_VARIATION_SELECTOR_P (c)))
3720 continue;
3721 if (NILP (font_object))
3722 {
3723 font_object = font_for_char (face, c, pos - 1, string);
3724 if (NILP (font_object))
3725 return Qnil;
3726 continue;
3727 }
3728 if (font_encode_char (font_object, c) == FONT_INVALID_CODE)
3729 *limit = pos - 1;
3730 }
3731 return font_object;
3732 }
3733 #endif
3734
3735
3736
3737
3738 DEFUN ("fontp", Ffontp, Sfontp, 1, 2, 0,
3739 doc:
3740
3741
3742
3743 )
3744 (Lisp_Object object, Lisp_Object extra_type)
3745 {
3746 if (NILP (extra_type))
3747 return (FONTP (object) ? Qt : Qnil);
3748 if (EQ (extra_type, Qfont_spec))
3749 return (FONT_SPEC_P (object) ? Qt : Qnil);
3750 if (EQ (extra_type, Qfont_entity))
3751 return (FONT_ENTITY_P (object) ? Qt : Qnil);
3752 if (EQ (extra_type, Qfont_object))
3753 return (FONT_OBJECT_P (object) ? Qt : Qnil);
3754 wrong_type_argument (Qfont_extra_type, extra_type); ;
3755 }
3756
3757 DEFUN ("font-spec", Ffont_spec, Sfont_spec, 0, MANY, 0,
3758 doc:
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840 )
3841 (ptrdiff_t nargs, Lisp_Object *args)
3842 {
3843 Lisp_Object spec = font_make_spec ();
3844 ptrdiff_t i;
3845
3846 for (i = 0; i < nargs; i += 2)
3847 {
3848 Lisp_Object key = args[i], val;
3849
3850 CHECK_SYMBOL (key);
3851 if (i + 1 >= nargs)
3852 error ("No value for key `%s'", SDATA (SYMBOL_NAME (key)));
3853 val = args[i + 1];
3854
3855 if (EQ (key, QCname))
3856 {
3857 CHECK_STRING (val);
3858 if (font_parse_name (SSDATA (val), SBYTES (val), spec) < 0)
3859 error ("Invalid font name: %s", SSDATA (val));
3860 font_put_extra (spec, key, val);
3861 }
3862 else
3863 {
3864 int idx = get_font_prop_index (key);
3865
3866 if (idx >= 0)
3867 {
3868 val = font_prop_validate (idx, Qnil, val);
3869 if (idx < FONT_EXTRA_INDEX)
3870 ASET (spec, idx, val);
3871 else
3872 font_put_extra (spec, key, val);
3873 }
3874 else
3875 font_put_extra (spec, key, font_prop_validate (0, key, val));
3876 }
3877 }
3878 return spec;
3879 }
3880
3881
3882
3883
3884
3885 Lisp_Object
3886 copy_font_spec (Lisp_Object font)
3887 {
3888 enum { font_spec_size = VECSIZE (struct font_spec) };
3889 Lisp_Object new_spec, tail, *pcdr;
3890 struct font_spec *spec;
3891
3892 CHECK_FONT (font);
3893
3894
3895 spec = (struct font_spec *) allocate_vector (font_spec_size);
3896 XSETPVECTYPESIZE (spec, PVEC_FONT, FONT_SPEC_MAX,
3897 font_spec_size - FONT_SPEC_MAX);
3898
3899 spec->props[FONT_TYPE_INDEX] = spec->props[FONT_EXTRA_INDEX] = Qnil;
3900
3901
3902 memcpy (spec->props + 1, XVECTOR (font)->contents + 1,
3903 (FONT_EXTRA_INDEX - 1) * word_size);
3904
3905
3906 pcdr = spec->props + FONT_EXTRA_INDEX;
3907 for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
3908 if (!EQ (XCAR (XCAR (tail)), QCfont_entity))
3909 {
3910 *pcdr = Fcons (Fcons (XCAR (XCAR (tail)), CDR (XCAR (tail))), Qnil);
3911 pcdr = xcdr_addr (*pcdr);
3912 }
3913
3914 XSETFONT (new_spec, spec);
3915 return new_spec;
3916 }
3917
3918
3919
3920
3921 Lisp_Object
3922 merge_font_spec (Lisp_Object from, Lisp_Object to)
3923 {
3924 Lisp_Object extra, tail;
3925 int i;
3926
3927 CHECK_FONT (from);
3928 CHECK_FONT (to);
3929 to = copy_font_spec (to);
3930 for (i = 0; i < FONT_EXTRA_INDEX; i++)
3931 ASET (to, i, AREF (from, i));
3932 extra = AREF (to, FONT_EXTRA_INDEX);
3933 for (tail = AREF (from, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
3934 if (! EQ (XCAR (XCAR (tail)), Qfont_entity))
3935 {
3936 Lisp_Object slot = assq_no_quit (XCAR (XCAR (tail)), extra);
3937
3938 if (! NILP (slot))
3939 XSETCDR (slot, XCDR (XCAR (tail)));
3940 else
3941 extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
3942 }
3943 ASET (to, FONT_EXTRA_INDEX, extra);
3944 return to;
3945 }
3946
3947 DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
3948 doc:
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976 )
3977 (Lisp_Object font, Lisp_Object key)
3978 {
3979 int idx;
3980 Lisp_Object val;
3981
3982 CHECK_FONT (font);
3983 CHECK_SYMBOL (key);
3984
3985 idx = get_font_prop_index (key);
3986 if (idx >= FONT_WEIGHT_INDEX && idx <= FONT_WIDTH_INDEX)
3987 return font_style_symbolic (font, idx, 0);
3988 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
3989 return AREF (font, idx);
3990 val = Fassq (key, AREF (font, FONT_EXTRA_INDEX));
3991 if (NILP (val) && FONT_OBJECT_P (font))
3992 {
3993 struct font *fontp = XFONT_OBJECT (font);
3994
3995 if (EQ (key, QCotf))
3996 {
3997 if (fontp->driver->otf_capability)
3998 val = fontp->driver->otf_capability (fontp);
3999 else
4000 val = Fcons (Qnil, Qnil);
4001 }
4002 else if (EQ (key, QCcombining_capability))
4003 {
4004 if (fontp->driver->combining_capability)
4005 val = fontp->driver->combining_capability (fontp);
4006 }
4007 }
4008 else
4009 val = Fcdr (val);
4010 return val;
4011 }
4012
4013 #ifdef HAVE_WINDOW_SYSTEM
4014
4015 DEFUN ("font-face-attributes", Ffont_face_attributes, Sfont_face_attributes, 1, 2, 0,
4016 doc:
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027 )
4028 (Lisp_Object font, Lisp_Object frame)
4029 {
4030 struct frame *f = decode_live_frame (frame);
4031 Lisp_Object plist[10];
4032 Lisp_Object val;
4033 int n = 0;
4034
4035 if (STRINGP (font))
4036 {
4037 int fontset = fs_query_fontset (font, 0);
4038 Lisp_Object name = font;
4039 if (fontset >= 0)
4040 font = fontset_ascii (fontset);
4041 font = font_spec_from_name (name);
4042 if (! FONTP (font))
4043 signal_error ("Invalid font name", name);
4044 }
4045 else if (! FONTP (font))
4046 signal_error ("Invalid font object", font);
4047
4048 val = AREF (font, FONT_FAMILY_INDEX);
4049 if (! NILP (val))
4050 {
4051 plist[n++] = QCfamily;
4052 plist[n++] = SYMBOL_NAME (val);
4053 }
4054
4055 val = AREF (font, FONT_SIZE_INDEX);
4056 if (FIXNUMP (val))
4057 {
4058 Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
4059 int dpi = FIXNUMP (font_dpi) ? XFIXNUM (font_dpi) : FRAME_RES_Y (f);
4060 plist[n++] = QCheight;
4061 plist[n++] = make_fixnum (PIXEL_TO_POINT (XFIXNUM (val) * 10, dpi));
4062 }
4063 else if (FLOATP (val))
4064 {
4065 plist[n++] = QCheight;
4066 plist[n++] = make_fixnum (10 * (int) XFLOAT_DATA (val));
4067 }
4068
4069 val = FONT_WEIGHT_FOR_FACE (font);
4070 if (! NILP (val))
4071 {
4072 plist[n++] = QCweight;
4073 plist[n++] = val;
4074 }
4075
4076 val = FONT_SLANT_FOR_FACE (font);
4077 if (! NILP (val))
4078 {
4079 plist[n++] = QCslant;
4080 plist[n++] = val;
4081 }
4082
4083 val = FONT_WIDTH_FOR_FACE (font);
4084 if (! NILP (val))
4085 {
4086 plist[n++] = QCwidth;
4087 plist[n++] = val;
4088 }
4089
4090 return Flist (n, plist);
4091 }
4092
4093 #endif
4094
4095 DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
4096 doc:
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106 )
4107 (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
4108 {
4109 int idx;
4110
4111 idx = get_font_prop_index (prop);
4112 if (idx >= 0 && idx < FONT_EXTRA_INDEX)
4113 {
4114 CHECK_FONT_SPEC (font);
4115 ASET (font, idx, font_prop_validate (idx, Qnil, val));
4116 }
4117 else
4118 {
4119 if (EQ (prop, QCname)
4120 || EQ (prop, QCscript)
4121 || EQ (prop, QClang)
4122 || EQ (prop, QCotf))
4123 CHECK_FONT_SPEC (font);
4124 else
4125 CHECK_FONT (font);
4126 font_put_extra (font, prop, font_prop_validate (0, prop, val));
4127 }
4128 return val;
4129 }
4130
4131 DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0,
4132 doc:
4133
4134
4135
4136
4137 )
4138 (Lisp_Object font_spec, Lisp_Object frame, Lisp_Object num, Lisp_Object prefer)
4139 {
4140 struct frame *f = decode_live_frame (frame);
4141 Lisp_Object vec, list;
4142 EMACS_INT n = 0;
4143
4144 CHECK_FONT_SPEC (font_spec);
4145 if (! NILP (num))
4146 {
4147 CHECK_FIXNUM (num);
4148 n = XFIXNUM (num);
4149 if (n <= 0)
4150 return Qnil;
4151 }
4152 if (! NILP (prefer))
4153 CHECK_FONT_SPEC (prefer);
4154
4155 list = font_list_entities (f, font_spec);
4156 if (NILP (list))
4157 return Qnil;
4158 if (NILP (XCDR (list))
4159 && ASIZE (XCAR (list)) == 1)
4160 return list1 (AREF (XCAR (list), 0));
4161
4162 if (! NILP (prefer))
4163 vec = font_sort_entities (list, prefer, f, 0);
4164 else
4165 vec = font_vconcat_entity_vectors (list);
4166 if (n == 0 || n >= ASIZE (vec))
4167 list = CALLN (Fappend, vec, Qnil);
4168 else
4169 {
4170 for (list = Qnil, n--; n >= 0; n--)
4171 list = Fcons (AREF (vec, n), list);
4172 }
4173 return list;
4174 }
4175
4176 DEFUN ("font-family-list", Ffont_family_list, Sfont_family_list, 0, 1, 0,
4177 doc:
4178 )
4179 (Lisp_Object frame)
4180 {
4181 struct frame *f = decode_live_frame (frame);
4182 struct font_driver_list *driver_list;
4183 Lisp_Object list = Qnil;
4184
4185 for (driver_list = f->font_driver_list; driver_list;
4186 driver_list = driver_list->next)
4187 if (driver_list->driver->list_family)
4188 {
4189 Lisp_Object val = driver_list->driver->list_family (f);
4190 Lisp_Object tail = list;
4191
4192 for (; CONSP (val); val = XCDR (val))
4193 if (NILP (Fmemq (XCAR (val), tail))
4194 && SYMBOLP (XCAR (val)))
4195 list = Fcons (SYMBOL_NAME (XCAR (val)), list);
4196 }
4197 return list;
4198 }
4199
4200 DEFUN ("find-font", Ffind_font, Sfind_font, 1, 2, 0,
4201 doc:
4202 )
4203 (Lisp_Object font_spec, Lisp_Object frame)
4204 {
4205 Lisp_Object val = Flist_fonts (font_spec, frame, make_fixnum (1), Qnil);
4206
4207 if (CONSP (val))
4208 val = XCAR (val);
4209 return val;
4210 }
4211
4212 DEFUN ("font-xlfd-name", Ffont_xlfd_name, Sfont_xlfd_name, 1, 2, 0,
4213 doc:
4214
4215
4216
4217 )
4218 (Lisp_Object font, Lisp_Object fold_wildcards)
4219 {
4220 char name[256];
4221 int namelen, pixel_size = 0;
4222
4223 CHECK_FONT (font);
4224
4225 if (FONT_OBJECT_P (font))
4226 {
4227 Lisp_Object font_name = AREF (font, FONT_NAME_INDEX);
4228
4229 if (STRINGP (font_name)
4230 && SDATA (font_name)[0] == '-')
4231 {
4232 if (NILP (fold_wildcards))
4233 return font_name;
4234 lispstpcpy (name, font_name);
4235 namelen = SBYTES (font_name);
4236 goto done;
4237 }
4238 pixel_size = XFONT_OBJECT (font)->pixel_size;
4239 }
4240 namelen = font_unparse_xlfd (font, pixel_size, name, 256);
4241 if (namelen < 0)
4242 return Qnil;
4243 done:
4244 if (! NILP (fold_wildcards))
4245 {
4246 char *p0 = name, *p1;
4247
4248 while ((p1 = strstr (p0, "-*-*")))
4249 {
4250 memmove (p1, p1 + 2, (name + namelen + 1) - (p1 + 2));
4251 namelen -= 2;
4252 p0 = p1;
4253 }
4254 }
4255
4256 return make_string (name, namelen);
4257 }
4258
4259 void
4260 clear_font_cache (struct frame *f)
4261 {
4262 struct font_driver_list *driver_list = f->font_driver_list;
4263
4264 for (; driver_list; driver_list = driver_list->next)
4265 if (driver_list->on)
4266 {
4267 Lisp_Object val, tmp, cache = driver_list->driver->get_cache (f);
4268
4269 val = XCDR (cache);
4270 while (eassert (CONSP (val)),
4271 ! EQ (XCAR (XCAR (val)), driver_list->driver->type))
4272 val = XCDR (val);
4273 tmp = XCDR (XCAR (val));
4274 if (XFIXNUM (XCAR (tmp)) == 0)
4275 {
4276 font_clear_cache (f, XCAR (val), driver_list->driver);
4277 XSETCDR (cache, XCDR (val));
4278 }
4279 }
4280 }
4281
4282 DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
4283 doc: )
4284 (void)
4285 {
4286 Lisp_Object list, frame;
4287
4288 FOR_EACH_FRAME (list, frame)
4289 clear_font_cache (XFRAME (frame));
4290
4291 return Qnil;
4292 }
4293
4294
4295 void
4296 font_fill_lglyph_metrics (Lisp_Object glyph, struct font *font, unsigned int code)
4297 {
4298 struct font_metrics metrics;
4299
4300 LGLYPH_SET_CODE (glyph, code);
4301 font->driver->text_extents (font, &code, 1, &metrics);
4302 LGLYPH_SET_LBEARING (glyph, metrics.lbearing);
4303 LGLYPH_SET_RBEARING (glyph, metrics.rbearing);
4304 LGLYPH_SET_WIDTH (glyph, metrics.width);
4305 LGLYPH_SET_ASCENT (glyph, metrics.ascent);
4306 LGLYPH_SET_DESCENT (glyph, metrics.descent);
4307 }
4308
4309
4310 DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 2, 2, 0,
4311 doc:
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324 )
4325 (Lisp_Object gstring, Lisp_Object direction)
4326 {
4327 struct font *font;
4328 Lisp_Object font_object, n, glyph;
4329 ptrdiff_t i, from, to;
4330
4331 if (! composition_gstring_p (gstring))
4332 signal_error ("Invalid glyph-string: ", gstring);
4333 if (! NILP (LGSTRING_ID (gstring)))
4334 return gstring;
4335 Lisp_Object cached_gstring =
4336 composition_gstring_lookup_cache (LGSTRING_HEADER (gstring));
4337 if (! NILP (cached_gstring))
4338 return cached_gstring;
4339 font_object = LGSTRING_FONT (gstring);
4340 CHECK_FONT_OBJECT (font_object);
4341 font = XFONT_OBJECT (font_object);
4342 if (! font->driver->shape)
4343 return Qnil;
4344
4345
4346 for (i = 0; i < 3; i++)
4347 {
4348 n = font->driver->shape (gstring, direction);
4349 if (FIXNUMP (n))
4350 break;
4351 gstring = larger_vector (gstring,
4352 LGSTRING_GLYPH_LEN (gstring), -1);
4353 }
4354 if (i == 3 || XFIXNUM (n) == 0)
4355 return Qnil;
4356 if (XFIXNUM (n) < LGSTRING_GLYPH_LEN (gstring))
4357 LGSTRING_SET_GLYPH (gstring, XFIXNUM (n), Qnil);
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373 glyph = LGSTRING_GLYPH (gstring, 0);
4374 from = LGLYPH_FROM (glyph);
4375 to = LGLYPH_TO (glyph);
4376 if (from != 0 || to < from)
4377 goto shaper_error;
4378 for (i = 1; i < LGSTRING_GLYPH_LEN (gstring); i++)
4379 {
4380 glyph = LGSTRING_GLYPH (gstring, i);
4381 if (NILP (glyph))
4382 break;
4383 if (! (LGLYPH_FROM (glyph) <= LGLYPH_TO (glyph)
4384 && (LGLYPH_FROM (glyph) == from
4385 ? LGLYPH_TO (glyph) == to
4386 : LGLYPH_FROM (glyph) == to + 1)))
4387 goto shaper_error;
4388 from = LGLYPH_FROM (glyph);
4389 to = LGLYPH_TO (glyph);
4390 }
4391 composition_gstring_adjust_zero_width (gstring);
4392 return composition_gstring_put_cache (gstring, XFIXNUM (n));
4393
4394 shaper_error:
4395 return Qnil;
4396 }
4397
4398 DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
4399 2, 2, 0,
4400 doc:
4401
4402
4403
4404
4405 )
4406 (Lisp_Object font_object, Lisp_Object character)
4407 {
4408 unsigned variations[256];
4409 struct font *font;
4410 int i, n;
4411 Lisp_Object val;
4412
4413 CHECK_FONT_OBJECT (font_object);
4414 CHECK_CHARACTER (character);
4415 font = XFONT_OBJECT (font_object);
4416 if (! font->driver->get_variation_glyphs)
4417 return Qnil;
4418 n = font->driver->get_variation_glyphs (font, XFIXNUM (character), variations);
4419 if (! n)
4420 return Qnil;
4421 val = Qnil;
4422 for (i = 0; i < 255; i++)
4423 if (variations[i])
4424 {
4425 int vs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
4426 Lisp_Object code = INT_TO_INTEGER (variations[i]);
4427 val = Fcons (Fcons (make_fixnum (vs), code), val);
4428 }
4429 return val;
4430 }
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468 DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0,
4469 doc: )
4470 (Lisp_Object position, Lisp_Object ch)
4471 {
4472 ptrdiff_t pos, pos_byte, dummy;
4473 int face_id;
4474 int c;
4475 struct frame *f;
4476
4477 if (NILP (position))
4478 {
4479 CHECK_CHARACTER (ch);
4480 c = XFIXNUM (ch);
4481 f = XFRAME (selected_frame);
4482 face_id = lookup_basic_face (NULL, f, DEFAULT_FACE_ID);
4483 pos = -1;
4484 }
4485 else
4486 {
4487 Lisp_Object window;
4488 struct window *w;
4489
4490 EMACS_INT fixed_pos = fix_position (position);
4491 if (! (BEGV <= fixed_pos && fixed_pos < ZV))
4492 args_out_of_range_3 (position, make_fixnum (BEGV), make_fixnum (ZV));
4493 pos = fixed_pos;
4494 pos_byte = CHAR_TO_BYTE (pos);
4495 if (NILP (ch))
4496 c = FETCH_CHAR (pos_byte);
4497 else
4498 {
4499 CHECK_FIXNAT (ch);
4500 c = XFIXNUM (ch);
4501 }
4502 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
4503 if (NILP (window))
4504 return Qnil;
4505 w = XWINDOW (window);
4506 f = XFRAME (w->frame);
4507 face_id = face_at_buffer_position (w, pos, &dummy,
4508 pos + 100, false, -1, 0);
4509 }
4510 if (! CHAR_VALID_P (c))
4511 return Qnil;
4512
4513 if (! FRAME_WINDOW_P (f))
4514 return terminal_glyph_code (FRAME_TERMINAL (f), c);
4515
4516
4517
4518 if (FRAME_FACE_CACHE (f)->used == 0)
4519 recompute_basic_faces (f);
4520
4521 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c, pos, Qnil);
4522 struct face *face = FACE_FROM_ID (f, face_id);
4523 if (! face->font)
4524 return Qnil;
4525 unsigned code = face->font->driver->encode_char (face->font, c);
4526 if (code == FONT_INVALID_CODE)
4527 return Qnil;
4528 Lisp_Object font_object;
4529 XSETFONT (font_object, face->font);
4530 return Fcons (font_object, INT_TO_INTEGER (code));
4531 }
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544 #if 0
4545
4546 #define LGSTRING_HEADER_SIZE 6
4547 #define LGSTRING_GLYPH_SIZE 8
4548
4549 static int
4550 check_gstring (Lisp_Object gstring)
4551 {
4552 Lisp_Object val;
4553 ptrdiff_t i;
4554 int j;
4555
4556 CHECK_VECTOR (gstring);
4557 val = AREF (gstring, 0);
4558 CHECK_VECTOR (val);
4559 if (ASIZE (val) < LGSTRING_HEADER_SIZE)
4560 goto err;
4561 CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
4562 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING)))
4563 CHECK_FIXNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_LBEARING));
4564 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING)))
4565 CHECK_FIXNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_RBEARING));
4566 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH)))
4567 CHECK_FIXNAT (LGSTRING_SLOT (gstring, LGSTRING_IX_WIDTH));
4568 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
4569 CHECK_FIXNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
4570 if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
4571 CHECK_FIXNUM (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
4572
4573 for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
4574 {
4575 val = LGSTRING_GLYPH (gstring, i);
4576 CHECK_VECTOR (val);
4577 if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
4578 goto err;
4579 if (NILP (AREF (val, LGLYPH_IX_CHAR)))
4580 break;
4581 CHECK_FIXNAT (AREF (val, LGLYPH_IX_FROM));
4582 CHECK_FIXNAT (AREF (val, LGLYPH_IX_TO));
4583 CHECK_CHARACTER (AREF (val, LGLYPH_IX_CHAR));
4584 if (!NILP (AREF (val, LGLYPH_IX_CODE)))
4585 CHECK_FIXNAT (AREF (val, LGLYPH_IX_CODE));
4586 if (!NILP (AREF (val, LGLYPH_IX_WIDTH)))
4587 CHECK_FIXNAT (AREF (val, LGLYPH_IX_WIDTH));
4588 if (!NILP (AREF (val, LGLYPH_IX_ADJUSTMENT)))
4589 {
4590 val = AREF (val, LGLYPH_IX_ADJUSTMENT);
4591 CHECK_VECTOR (val);
4592 if (ASIZE (val) < 3)
4593 goto err;
4594 for (j = 0; j < 3; j++)
4595 CHECK_FIXNUM (AREF (val, j));
4596 }
4597 }
4598 return i;
4599 err:
4600 error ("Invalid glyph-string format");
4601 return -1;
4602 }
4603
4604 static void
4605 check_otf_features (Lisp_Object otf_features)
4606 {
4607 Lisp_Object val;
4608
4609 CHECK_CONS (otf_features);
4610 CHECK_SYMBOL (XCAR (otf_features));
4611 otf_features = XCDR (otf_features);
4612 CHECK_CONS (otf_features);
4613 CHECK_SYMBOL (XCAR (otf_features));
4614 otf_features = XCDR (otf_features);
4615 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
4616 {
4617 CHECK_SYMBOL (XCAR (val));
4618 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
4619 error ("Invalid OTF GSUB feature: %s",
4620 SDATA (SYMBOL_NAME (XCAR (val))));
4621 }
4622 otf_features = XCDR (otf_features);
4623 for (val = Fcar (otf_features); CONSP (val); val = XCDR (val))
4624 {
4625 CHECK_SYMBOL (XCAR (val));
4626 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
4627 error ("Invalid OTF GPOS feature: %s",
4628 SDATA (SYMBOL_NAME (XCAR (val))));
4629 }
4630 }
4631
4632 #ifdef HAVE_LIBOTF
4633 #include <otf.h>
4634
4635 Lisp_Object otf_list;
4636
4637 static Lisp_Object
4638 otf_tag_symbol (OTF_Tag tag)
4639 {
4640 char name[5];
4641
4642 OTF_tag_name (tag, name);
4643 return Fintern (make_unibyte_string (name, 4), Qnil);
4644 }
4645
4646 static OTF *
4647 otf_open (Lisp_Object file)
4648 {
4649 Lisp_Object val = Fassoc (file, otf_list, Qnil);
4650 OTF *otf;
4651
4652 if (! NILP (val))
4653 otf = xmint_pointer (XCDR (val));
4654 else
4655 {
4656 otf = STRINGP (file) ? OTF_open (SSDATA (file)) : NULL;
4657 val = make_mint_ptr (otf);
4658 otf_list = Fcons (Fcons (file, val), otf_list);
4659 }
4660 return otf;
4661 }
4662
4663
4664
4665
4666
4667
4668 Lisp_Object
4669 font_otf_capability (struct font *font)
4670 {
4671 OTF *otf;
4672 Lisp_Object capability = Fcons (Qnil, Qnil);
4673 int i;
4674
4675 otf = otf_open (font->props[FONT_FILE_INDEX]);
4676 if (! otf)
4677 return Qnil;
4678 for (i = 0; i < 2; i++)
4679 {
4680 OTF_GSUB_GPOS *gsub_gpos;
4681 Lisp_Object script_list = Qnil;
4682 int j;
4683
4684 if (OTF_get_features (otf, i == 0) < 0)
4685 continue;
4686 gsub_gpos = i == 0 ? otf->gsub : otf->gpos;
4687 for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--)
4688 {
4689 OTF_Script *script = gsub_gpos->ScriptList.Script + j;
4690 Lisp_Object langsys_list = Qnil;
4691 Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag);
4692 int k;
4693
4694 for (k = script->LangSysCount; k >= 0; k--)
4695 {
4696 OTF_LangSys *langsys;
4697 Lisp_Object feature_list = Qnil;
4698 Lisp_Object langsys_tag;
4699 int l;
4700
4701 if (k == script->LangSysCount)
4702 {
4703 langsys = &script->DefaultLangSys;
4704 langsys_tag = Qnil;
4705 }
4706 else
4707 {
4708 langsys = script->LangSys + k;
4709 langsys_tag
4710 = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
4711 }
4712 for (l = langsys->FeatureCount - 1; l >= 0; l--)
4713 {
4714 OTF_Feature *feature
4715 = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
4716 Lisp_Object feature_tag
4717 = otf_tag_symbol (feature->FeatureTag);
4718
4719 feature_list = Fcons (feature_tag, feature_list);
4720 }
4721 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
4722 langsys_list);
4723 }
4724 script_list = Fcons (Fcons (script_tag, langsys_list),
4725 script_list);
4726 }
4727
4728 if (i == 0)
4729 XSETCAR (capability, script_list);
4730 else
4731 XSETCDR (capability, script_list);
4732 }
4733
4734 return capability;
4735 }
4736
4737
4738
4739
4740
4741
4742 static void
4743 generate_otf_features (Lisp_Object spec, char *features)
4744 {
4745 Lisp_Object val;
4746 char *p;
4747 bool asterisk;
4748
4749 p = features;
4750 *p = '\0';
4751 for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
4752 {
4753 val = XCAR (spec);
4754 CHECK_SYMBOL (val);
4755 if (p > features)
4756 *p++ = ',';
4757 if (SREF (SYMBOL_NAME (val), 0) == '*')
4758 {
4759 asterisk = 1;
4760 *p++ = '*';
4761 }
4762 else if (! asterisk)
4763 {
4764 val = SYMBOL_NAME (val);
4765 p += esprintf (p, "%s", SDATA (val));
4766 }
4767 else
4768 {
4769 val = SYMBOL_NAME (val);
4770 p += esprintf (p, "~%s", SDATA (val));
4771 }
4772 }
4773 if (CONSP (spec))
4774 error ("OTF spec too long");
4775 }
4776
4777 Lisp_Object
4778 font_otf_DeviceTable (OTF_DeviceTable *device_table)
4779 {
4780 int len = device_table->StartSize - device_table->EndSize + 1;
4781
4782 return Fcons (make_fixnum (len),
4783 make_unibyte_string (device_table->DeltaValue, len));
4784 }
4785
4786 Lisp_Object
4787 font_otf_ValueRecord (int value_format, OTF_ValueRecord *value_record)
4788 {
4789 Lisp_Object val = make_nil_vector (8);
4790
4791 if (value_format & OTF_XPlacement)
4792 ASET (val, 0, make_fixnum (value_record->XPlacement));
4793 if (value_format & OTF_YPlacement)
4794 ASET (val, 1, make_fixnum (value_record->YPlacement));
4795 if (value_format & OTF_XAdvance)
4796 ASET (val, 2, make_fixnum (value_record->XAdvance));
4797 if (value_format & OTF_YAdvance)
4798 ASET (val, 3, make_fixnum (value_record->YAdvance));
4799 if (value_format & OTF_XPlaDevice)
4800 ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
4801 if (value_format & OTF_YPlaDevice)
4802 ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
4803 if (value_format & OTF_XAdvDevice)
4804 ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
4805 if (value_format & OTF_YAdvDevice)
4806 ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
4807 return val;
4808 }
4809
4810 Lisp_Object
4811 font_otf_Anchor (OTF_Anchor *anchor)
4812 {
4813 Lisp_Object val = make_nil_vector (anchor->AnchorFormat + 1);
4814 ASET (val, 0, make_fixnum (anchor->XCoordinate));
4815 ASET (val, 1, make_fixnum (anchor->YCoordinate));
4816 if (anchor->AnchorFormat == 2)
4817 ASET (val, 2, make_fixnum (anchor->f.f1.AnchorPoint));
4818 else
4819 {
4820 ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
4821 ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
4822 }
4823 return val;
4824 }
4825 #endif
4826
4827 DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
4828 doc:
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858 )
4859 (Lisp_Object otf_features, Lisp_Object gstring_in, Lisp_Object from, Lisp_Object to, Lisp_Object gstring_out, Lisp_Object index)
4860 {
4861 Lisp_Object font_object = LGSTRING_FONT (gstring_in);
4862 Lisp_Object val;
4863 struct font *font;
4864 int len, num;
4865
4866 check_otf_features (otf_features);
4867 CHECK_FONT_OBJECT (font_object);
4868 font = XFONT_OBJECT (font_object);
4869 if (! font->driver->otf_drive)
4870 error ("Font backend %s can't drive OpenType GSUB table",
4871 SDATA (SYMBOL_NAME (font->driver->type)));
4872 CHECK_CONS (otf_features);
4873 CHECK_SYMBOL (XCAR (otf_features));
4874 val = XCDR (otf_features);
4875 CHECK_SYMBOL (XCAR (val));
4876 val = XCDR (otf_features);
4877 if (! NILP (val))
4878 CHECK_CONS (val);
4879 len = check_gstring (gstring_in);
4880 CHECK_VECTOR (gstring_out);
4881 CHECK_FIXNAT (from);
4882 CHECK_FIXNAT (to);
4883 CHECK_FIXNAT (index);
4884
4885 if (XFIXNUM (from) >= XFIXNUM (to) || XFIXNUM (to) > len)
4886 args_out_of_range_3 (from, to, make_fixnum (len));
4887 if (XFIXNUM (index) >= ASIZE (gstring_out))
4888 args_out_of_range (index, make_fixnum (ASIZE (gstring_out)));
4889 num = font->driver->otf_drive (font, otf_features,
4890 gstring_in, XFIXNUM (from), XFIXNUM (to),
4891 gstring_out, XFIXNUM (index), 0);
4892 if (num < 0)
4893 return Qnil;
4894 return make_fixnum (num);
4895 }
4896
4897 DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
4898 3, 3, 0,
4899 doc:
4900
4901
4902
4903
4904
4905
4906
4907
4908 )
4909 (Lisp_Object font_object, Lisp_Object character, Lisp_Object otf_features)
4910 {
4911 struct font *font = CHECK_FONT_GET_OBJECT (font_object);
4912 Lisp_Object gstring_in, gstring_out, g;
4913 Lisp_Object alternates;
4914 int i, num;
4915
4916 if (! font->driver->otf_drive)
4917 error ("Font backend %s can't drive OpenType GSUB table",
4918 SDATA (SYMBOL_NAME (font->driver->type)));
4919 CHECK_CHARACTER (character);
4920 CHECK_CONS (otf_features);
4921
4922 gstring_in = Ffont_make_gstring (font_object, make_fixnum (1));
4923 g = LGSTRING_GLYPH (gstring_in, 0);
4924 LGLYPH_SET_CHAR (g, XFIXNUM (character));
4925 gstring_out = Ffont_make_gstring (font_object, make_fixnum (10));
4926 while ((num = font->driver->otf_drive (font, otf_features, gstring_in, 0, 1,
4927 gstring_out, 0, 1)) < 0)
4928 gstring_out = Ffont_make_gstring (font_object,
4929 make_fixnum (ASIZE (gstring_out) * 2));
4930 alternates = Qnil;
4931 for (i = 0; i < num; i++)
4932 {
4933 Lisp_Object g = LGSTRING_GLYPH (gstring_out, i);
4934 int c = LGLYPH_CHAR (g);
4935 unsigned code = LGLYPH_CODE (g);
4936
4937 alternates = Fcons (Fcons (make_fixnum (code),
4938 c > 0 ? make_fixnum (c) : Qnil),
4939 alternates);
4940 }
4941 return Fnreverse (alternates);
4942 }
4943 #endif
4944
4945
4946 #ifdef FONT_DEBUG
4947
4948 DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0,
4949 doc: )
4950 (Lisp_Object font_entity, Lisp_Object size, Lisp_Object frame)
4951 {
4952 intmax_t isize;
4953 struct frame *f = decode_live_frame (frame);
4954
4955 CHECK_FONT_ENTITY (font_entity);
4956
4957 if (NILP (size))
4958 isize = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
4959 else
4960 {
4961 CHECK_NUMBER (size);
4962 if (FLOATP (size))
4963 isize = POINT_TO_PIXEL (XFLOAT_DATA (size), FRAME_RES_Y (f));
4964 else if (! integer_to_intmax (size, &isize))
4965 args_out_of_range (font_entity, size);
4966 if (! (INT_MIN <= isize && isize <= INT_MAX))
4967 args_out_of_range (font_entity, size);
4968 if (isize == 0)
4969 isize = 120;
4970 }
4971 return font_open_entity (f, font_entity, isize);
4972 }
4973
4974 DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0,
4975 doc: )
4976 (Lisp_Object font_object, Lisp_Object frame)
4977 {
4978 CHECK_FONT_OBJECT (font_object);
4979 font_close_object (decode_live_frame (frame), font_object);
4980 return Qnil;
4981 }
4982
4983 DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
4984 doc:
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023 )
5024 (Lisp_Object font_object)
5025 {
5026 struct font *font = CHECK_FONT_GET_OBJECT (font_object);
5027 return CALLN (Fvector,
5028 AREF (font_object, FONT_NAME_INDEX),
5029 AREF (font_object, FONT_FILE_INDEX),
5030 make_fixnum (font->pixel_size),
5031 make_fixnum (font->max_width),
5032 make_fixnum (font->ascent),
5033 make_fixnum (font->descent),
5034 make_fixnum (font->space_width),
5035 make_fixnum (font->average_width),
5036 (font->driver->otf_capability
5037 ? Fcons (Qopentype, font->driver->otf_capability (font))
5038 : Qnil));
5039 }
5040
5041 DEFUN ("font-has-char-p", Ffont_has_char_p, Sfont_has_char_p, 2, 3, 0,
5042 doc:
5043
5044
5045
5046
5047 )
5048 (Lisp_Object font, Lisp_Object ch, Lisp_Object frame)
5049 {
5050 struct frame *f;
5051 CHECK_FONT (font);
5052 CHECK_CHARACTER (ch);
5053
5054 if (NILP (frame))
5055 f = XFRAME (selected_frame);
5056 else
5057 {
5058 CHECK_FRAME (frame);
5059 f = XFRAME (frame);
5060 }
5061
5062 if (font_has_char (f, font, XFIXNAT (ch)) <= 0)
5063 return Qnil;
5064 else
5065 return Qt;
5066 }
5067
5068 DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
5069 doc:
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092 )
5093 (Lisp_Object font_object, Lisp_Object from, Lisp_Object to,
5094 Lisp_Object object)
5095 {
5096 struct font *font = CHECK_FONT_GET_OBJECT (font_object);
5097 ptrdiff_t len;
5098 Lisp_Object *chars;
5099 USE_SAFE_ALLOCA;
5100
5101 if (NILP (object))
5102 {
5103 ptrdiff_t charpos, bytepos;
5104
5105 validate_region (&from, &to);
5106 if (EQ (from, to))
5107 return Qnil;
5108 len = XFIXNAT (to) - XFIXNAT (from);
5109 SAFE_ALLOCA_LISP (chars, len);
5110 charpos = XFIXNAT (from);
5111 bytepos = CHAR_TO_BYTE (charpos);
5112 for (ptrdiff_t i = 0; charpos < XFIXNAT (to); i++)
5113 {
5114 int c = fetch_char_advance (&charpos, &bytepos);
5115 chars[i] = make_fixnum (c);
5116 }
5117 }
5118 else if (STRINGP (object))
5119 {
5120 const unsigned char *p;
5121 ptrdiff_t ifrom, ito;
5122
5123 validate_subarray (object, from, to, SCHARS (object), &ifrom, &ito);
5124 if (ifrom == ito)
5125 return Qnil;
5126 len = ito - ifrom;
5127 SAFE_ALLOCA_LISP (chars, len);
5128 p = SDATA (object);
5129 if (STRING_MULTIBYTE (object))
5130 {
5131 int c;
5132
5133
5134 for (ptrdiff_t i = 0; i < ifrom; i++)
5135 p += BYTES_BY_CHAR_HEAD (*p);
5136
5137
5138 for (ptrdiff_t i = 0; i < len; i++)
5139 {
5140 c = string_char_advance (&p);
5141 chars[i] = make_fixnum (c);
5142 }
5143 }
5144 else
5145 for (ptrdiff_t i = 0; i < len; i++)
5146 chars[i] = make_fixnum (p[ifrom + i]);
5147 }
5148 else if (VECTORP (object))
5149 {
5150 ptrdiff_t ifrom, ito;
5151
5152 validate_subarray (object, from, to, ASIZE (object), &ifrom, &ito);
5153 if (ifrom == ito)
5154 return Qnil;
5155 len = ito - ifrom;
5156 for (ptrdiff_t i = 0; i < len; i++)
5157 {
5158 Lisp_Object elt = AREF (object, ifrom + i);
5159 CHECK_CHARACTER (elt);
5160 }
5161 chars = aref_addr (object, ifrom);
5162 }
5163 else
5164 wrong_type_argument (Qarrayp, object);
5165
5166 Lisp_Object vec = make_nil_vector (len);
5167 for (ptrdiff_t i = 0; i < len; i++)
5168 {
5169 Lisp_Object g;
5170 int c = XFIXNAT (chars[i]);
5171 unsigned code;
5172 struct font_metrics metrics;
5173
5174 code = font->driver->encode_char (font, c);
5175 if (code == FONT_INVALID_CODE)
5176 {
5177 ASET (vec, i, Qnil);
5178 continue;
5179 }
5180 g = LGLYPH_NEW ();
5181 LGLYPH_SET_FROM (g, i);
5182 LGLYPH_SET_TO (g, i);
5183 LGLYPH_SET_CHAR (g, c);
5184 LGLYPH_SET_CODE (g, code);
5185 font->driver->text_extents (font, &code, 1, &metrics);
5186 LGLYPH_SET_WIDTH (g, metrics.width);
5187 LGLYPH_SET_LBEARING (g, metrics.lbearing);
5188 LGLYPH_SET_RBEARING (g, metrics.rbearing);
5189 LGLYPH_SET_ASCENT (g, metrics.ascent);
5190 LGLYPH_SET_DESCENT (g, metrics.descent);
5191 ASET (vec, i, g);
5192 }
5193 if (! VECTORP (object))
5194 SAFE_FREE ();
5195 return vec;
5196 }
5197
5198 DEFUN ("font-match-p", Ffont_match_p, Sfont_match_p, 2, 2, 0,
5199 doc:
5200 )
5201 (Lisp_Object spec, Lisp_Object font)
5202 {
5203 CHECK_FONT_SPEC (spec);
5204 CHECK_FONT (font);
5205
5206 return (font_match_p (spec, font) ? Qt : Qnil);
5207 }
5208
5209 DEFUN ("font-at", Ffont_at, Sfont_at, 1, 3, 0,
5210 doc:
5211
5212
5213
5214 )
5215 (Lisp_Object position, Lisp_Object window, Lisp_Object string)
5216 {
5217 struct window *w = decode_live_window (window);
5218 EMACS_INT pos;
5219
5220 if (NILP (string))
5221 {
5222 if (XBUFFER (w->contents) != current_buffer)
5223 error ("Specified window is not displaying the current buffer");
5224 pos = fix_position (position);
5225 if (! (BEGV <= pos && pos < ZV))
5226 args_out_of_range_3 (position, make_fixnum (BEGV), make_fixnum (ZV));
5227 }
5228 else
5229 {
5230 CHECK_FIXNUM (position);
5231 CHECK_STRING (string);
5232 pos = XFIXNUM (position);
5233 if (! (0 <= pos && pos < SCHARS (string)))
5234 args_out_of_range (string, position);
5235 }
5236
5237 return font_at (-1, pos, NULL, w, string);
5238 }
5239
5240 #if 0
5241 DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
5242 doc:
5243
5244 )
5245 (Lisp_Object font_object, Lisp_Object string)
5246 {
5247 Lisp_Object frame = selected_frame;
5248 struct frame *f = XFRAME (frame);
5249 struct font *font;
5250 struct face *face;
5251 int i, len, width;
5252 unsigned *code;
5253
5254 CHECK_FONT_GET_OBJECT (font_object, font);
5255 CHECK_STRING (string);
5256 len = SCHARS (string);
5257 code = alloca (sizeof (unsigned) * len);
5258 for (i = 0; i < len; i++)
5259 {
5260 Lisp_Object ch = Faref (string, make_fixnum (i));
5261 Lisp_Object val;
5262 int c = XFIXNUM (ch);
5263
5264 code[i] = font->driver->encode_char (font, c);
5265 if (code[i] == FONT_INVALID_CODE)
5266 break;
5267 }
5268 face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
5269 face->fontp = font;
5270 if (font->driver->prepare_face)
5271 font->driver->prepare_face (f, face);
5272 width = font->driver->text_extents (font, code, i, NULL);
5273 len = font->driver->draw_text (f, face, 0, font->ascent, code, i, width);
5274 if (font->driver->done_face)
5275 font->driver->done_face (f, face);
5276 face->fontp = NULL;
5277 return make_fixnum (len);
5278 }
5279 #endif
5280
5281 DEFUN ("frame-font-cache", Fframe_font_cache, Sframe_font_cache, 0, 1, 0,
5282 doc:
5283 )
5284 (Lisp_Object frame)
5285 {
5286 #ifdef HAVE_WINDOW_SYSTEM
5287 struct frame *f = decode_live_frame (frame);
5288
5289 if (FRAME_WINDOW_P (f))
5290 return FRAME_DISPLAY_INFO (f)->name_list_element;
5291 else
5292 #endif
5293 return Qnil;
5294 }
5295
5296 #endif
5297
5298 #ifdef HAVE_WINDOW_SYSTEM
5299
5300 DEFUN ("font-info", Ffont_info, Sfont_info, 1, 2, 0,
5301 doc:
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342 )
5343 (Lisp_Object name, Lisp_Object frame)
5344 {
5345 struct frame *f;
5346 struct font *font;
5347 Lisp_Object info;
5348 Lisp_Object font_object;
5349
5350 if (! FONTP (name))
5351 CHECK_STRING (name);
5352 f = decode_window_system_frame (frame);
5353
5354 if (STRINGP (name))
5355 {
5356 int fontset = fs_query_fontset (name, 0);
5357
5358 if (fontset >= 0)
5359 name = fontset_ascii (fontset);
5360 font_object = font_open_by_name (f, name);
5361 }
5362 else if (FONT_OBJECT_P (name))
5363 font_object = name;
5364 else if (FONT_ENTITY_P (name))
5365 font_object = font_open_entity (f, name, 0);
5366 else
5367 {
5368 struct face *face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
5369 Lisp_Object entity = font_matching_entity (f, face->lface, name);
5370
5371 font_object = ! NILP (entity) ? font_open_entity (f, entity, 0) : Qnil;
5372 }
5373 if (NILP (font_object))
5374 return Qnil;
5375 font = XFONT_OBJECT (font_object);
5376
5377
5378 eassert (XFONT_OBJECT (font_object)->max_width < 1024 * 1024 * 1024);
5379
5380 info = CALLN (Fvector,
5381 AREF (font_object, FONT_NAME_INDEX),
5382 AREF (font_object, FONT_FULLNAME_INDEX),
5383 make_fixnum (font->pixel_size),
5384 make_fixnum (font->height),
5385 make_fixnum (font->baseline_offset),
5386 make_fixnum (font->relative_compose),
5387 make_fixnum (font->default_ascent),
5388 make_fixnum (font->max_width),
5389 make_fixnum (font->ascent),
5390 make_fixnum (font->descent),
5391 make_fixnum (font->space_width),
5392 make_fixnum (font->average_width),
5393 AREF (font_object, FONT_FILE_INDEX),
5394 (font->driver->otf_capability
5395 ? Fcons (Qopentype, font->driver->otf_capability (font))
5396 : Qnil));
5397
5398 #if 0
5399
5400
5401
5402 font_close_object (f, font_object);
5403 #endif
5404 return info;
5405 }
5406 #endif
5407
5408
5409 #define BUILD_STYLE_TABLE(TBL) build_style_table (TBL, ARRAYELTS (TBL))
5410
5411 static Lisp_Object
5412 build_style_table (const struct table_entry *entry, int nelement)
5413 {
5414 Lisp_Object table = make_nil_vector (nelement);
5415 for (int i = 0; i < nelement; i++)
5416 {
5417 int j;
5418 for (j = 0; entry[i].names[j]; j++)
5419 continue;
5420 Lisp_Object elt = make_nil_vector (j + 1);
5421 ASET (elt, 0, make_fixnum (entry[i].numeric));
5422 for (j = 0; entry[i].names[j]; j++)
5423 ASET (elt, j + 1, intern_c_string (entry[i].names[j]));
5424 ASET (table, i, elt);
5425 }
5426 return table;
5427 }
5428
5429
5430
5431
5432 static Lisp_Object Vfont_log_deferred;
5433
5434
5435
5436
5437
5438 void
5439 font_add_log (const char *action, Lisp_Object arg, Lisp_Object result)
5440 {
5441 Lisp_Object val;
5442 int i;
5443
5444 if (EQ (Vfont_log, Qt))
5445 return;
5446 if (STRINGP (AREF (Vfont_log_deferred, 0)))
5447 {
5448 char *str = SSDATA (AREF (Vfont_log_deferred, 0));
5449
5450 ASET (Vfont_log_deferred, 0, Qnil);
5451 font_add_log (str, AREF (Vfont_log_deferred, 1),
5452 AREF (Vfont_log_deferred, 2));
5453 }
5454
5455 if (FONTP (arg))
5456 {
5457 Lisp_Object tail, elt;
5458 AUTO_STRING (equal, "=");
5459
5460 val = Ffont_xlfd_name (arg, Qt);
5461 for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
5462 tail = XCDR (tail))
5463 {
5464 elt = XCAR (tail);
5465 if (EQ (XCAR (elt), QCscript)
5466 && SYMBOLP (XCDR (elt)))
5467 val = concat3 (val, SYMBOL_NAME (QCscript),
5468 concat2 (equal, SYMBOL_NAME (XCDR (elt))));
5469 else if (EQ (XCAR (elt), QClang)
5470 && SYMBOLP (XCDR (elt)))
5471 val = concat3 (val, SYMBOL_NAME (QClang),
5472 concat2 (equal, SYMBOL_NAME (XCDR (elt))));
5473 else if (EQ (XCAR (elt), QCotf)
5474 && CONSP (XCDR (elt)) && SYMBOLP (XCAR (XCDR (elt))))
5475 val = concat3 (val, SYMBOL_NAME (QCotf),
5476 concat2 (equal, SYMBOL_NAME (XCAR (XCDR (elt)))));
5477 }
5478 arg = val;
5479 }
5480
5481 if (CONSP (result)
5482 && VECTORP (XCAR (result))
5483 && ASIZE (XCAR (result)) > 0
5484 && FONTP (AREF (XCAR (result), 0)))
5485 result = font_vconcat_entity_vectors (result);
5486 if (FONTP (result))
5487 {
5488 val = Ffont_xlfd_name (result, Qt);
5489 if (! FONT_SPEC_P (result))
5490 {
5491 AUTO_STRING (colon, ":");
5492 val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
5493 colon, val);
5494 }
5495 result = val;
5496 }
5497 else if (CONSP (result))
5498 {
5499 Lisp_Object tail;
5500 result = Fcopy_sequence (result);
5501 for (tail = result; CONSP (tail); tail = XCDR (tail))
5502 {
5503 val = XCAR (tail);
5504 if (FONTP (val))
5505 val = Ffont_xlfd_name (val, Qt);
5506 XSETCAR (tail, val);
5507 }
5508 }
5509 else if (VECTORP (result))
5510 {
5511 result = Fcopy_sequence (result);
5512 for (i = 0; i < ASIZE (result); i++)
5513 {
5514 val = AREF (result, i);
5515 if (FONTP (val))
5516 val = Ffont_xlfd_name (val, Qt);
5517 ASET (result, i, val);
5518 }
5519 }
5520 Vfont_log = Fcons (list3 (intern (action), arg, result), Vfont_log);
5521 }
5522
5523
5524
5525
5526
5527 void
5528 font_deferred_log (const char *action, Lisp_Object arg, Lisp_Object result)
5529 {
5530 if (EQ (Vfont_log, Qt))
5531 return;
5532 ASET (Vfont_log_deferred, 0, build_string (action));
5533 ASET (Vfont_log_deferred, 1, arg);
5534 ASET (Vfont_log_deferred, 2, result);
5535 }
5536
5537 void
5538 font_drop_xrender_surfaces (struct frame *f)
5539 {
5540 struct font_driver_list *list;
5541
5542 for (list = f->font_driver_list; list; list = list->next)
5543 if (list->on && list->driver->drop_xrender_surfaces)
5544 list->driver->drop_xrender_surfaces (f);
5545 }
5546
5547 void
5548 syms_of_font (void)
5549 {
5550 sort_shift_bits[FONT_TYPE_INDEX] = 0;
5551 sort_shift_bits[FONT_SLANT_INDEX] = 2;
5552 sort_shift_bits[FONT_WEIGHT_INDEX] = 9;
5553 sort_shift_bits[FONT_SIZE_INDEX] = 16;
5554 sort_shift_bits[FONT_WIDTH_INDEX] = 23;
5555
5556 PDUMPER_REMEMBER_SCALAR (sort_shift_bits);
5557
5558 font_charset_alist = Qnil;
5559 staticpro (&font_charset_alist);
5560
5561 DEFSYM (Qopentype, "opentype");
5562
5563
5564
5565 DEFSYM (Qcanonical_combining_class, "canonical-combining-class");
5566
5567
5568 DEFSYM (Qascii_0, "ascii-0");
5569 DEFSYM (Qiso8859_1, "iso8859-1");
5570 DEFSYM (Qiso10646_1, "iso10646-1");
5571 DEFSYM (Qunicode_bmp, "unicode-bmp");
5572 DEFSYM (Qemoji, "emoji");
5573
5574
5575 DEFSYM (QCotf, ":otf");
5576 DEFSYM (QClang, ":lang");
5577 DEFSYM (QCscript, ":script");
5578 DEFSYM (QCantialias, ":antialias");
5579 DEFSYM (QCfoundry, ":foundry");
5580 DEFSYM (QCadstyle, ":adstyle");
5581 DEFSYM (QCregistry, ":registry");
5582 DEFSYM (QCspacing, ":spacing");
5583 DEFSYM (QCdpi, ":dpi");
5584 DEFSYM (QCscalable, ":scalable");
5585 DEFSYM (QCavgwidth, ":avgwidth");
5586 DEFSYM (QCfont_entity, ":font-entity");
5587 DEFSYM (QCcombining_capability, ":combining-capability");
5588
5589
5590 DEFSYM (Qc, "c");
5591 DEFSYM (Qm, "m");
5592 DEFSYM (Qp, "p");
5593 DEFSYM (Qd, "d");
5594
5595
5596
5597 DEFSYM (Qja, "ja");
5598 DEFSYM (Qko, "ko");
5599
5600 DEFSYM (QCuser_spec, ":user-spec");
5601
5602
5603 DEFSYM (QL2R, "L2R");
5604 DEFSYM (QR2L, "R2L");
5605
5606 DEFSYM (Qfont_extra_type, "font-extra-type");
5607 DEFSYM (Qfont_driver_superseded_by, "font-driver-superseded-by");
5608
5609 scratch_font_spec = Ffont_spec (0, NULL);
5610 staticpro (&scratch_font_spec);
5611 scratch_font_prefer = Ffont_spec (0, NULL);
5612 staticpro (&scratch_font_prefer);
5613
5614 Vfont_log_deferred = make_nil_vector (3);
5615 staticpro (&Vfont_log_deferred);
5616
5617 #if 0
5618 #ifdef HAVE_LIBOTF
5619 staticpro (&otf_list);
5620 otf_list = Qnil;
5621 #endif
5622 #endif
5623
5624 defsubr (&Sfontp);
5625 defsubr (&Sfont_spec);
5626 defsubr (&Sfont_get);
5627 #ifdef HAVE_WINDOW_SYSTEM
5628 defsubr (&Sfont_face_attributes);
5629 #endif
5630 defsubr (&Sfont_put);
5631 defsubr (&Slist_fonts);
5632 defsubr (&Sfont_family_list);
5633 defsubr (&Sfind_font);
5634 defsubr (&Sfont_xlfd_name);
5635 defsubr (&Sclear_font_cache);
5636 defsubr (&Sfont_shape_gstring);
5637 defsubr (&Sfont_variation_glyphs);
5638 defsubr (&Sinternal_char_font);
5639 #if 0
5640 defsubr (&Sfont_drive_otf);
5641 defsubr (&Sfont_otf_alternates);
5642 #endif
5643
5644 #ifdef FONT_DEBUG
5645 defsubr (&Sopen_font);
5646 defsubr (&Sclose_font);
5647 defsubr (&Squery_font);
5648 defsubr (&Sfont_get_glyphs);
5649 defsubr (&Sfont_has_char_p);
5650 defsubr (&Sfont_match_p);
5651 defsubr (&Sfont_at);
5652 #if 0
5653 defsubr (&Sdraw_string);
5654 #endif
5655 defsubr (&Sframe_font_cache);
5656 #endif
5657 #ifdef HAVE_WINDOW_SYSTEM
5658 defsubr (&Sfont_info);
5659 #endif
5660
5661 DEFVAR_LISP ("font-encoding-alist", Vfont_encoding_alist,
5662 doc:
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680 );
5681 Vfont_encoding_alist = Qnil;
5682
5683
5684
5685
5686
5687
5688 DEFVAR_LISP_NOPRO ("font-weight-table", Vfont_weight_table,
5689 doc:
5690
5691
5692
5693 );
5694 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
5695 make_symbol_constant (intern_c_string ("font-weight-table"));
5696
5697 DEFVAR_LISP_NOPRO ("font-slant-table", Vfont_slant_table,
5698 doc:
5699
5700 );
5701 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
5702 make_symbol_constant (intern_c_string ("font-slant-table"));
5703
5704 DEFVAR_LISP_NOPRO ("font-width-table", Vfont_width_table,
5705 doc:
5706
5707 );
5708 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
5709 make_symbol_constant (intern_c_string ("font-width-table"));
5710
5711 staticpro (&font_style_table);
5712 font_style_table = CALLN (Fvector, Vfont_weight_table, Vfont_slant_table,
5713 Vfont_width_table);
5714
5715 DEFVAR_LISP ("font-log", Vfont_log, doc:
5716
5717
5718
5719 );
5720 Vfont_log = Qnil;
5721
5722 DEFVAR_BOOL ("inhibit-compacting-font-caches", inhibit_compacting_font_caches,
5723 doc:
5724
5725
5726
5727
5728
5729
5730
5731
5732 );
5733
5734 #ifdef WINDOWSNT
5735
5736
5737 inhibit_compacting_font_caches = 1;
5738 #else
5739 inhibit_compacting_font_caches = 0;
5740 #endif
5741
5742 DEFVAR_BOOL ("xft-ignore-color-fonts",
5743 xft_ignore_color_fonts,
5744 doc:
5745
5746 );
5747 xft_ignore_color_fonts = true;
5748
5749 DEFVAR_BOOL ("query-all-font-backends", query_all_font_backends,
5750 doc:
5751
5752
5753 );
5754 query_all_font_backends = false;
5755
5756 #ifdef HAVE_WINDOW_SYSTEM
5757 #ifdef HAVE_FREETYPE
5758 syms_of_ftfont ();
5759 #ifdef HAVE_X_WINDOWS
5760 syms_of_xfont ();
5761 #ifdef USE_CAIRO
5762 syms_of_ftcrfont ();
5763 #else
5764 #ifdef HAVE_XFT
5765 syms_of_xftfont ();
5766 #endif
5767 #endif
5768 #else
5769 #ifdef USE_CAIRO
5770 syms_of_ftcrfont ();
5771 #endif
5772 #endif
5773 #else
5774 #ifdef HAVE_X_WINDOWS
5775 syms_of_xfont ();
5776 #endif
5777 #endif
5778 #ifdef HAVE_BDFFONT
5779 syms_of_bdffont ();
5780 #endif
5781 #ifdef HAVE_NTGUI
5782 syms_of_w32font ();
5783 #endif
5784 #ifdef USE_BE_CAIRO
5785 syms_of_ftcrfont ();
5786 #endif
5787 #endif
5788 }
5789
5790 void
5791 init_font (void)
5792 {
5793 Vfont_log = egetenv ("EMACS_FONT_LOG") ? Qnil : Qt;
5794 }