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