New file.
[bpt/emacs.git] / src / xfont.c
CommitLineData
c2f5bfd6
KH
1/* xfont.c -- X core font driver.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Copyright (C) 2006
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9GNU Emacs is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Emacs; see the file COPYING. If not, write to
21the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22Boston, MA 02110-1301, USA. */
23
24#include <config.h>
25#include <stdio.h>
26#include <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"
37
38\f
39/* X core font driver. */
40
41Lisp_Object Qx;
42
43/* Alist of font registry symbol and the corresponding charsets
44 information. The information is retrieved from
45 Vfont_encoding_alist on demand.
46
47 Eash element has the form:
48 (REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID))
49 or
50 (REGISTRY . nil)
51
52 In the former form, ENCODING-CHARSET-ID is an ID of a charset that
53 encodes a character code to a glyph code of a font, and
54 REPERTORY-CHARSET-ID is an ID of a charset that tells if a
55 character is supported by a font.
56
57 The latter form means that the information for REGISTRY couldn't be
58 retrieved. */
59static Lisp_Object x_font_charset_alist;
60
61/* Prototypes of support functions. */
62extern void x_clear_errors P_ ((Display *));
63
64static char *xfont_query_font P_ ((Display *, char *, Lisp_Object));
65static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
66static int xfont_registry_charsets P_ ((Lisp_Object, struct charset **,
67 struct charset **));
68
69static char *
70xfont_query_font (display, name, spec)
71 Display *display;
72 char *name;
73 Lisp_Object spec;
74{
75 XFontStruct *font;
76
77 BLOCK_INPUT;
78 x_catch_errors (display);
79 font = XLoadQueryFont (display, name);
80 name = NULL;
81 if (x_had_errors_p (display))
82 {
83 /* This error is perhaps due to insufficient memory on X
84 server. Let's just ignore it. */
85 x_clear_errors (display);
86 }
87 else if (font)
88 {
89 unsigned long value;
90
91 if (XGetFontProperty (font, XA_FONT, &value))
92 {
93 char *n = (char *) XGetAtomName (display, (Atom) value);
94
95 if (font_parse_xlfd (n, spec, 0) >= 0)
96 name = n;
97 else
98 XFree (n);
99 }
100 XFreeFont (display, font);
101 }
102 x_uncatch_errors ();
103 UNBLOCK_INPUT;
104
105 return name;
106}
107
108
109/* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B
110 is not contained in the font. */
111
112static XCharStruct *
113xfont_get_pcm (xfont, char2b)
114 XFontStruct *xfont;
115 XChar2b *char2b;
116{
117 /* The result metric information. */
118 XCharStruct *pcm = NULL;
119
120 xassert (xfont && char2b);
121
122 if (xfont->per_char != NULL)
123 {
124 if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
125 {
126 /* min_char_or_byte2 specifies the linear character index
127 corresponding to the first element of the per_char array,
128 max_char_or_byte2 is the index of the last character. A
129 character with non-zero CHAR2B->byte1 is not in the font.
130 A character with byte2 less than min_char_or_byte2 or
131 greater max_char_or_byte2 is not in the font. */
132 if (char2b->byte1 == 0
133 && char2b->byte2 >= xfont->min_char_or_byte2
134 && char2b->byte2 <= xfont->max_char_or_byte2)
135 pcm = xfont->per_char + char2b->byte2 - xfont->min_char_or_byte2;
136 }
137 else
138 {
139 /* If either min_byte1 or max_byte1 are nonzero, both
140 min_char_or_byte2 and max_char_or_byte2 are less than
141 256, and the 2-byte character index values corresponding
142 to the per_char array element N (counting from 0) are:
143
144 byte1 = N/D + min_byte1
145 byte2 = N\D + min_char_or_byte2
146
147 where:
148
149 D = max_char_or_byte2 - min_char_or_byte2 + 1
150 / = integer division
151 \ = integer modulus */
152 if (char2b->byte1 >= xfont->min_byte1
153 && char2b->byte1 <= xfont->max_byte1
154 && char2b->byte2 >= xfont->min_char_or_byte2
155 && char2b->byte2 <= xfont->max_char_or_byte2)
156 pcm = (xfont->per_char
157 + ((xfont->max_char_or_byte2 - xfont->min_char_or_byte2 + 1)
158 * (char2b->byte1 - xfont->min_byte1))
159 + (char2b->byte2 - xfont->min_char_or_byte2));
160 }
161 }
162 else
163 {
164 /* If the per_char pointer is null, all glyphs between the first
165 and last character indexes inclusive have the same
166 information, as given by both min_bounds and max_bounds. */
167 if (char2b->byte2 >= xfont->min_char_or_byte2
168 && char2b->byte2 <= xfont->max_char_or_byte2)
169 pcm = &xfont->max_bounds;
170 }
171
172 return ((pcm == NULL
173 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
174 ? NULL : pcm);
175}
176
177extern Lisp_Object find_font_encoding P_ ((Lisp_Object));
178
179/* Return encoding charset and repertory charset for REGISTRY in
180 ENCODING and REPERTORY correspondingly. If correct information for
181 REGISTRY is available, return 0. Otherwise return -1. */
182
183static int
184xfont_registry_charsets (registry, encoding, repertory)
185 Lisp_Object registry;
186 struct charset **encoding, **repertory;
187{
188 Lisp_Object val;
189 int encoding_id, repertory_id;
190
191 val = assq_no_quit (registry, x_font_charset_alist);
192 if (! NILP (val))
193 {
194 val = XCDR (val);
195 if (NILP (val))
196 return -1;
197 encoding_id = XINT (XCAR (val));
198 repertory_id = XINT (XCDR (val));
199 }
200 else
201 {
202 val = find_font_encoding (SYMBOL_NAME (registry));
203 if (SYMBOLP (val) && CHARSETP (val))
204 {
205 encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val));
206 }
207 else if (CONSP (val))
208 {
209 if (! CHARSETP (XCAR (val)))
210 goto invalid_entry;
211 encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val)));
212 if (NILP (XCDR (val)))
213 repertory_id = -1;
214 else
215 {
216 if (! CHARSETP (XCDR (val)))
217 goto invalid_entry;
218 repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val)));
219 }
220 }
221 else
222 goto invalid_entry;
223 val = Fcons (make_number (encoding_id), make_number (repertory_id));
224 x_font_charset_alist
225 = nconc2 (x_font_charset_alist, Fcons (Fcons (registry, val), Qnil));
226 }
227
228 if (encoding)
229 *encoding = CHARSET_FROM_ID (encoding_id);
230 if (repertory)
231 *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
232 return 0;
233
234 invalid_entry:
235 x_font_charset_alist
236 = nconc2 (x_font_charset_alist, Fcons (Fcons (registry, Qnil), Qnil));
237 return -1;
238}
239
240static Lisp_Object xfont_get_cache P_ ((Lisp_Object));
241static int xfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object));
242static Lisp_Object xfont_list P_ ((Lisp_Object, Lisp_Object));
243static Lisp_Object xfont_list_family P_ ((Lisp_Object));
244static struct font *xfont_open P_ ((FRAME_PTR, Lisp_Object, int));
245static void xfont_close P_ ((FRAME_PTR, struct font *));
246static int xfont_prepare_face P_ ((FRAME_PTR, struct face *));
247#if 0
248static void xfont_done_face P_ ((FRAME_PTR, struct face *));
249#endif
250static int xfont_has_char P_ ((Lisp_Object, int));
251static unsigned xfont_encode_char P_ ((struct font *, int));
252static int xfont_text_extents P_ ((struct font *, unsigned *, int,
253 struct font_metrics *));
254static int xfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
255
256struct font_driver xfont_driver =
257 {
258 (Lisp_Object) NULL, /* Qx */
259 xfont_get_cache,
260 xfont_parse_name,
261 xfont_list,
262 xfont_list_family,
263 NULL,
264 xfont_open,
265 xfont_close,
266 xfont_prepare_face,
267 NULL /*xfont_done_face*/,
268 xfont_has_char,
269 xfont_encode_char,
270 xfont_text_extents,
271 xfont_draw,
272 };
273
274extern Lisp_Object QCname;
275
276static Lisp_Object
277xfont_get_cache (frame)
278 Lisp_Object frame;
279{
280 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (frame));
281
282 return (dpyinfo->name_list_element);
283}
284
285static int
286xfont_parse_name (f, name, spec)
287 FRAME_PTR f;
288 char *name;
289 Lisp_Object spec;
290{
291 if (font_parse_xlfd (name, spec, 0) >= 0)
292 return 0;
293 name = xfont_query_font (FRAME_X_DISPLAY (f), name, spec);
294 if (name)
295 {
296 XFree (name);
297 return 0;
298 }
299 return -1;
300}
301
302extern Lisp_Object Vface_alternative_font_registry_alist;
303
304static Lisp_Object
305xfont_list (frame, spec)
306 Lisp_Object frame, spec;
307{
308 FRAME_PTR f = XFRAME (frame);
309 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
310 Lisp_Object *vec, val, extra, font_name, entity;
311 char name[256], **names;
312 int i, idx, limit, num_fonts;
313 int error_occurred = 0;
314 USE_SAFE_ALLOCA;
315
316 extra = AREF (spec, FONT_EXTRA_INDEX);
317 font_name = Qnil;
318 if (CONSP (extra))
319 {
320 val = Fassq (QCotf, extra);
321 if (! NILP (val))
322 return null_vector;
323 val = Fassq (QCname, extra);
324 if (CONSP (val))
325 font_name = XCDR (val);
326 }
327
328 if (! STRINGP (font_name)
329 && font_unparse_xlfd (spec, 0, name, 256) < 0)
330 return null_vector;
331
332 BLOCK_INPUT;
333 x_catch_errors (dpyinfo->display);
334
335 if (STRINGP (font_name))
336 {
337 XFontStruct *font = XLoadQueryFont (dpyinfo->display,
338 (char *) SDATA (font_name));
339 unsigned long value;
340
341 num_fonts = 0;
342 if (x_had_errors_p (dpyinfo->display))
343 {
344 /* This error is perhaps due to insufficient memory on X
345 server. Let's just ignore it. */
346 font = NULL;
347 error_occurred = 1;
348 x_clear_errors (dpyinfo->display);
349 }
350 if (font)
351 {
352 if (XGetFontProperty (font, XA_FONT, &value))
353 {
354 char *n = (char *) XGetAtomName (dpyinfo->display, (Atom) value);
355 int len = strlen (n);
356 char *tmp;
357
358 /* If DXPC (a Differential X Protocol Compressor)
359 Ver.3.7 is running, XGetAtomName will return null
360 string. We must avoid such a name. */
361 if (len > 0)
362 {
363 num_fonts = 1;
364 names = (char **) alloca (sizeof (char *));
365 /* Some systems only allow alloca assigned to a
366 simple var. */
367 tmp = (char *) alloca (len + 1); names[0] = tmp;
368 bcopy (n, names[0], len + 1);
369 }
370 XFree (n);
371 }
372 XFreeFont (dpyinfo->display, font);
373 }
374 }
375 else
376 {
377 Lisp_Object registry = AREF (spec, FONT_REGISTRY_INDEX);
378 Lisp_Object alter = Qnil;
379 char *r = NULL;
380
381 if (! NILP (registry))
382 alter = Fassoc_string (SYMBOL_NAME (registry),
383 Vface_alternative_font_registry_alist);
384 while (1)
385 {
386 for (limit = 512, num_fonts = 0; ; limit *= 2)
387 {
388 names = XListFonts (dpyinfo->display, name, limit, &num_fonts);
389 if (x_had_errors_p (dpyinfo->display))
390 {
391 /* This error is perhaps due to insufficient memory
392 on X server. Let's just ignore it. */
393 x_clear_errors (dpyinfo->display);
394 error_occurred = 1;
395 num_fonts = 0;
396 break;
397 }
398 if (num_fonts < limit)
399 break;
400 XFreeFontNames (names);
401 }
402 if (num_fonts > 0
403 || NILP (alter))
404 break;
405
406 /* Setup for trying alternatives. */
407 if (! r
408 && ! (r = strstr (name, (char *) SDATA (SYMBOL_NAME (registry)))))
409 abort ();
410 while (1)
411 {
412 registry = Qnil;
413 alter = XCDR (alter);
414 if (NILP (alter))
415 break;
416 registry = XCAR (alter);
417 if ((r - name) + SBYTES (registry) < 255)
418 break;
419 }
420 if (NILP (registry))
421 break;
422 bcopy (SDATA (registry), r, SBYTES (registry));
423 }
424 }
425
426 x_uncatch_errors ();
427 UNBLOCK_INPUT;
428
429 if (error_occurred)
430 return Qnil;
431 if (num_fonts == 0)
432 return null_vector;
433
434 entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
435 ASET (entity, FONT_TYPE_INDEX, Qx);
436 ASET (entity, FONT_FRAME_INDEX, frame);
437
438 SAFE_ALLOCA_LISP (vec, num_fonts);
439 for (i = idx = 0; i < num_fonts; i++)
440 {
441 if (font_parse_xlfd (names[i], entity, 0) > 0)
442 vec[idx++] = Fcopy_sequence (entity);
443 }
444 if (! STRINGP (font_name))
445 {
446 BLOCK_INPUT;
447 XFreeFontNames (names);
448 UNBLOCK_INPUT;
449 }
450 val = Fvector (idx, vec);
451 SAFE_FREE ();
452
453 return val;
454}
455
456static int
457memq_no_quit (elt, list)
458 Lisp_Object elt, list;
459{
460 while (CONSP (list) && ! EQ (XCAR (list), elt))
461 list = XCDR (list);
462 return (CONSP (list));
463}
464
465static Lisp_Object
466xfont_list_family (frame)
467{
468 FRAME_PTR f = XFRAME (frame);
469 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
470 char **names;
471 int num_fonts, i;
472 Lisp_Object list;
473 char *last_family;
474 int last_len;
475
476 BLOCK_INPUT;
477 x_catch_errors (dpyinfo->display);
478 names = XListFonts (dpyinfo->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
479 0x8000, &num_fonts);
480 if (x_had_errors_p (dpyinfo->display))
481 {
482 /* This error is perhaps due to insufficient memory on X server.
483 Let's just ignore it. */
484 x_clear_errors (dpyinfo->display);
485 num_fonts = 0;
486 }
487
488 list = Qnil;
489 for (i = 0, last_len = 0; i < num_fonts; i++)
490 {
491 char *p0 = names[i], *p1;
492 Lisp_Object family;
493
494 p0++; /* skip the leading '-' */
495 while (*p0 && *p0 != '-') p0++; /* skip foundry */
496 if (! *p0)
497 continue;
498 p1 = ++p0;
499 while (*p1 && *p1 != '-') p1++; /* find the end of family */
500 if (! *p1 || p1 == p0)
501 continue;
502 if (last_len == p1 - p0
503 && bcmp (last_family, p0, last_len) == 0)
504 continue;
505 last_len = p1 - p0;
506 last_family = p0;
507 family = intern_downcase (p0, last_len);
508 if (! memq_no_quit (family, list))
509 list = Fcons (family, list);
510 }
511
512 XFreeFontNames (names);
513 x_uncatch_errors ();
514 UNBLOCK_INPUT;
515
516 return list;
517}
518
519static struct font *
520xfont_open (f, entity, pixel_size)
521 FRAME_PTR f;
522 Lisp_Object entity;
523 int pixel_size;
524{
525 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
526 Display *display = dpyinfo->display;
527 char name[256];
528 int len;
529 unsigned long value;
530 Lisp_Object registry;
531 struct charset *encoding, *repertory;
532 struct font *font;
533 XFontStruct *xfont;
534
535 /* At first, check if we know how to encode characters for this
536 font. */
537 registry = AREF (entity, FONT_REGISTRY_INDEX);
538 if (xfont_registry_charsets (registry, &encoding, &repertory) < 0)
539 return NULL;
540
541 if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
542 pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
543 len = font_unparse_xlfd (entity, pixel_size, name, 256);
544 if (len <= 0)
545 return NULL;
546
547 BLOCK_INPUT;
548 x_catch_errors (display);
549 xfont = XLoadQueryFont (display, name);
550 if (x_had_errors_p (display))
551 {
552 /* This error is perhaps due to insufficient memory on X server.
553 Let's just ignore it. */
554 x_clear_errors (display);
555 xfont = NULL;
556 }
557 x_uncatch_errors ();
558 UNBLOCK_INPUT;
559
560 if (! xfont)
561 return NULL;
562 font = malloc (sizeof (struct font));
563 font->font.font = xfont;
564 font->entity = entity;
565 font->pixel_size = pixel_size;
566 font->driver = &xfont_driver;
567 font->font.name = malloc (len + 1);
568 if (! font->font.name)
569 {
570 XFreeFont (display, xfont);
571 free (font);
572 return NULL;
573 }
574 bcopy (name, font->font.name, len + 1);
575 font->font.charset = encoding->id;
576 font->encoding_charset = encoding->id;
577 font->repertory_charet = repertory ? repertory->id : -1;
578 font->ascent = xfont->ascent;
579 font->descent = xfont->descent;
580
581 if (xfont->min_bounds.width == xfont->max_bounds.width)
582 {
583 /* Fixed width font. */
584 font->font.average_width = font->font.space_width
585 = xfont->min_bounds.width;
586 }
587 else
588 {
589 XChar2b char2b;
590 XCharStruct *pcm;
591
592 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
593 pcm = xfont_get_pcm (xfont, &char2b);
594 if (pcm)
595 font->font.space_width = pcm->width;
596 else
597 font->font.space_width = xfont->max_bounds.width;
598
599 font->font.average_width
600 = (XGetFontProperty (xfont, dpyinfo->Xatom_AVERAGE_WIDTH, &value)
601 ? (long) value / 10 : 0);
602 if (font->font.average_width < 0)
603 font->font.average_width = - font->font.average_width;
604 if (font->font.average_width == 0)
605 {
606 if (pcm)
607 {
608 int width = pcm->width;
609 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
610 if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
611 width += pcm->width;
612 font->font.average_width = width / 95;
613 }
614 else
615 font->font.average_width = xfont->max_bounds.width;
616 }
617 }
618 font->min_width = xfont->min_bounds.width;
619 if (font->min_width <= 0)
620 font->min_width = font->font.space_width;
621
622 BLOCK_INPUT;
623 /* Try to get the full name of FONT. Put it in FULL_NAME. */
624 if (XGetFontProperty (xfont, XA_FONT, &value))
625 {
626 char *full_name = NULL, *p0, *p;
627 int dashes = 0;
628
629 p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);;
630 /* Count the number of dashes in the "full name".
631 If it is too few, this isn't really the font's full name,
632 so don't use it.
633 In X11R4, the fonts did not come with their canonical names
634 stored in them. */
635 while (*p)
636 {
637 if (*p == '-')
638 dashes++;
639 p++;
640 }
641
642 if (dashes >= 13)
643 {
644 full_name = (char *) malloc (p - p0 + 1);
645 if (full_name)
646 bcopy (p0, full_name, p - p0 + 1);
647 }
648 XFree (p0);
649
650 if (full_name)
651 font->font.full_name = full_name;
652 else
653 font->font.full_name = font->font.name;
654 }
655 font->file_name = NULL;
656
657 font->font.size = xfont->max_bounds.width;
658 font->font.height = xfont->ascent + xfont->descent;
659 font->font.baseline_offset
660 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
661 ? (long) value : 0);
662 font->font.relative_compose
663 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
664 ? (long) value : 0);
665 font->font.default_ascent
666 = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
667 ? (long) value : 0);
668 font->font.vertical_centering
669 = (STRINGP (Vvertical_centering_font_regexp)
670 && (fast_c_string_match_ignore_case
671 (Vvertical_centering_font_regexp, font->font.full_name) >= 0));
672
673 UNBLOCK_INPUT;
674
675 dpyinfo->n_fonts++;
676
677 /* Set global flag fonts_changed_p to non-zero if the font loaded
678 has a character with a smaller width than any other character
679 before, or if the font loaded has a smaller height than any other
680 font loaded before. If this happens, it will make a glyph matrix
681 reallocation necessary. */
682 if (dpyinfo->n_fonts == 1)
683 {
684 dpyinfo->smallest_font_height = font->font.height;
685 dpyinfo->smallest_char_width = font->min_width;
686 fonts_changed_p = 1;
687 }
688 else
689 {
690 if (dpyinfo->smallest_font_height > font->font.height)
691 dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1;
692 if (dpyinfo->smallest_char_width > font->min_width)
693 dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1;
694 }
695
696 return font;
697}
698
699static void
700xfont_close (f, font)
701 FRAME_PTR f;
702 struct font *font;
703{
704 BLOCK_INPUT;
705 XFreeFont (FRAME_X_DISPLAY (f), font->font.font);
706 UNBLOCK_INPUT;
707
708 if (font->font.name != font->font.full_name)
709 free (font->font.full_name);
710 free (font->font.name);
711 free (font);
712 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
713}
714
715static int
716xfont_prepare_face (f, face)
717 FRAME_PTR f;
718 struct face *face;
719{
720 BLOCK_INPUT;
721 XSetFont (FRAME_X_DISPLAY (f), face->gc, face->font->fid);
722 UNBLOCK_INPUT;
723
724 return 0;
725}
726
727#if 0
728static void
729xfont_done_face (f, face)
730 FRAME_PTR f;
731 struct face *face;
732{
733 if (face->extra)
734 {
735 BLOCK_INPUT;
736 XFreeGC (FRAME_X_DISPLAY (f), (GC) face->extra);
737 UNBLOCK_INPUT;
738 face->extra = NULL;
739 }
740}
741#endif /* 0 */
742
743static int
744xfont_has_char (entity, c)
745 Lisp_Object entity;
746 int c;
747{
748 Lisp_Object registry = AREF (entity, FONT_REGISTRY_INDEX);
749 struct charset *repertory;
750
751 if (xfont_registry_charsets (registry, NULL, &repertory) < 0)
752 return -1;
753 if (! repertory)
754 return -1;
755 return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
756}
757
758static unsigned
759xfont_encode_char (font, c)
760 struct font *font;
761 int c;
762{
763 struct charset *charset;
764 unsigned code;
765 XChar2b char2b;
766
767 charset = CHARSET_FROM_ID (font->encoding_charset);
768 code = ENCODE_CHAR (charset, c);
769 if (code == CHARSET_INVALID_CODE (charset))
770 return 0xFFFFFFFF;
771 if (font->repertory_charet >= 0)
772 {
773 charset = CHARSET_FROM_ID (font->repertory_charet);
774 return (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset)
775 ? code : 0xFFFFFFFF);
776 }
777 char2b.byte1 = code >> 16;
778 char2b.byte2 = code & 0xFFFF;
779 return (xfont_get_pcm (font->font.font, &char2b) ? code : 0xFFFFFFFF);
780}
781
782static int
783xfont_text_extents (font, code, nglyphs, metrics)
784 struct font *font;
785 unsigned *code;
786 int nglyphs;
787 struct font_metrics *metrics;
788{
789 int width = 0;
790 int i, x;
791
792 if (metrics)
793 bzero (metrics, sizeof (struct font_metrics));
794 for (i = 0, x = 0; i < nglyphs; i++)
795 {
796 XChar2b char2b;
797 static XCharStruct *pcm;
798
799 if (code[i] >= 0x10000)
800 continue;
801 char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF;
802 pcm = xfont_get_pcm (font->font.font, &char2b);
803 if (! pcm)
804 continue;
805 if (metrics->lbearing > width + pcm->lbearing)
806 metrics->lbearing = width + pcm->lbearing;
807 if (metrics->rbearing < width + pcm->rbearing)
808 metrics->rbearing = width + pcm->rbearing;
809 if (metrics->ascent < pcm->ascent)
810 metrics->ascent = pcm->ascent;
811 if (metrics->descent < pcm->descent)
812 metrics->descent = pcm->descent;
813 width += pcm->width;
814 }
815 if (metrics)
816 metrics->width = width;
817 return width;
818}
819
820static int
821xfont_draw (s, from, to, x, y, with_background)
822 struct glyph_string *s;
823 int from, to, x, y, with_background;
824{
825 XFontStruct *xfont = s->face->font;
826 int len = to - from;
827
828 if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
829 {
830 char *str;
831 int i;
832 USE_SAFE_ALLOCA;
833
834 SAFE_ALLOCA (str, char *, len);
835 for (i = 0; i < len ; i++)
836 str[i] = XCHAR2B_BYTE2 (s->char2b + from + i);
837 if (with_background > 0)
838 XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
839 s->gc, x, y, str, len);
840 else
841 XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
842 s->gc, x, y, str, len);
843 SAFE_FREE ();
844 return s->nchars;
845 }
846
847 if (with_background > 0)
848 XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
849 s->gc, x, y, s->char2b + from, len);
850 else
851 XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
852 s->gc, x, y, s->char2b + from, len);
853
854 return len;
855}
856
857
858\f
859void
860syms_of_xfont ()
861{
862 staticpro (&x_font_charset_alist);
863 x_font_charset_alist = Qnil;
864
865 DEFSYM (Qx, "x");
866 xfont_driver.type = Qx;
867 register_font_driver (&xfont_driver, NULL);
868}