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