(xfont_chars_supported, xfont_supported_scripts): New
[bpt/emacs.git] / src / xfont.c
CommitLineData
c2f5bfd6 1/* xfont.c -- X core font driver.
76b6f707
GM
2 Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009
c2f5bfd6
KH
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
c2f5bfd6 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
c2f5bfd6
KH
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c2f5bfd6
KH
21
22#include <config.h>
23#include <stdio.h>
f0c55750 24#include <stdlib.h>
c2f5bfd6
KH
25#include <X11/Xlib.h>
26
27#include "lisp.h"
28#include "dispextern.h"
29#include "xterm.h"
30#include "frame.h"
31#include "blockinput.h"
32#include "character.h"
33#include "charset.h"
34#include "fontset.h"
35#include "font.h"
f0c55750 36#include "ccl.h"
c2f5bfd6
KH
37
38\f
39/* X core font driver. */
40
f0c55750
KH
41struct xfont_info
42{
43 struct font font;
44 Display *display;
45 XFontStruct *xfont;
46};
47
c2f5bfd6
KH
48/* Prototypes of support functions. */
49extern void x_clear_errors P_ ((Display *));
50
c2f5bfd6 51static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
f0c55750 52static void xfont_find_ccl_program P_ ((struct font *));
c2f5bfd6
KH
53
54/* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B
55 is not contained in the font. */
56
57static XCharStruct *
58xfont_get_pcm (xfont, char2b)
59 XFontStruct *xfont;
60 XChar2b *char2b;
61{
62 /* The result metric information. */
63 XCharStruct *pcm = NULL;
64
960d80b9 65 font_assert (xfont && char2b);
c2f5bfd6
KH
66
67 if (xfont->per_char != NULL)
68 {
69 if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
70 {
71 /* min_char_or_byte2 specifies the linear character index
72 corresponding to the first element of the per_char array,
73 max_char_or_byte2 is the index of the last character. A
74 character with non-zero CHAR2B->byte1 is not in the font.
75 A character with byte2 less than min_char_or_byte2 or
76 greater max_char_or_byte2 is not in the font. */
77 if (char2b->byte1 == 0
78 && char2b->byte2 >= xfont->min_char_or_byte2
79 && char2b->byte2 <= xfont->max_char_or_byte2)
80 pcm = xfont->per_char + char2b->byte2 - xfont->min_char_or_byte2;
81 }
82 else
83 {
84 /* If either min_byte1 or max_byte1 are nonzero, both
85 min_char_or_byte2 and max_char_or_byte2 are less than
86 256, and the 2-byte character index values corresponding
87 to the per_char array element N (counting from 0) are:
88
89 byte1 = N/D + min_byte1
90 byte2 = N\D + min_char_or_byte2
91
92 where:
93
94 D = max_char_or_byte2 - min_char_or_byte2 + 1
95 / = integer division
96 \ = integer modulus */
97 if (char2b->byte1 >= xfont->min_byte1
98 && char2b->byte1 <= xfont->max_byte1
99 && char2b->byte2 >= xfont->min_char_or_byte2
100 && char2b->byte2 <= xfont->max_char_or_byte2)
101 pcm = (xfont->per_char
102 + ((xfont->max_char_or_byte2 - xfont->min_char_or_byte2 + 1)
103 * (char2b->byte1 - xfont->min_byte1))
104 + (char2b->byte2 - xfont->min_char_or_byte2));
105 }
106 }
107 else
108 {
109 /* If the per_char pointer is null, all glyphs between the first
110 and last character indexes inclusive have the same
111 information, as given by both min_bounds and max_bounds. */
112 if (char2b->byte2 >= xfont->min_char_or_byte2
113 && char2b->byte2 <= xfont->max_char_or_byte2)
114 pcm = &xfont->max_bounds;
115 }
116
117 return ((pcm == NULL
118 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
119 ? NULL : pcm);
120}
121
f0c55750
KH
122/* Find a CCL program for a font specified by FONTP, and set the member
123 `encoder' of the structure. */
124
125static void
126xfont_find_ccl_program (font)
127 struct font *font;
128{
129 Lisp_Object list, elt;
130
131 elt = Qnil;
132 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
133 {
134 elt = XCAR (list);
135 if (CONSP (elt)
136 && STRINGP (XCAR (elt))
137 && ((fast_string_match_ignore_case (XCAR (elt),
138 font->props[FONT_NAME_INDEX])
139 >= 0)
140 || (fast_string_match_ignore_case (XCAR (elt),
141 font->props[FONT_FULLNAME_INDEX])
142 >= 0)))
143 break;
144 }
145
146 if (! NILP (list))
147 {
148 struct ccl_program *ccl
149 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
150
151 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
152 xfree (ccl);
153 else
154 font->font_encoder = ccl;
155 }
156}
157
feb2737b 158static Lisp_Object xfont_get_cache P_ ((FRAME_PTR));
c2f5bfd6 159static Lisp_Object xfont_list P_ ((Lisp_Object, Lisp_Object));
6e34c9c1 160static Lisp_Object xfont_match P_ ((Lisp_Object, Lisp_Object));
c2f5bfd6 161static Lisp_Object xfont_list_family P_ ((Lisp_Object));
f0c55750 162static Lisp_Object xfont_open P_ ((FRAME_PTR, Lisp_Object, int));
c2f5bfd6
KH
163static void xfont_close P_ ((FRAME_PTR, struct font *));
164static int xfont_prepare_face P_ ((FRAME_PTR, struct face *));
c2f5bfd6
KH
165static int xfont_has_char P_ ((Lisp_Object, int));
166static unsigned xfont_encode_char P_ ((struct font *, int));
167static int xfont_text_extents P_ ((struct font *, unsigned *, int,
168 struct font_metrics *));
169static int xfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
f0c55750 170static int xfont_check P_ ((FRAME_PTR, struct font *));
c2f5bfd6
KH
171
172struct font_driver xfont_driver =
173 {
575abfb7 174 0, /* Qx */
f0c55750 175 0, /* case insensitive */
c2f5bfd6 176 xfont_get_cache,
c2f5bfd6 177 xfont_list,
6e34c9c1 178 xfont_match,
c2f5bfd6
KH
179 xfont_list_family,
180 NULL,
181 xfont_open,
182 xfont_close,
183 xfont_prepare_face,
f0c55750 184 NULL,
c2f5bfd6
KH
185 xfont_has_char,
186 xfont_encode_char,
187 xfont_text_extents,
f0c55750
KH
188 xfont_draw,
189 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
190 xfont_check
c2f5bfd6
KH
191 };
192
193extern Lisp_Object QCname;
194
195static Lisp_Object
feb2737b
KH
196xfont_get_cache (f)
197 FRAME_PTR f;
c2f5bfd6 198{
feb2737b 199 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c2f5bfd6
KH
200
201 return (dpyinfo->name_list_element);
202}
203
c2f5bfd6
KH
204extern Lisp_Object Vface_alternative_font_registry_alist;
205
f0c55750
KH
206static int
207compare_font_names (const void *name1, const void *name2)
208{
7740d2c7
KH
209 return xstrcasecmp (*(const unsigned char **) name1,
210 *(const unsigned char **) name2);
f0c55750
KH
211}
212
6a705b23
KH
213/* Decode XLFD as iso-8859-1 into OUTPUT, and return the byte length
214 of the decoding result. LEN is the byte length of XLFD, or -1 if
215 XLFD is NULL terminated. The caller must assure that OUTPUT is at
216 least twice (plus 1) as large as XLFD. */
217
218static int
219xfont_decode_coding_xlfd (char *xlfd, int len, char *output)
220{
221 char *p0 = xlfd, *p1 = output;
222 int c;
8510724d 223
6a705b23
KH
224 while (*p0)
225 {
226 c = *(unsigned char *) p0++;
227 p1 += CHAR_STRING (c, p1);
228 if (--len == 0)
229 break;
230 }
231 *p1 = 0;
232 return (p1 - output);
233}
234
235/* Encode XLFD from UTF-8 to iso-8859-1 destructively, and return the
236 resulting byte length. If XLFD contains unencodable character,
237 return -1. */
238
239static int
240xfont_encode_coding_xlfd (char *xlfd)
241{
242 const unsigned char *p0 = (unsigned char *) xlfd;
243 unsigned char *p1 = (unsigned char *) xlfd;
244 int len = 0;
8510724d 245
6a705b23
KH
246 while (*p0)
247 {
248 int c = STRING_CHAR_ADVANCE (p0);
249
250 if (c >= 0x100)
251 return -1;
252 *p1++ = c;
253 len++;
254 }
255 *p1 = 0;
256 return len;
257}
258
5a189ffa
KH
259/* Check if CHARS (cons or vector) is supported by XFONT whose
260 encoding charset is ENCODING (XFONT is NULL) or by a font whose
261 registry corresponds to ENCODING and REPERTORY.
262 Return 1 if supported, return 0 otherwise. */
263
264static int
265xfont_chars_supported (Lisp_Object chars, XFontStruct *xfont,
266 struct charset *encoding, struct charset *repertory)
267{
268 struct charset *charset = repertory ? repertory : encoding;
269
270 if (CONSP (chars))
271 {
272 for (; CONSP (chars); chars = XCDR (chars))
273 {
274 int c = XINT (XCAR (chars));
275 unsigned code = ENCODE_CHAR (charset, c);
276 XChar2b char2b;
277
278 if (code == CHARSET_INVALID_CODE (charset))
279 break;
280 if (! xfont)
281 continue;
282 if (code >= 0x10000)
283 break;
284 char2b.byte1 = code >> 8;
285 char2b.byte2 = code & 0xFF;
286 if (! xfont_get_pcm (xfont, &char2b))
287 break;
288 }
289 return (NILP (chars));
290 }
291 else if (VECTORP (chars))
292 {
293 int i;
294
295 for (i = ASIZE (chars) - 1; i >= 0; i--)
296 {
297 int c = XINT (AREF (chars, i));
298 unsigned code = ENCODE_CHAR (charset, c);
299 XChar2b char2b;
300
301 if (code == CHARSET_INVALID_CODE (charset))
302 continue;
303 if (! xfont)
304 break;
305 if (code >= 0x10000)
306 continue;
307 char2b.byte1 = code >> 8;
308 char2b.byte2 = code & 0xFF;
309 if (xfont_get_pcm (xfont, &char2b))
310 break;
311 }
312 return (i >= 0);
313 }
314 return 0;
315}
316
317/* A hash table recoding which font supports which scritps. Each key
318 is a vector of characteristic font propertis FOUNDRY to WIDTH and
319 ADDSTYLE, and each value is a list of script symbols.
320
321 We assume that fonts that have the same value in the above
322 properties supports the same set of characters on all displays. */
323
324static Lisp_Object xfont_scripts_cache;
325
326/* Re-usable vector to store characteristic font properites. */
327static Lisp_Object xfont_scratch_props;
328
329extern Lisp_Object Qlatin;
330
331/* Return a list of scripts supported by the font of FONTNAME whose
332 characteristic properties are in PROPS and whose encoding charset
333 is ENCODING. A caller must call BLOCK_INPUT in advance. */
92f19280
KH
334
335static Lisp_Object
5a189ffa
KH
336xfont_supported_scripts (Display *display, char *fontname, Lisp_Object props,
337 struct charset *encoding)
338{
339 Lisp_Object scripts;
340
341 /* Two special cases to avoid opening rather big fonts. */
342 if (EQ (AREF (props, 2), Qja))
343 return Fcons (intern ("kana"), Fcons (intern ("han"), Qnil));
344 if (EQ (AREF (props, 2), Qko))
345 return Fcons (intern ("hangul"), Qnil);
346 scripts = Fgethash (props, xfont_scripts_cache, Qt);
347 if (EQ (scripts, Qt))
348 {
349 XFontStruct *xfont;
350 Lisp_Object val;
351
352 scripts = Qnil;
353 xfont = XLoadQueryFont (display, fontname);
354 if (xfont)
355 {
356 if (xfont->per_char)
357 {
358 for (val = Vscript_representative_chars; CONSP (val);
359 val = XCDR (val))
360 if (CONSP (XCAR (val)) && SYMBOLP (XCAR (XCAR (val))))
361 {
362 Lisp_Object script = XCAR (XCAR (val));
363 Lisp_Object chars = XCDR (XCAR (val));
364
365 if (xfont_chars_supported (chars, xfont, encoding, NULL))
366 scripts = Fcons (script, scripts);
367 }
368 }
369 XFreeFont (display, xfont);
370 }
371 if (EQ (AREF (props, 3), Qiso10646_1)
372 && NILP (Fmemq (Qlatin, scripts)))
373 scripts = Fcons (Qlatin, scripts);
374 Fputhash (Fcopy_sequence (props), scripts, xfont_scripts_cache);
375 }
376 return scripts;
377}
378
379extern Lisp_Object Vscalable_fonts_allowed;
380
381static Lisp_Object
382xfont_list_pattern (Display *display, char *pattern,
383 Lisp_Object registry, Lisp_Object script)
c2f5bfd6 384{
6c4aeab6 385 Lisp_Object list = Qnil;
5a189ffa
KH
386 Lisp_Object chars = Qnil;
387 struct charset *encoding, *repertory = NULL;
6c4aeab6
KH
388 int i, limit, num_fonts;
389 char **names;
6a705b23
KH
390 /* Large enough to decode the longest XLFD (255 bytes). */
391 char buf[512];
c2f5bfd6 392
5a189ffa
KH
393 if (! NILP (registry)
394 && font_registry_charsets (registry, &encoding, &repertory) < 0)
395 /* Unknown REGISTRY, not supported. */
396 return Qnil;
397 if (! NILP (script))
398 {
399 chars = assq_no_quit (script, Vscript_representative_chars);
400 if (NILP (chars))
401 /* We can't tell whether or not a font supports SCRIPT. */
402 return Qnil;
403 chars = XCDR (chars);
404 if (repertory)
405 {
406 if (! xfont_chars_supported (chars, NULL, encoding, repertory))
407 return Qnil;
408 script = Qnil;
409 }
410 }
411 if (! repertory && NILP (xfont_scripts_cache))
412 {
413 Lisp_Object args[2];
414
415 args[0] = QCtest;
416 args[1] = Qequal;
417 xfont_scripts_cache = Fmake_hash_table (2, args);
418 }
419
c2f5bfd6 420 BLOCK_INPUT;
6c4aeab6 421 x_catch_errors (display);
c2f5bfd6 422
6c4aeab6 423 for (limit = 512; ; limit *= 2)
c2f5bfd6 424 {
6c4aeab6
KH
425 names = XListFonts (display, pattern, limit, &num_fonts);
426 if (x_had_errors_p (display))
c2f5bfd6
KH
427 {
428 /* This error is perhaps due to insufficient memory on X
429 server. Let's just ignore it. */
6c4aeab6
KH
430 x_clear_errors (display);
431 num_fonts = 0;
432 break;
c2f5bfd6 433 }
6c4aeab6
KH
434 if (num_fonts < limit)
435 break;
436 XFreeFontNames (names);
437 }
438
f0c55750 439 if (num_fonts > 0)
6c4aeab6 440 {
f0c55750 441 char **indices = alloca (sizeof (char *) * num_fonts);
5a189ffa
KH
442 Lisp_Object *props;
443 Lisp_Object scripts = Qnil;
6c4aeab6 444
5a189ffa
KH
445 if (NILP (xfont_scratch_props))
446 {
447 xfont_scratch_props = Fmake_vector (make_number (8), Qnil);
448 props = XVECTOR (xfont_scratch_props)->contents;
449 }
450 else
451 {
452 props = XVECTOR (xfont_scratch_props)->contents;
453 for (i = 0; i < 8; i++)
454 props[i] = Qnil;
455 }
f0c55750
KH
456 for (i = 0; i < num_fonts; i++)
457 indices[i] = names[i];
458 qsort (indices, num_fonts, sizeof (char *), compare_font_names);
6c4aeab6 459
f0c55750 460 for (i = 0; i < num_fonts; i++)
c2f5bfd6 461 {
f0c55750 462 Lisp_Object entity;
6c4aeab6 463
05131107 464 if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
6c4aeab6 465 continue;
f0c55750 466 entity = font_make_entity ();
6a705b23 467 xfont_decode_coding_xlfd (indices[i], -1, buf);
5a189ffa
KH
468 font_parse_xlfd (buf, entity);
469 ASET (entity, FONT_TYPE_INDEX, Qx);
470 /* Avoid auto-scaled fonts. */
471 if (XINT (AREF (entity, FONT_DPI_INDEX)) != 0
472 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0)
473 continue;
474 /* Avoid not-allowed scalable fonts. */
475 if (NILP (Vscalable_fonts_allowed))
c2f5bfd6 476 {
5a189ffa 477 if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
6c4aeab6 478 continue;
5a189ffa
KH
479 }
480 else if (CONSP (Vscalable_fonts_allowed))
481 {
482 Lisp_Object tail, elt;
483
484 for (tail = Vscalable_fonts_allowed; CONSP (tail);
485 tail = XCDR (tail))
f0c55750 486 {
5a189ffa
KH
487 elt = XCAR (tail);
488 if (STRINGP (elt)
489 && fast_c_string_match_ignore_case (elt, indices[i]) >= 0)
490 break;
f0c55750 491 }
5a189ffa
KH
492 if (! CONSP (tail))
493 continue;
c2f5bfd6 494 }
f0c55750 495
5a189ffa
KH
496 /* Update encoding and repertory if necessary. */
497 if (! EQ (registry, AREF (entity, FONT_REGISTRY_INDEX)))
498 {
499 registry = AREF (entity, FONT_REGISTRY_INDEX);
500 if (font_registry_charsets (registry, &encoding, &repertory) < 0)
501 encoding = NULL;
502 }
503 if (! encoding)
504 /* Unknown REGISTRY, not supported. */
505 continue;
506 if (repertory)
507 {
508 if (NILP (script)
509 || xfont_chars_supported (chars, NULL, encoding, repertory))
510 list = Fcons (entity, list);
511 continue;
512 }
513 if (memcmp (props, &(AREF (entity, FONT_FOUNDRY_INDEX)),
514 sizeof (Lisp_Object) * 7)
515 || ! EQ (AREF (entity, FONT_SPACING_INDEX), props[7]))
516 {
517 memcpy (props, &(AREF (entity, FONT_FOUNDRY_INDEX)),
518 sizeof (Lisp_Object) * 7);
519 props[7] = AREF (entity, FONT_SPACING_INDEX);
520 scripts = xfont_supported_scripts (display, indices[i],
521 xfont_scratch_props, encoding);
522 }
523 if (NILP (script)
524 || ! NILP (Fmemq (script, scripts)))
f0c55750 525 list = Fcons (entity, list);
c2f5bfd6 526 }
019e13ef 527 XFreeFontNames (names);
c2f5bfd6
KH
528 }
529
530 x_uncatch_errors ();
531 UNBLOCK_INPUT;
532
960d80b9 533 font_add_log ("xfont-list", build_string (pattern), list);
6c4aeab6
KH
534 return list;
535}
c2f5bfd6 536
6c4aeab6
KH
537static Lisp_Object
538xfont_list (frame, spec)
539 Lisp_Object frame, spec;
540{
541 FRAME_PTR f = XFRAME (frame);
542 Display *display = FRAME_X_DISPLAY_INFO (f)->display;
5a189ffa 543 Lisp_Object registry, list, val, extra, script;
6c4aeab6 544 int len;
6a705b23
KH
545 /* Large enough to contain the longest XLFD (255 bytes) in UTF-8. */
546 char name[512];
8510724d 547
6c4aeab6 548 extra = AREF (spec, FONT_EXTRA_INDEX);
6c4aeab6 549 if (CONSP (extra))
c2f5bfd6 550 {
6c4aeab6 551 val = assq_no_quit (QCotf, extra);
6c4aeab6 552 if (! NILP (val))
f0c55750
KH
553 return Qnil;
554 val = assq_no_quit (QClang, extra);
6c4aeab6 555 if (! NILP (val))
f0c55750 556 return Qnil;
c2f5bfd6 557 }
398dbf26 558
f0c55750 559 registry = AREF (spec, FONT_REGISTRY_INDEX);
6a705b23
KH
560 len = font_unparse_xlfd (spec, 0, name, 512);
561 if (len < 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
f0c55750 562 return Qnil;
5a189ffa
KH
563
564 val = assq_no_quit (QCscript, extra);
565 script = CDR (val);
566 list = xfont_list_pattern (display, name, registry, script);
f0c55750 567 if (NILP (list) && NILP (registry))
c2f5bfd6 568 {
f0c55750
KH
569 /* Try iso10646-1 */
570 char *r = name + len - 9; /* 9 == strlen (iso8859-1) */
571
572 if (r - name + 10 < 256) /* 10 == strlen (iso10646-1) */
6c4aeab6 573 {
f0c55750 574 strcpy (r, "iso10646-1");
5a189ffa 575 list = xfont_list_pattern (display, name, Qiso10646_1, script);
f0c55750
KH
576 }
577 }
578 if (NILP (list) && ! NILP (registry))
579 {
37470f4d 580 /* Try alternate registries. */
f0c55750 581 Lisp_Object alter;
6c4aeab6 582
f0c55750
KH
583 if ((alter = Fassoc (SYMBOL_NAME (registry),
584 Vface_alternative_font_registry_alist),
585 CONSP (alter)))
586 {
587 /* Pointer to REGISTRY-ENCODING field. */
588 char *r = name + len - SBYTES (SYMBOL_NAME (registry));
589
590 for (alter = XCDR (alter); CONSP (alter); alter = XCDR (alter))
591 if (STRINGP (XCAR (alter))
592 && ((r - name) + SBYTES (XCAR (alter))) < 256)
593 {
594 strcpy (r, (char *) SDATA (XCAR (alter)));
5a189ffa 595 list = xfont_list_pattern (display, name, registry, script);
f0c55750
KH
596 if (! NILP (list))
597 break;
598 }
6c4aeab6 599 }
c2f5bfd6 600 }
37470f4d
KH
601 if (NILP (list))
602 {
603 /* Try alias. */
604 val = assq_no_quit (QCname, AREF (spec, FONT_EXTRA_INDEX));
6a705b23
KH
605 if (CONSP (val) && STRINGP (XCDR (val)) && SBYTES (XCDR (val)) < 512)
606 {
607 bcopy (SDATA (XCDR (val)), name, SBYTES (XCDR (val)) + 1);
608 if (xfont_encode_coding_xlfd (name) < 0)
609 return Qnil;
5a189ffa 610 list = xfont_list_pattern (display, name, registry, script);
6a705b23 611 }
37470f4d 612 }
398dbf26 613
f0c55750 614 return list;
c2f5bfd6
KH
615}
616
6e34c9c1
KH
617static Lisp_Object
618xfont_match (frame, spec)
619 Lisp_Object frame, spec;
620{
621 FRAME_PTR f = XFRAME (frame);
622 Display *display = FRAME_X_DISPLAY_INFO (f)->display;
623 Lisp_Object extra, val, entity;
6a705b23 624 char name[512];
6e34c9c1
KH
625 XFontStruct *xfont;
626 unsigned long value;
627
628 extra = AREF (spec, FONT_EXTRA_INDEX);
629 val = assq_no_quit (QCname, extra);
630 if (! CONSP (val) || ! STRINGP (XCDR (val)))
f0c55750 631 {
6a705b23 632 if (font_unparse_xlfd (spec, 0, name, 512) < 0)
f0c55750 633 return Qnil;
f0c55750 634 }
6a705b23
KH
635 else if (SBYTES (XCDR (val)) < 512)
636 bcopy (SDATA (XCDR (val)), name, SBYTES (XCDR (val)) + 1);
f0c55750 637 else
6a705b23
KH
638 return Qnil;
639 if (xfont_encode_coding_xlfd (name) < 0)
640 return Qnil;
6e34c9c1 641
9c6d1df5 642 BLOCK_INPUT;
6e34c9c1 643 entity = Qnil;
6e34c9c1
KH
644 xfont = XLoadQueryFont (display, name);
645 if (xfont)
646 {
647 if (XGetFontProperty (xfont, XA_FONT, &value))
648 {
649 int len;
6a705b23 650 char *s;
6e34c9c1 651
6a705b23
KH
652 s = (char *) XGetAtomName (display, (Atom) value);
653 len = strlen (s);
6e34c9c1
KH
654
655 /* If DXPC (a Differential X Protocol Compressor)
656 Ver.3.7 is running, XGetAtomName will return null
657 string. We must avoid such a name. */
658 if (len > 0)
659 {
f0c55750 660 entity = font_make_entity ();
6e34c9c1 661 ASET (entity, FONT_TYPE_INDEX, Qx);
6a705b23 662 xfont_decode_coding_xlfd (s, -1, name);
6e34c9c1
KH
663 if (font_parse_xlfd (name, entity) < 0)
664 entity = Qnil;
665 }
6a705b23 666 XFree (s);
6e34c9c1
KH
667 }
668 XFreeFont (display, xfont);
669 }
9c6d1df5 670 UNBLOCK_INPUT;
6e34c9c1 671
960d80b9 672 font_add_log ("xfont-match", spec, entity);
6e34c9c1
KH
673 return entity;
674}
675
c2f5bfd6
KH
676static Lisp_Object
677xfont_list_family (frame)
9df50a31 678 Lisp_Object frame;
c2f5bfd6
KH
679{
680 FRAME_PTR f = XFRAME (frame);
681 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
682 char **names;
683 int num_fonts, i;
684 Lisp_Object list;
685 char *last_family;
686 int last_len;
687
688 BLOCK_INPUT;
689 x_catch_errors (dpyinfo->display);
690 names = XListFonts (dpyinfo->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
691 0x8000, &num_fonts);
692 if (x_had_errors_p (dpyinfo->display))
693 {
694 /* This error is perhaps due to insufficient memory on X server.
695 Let's just ignore it. */
696 x_clear_errors (dpyinfo->display);
697 num_fonts = 0;
698 }
699
700 list = Qnil;
701 for (i = 0, last_len = 0; i < num_fonts; i++)
702 {
6a705b23 703 char *p0 = names[i], *p1, buf[512];
c2f5bfd6 704 Lisp_Object family;
6a705b23 705 int decoded_len;
c2f5bfd6
KH
706
707 p0++; /* skip the leading '-' */
708 while (*p0 && *p0 != '-') p0++; /* skip foundry */
709 if (! *p0)
710 continue;
711 p1 = ++p0;
712 while (*p1 && *p1 != '-') p1++; /* find the end of family */
713 if (! *p1 || p1 == p0)
714 continue;
715 if (last_len == p1 - p0
716 && bcmp (last_family, p0, last_len) == 0)
717 continue;
718 last_len = p1 - p0;
719 last_family = p0;
6a705b23
KH
720
721 decoded_len = xfont_decode_coding_xlfd (p0, last_len, buf);
722 family = font_intern_prop (p0, decoded_len, 1);
29428bb8 723 if (NILP (assq_no_quit (family, list)))
c2f5bfd6
KH
724 list = Fcons (family, list);
725 }
726
727 XFreeFontNames (names);
728 x_uncatch_errors ();
729 UNBLOCK_INPUT;
730
731 return list;
732}
733
f0c55750
KH
734extern Lisp_Object QCavgwidth;
735
736static Lisp_Object
c2f5bfd6
KH
737xfont_open (f, entity, pixel_size)
738 FRAME_PTR f;
739 Lisp_Object entity;
740 int pixel_size;
741{
742 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
743 Display *display = dpyinfo->display;
6a705b23 744 char name[512];
c2f5bfd6
KH
745 int len;
746 unsigned long value;
747 Lisp_Object registry;
748 struct charset *encoding, *repertory;
f0c55750 749 Lisp_Object font_object, fullname;
c2f5bfd6
KH
750 struct font *font;
751 XFontStruct *xfont;
398dbf26 752 int i;
c2f5bfd6
KH
753
754 /* At first, check if we know how to encode characters for this
755 font. */
756 registry = AREF (entity, FONT_REGISTRY_INDEX);
a9822ae8 757 if (font_registry_charsets (registry, &encoding, &repertory) < 0)
c8e0e16d
KH
758 {
759 font_add_log (" x:unknown registry", registry, Qnil);
760 return Qnil;
761 }
c2f5bfd6
KH
762
763 if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
764 pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
f0c55750
KH
765 else if (pixel_size == 0)
766 {
767 if (FRAME_FONT (f))
768 pixel_size = FRAME_FONT (f)->pixel_size;
769 else
770 pixel_size = 14;
771 }
6a705b23
KH
772 len = font_unparse_xlfd (entity, pixel_size, name, 512);
773 if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
c8e0e16d
KH
774 {
775 font_add_log (" x:unparse failed", entity, Qnil);
776 return Qnil;
777 }
c2f5bfd6
KH
778
779 BLOCK_INPUT;
780 x_catch_errors (display);
781 xfont = XLoadQueryFont (display, name);
782 if (x_had_errors_p (display))
783 {
784 /* This error is perhaps due to insufficient memory on X server.
785 Let's just ignore it. */
786 x_clear_errors (display);
787 xfont = NULL;
788 }
2f73901f
KH
789 else if (! xfont)
790 {
791 /* Some version of X lists:
792 -misc-fixed-medium-r-normal--20-*-75-75-c-100-iso8859-1
793 -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
794 but can open only:
795 -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
796 and
797 -misc-fixed-medium-r-normal--20-*-*-*-c-100-iso8859-1
798 So, we try again with wildcards in RESX and RESY. */
799 Lisp_Object temp;
800
801 temp = Fcopy_font_spec (entity);
802 ASET (temp, FONT_DPI_INDEX, Qnil);
6a705b23
KH
803 len = font_unparse_xlfd (temp, pixel_size, name, 512);
804 if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
2f73901f
KH
805 {
806 font_add_log (" x:unparse failed", temp, Qnil);
807 return Qnil;
808 }
809 xfont = XLoadQueryFont (display, name);
810 if (x_had_errors_p (display))
811 {
812 /* This error is perhaps due to insufficient memory on X server.
813 Let's just ignore it. */
814 x_clear_errors (display);
815 xfont = NULL;
816 }
817 }
f0c55750
KH
818 fullname = Qnil;
819 /* Try to get the full name of FONT. */
820 if (xfont && XGetFontProperty (xfont, XA_FONT, &value))
821 {
822 char *p0, *p;
823 int dashes = 0;
824
8510724d 825 p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
f0c55750
KH
826 /* Count the number of dashes in the "full name".
827 If it is too few, this isn't really the font's full name,
828 so don't use it.
829 In X11R4, the fonts did not come with their canonical names
830 stored in them. */
831 while (*p)
832 {
833 if (*p == '-')
834 dashes++;
835 p++;
836 }
837
838 if (dashes >= 13)
6a705b23
KH
839 {
840 len = xfont_decode_coding_xlfd (p0, -1, name);
841 fullname = Fdowncase (make_string (name, len));
842 }
f0c55750
KH
843 XFree (p0);
844 }
c2f5bfd6
KH
845 x_uncatch_errors ();
846 UNBLOCK_INPUT;
847
848 if (! xfont)
c8e0e16d
KH
849 {
850 font_add_log (" x:open failed", build_string (name), Qnil);
851 return Qnil;
852 }
f0c55750 853
947eecfb
KH
854 font_object = font_make_object (VECSIZE (struct xfont_info),
855 entity, pixel_size);
f0c55750
KH
856 ASET (font_object, FONT_TYPE_INDEX, Qx);
857 if (STRINGP (fullname))
6a705b23
KH
858 {
859 font_parse_xlfd ((char *) SDATA (fullname), font_object);
860 ASET (font_object, FONT_NAME_INDEX, fullname);
861 }
f0c55750 862 else
6a705b23
KH
863 {
864 char buf[512];
865
866 len = xfont_decode_coding_xlfd (name, -1, buf);
867 ASET (font_object, FONT_NAME_INDEX, make_string (buf, len));
868 }
f0c55750
KH
869 ASET (font_object, FONT_FULLNAME_INDEX, fullname);
870 ASET (font_object, FONT_FILE_INDEX, Qnil);
871 ASET (font_object, FONT_FORMAT_INDEX, Qx);
872 font = XFONT_OBJECT (font_object);
873 ((struct xfont_info *) font)->xfont = xfont;
874 ((struct xfont_info *) font)->display = FRAME_X_DISPLAY (f);
c2f5bfd6
KH
875 font->pixel_size = pixel_size;
876 font->driver = &xfont_driver;
c2f5bfd6 877 font->encoding_charset = encoding->id;
1886668d 878 font->repertory_charset = repertory ? repertory->id : -1;
c2f5bfd6
KH
879 font->ascent = xfont->ascent;
880 font->descent = xfont->descent;
f0c55750
KH
881 font->height = font->ascent + font->descent;
882 font->min_width = xfont->min_bounds.width;
c2f5bfd6
KH
883 if (xfont->min_bounds.width == xfont->max_bounds.width)
884 {
885 /* Fixed width font. */
f0c55750 886 font->average_width = font->space_width = xfont->min_bounds.width;
c2f5bfd6
KH
887 }
888 else
889 {
c2f5bfd6 890 XCharStruct *pcm;
f0c55750
KH
891 XChar2b char2b;
892 Lisp_Object val;
c2f5bfd6
KH
893
894 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
895 pcm = xfont_get_pcm (xfont, &char2b);
896 if (pcm)
f0c55750 897 font->space_width = pcm->width;
c2f5bfd6 898 else
f0c55750
KH
899 font->space_width = 0;
900
901 val = Ffont_get (font_object, QCavgwidth);
902 if (INTEGERP (val))
903 font->average_width = XINT (val);
904 if (font->average_width < 0)
905 font->average_width = - font->average_width;
906 if (font->average_width == 0
907 && encoding->ascii_compatible_p)
c2f5bfd6 908 {
f0c55750 909 int width = font->space_width, n = pcm != NULL;
c2f5bfd6 910
f0c55750
KH
911 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
912 if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
913 width += pcm->width, n++;
4f64a164
KH
914 if (n > 0)
915 font->average_width = width / n;
c2f5bfd6 916 }
4f64a164
KH
917 if (font->average_width == 0)
918 /* No easy way other than this to get a reasonable
919 average_width. */
920 font->average_width
921 = (xfont->min_bounds.width + xfont->max_bounds.width) / 2;
c2f5bfd6 922 }
c2f5bfd6 923
f0c55750
KH
924 BLOCK_INPUT;
925 font->underline_thickness
926 = (XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &value)
927 ? (long) value : 0);
928 font->underline_position
929 = (XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &value)
930 ? (long) value : -1);
931 font->baseline_offset
c2f5bfd6
KH
932 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
933 ? (long) value : 0);
f0c55750 934 font->relative_compose
c2f5bfd6
KH
935 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
936 ? (long) value : 0);
f0c55750 937 font->default_ascent
c2f5bfd6
KH
938 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
939 ? (long) value : 0);
c2f5bfd6
KH
940 UNBLOCK_INPUT;
941
f0c55750
KH
942 if (NILP (fullname))
943 fullname = AREF (font_object, FONT_NAME_INDEX);
634c4da0
KH
944 font->vertical_centering
945 = (STRINGP (Vvertical_centering_font_regexp)
946 && (fast_string_match_ignore_case
947 (Vvertical_centering_font_regexp, fullname) >= 0));
c2f5bfd6 948
f0c55750 949 return font_object;
c2f5bfd6
KH
950}
951
952static void
953xfont_close (f, font)
954 FRAME_PTR f;
955 struct font *font;
956{
957 BLOCK_INPUT;
f0c55750 958 XFreeFont (FRAME_X_DISPLAY (f), ((struct xfont_info *) font)->xfont);
c2f5bfd6 959 UNBLOCK_INPUT;
c2f5bfd6
KH
960}
961
962static int
963xfont_prepare_face (f, face)
964 FRAME_PTR f;
965 struct face *face;
966{
967 BLOCK_INPUT;
f0c55750
KH
968 XSetFont (FRAME_X_DISPLAY (f), face->gc,
969 ((struct xfont_info *) face->font)->xfont->fid);
c2f5bfd6
KH
970 UNBLOCK_INPUT;
971
972 return 0;
973}
974
c2f5bfd6 975static int
bd0af90d
KH
976xfont_has_char (font, c)
977 Lisp_Object font;
c2f5bfd6
KH
978 int c;
979{
bd0af90d 980 Lisp_Object registry = AREF (font, FONT_REGISTRY_INDEX);
d156542d 981 struct charset *encoding;
bd0af90d 982 struct charset *repertory = NULL;
c2f5bfd6 983
bd0af90d
KH
984 if (EQ (registry, Qiso10646_1))
985 {
5a189ffa 986 encoding = CHARSET_FROM_ID (charset_unicode);
bd0af90d
KH
987 /* We use a font of `ja' and `ko' adstyle only for a character
988 in JISX0208 and KSC5601 charsets respectively. */
989 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
990 && charset_jisx0208 >= 0)
5a189ffa 991 repertory = CHARSET_FROM_ID (charset_jisx0208);
bd0af90d
KH
992 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
993 && charset_ksc5601 >= 0)
5a189ffa 994 repertory = CHARSET_FROM_ID (charset_ksc5601);
bd0af90d
KH
995 }
996 else if (font_registry_charsets (registry, &encoding, &repertory) < 0)
997 /* Unknown REGISTRY, not usable. */
998 return 0;
d156542d
KH
999 if (ASCII_CHAR_P (c) && encoding->ascii_compatible_p)
1000 return 1;
c2f5bfd6
KH
1001 if (! repertory)
1002 return -1;
1003 return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
1004}
1005
1006static unsigned
1007xfont_encode_char (font, c)
1008 struct font *font;
1009 int c;
1010{
f0c55750 1011 XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
c2f5bfd6
KH
1012 struct charset *charset;
1013 unsigned code;
1014 XChar2b char2b;
1015
1016 charset = CHARSET_FROM_ID (font->encoding_charset);
1017 code = ENCODE_CHAR (charset, c);
1018 if (code == CHARSET_INVALID_CODE (charset))
21138cff 1019 return FONT_INVALID_CODE;
1886668d 1020 if (font->repertory_charset >= 0)
c2f5bfd6 1021 {
1886668d 1022 charset = CHARSET_FROM_ID (font->repertory_charset);
c2f5bfd6 1023 return (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset)
21138cff 1024 ? code : FONT_INVALID_CODE);
c2f5bfd6 1025 }
88649c62
KH
1026 char2b.byte1 = code >> 8;
1027 char2b.byte2 = code & 0xFF;
f0c55750 1028 return (xfont_get_pcm (xfont, &char2b) ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
1029}
1030
1031static int
1032xfont_text_extents (font, code, nglyphs, metrics)
1033 struct font *font;
1034 unsigned *code;
1035 int nglyphs;
1036 struct font_metrics *metrics;
1037{
f0c55750 1038 XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
c2f5bfd6 1039 int width = 0;
41fa3e2c 1040 int i, first, x;
c2f5bfd6
KH
1041
1042 if (metrics)
1043 bzero (metrics, sizeof (struct font_metrics));
41fa3e2c 1044 for (i = 0, x = 0, first = 1; i < nglyphs; i++)
c2f5bfd6
KH
1045 {
1046 XChar2b char2b;
1047 static XCharStruct *pcm;
1048
1049 if (code[i] >= 0x10000)
1050 continue;
1051 char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF;
f0c55750 1052 pcm = xfont_get_pcm (xfont, &char2b);
c2f5bfd6
KH
1053 if (! pcm)
1054 continue;
41fa3e2c
KH
1055 if (first)
1056 {
1057 if (metrics)
1058 {
1059 metrics->lbearing = pcm->lbearing;
1060 metrics->rbearing = pcm->rbearing;
1061 metrics->ascent = pcm->ascent;
1062 metrics->descent = pcm->descent;
1063 }
1064 first = 0;
1065 }
1066 else
1067 {
1068 if (metrics)
1069 {
1070 if (metrics->lbearing > width + pcm->lbearing)
1071 metrics->lbearing = width + pcm->lbearing;
1072 if (metrics->rbearing < width + pcm->rbearing)
1073 metrics->rbearing = width + pcm->rbearing;
1074 if (metrics->ascent < pcm->ascent)
1075 metrics->ascent = pcm->ascent;
1076 if (metrics->descent < pcm->descent)
1077 metrics->descent = pcm->descent;
1078 }
1079 }
c2f5bfd6
KH
1080 width += pcm->width;
1081 }
1082 if (metrics)
1083 metrics->width = width;
1084 return width;
1085}
1086
1087static int
1088xfont_draw (s, from, to, x, y, with_background)
1089 struct glyph_string *s;
1090 int from, to, x, y, with_background;
1091{
f0c55750 1092 XFontStruct *xfont = ((struct xfont_info *) s->font)->xfont;
c2f5bfd6 1093 int len = to - from;
6e34c9c1 1094 GC gc = s->gc;
298fd5b1 1095 int i;
6e34c9c1 1096
f0c55750 1097 if (s->gc != s->face->gc)
6e34c9c1 1098 {
d45fefc7 1099 BLOCK_INPUT;
f0c55750 1100 XSetFont (s->display, gc, xfont->fid);
d45fefc7 1101 UNBLOCK_INPUT;
6e34c9c1 1102 }
c2f5bfd6
KH
1103
1104 if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
1105 {
1106 char *str;
c2f5bfd6
KH
1107 USE_SAFE_ALLOCA;
1108
1109 SAFE_ALLOCA (str, char *, len);
1110 for (i = 0; i < len ; i++)
1111 str[i] = XCHAR2B_BYTE2 (s->char2b + from + i);
d45fefc7 1112 BLOCK_INPUT;
c2f5bfd6 1113 if (with_background > 0)
298fd5b1
KH
1114 {
1115 if (s->padding_p)
1116 for (i = 0; i < len; i++)
1117 XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1118 gc, x + i, y, str + i, 1);
1119 else
1120 XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1121 gc, x, y, str, len);
1122 }
c2f5bfd6 1123 else
298fd5b1
KH
1124 {
1125 if (s->padding_p)
1126 for (i = 0; i < len; i++)
1127 XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1128 gc, x + i, y, str + i, 1);
1129 else
1130 XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1131 gc, x, y, str, len);
1132 }
d45fefc7 1133 UNBLOCK_INPUT;
c2f5bfd6
KH
1134 SAFE_FREE ();
1135 return s->nchars;
1136 }
1137
d45fefc7 1138 BLOCK_INPUT;
c2f5bfd6 1139 if (with_background > 0)
298fd5b1
KH
1140 {
1141 if (s->padding_p)
1142 for (i = 0; i < len; i++)
1143 XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1144 gc, x + i, y, s->char2b + from + i, 1);
1145 else
1146 XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1147 gc, x, y, s->char2b + from, len);
1148 }
c2f5bfd6 1149 else
298fd5b1
KH
1150 {
1151 if (s->padding_p)
1152 for (i = 0; i < len; i++)
1153 XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1154 gc, x + i, y, s->char2b + from + i, 1);
1155 else
1156 XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
1157 gc, x, y, s->char2b + from, len);
1158 }
d45fefc7 1159 UNBLOCK_INPUT;
c2f5bfd6
KH
1160
1161 return len;
1162}
1163
f0c55750
KH
1164static int
1165xfont_check (f, font)
1166 FRAME_PTR f;
1167 struct font *font;
1168{
1169 struct xfont_info *xfont = (struct xfont_info *) font;
1170
1171 return (FRAME_X_DISPLAY (f) == xfont->display ? 0 : -1);
1172}
1173
c2f5bfd6
KH
1174\f
1175void
1176syms_of_xfont ()
1177{
5a189ffa
KH
1178 staticpro (&xfont_scripts_cache);
1179 xfont_scripts_cache = Qnil;
1180 staticpro (&xfont_scratch_props);
1181 xfont_scratch_props = Qnil;;
c2f5bfd6
KH
1182 xfont_driver.type = Qx;
1183 register_font_driver (&xfont_driver, NULL);
1184}
885b7d09
MB
1185
1186/* arch-tag: 23c5f366-a5ee-44b7-a3b7-90d6da7fd749
1187 (do not change this comment) */