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)
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 Lisp_Object xfont_list
P_ ((Lisp_Object
, Lisp_Object
));
242 static Lisp_Object xfont_list_family
P_ ((Lisp_Object
));
243 static struct font
*xfont_open
P_ ((FRAME_PTR
, Lisp_Object
, int));
244 static void xfont_close
P_ ((FRAME_PTR
, struct font
*));
245 static int xfont_prepare_face
P_ ((FRAME_PTR
, struct face
*));
247 static void xfont_done_face
P_ ((FRAME_PTR
, struct face
*));
249 static int xfont_has_char
P_ ((Lisp_Object
, int));
250 static unsigned xfont_encode_char
P_ ((struct font
*, int));
251 static int xfont_text_extents
P_ ((struct font
*, unsigned *, int,
252 struct font_metrics
*));
253 static int xfont_draw
P_ ((struct glyph_string
*, int, int, int, int, int));
255 struct font_driver xfont_driver
=
257 (Lisp_Object
) NULL
, /* Qx */
265 NULL
/*xfont_done_face*/,
272 extern Lisp_Object QCname
;
275 xfont_get_cache (frame
)
278 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (XFRAME (frame
));
280 return (dpyinfo
->name_list_element
);
283 extern Lisp_Object Vface_alternative_font_registry_alist
;
286 xfont_list_pattern (frame
, display
, pattern
)
291 Lisp_Object list
= Qnil
;
292 int i
, limit
, num_fonts
;
296 x_catch_errors (display
);
298 for (limit
= 512; ; limit
*= 2)
300 names
= XListFonts (display
, pattern
, limit
, &num_fonts
);
301 if (x_had_errors_p (display
))
303 /* This error is perhaps due to insufficient memory on X
304 server. Let's just ignore it. */
305 x_clear_errors (display
);
309 if (num_fonts
< limit
)
311 XFreeFontNames (names
);
314 for (i
= 0; i
< num_fonts
; i
++)
316 Lisp_Object entity
= Fmake_vector (make_number (FONT_ENTITY_MAX
), Qnil
);
319 ASET (entity
, FONT_TYPE_INDEX
, Qx
);
320 ASET (entity
, FONT_FRAME_INDEX
, frame
);
322 result
= font_parse_xlfd (names
[i
], entity
);
325 /* This may be an alias name. Try to get the full XLFD name
326 from XA_FONT property of the font. */
327 XFontStruct
*font
= XLoadQueryFont (display
, names
[i
]);
332 if (XGetFontProperty (font
, XA_FONT
, &value
))
334 char *name
= (char *) XGetAtomName (display
, (Atom
) value
);
335 int len
= strlen (name
);
337 /* If DXPC (a Differential X Protocol Compressor)
338 Ver.3.7 is running, XGetAtomName will return null
339 string. We must avoid such a name. */
341 result
= font_parse_xlfd (name
, entity
);
344 XFreeFont (display
, font
);
349 Lisp_Object val
= AREF (entity
, FONT_EXTRA_INDEX
);
350 char *p
= (char *) SDATA (SYMBOL_NAME (val
));
352 /* P == "RESX-RESY-SPACING-AVGWIDTH. We rejust this font if
353 it's an autoscaled one (i.e. RESX > 0 && AVGWIDTH == 0). */
356 p
+= SBYTES (SYMBOL_NAME (val
));
357 while (p
[-1] != '-') p
--;
361 list
= Fcons (entity
, list
);
372 xfont_list (frame
, spec
)
373 Lisp_Object frame
, spec
;
375 FRAME_PTR f
= XFRAME (frame
);
376 Display
*display
= FRAME_X_DISPLAY_INFO (f
)->display
;
377 Lisp_Object list
, val
, extra
, font_name
;
381 extra
= AREF (spec
, FONT_EXTRA_INDEX
);
385 val
= assq_no_quit (QCotf
, extra
);
388 val
= assq_no_quit (QCscript
, extra
);
391 val
= assq_no_quit (QClanguage
, extra
);
394 val
= assq_no_quit (QCname
, extra
);
396 font_name
= XCDR (val
);
399 if (STRINGP (font_name
))
400 list
= xfont_list_pattern (frame
, display
, (char *) SDATA (font_name
));
401 else if ((len
= font_unparse_xlfd (spec
, 0, name
, 256)) < 0)
405 list
= xfont_list_pattern (frame
, display
, name
);
408 Lisp_Object registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
411 if (! NILP (registry
)
412 && (alter
= Fassoc (SYMBOL_NAME (registry
),
413 Vface_alternative_font_registry_alist
))
416 /* Pointer to REGISTRY-ENCODING field. */
417 char *r
= name
+ len
- SBYTES (SYMBOL_NAME (registry
));
419 for (alter
= XCDR (alter
); CONSP (alter
); alter
= XCDR (alter
))
420 if (STRINGP (XCAR (alter
))
421 && ((r
- name
) + SBYTES (XCAR (alter
))) < 255)
423 strcpy (r
, (char *) SDATA (XCAR (alter
)));
424 list
= xfont_list_pattern (frame
, display
, name
);
432 return (NILP (list
) ? null_vector
: Fvconcat (1, &list
));
436 memq_no_quit (elt
, list
)
437 Lisp_Object elt
, list
;
439 while (CONSP (list
) && ! EQ (XCAR (list
), elt
))
441 return (CONSP (list
));
445 xfont_list_family (frame
)
448 FRAME_PTR f
= XFRAME (frame
);
449 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
457 x_catch_errors (dpyinfo
->display
);
458 names
= XListFonts (dpyinfo
->display
, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
460 if (x_had_errors_p (dpyinfo
->display
))
462 /* This error is perhaps due to insufficient memory on X server.
463 Let's just ignore it. */
464 x_clear_errors (dpyinfo
->display
);
469 for (i
= 0, last_len
= 0; i
< num_fonts
; i
++)
471 char *p0
= names
[i
], *p1
;
474 p0
++; /* skip the leading '-' */
475 while (*p0
&& *p0
!= '-') p0
++; /* skip foundry */
479 while (*p1
&& *p1
!= '-') p1
++; /* find the end of family */
480 if (! *p1
|| p1
== p0
)
482 if (last_len
== p1
- p0
483 && bcmp (last_family
, p0
, last_len
) == 0)
487 family
= intern_downcase (p0
, last_len
);
488 if (! memq_no_quit (family
, list
))
489 list
= Fcons (family
, list
);
492 XFreeFontNames (names
);
500 xfont_open (f
, entity
, pixel_size
)
505 Display_Info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
506 Display
*display
= dpyinfo
->display
;
510 Lisp_Object registry
;
511 struct charset
*encoding
, *repertory
;
515 /* At first, check if we know how to encode characters for this
517 registry
= AREF (entity
, FONT_REGISTRY_INDEX
);
518 if (xfont_registry_charsets (registry
, &encoding
, &repertory
) < 0)
521 if (XINT (AREF (entity
, FONT_SIZE_INDEX
)) != 0)
522 pixel_size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
523 len
= font_unparse_xlfd (entity
, pixel_size
, name
, 256);
528 x_catch_errors (display
);
529 xfont
= XLoadQueryFont (display
, name
);
530 if (x_had_errors_p (display
))
532 /* This error is perhaps due to insufficient memory on X server.
533 Let's just ignore it. */
534 x_clear_errors (display
);
542 font
= malloc (sizeof (struct font
));
543 font
->font
.font
= xfont
;
544 font
->entity
= entity
;
545 font
->pixel_size
= pixel_size
;
546 font
->driver
= &xfont_driver
;
547 font
->font
.name
= malloc (len
+ 1);
548 if (! font
->font
.name
)
550 XFreeFont (display
, xfont
);
554 bcopy (name
, font
->font
.name
, len
+ 1);
555 font
->font
.charset
= encoding
->id
;
556 font
->encoding_charset
= encoding
->id
;
557 font
->repertory_charset
= repertory
? repertory
->id
: -1;
558 font
->ascent
= xfont
->ascent
;
559 font
->descent
= xfont
->descent
;
561 if (xfont
->min_bounds
.width
== xfont
->max_bounds
.width
)
563 /* Fixed width font. */
564 font
->font
.average_width
= font
->font
.space_width
565 = xfont
->min_bounds
.width
;
572 char2b
.byte1
= 0x00, char2b
.byte2
= 0x20;
573 pcm
= xfont_get_pcm (xfont
, &char2b
);
575 font
->font
.space_width
= pcm
->width
;
577 font
->font
.space_width
= xfont
->max_bounds
.width
;
579 font
->font
.average_width
580 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_AVERAGE_WIDTH
, &value
)
581 ? (long) value
/ 10 : 0);
582 if (font
->font
.average_width
< 0)
583 font
->font
.average_width
= - font
->font
.average_width
;
584 if (font
->font
.average_width
== 0)
588 int width
= pcm
->width
;
589 for (char2b
.byte2
= 33; char2b
.byte2
<= 126; char2b
.byte2
++)
590 if ((pcm
= xfont_get_pcm (xfont
, &char2b
)) != NULL
)
592 font
->font
.average_width
= width
/ 95;
595 font
->font
.average_width
= xfont
->max_bounds
.width
;
598 font
->min_width
= xfont
->min_bounds
.width
;
599 if (font
->min_width
<= 0)
600 font
->min_width
= font
->font
.space_width
;
603 /* Try to get the full name of FONT. Put it in FULL_NAME. */
604 if (XGetFontProperty (xfont
, XA_FONT
, &value
))
606 char *full_name
= NULL
, *p0
, *p
;
609 p0
= p
= (char *) XGetAtomName (FRAME_X_DISPLAY (f
), (Atom
) value
);;
610 /* Count the number of dashes in the "full name".
611 If it is too few, this isn't really the font's full name,
613 In X11R4, the fonts did not come with their canonical names
624 full_name
= (char *) malloc (p
- p0
+ 1);
626 bcopy (p0
, full_name
, p
- p0
+ 1);
631 font
->font
.full_name
= full_name
;
633 font
->font
.full_name
= font
->font
.name
;
635 font
->file_name
= NULL
;
637 font
->font
.size
= xfont
->max_bounds
.width
;
638 font
->font
.height
= xfont
->ascent
+ xfont
->descent
;
639 font
->font
.baseline_offset
640 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_MULE_BASELINE_OFFSET
, &value
)
642 font
->font
.relative_compose
643 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_MULE_RELATIVE_COMPOSE
, &value
)
645 font
->font
.default_ascent
646 = (XGetFontProperty (xfont
, dpyinfo
->Xatom_MULE_DEFAULT_ASCENT
, &value
)
648 font
->font
.vertical_centering
649 = (STRINGP (Vvertical_centering_font_regexp
)
650 && (fast_c_string_match_ignore_case
651 (Vvertical_centering_font_regexp
, font
->font
.full_name
) >= 0));
657 /* Set global flag fonts_changed_p to non-zero if the font loaded
658 has a character with a smaller width than any other character
659 before, or if the font loaded has a smaller height than any other
660 font loaded before. If this happens, it will make a glyph matrix
661 reallocation necessary. */
662 if (dpyinfo
->n_fonts
== 1)
664 dpyinfo
->smallest_font_height
= font
->font
.height
;
665 dpyinfo
->smallest_char_width
= font
->min_width
;
670 if (dpyinfo
->smallest_font_height
> font
->font
.height
)
671 dpyinfo
->smallest_font_height
= font
->font
.height
, fonts_changed_p
|= 1;
672 if (dpyinfo
->smallest_char_width
> font
->min_width
)
673 dpyinfo
->smallest_char_width
= font
->min_width
, fonts_changed_p
|= 1;
680 xfont_close (f
, font
)
685 XFreeFont (FRAME_X_DISPLAY (f
), font
->font
.font
);
688 if (font
->font
.name
!= font
->font
.full_name
)
689 free (font
->font
.full_name
);
690 free (font
->font
.name
);
692 FRAME_X_DISPLAY_INFO (f
)->n_fonts
--;
696 xfont_prepare_face (f
, face
)
701 XSetFont (FRAME_X_DISPLAY (f
), face
->gc
, face
->font
->fid
);
709 xfont_done_face (f
, face
)
716 XFreeGC (FRAME_X_DISPLAY (f
), (GC
) face
->extra
);
724 xfont_has_char (entity
, c
)
728 Lisp_Object registry
= AREF (entity
, FONT_REGISTRY_INDEX
);
729 struct charset
*repertory
;
731 if (xfont_registry_charsets (registry
, NULL
, &repertory
) < 0)
735 return (ENCODE_CHAR (repertory
, c
) != CHARSET_INVALID_CODE (repertory
));
739 xfont_encode_char (font
, c
)
743 struct charset
*charset
;
747 charset
= CHARSET_FROM_ID (font
->encoding_charset
);
748 code
= ENCODE_CHAR (charset
, c
);
749 if (code
== CHARSET_INVALID_CODE (charset
))
751 if (font
->repertory_charset
>= 0)
753 charset
= CHARSET_FROM_ID (font
->repertory_charset
);
754 return (ENCODE_CHAR (charset
, c
) != CHARSET_INVALID_CODE (charset
)
755 ? code
: 0xFFFFFFFF);
757 char2b
.byte1
= code
>> 8;
758 char2b
.byte2
= code
& 0xFF;
759 return (xfont_get_pcm (font
->font
.font
, &char2b
) ? code
: 0xFFFFFFFF);
763 xfont_text_extents (font
, code
, nglyphs
, metrics
)
767 struct font_metrics
*metrics
;
773 bzero (metrics
, sizeof (struct font_metrics
));
774 for (i
= 0, x
= 0; i
< nglyphs
; i
++)
777 static XCharStruct
*pcm
;
779 if (code
[i
] >= 0x10000)
781 char2b
.byte1
= code
[i
] >> 8, char2b
.byte2
= code
[i
] & 0xFF;
782 pcm
= xfont_get_pcm (font
->font
.font
, &char2b
);
785 if (metrics
->lbearing
> width
+ pcm
->lbearing
)
786 metrics
->lbearing
= width
+ pcm
->lbearing
;
787 if (metrics
->rbearing
< width
+ pcm
->rbearing
)
788 metrics
->rbearing
= width
+ pcm
->rbearing
;
789 if (metrics
->ascent
< pcm
->ascent
)
790 metrics
->ascent
= pcm
->ascent
;
791 if (metrics
->descent
< pcm
->descent
)
792 metrics
->descent
= pcm
->descent
;
796 metrics
->width
= width
;
801 xfont_draw (s
, from
, to
, x
, y
, with_background
)
802 struct glyph_string
*s
;
803 int from
, to
, x
, y
, with_background
;
805 XFontStruct
*xfont
= s
->face
->font
;
808 if (xfont
->min_byte1
== 0 && xfont
->max_byte1
== 0)
814 SAFE_ALLOCA (str
, char *, len
);
815 for (i
= 0; i
< len
; i
++)
816 str
[i
] = XCHAR2B_BYTE2 (s
->char2b
+ from
+ i
);
817 if (with_background
> 0)
818 XDrawImageString (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
819 s
->gc
, x
, y
, str
, len
);
821 XDrawString (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
822 s
->gc
, x
, y
, str
, len
);
827 if (with_background
> 0)
828 XDrawImageString16 (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
829 s
->gc
, x
, y
, s
->char2b
+ from
, len
);
831 XDrawString16 (FRAME_X_DISPLAY (s
->f
), FRAME_X_WINDOW (s
->f
),
832 s
->gc
, x
, y
, s
->char2b
+ from
, len
);
842 staticpro (&x_font_charset_alist
);
843 x_font_charset_alist
= Qnil
;
846 xfont_driver
.type
= Qx
;
847 register_font_driver (&xfont_driver
, NULL
);
850 /* arch-tag: 23c5f366-a5ee-44b7-a3b7-90d6da7fd749
851 (do not change this comment) */