1 /* xfont.c -- X core font driver.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
9 GNU Emacs is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
29 #include "dispextern.h"
32 #include "blockinput.h"
33 #include "character.h"
39 /* X core font driver. */
43 /* Alist of font registry symbol and the corresponding charsets
44 information. The information is retrieved from
45 Vfont_encoding_alist on demand.
47 Eash element has the form:
48 (REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID))
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.
57 The latter form means that the information for REGISTRY couldn't be
59 static Lisp_Object x_font_charset_alist
;
61 /* Prototypes of support functions. */
62 extern void x_clear_errors
P_ ((Display
*));
64 static char *xfont_query_font
P_ ((Display
*, char *, Lisp_Object
));
65 static XCharStruct
*xfont_get_pcm
P_ ((XFontStruct
*, XChar2b
*));
66 static int xfont_registry_charsets
P_ ((Lisp_Object
, struct charset
**,
70 xfont_query_font (display
, name
, spec
)
78 x_catch_errors (display
);
79 font
= XLoadQueryFont (display
, name
);
81 if (x_had_errors_p (display
))
83 /* This error is perhaps due to insufficient memory on X
84 server. Let's just ignore it. */
85 x_clear_errors (display
);
91 if (XGetFontProperty (font
, XA_FONT
, &value
))
93 char *n
= (char *) XGetAtomName (display
, (Atom
) value
);
95 if (font_parse_xlfd (n
, spec
, 0) >= 0)
100 XFreeFont (display
, font
);
109 /* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B
110 is not contained in the font. */
113 xfont_get_pcm (xfont
, char2b
)
117 /* The result metric information. */
118 XCharStruct
*pcm
= NULL
;
120 xassert (xfont
&& char2b
);
122 if (xfont
->per_char
!= NULL
)
124 if (xfont
->min_byte1
== 0 && xfont
->max_byte1
== 0)
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
;
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:
144 byte1 = N/D + min_byte1
145 byte2 = N\D + min_char_or_byte2
149 D = max_char_or_byte2 - min_char_or_byte2 + 1
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
));
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
;
173 || (pcm
->width
== 0 && (pcm
->rbearing
- pcm
->lbearing
) == 0))
177 extern Lisp_Object find_font_encoding
P_ ((Lisp_Object
));
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. */
184 xfont_registry_charsets (registry
, encoding
, repertory
)
185 Lisp_Object registry
;
186 struct charset
**encoding
, **repertory
;
189 int encoding_id
, repertory_id
;
191 val
= assq_no_quit (registry
, x_font_charset_alist
);
197 encoding_id
= XINT (XCAR (val
));
198 repertory_id
= XINT (XCDR (val
));
202 val
= find_font_encoding (SYMBOL_NAME (registry
));
203 if (SYMBOLP (val
) && CHARSETP (val
))
205 encoding_id
= repertory_id
= XINT (CHARSET_SYMBOL_ID (val
));
207 else if (CONSP (val
))
209 if (! CHARSETP (XCAR (val
)))
211 encoding_id
= XINT (CHARSET_SYMBOL_ID (XCAR (val
)));
212 if (NILP (XCDR (val
)))
216 if (! CHARSETP (XCDR (val
)))
218 repertory_id
= XINT (CHARSET_SYMBOL_ID (XCDR (val
)));
223 val
= Fcons (make_number (encoding_id
), make_number (repertory_id
));
225 = nconc2 (x_font_charset_alist
, Fcons (Fcons (registry
, val
), Qnil
));
229 *encoding
= CHARSET_FROM_ID (encoding_id
);
231 *repertory
= repertory_id
>= 0 ? CHARSET_FROM_ID (repertory_id
) : NULL
;
236 = nconc2 (x_font_charset_alist
, Fcons (Fcons (registry
, Qnil
), Qnil
));
240 static Lisp_Object xfont_get_cache
P_ ((Lisp_Object
));
241 static int xfont_parse_name
P_ ((FRAME_PTR
, char *, Lisp_Object
));
242 static Lisp_Object xfont_list
P_ ((Lisp_Object
, Lisp_Object
));
243 static Lisp_Object xfont_list_family
P_ ((Lisp_Object
));
244 static struct font
*xfont_open
P_ ((FRAME_PTR
, Lisp_Object
, int));
245 static void xfont_close
P_ ((FRAME_PTR
, struct font
*));
246 static int xfont_prepare_face
P_ ((FRAME_PTR
, struct face
*));
248 static void xfont_done_face
P_ ((FRAME_PTR
, struct face
*));
250 static int xfont_has_char
P_ ((Lisp_Object
, int));
251 static unsigned xfont_encode_char
P_ ((struct font
*, int));
252 static int xfont_text_extents
P_ ((struct font
*, unsigned *, int,
253 struct font_metrics
*));
254 static int xfont_draw
P_ ((struct glyph_string
*, int, int, int, int, int));
256 struct font_driver xfont_driver
=
258 (Lisp_Object
) NULL
, /* Qx */
267 NULL
/*xfont_done_face*/,
274 extern Lisp_Object QCname
;
277 xfont_get_cache (frame
)
280 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (XFRAME (frame
));
282 return (dpyinfo
->name_list_element
);
286 xfont_parse_name (f
, name
, spec
)
291 if (font_parse_xlfd (name
, spec
, 0) >= 0)
293 name
= xfont_query_font (FRAME_X_DISPLAY (f
), name
, spec
);
302 extern Lisp_Object Vface_alternative_font_registry_alist
;
305 xfont_list (frame
, spec
)
306 Lisp_Object frame
, spec
;
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;
316 extra
= AREF (spec
, FONT_EXTRA_INDEX
);
320 val
= Fassq (QCotf
, extra
);
323 val
= Fassq (QCname
, extra
);
325 font_name
= XCDR (val
);
328 if (! STRINGP (font_name
)
329 && font_unparse_xlfd (spec
, 0, name
, 256) < 0)
333 x_catch_errors (dpyinfo
->display
);
335 if (STRINGP (font_name
))
337 XFontStruct
*font
= XLoadQueryFont (dpyinfo
->display
,
338 (char *) SDATA (font_name
));
342 if (x_had_errors_p (dpyinfo
->display
))
344 /* This error is perhaps due to insufficient memory on X
345 server. Let's just ignore it. */
348 x_clear_errors (dpyinfo
->display
);
352 if (XGetFontProperty (font
, XA_FONT
, &value
))
354 char *n
= (char *) XGetAtomName (dpyinfo
->display
, (Atom
) value
);
355 int len
= strlen (n
);
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. */
364 names
= (char **) alloca (sizeof (char *));
365 /* Some systems only allow alloca assigned to a
367 tmp
= (char *) alloca (len
+ 1); names
[0] = tmp
;
368 bcopy (n
, names
[0], len
+ 1);
372 XFreeFont (dpyinfo
->display
, font
);
377 Lisp_Object registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
378 Lisp_Object alter
= Qnil
;
381 if (! NILP (registry
))
382 alter
= Fassoc_string (SYMBOL_NAME (registry
),
383 Vface_alternative_font_registry_alist
);
386 for (limit
= 512, num_fonts
= 0; ; limit
*= 2)
388 names
= XListFonts (dpyinfo
->display
, name
, limit
, &num_fonts
);
389 if (x_had_errors_p (dpyinfo
->display
))
391 /* This error is perhaps due to insufficient memory
392 on X server. Let's just ignore it. */
393 x_clear_errors (dpyinfo
->display
);
398 if (num_fonts
< limit
)
400 XFreeFontNames (names
);
406 /* Setup for trying alternatives. */
408 && ! (r
= strstr (name
, (char *) SDATA (SYMBOL_NAME (registry
)))))
413 alter
= XCDR (alter
);
416 registry
= XCAR (alter
);
417 if ((r
- name
) + SBYTES (registry
) < 255)
422 bcopy (SDATA (registry
), r
, SBYTES (registry
));
434 entity
= Fmake_vector (make_number (FONT_ENTITY_MAX
), Qnil
);
435 ASET (entity
, FONT_TYPE_INDEX
, Qx
);
436 ASET (entity
, FONT_FRAME_INDEX
, frame
);
438 SAFE_ALLOCA_LISP (vec
, num_fonts
);
439 for (i
= idx
= 0; i
< num_fonts
; i
++)
441 if (font_parse_xlfd (names
[i
], entity
, 0) > 0)
442 vec
[idx
++] = Fcopy_sequence (entity
);
444 if (! STRINGP (font_name
))
447 XFreeFontNames (names
);
450 val
= Fvector (idx
, vec
);
457 memq_no_quit (elt
, list
)
458 Lisp_Object elt
, list
;
460 while (CONSP (list
) && ! EQ (XCAR (list
), elt
))
462 return (CONSP (list
));
466 xfont_list_family (frame
)
468 FRAME_PTR f
= XFRAME (frame
);
469 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
477 x_catch_errors (dpyinfo
->display
);
478 names
= XListFonts (dpyinfo
->display
, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
480 if (x_had_errors_p (dpyinfo
->display
))
482 /* This error is perhaps due to insufficient memory on X server.
483 Let's just ignore it. */
484 x_clear_errors (dpyinfo
->display
);
489 for (i
= 0, last_len
= 0; i
< num_fonts
; i
++)
491 char *p0
= names
[i
], *p1
;
494 p0
++; /* skip the leading '-' */
495 while (*p0
&& *p0
!= '-') p0
++; /* skip foundry */
499 while (*p1
&& *p1
!= '-') p1
++; /* find the end of family */
500 if (! *p1
|| p1
== p0
)
502 if (last_len
== p1
- p0
503 && bcmp (last_family
, p0
, last_len
) == 0)
507 family
= intern_downcase (p0
, last_len
);
508 if (! memq_no_quit (family
, list
))
509 list
= Fcons (family
, list
);
512 XFreeFontNames (names
);
520 xfont_open (f
, entity
, pixel_size
)
525 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
526 Display
*display
= dpyinfo
->display
;
530 Lisp_Object registry
;
531 struct charset
*encoding
, *repertory
;
535 /* At first, check if we know how to encode characters for this
537 registry
= AREF (entity
, FONT_REGISTRY_INDEX
);
538 if (xfont_registry_charsets (registry
, &encoding
, &repertory
) < 0)
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);
548 x_catch_errors (display
);
549 xfont
= XLoadQueryFont (display
, name
);
550 if (x_had_errors_p (display
))
552 /* This error is perhaps due to insufficient memory on X server.
553 Let's just ignore it. */
554 x_clear_errors (display
);
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
)
570 XFreeFont (display
, xfont
);
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
;
581 if (xfont
->min_bounds
.width
== xfont
->max_bounds
.width
)
583 /* Fixed width font. */
584 font
->font
.average_width
= font
->font
.space_width
585 = xfont
->min_bounds
.width
;
592 char2b
.byte1
= 0x00, char2b
.byte2
= 0x20;
593 pcm
= xfont_get_pcm (xfont
, &char2b
);
595 font
->font
.space_width
= pcm
->width
;
597 font
->font
.space_width
= xfont
->max_bounds
.width
;
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)
608 int width
= pcm
->width
;
609 for (char2b
.byte2
= 33; char2b
.byte2
<= 126; char2b
.byte2
++)
610 if ((pcm
= xfont_get_pcm (xfont
, &char2b
)) != NULL
)
612 font
->font
.average_width
= width
/ 95;
615 font
->font
.average_width
= xfont
->max_bounds
.width
;
618 font
->min_width
= xfont
->min_bounds
.width
;
619 if (font
->min_width
<= 0)
620 font
->min_width
= font
->font
.space_width
;
623 /* Try to get the full name of FONT. Put it in FULL_NAME. */
624 if (XGetFontProperty (xfont
, XA_FONT
, &value
))
626 char *full_name
= NULL
, *p0
, *p
;
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,
633 In X11R4, the fonts did not come with their canonical names
644 full_name
= (char *) malloc (p
- p0
+ 1);
646 bcopy (p0
, full_name
, p
- p0
+ 1);
651 font
->font
.full_name
= full_name
;
653 font
->font
.full_name
= font
->font
.name
;
655 font
->file_name
= NULL
;
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
)
662 font
->font
.relative_compose
663 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_MULE_RELATIVE_COMPOSE
, &value
)
665 font
->font
.default_ascent
666 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_MULE_DEFAULT_ASCENT
, &value
)
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));
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)
684 dpyinfo
->smallest_font_height
= font
->font
.height
;
685 dpyinfo
->smallest_char_width
= font
->min_width
;
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;
700 xfont_close (f
, font
)
705 XFreeFont (FRAME_X_DISPLAY (f
), font
->font
.font
);
708 if (font
->font
.name
!= font
->font
.full_name
)
709 free (font
->font
.full_name
);
710 free (font
->font
.name
);
712 FRAME_X_DISPLAY_INFO (f
)->n_fonts
--;
716 xfont_prepare_face (f
, face
)
721 XSetFont (FRAME_X_DISPLAY (f
), face
->gc
, face
->font
->fid
);
729 xfont_done_face (f
, face
)
736 XFreeGC (FRAME_X_DISPLAY (f
), (GC
) face
->extra
);
744 xfont_has_char (entity
, c
)
748 Lisp_Object registry
= AREF (entity
, FONT_REGISTRY_INDEX
);
749 struct charset
*repertory
;
751 if (xfont_registry_charsets (registry
, NULL
, &repertory
) < 0)
755 return (ENCODE_CHAR (repertory
, c
) != CHARSET_INVALID_CODE (repertory
));
759 xfont_encode_char (font
, c
)
763 struct charset
*charset
;
767 charset
= CHARSET_FROM_ID (font
->encoding_charset
);
768 code
= ENCODE_CHAR (charset
, c
);
769 if (code
== CHARSET_INVALID_CODE (charset
))
771 if (font
->repertory_charet
>= 0)
773 charset
= CHARSET_FROM_ID (font
->repertory_charet
);
774 return (ENCODE_CHAR (charset
, c
) != CHARSET_INVALID_CODE (charset
)
775 ? code
: 0xFFFFFFFF);
777 char2b
.byte1
= code
>> 8;
778 char2b
.byte2
= code
& 0xFF;
779 return (xfont_get_pcm (font
->font
.font
, &char2b
) ? code
: 0xFFFFFFFF);
783 xfont_text_extents (font
, code
, nglyphs
, metrics
)
787 struct font_metrics
*metrics
;
793 bzero (metrics
, sizeof (struct font_metrics
));
794 for (i
= 0, x
= 0; i
< nglyphs
; i
++)
797 static XCharStruct
*pcm
;
799 if (code
[i
] >= 0x10000)
801 char2b
.byte1
= code
[i
] >> 8, char2b
.byte2
= code
[i
] & 0xFF;
802 pcm
= xfont_get_pcm (font
->font
.font
, &char2b
);
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
;
816 metrics
->width
= width
;
821 xfont_draw (s
, from
, to
, x
, y
, with_background
)
822 struct glyph_string
*s
;
823 int from
, to
, x
, y
, with_background
;
825 XFontStruct
*xfont
= s
->face
->font
;
828 if (xfont
->min_byte1
== 0 && xfont
->max_byte1
== 0)
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
);
841 XDrawString (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
842 s
->gc
, x
, y
, str
, len
);
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
);
851 XDrawString16 (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
852 s
->gc
, x
, y
, s
->char2b
+ from
, len
);
862 staticpro (&x_font_charset_alist
);
863 x_font_charset_alist
= Qnil
;
866 xfont_driver
.type
= Qx
;
867 register_font_driver (&xfont_driver
, NULL
);
870 /* arch-tag: 23c5f366-a5ee-44b7-a3b7-90d6da7fd749
871 (do not change this comment) */