Mercurial > hg > xemacs-beta
comparison src/objects-x.c @ 3094:ad2f4ae9895b
[xemacs-hg @ 2005-11-26 11:45:47 by stephent]
Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Sat, 26 Nov 2005 11:46:25 +0000 |
parents | 491f8cf78a9c |
children | 859a2346db99 |
comparison
equal
deleted
inserted
replaced
3093:769dc945b085 | 3094:ad2f4ae9895b |
---|---|
36 #include "insdel.h" | 36 #include "insdel.h" |
37 | 37 |
38 #include "console-x-impl.h" | 38 #include "console-x-impl.h" |
39 #include "objects-x-impl.h" | 39 #include "objects-x-impl.h" |
40 | 40 |
41 #ifdef USE_XFT | |
42 #include "xft-fonts.h" | |
43 #endif | |
44 | |
41 int x_handle_non_fully_specified_fonts; | 45 int x_handle_non_fully_specified_fonts; |
42 | 46 |
43 | 47 |
44 /************************************************************************/ | 48 /************************************************************************/ |
45 /* color instances */ | 49 /* color instances */ |
46 /************************************************************************/ | 50 /************************************************************************/ |
47 | 51 |
48 /* Replacement for XAllocColor() that tries to return the nearest | |
49 available color if the colormap is full. Original was from FSFmacs, | |
50 but rewritten by Jareth Hein <jareth@camelot-soft.com> 97/11/25 | |
51 Modified by Lee Kindness <lkindness@csl.co.uk> 31/08/99 to handle previous | |
52 total failure which was due to a read/write colorcell being the nearest | |
53 match - tries the next nearest... | |
54 | |
55 Return value is 1 for normal success, 2 for nearest color success, | |
56 3 for Non-deallocable success. */ | |
57 int | |
58 allocate_nearest_color (Display *display, Colormap colormap, Visual *visual, | |
59 XColor *color_def) | |
60 { | |
61 int status; | |
62 | |
63 if (visual->X_CLASSFIELD == DirectColor || visual->X_CLASSFIELD == TrueColor) | |
64 { | |
65 if (XAllocColor (display, colormap, color_def) != 0) | |
66 { | |
67 status = 1; | |
68 } | |
69 else | |
70 { | |
71 /* We're dealing with a TrueColor/DirectColor visual, so play games | |
72 with the RGB values in the XColor struct. */ | |
73 /* #### JH: I'm not sure how a call to XAllocColor can fail in a | |
74 TrueColor or DirectColor visual, so I will just reformat the | |
75 request to match the requirements of the visual, and re-issue | |
76 the request. If this fails for anybody, I wanna know about it | |
77 so I can come up with a better plan */ | |
78 | |
79 unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk; | |
80 junk = visual->red_mask; | |
81 rshift = 0; | |
82 while ((junk & 0x1) == 0) { | |
83 junk = junk >> 1; | |
84 rshift ++; | |
85 } | |
86 rbits = 0; | |
87 while (junk != 0) { | |
88 junk = junk >> 1; | |
89 rbits++; | |
90 } | |
91 junk = visual->green_mask; | |
92 gshift = 0; | |
93 while ((junk & 0x1) == 0) { | |
94 junk = junk >> 1; | |
95 gshift ++; | |
96 } | |
97 gbits = 0; | |
98 while (junk != 0) { | |
99 junk = junk >> 1; | |
100 gbits++; | |
101 } | |
102 junk = visual->blue_mask; | |
103 bshift = 0; | |
104 while ((junk & 0x1) == 0) { | |
105 junk = junk >> 1; | |
106 bshift ++; | |
107 } | |
108 bbits = 0; | |
109 while (junk != 0) { | |
110 junk = junk >> 1; | |
111 bbits++; | |
112 } | |
113 | |
114 color_def->red = color_def->red >> (16 - rbits); | |
115 color_def->green = color_def->green >> (16 - gbits); | |
116 color_def->blue = color_def->blue >> (16 - bbits); | |
117 if (XAllocColor (display, colormap, color_def) != 0) | |
118 status = 1; | |
119 else | |
120 { | |
121 int rd, gr, bl; | |
122 /* #### JH: I'm punting here, knowing that doing this will at | |
123 least draw the color correctly. However, unless we convert | |
124 all of the functions that allocate colors (graphics | |
125 libraries, etc) to use this function doing this is very | |
126 likely to cause problems later... */ | |
127 | |
128 if (rbits > 8) | |
129 rd = color_def->red << (rbits - 8); | |
130 else | |
131 rd = color_def->red >> (8 - rbits); | |
132 if (gbits > 8) | |
133 gr = color_def->green << (gbits - 8); | |
134 else | |
135 gr = color_def->green >> (8 - gbits); | |
136 if (bbits > 8) | |
137 bl = color_def->blue << (bbits - 8); | |
138 else | |
139 bl = color_def->blue >> (8 - bbits); | |
140 color_def->pixel = (rd << rshift) | (gr << gshift) | (bl << | |
141 bshift); | |
142 status = 3; | |
143 } | |
144 } | |
145 } | |
146 else | |
147 { | |
148 XColor *cells = NULL; | |
149 /* JH: I can't believe there's no way to go backwards from a | |
150 colormap ID and get its visual and number of entries, but X | |
151 apparently isn't built that way... */ | |
152 int no_cells = visual->map_entries; | |
153 status = 0; | |
154 | |
155 if (XAllocColor (display, colormap, color_def) != 0) | |
156 status = 1; | |
157 else while( status != 2 ) | |
158 { | |
159 /* If we got to this point, the colormap is full, so we're | |
160 going to try and get the next closest color. The algorithm used | |
161 is a least-squares matching, which is what X uses for closest | |
162 color matching with StaticColor visuals. */ | |
163 int nearest; | |
164 long nearest_delta, trial_delta; | |
165 int x; | |
166 | |
167 if( cells == NULL ) | |
168 { | |
169 cells = alloca_array (XColor, no_cells); | |
170 for (x = 0; x < no_cells; x++) | |
171 cells[x].pixel = x; | |
172 | |
173 /* read the current colormap */ | |
174 XQueryColors (display, colormap, cells, no_cells); | |
175 } | |
176 | |
177 nearest = 0; | |
178 /* I'm assuming CSE so I'm not going to condense this. */ | |
179 nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8)) | |
180 * ((color_def->red >> 8) - (cells[0].red >> 8))) | |
181 + | |
182 (((color_def->green >> 8) - (cells[0].green >> 8)) | |
183 * ((color_def->green >> 8) - (cells[0].green >> | |
184 8))) | |
185 + | |
186 (((color_def->blue >> 8) - (cells[0].blue >> 8)) | |
187 * ((color_def->blue >> 8) - (cells[0].blue >> | |
188 8)))); | |
189 for (x = 1; x < no_cells; x++) | |
190 { | |
191 trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8)) | |
192 * ((color_def->red >> 8) - (cells[x].red >> 8))) | |
193 + | |
194 (((color_def->green >> 8) - (cells[x].green >> 8)) | |
195 * ((color_def->green >> 8) - (cells[x].green >> | |
196 8))) | |
197 + | |
198 (((color_def->blue >> 8) - (cells[x].blue >> 8)) | |
199 * ((color_def->blue >> 8) - (cells[x].blue >> | |
200 8)))); | |
201 | |
202 /* less? Ignore cells marked as previously failing */ | |
203 if( (trial_delta < nearest_delta) && | |
204 (cells[x].pixel != ULONG_MAX) ) | |
205 { | |
206 nearest = x; | |
207 nearest_delta = trial_delta; | |
208 } | |
209 } | |
210 color_def->red = cells[nearest].red; | |
211 color_def->green = cells[nearest].green; | |
212 color_def->blue = cells[nearest].blue; | |
213 if (XAllocColor (display, colormap, color_def) != 0) | |
214 status = 2; | |
215 else | |
216 /* LSK: Either the colour map has changed since | |
217 * we read it, or the colour is allocated | |
218 * read/write... Mark this cmap entry so it's | |
219 * ignored in the next iteration. | |
220 */ | |
221 cells[nearest].pixel = ULONG_MAX; | |
222 } | |
223 } | |
224 return status; | |
225 } | |
226 | |
227 static int | 52 static int |
228 x_parse_nearest_color (struct device *d, XColor *color, Lisp_Object name, | 53 x_parse_nearest_color (struct device *d, XColor *color, Lisp_Object name, |
229 Error_Behavior errb) | 54 Error_Behavior errb) |
230 { | 55 { |
231 Display *dpy = DEVICE_X_DISPLAY (d); | 56 Display *dpy = DEVICE_X_DISPLAY (d); |
244 { | 69 { |
245 maybe_signal_error (Qgui_error, "Unrecognized color", | 70 maybe_signal_error (Qgui_error, "Unrecognized color", |
246 name, Qcolor, errb); | 71 name, Qcolor, errb); |
247 return 0; | 72 return 0; |
248 } | 73 } |
249 result = allocate_nearest_color (dpy, cmap, visual, color); | 74 result = x_allocate_nearest_color (dpy, cmap, visual, color); |
250 if (!result) | 75 if (!result) |
251 { | 76 { |
252 maybe_signal_error (Qgui_error, "Couldn't allocate color", | 77 maybe_signal_error (Qgui_error, "Couldn't allocate color", |
253 name, Qcolor, errb); | 78 name, Qcolor, errb); |
254 return 0; | 79 return 0; |
260 static int | 85 static int |
261 x_initialize_color_instance (Lisp_Color_Instance *c, Lisp_Object name, | 86 x_initialize_color_instance (Lisp_Color_Instance *c, Lisp_Object name, |
262 Lisp_Object device, Error_Behavior errb) | 87 Lisp_Object device, Error_Behavior errb) |
263 { | 88 { |
264 XColor color; | 89 XColor color; |
90 #ifdef USE_XFT | |
91 XftColor xftColor; | |
92 #endif | |
265 int result; | 93 int result; |
266 | 94 |
267 result = x_parse_nearest_color (XDEVICE (device), &color, name, errb); | 95 result = x_parse_nearest_color (XDEVICE (device), &color, name, errb); |
268 | 96 |
269 if (!result) | 97 if (!result) |
275 if (result == 3) | 103 if (result == 3) |
276 COLOR_INSTANCE_X_DEALLOC (c) = 0; | 104 COLOR_INSTANCE_X_DEALLOC (c) = 0; |
277 else | 105 else |
278 COLOR_INSTANCE_X_DEALLOC (c) = 1; | 106 COLOR_INSTANCE_X_DEALLOC (c) = 1; |
279 COLOR_INSTANCE_X_COLOR (c) = color; | 107 COLOR_INSTANCE_X_COLOR (c) = color; |
108 | |
109 #ifdef USE_XFT | |
110 xftColor.pixel = color.pixel; | |
111 xftColor.color.red = color.red; | |
112 xftColor.color.green = color.green; | |
113 xftColor.color.blue = color.blue; | |
114 xftColor.color.alpha = 0xffff; | |
115 | |
116 COLOR_INSTANCE_X_XFTCOLOR (c) = xftColor; | |
117 #endif | |
118 | |
280 return 1; | 119 return 1; |
281 } | 120 } |
282 | 121 |
283 static void | 122 static void |
284 x_print_color_instance (Lisp_Color_Instance *c, | 123 x_print_color_instance (Lisp_Color_Instance *c, |
364 | 203 |
365 /************************************************************************/ | 204 /************************************************************************/ |
366 /* font instances */ | 205 /* font instances */ |
367 /************************************************************************/ | 206 /************************************************************************/ |
368 | 207 |
208 #ifdef USE_XFT | |
209 /* #### all these #defines should probably move to xft-fonts.h */ | |
210 | |
211 /* | |
212 The format of a fontname (as returned by fontconfig) is not well-documented, | |
213 But the character repertoire is represented in an ASCII-compatible way. See | |
214 fccharset.c (FcCharSetUnparse). So we can use UTF-8 for long names. | |
215 | |
216 Currently we have a hack where different versions of the unparsed name are | |
217 used in different contexts fairly arbitrarily. I don't think this is close | |
218 to coherency; even without the charset and lang properties fontconfig names | |
219 are too unwieldy to use. We need to rethink the approach here. I think | |
220 probably Lisp_Font_Instance.name should contain the font name as specified | |
221 to Lisp (almost surely much shorter than shortname, even, and most likely | |
222 wildcarded), while Lisp_Font_Instance.truename should contain the longname. | |
223 For now, I'm going to #ifdef the return values defaulting to short. -- sjt | |
224 */ | |
225 | |
226 /* DEBUGGING STUFF */ | |
227 | |
228 /* print message to stderr: one internal-format string argument */ | |
229 #define DEBUG_XFT0(level,s) \ | |
230 if (debug_xft > level) stderr_out (s) | |
231 | |
232 /* print message to stderr: one formatted argument */ | |
233 #define DEBUG_XFT1(level,format,x1) \ | |
234 if (debug_xft > level) stderr_out (format, x1) | |
235 | |
236 /* print message to stderr: two formatted arguments */ | |
237 #define DEBUG_XFT2(level,format,x1,x2) \ | |
238 if (debug_xft > level) stderr_out (format, x1, x2) | |
239 | |
240 /* print message to stderr: three formatted arguments */ | |
241 #define DEBUG_XFT3(level,format,x1,x2,x3) \ | |
242 if (debug_xft > level) stderr_out (format, x1, x2, x3) | |
243 | |
244 /* print message to stderr: four formatted arguments */ | |
245 #define DEBUG_XFT4(level,format,x1,x2,x3,x4) \ | |
246 if (debug_xft > level) stderr_out (format, x1, x2, x3, x4) | |
247 | |
248 /* print an Xft pattern to stderr | |
249 LEVEL is the debug level (to compare to debug_xft) | |
250 FORMAT is a newline-terminated printf format with one %s for the pattern | |
251 and must be internal format (eg, pure ASCII) | |
252 PATTERN is an FcPattern *. */ | |
253 #define PRINT_XFT_PATTERN(level,format,pattern) \ | |
254 do { \ | |
255 DECLARE_EISTRING (eistrpxft_name); \ | |
256 FcChar8 *name = FcNameUnparse (pattern); \ | |
257 \ | |
258 eicpy_ext(eistrpxft_name, name, Qxft_font_name_encoding); \ | |
259 DEBUG_XFT1 (level, format, eidata(eistrpxft_name)); \ | |
260 free (name); \ | |
261 } while (0) | |
262 | |
263 /* print a progress message | |
264 LEVEL is the debug level (to compare to debug_xft) | |
265 FONT is the Xft font name in UTF-8 (the native encoding of Xft) | |
266 LANG is the language being checked for support (must be ASCII). */ | |
267 #define CHECKING_LANG(level,font,lang) \ | |
268 do { \ | |
269 DECLARE_EISTRING (eistrcl_name); \ | |
270 eicpy_ext(eistrcl_name, font, Qxft_font_name_encoding); \ | |
271 DEBUG_XFT2 (level, "checking if %s handles %s\n", \ | |
272 eidata(eistrcl_name), lang); \ | |
273 } while (0) | |
274 | |
275 #endif /* USE_XFT */ | |
276 | |
369 static int | 277 static int |
370 x_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object UNUSED (name), | 278 x_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object UNUSED (name), |
371 Lisp_Object device, Error_Behavior errb) | 279 Lisp_Object device, Error_Behavior errb) |
372 { | 280 { |
373 Display *dpy = DEVICE_X_DISPLAY (XDEVICE (device)); | 281 Display *dpy = DEVICE_X_DISPLAY (XDEVICE (device)); |
374 XFontStruct *xf; | 282 Extbyte *extname; |
375 const Extbyte *extname; | 283 XFontStruct *fs = NULL; /* _F_ont _S_truct */ |
376 | 284 #ifdef USE_XFT |
285 XftFont *rf = NULL; /* _R_ender _F_ont (X Render extension) */ | |
286 #else | |
287 #define rf (0) | |
288 #endif | |
289 | |
290 #ifdef USE_XFT | |
291 DEBUG_XFT1 (2, "attempting to initialize font spec %s\n", | |
292 XSTRING_DATA(f->name)); | |
293 /* #### serialize (optimize) these later... */ | |
294 /* #### This function really needs to go away. | |
295 The problem is that the fontconfig/Xft functions work much too hard | |
296 to ensure that something is returned; but that something need not be | |
297 at all close to what we asked for. */ | |
298 LISP_STRING_TO_EXTERNAL (f->name, extname, Qxft_font_name_encoding); | |
299 rf = xft_open_font_by_name (dpy, extname); | |
300 #endif | |
377 LISP_STRING_TO_EXTERNAL (f->name, extname, Qx_font_name_encoding); | 301 LISP_STRING_TO_EXTERNAL (f->name, extname, Qx_font_name_encoding); |
378 xf = XLoadQueryFont (dpy, extname); | 302 fs = XLoadQueryFont (dpy, extname); |
379 | 303 |
380 if (!xf) | 304 if (!fs && !rf) |
381 { | 305 { |
382 maybe_signal_error (Qgui_error, "Couldn't load font", f->name, Qfont, | 306 /* #### should this refer to X and/or Xft? */ |
383 errb); | 307 maybe_signal_error (Qgui_error, "Couldn't load font", f->name, |
308 Qfont, errb); | |
384 return 0; | 309 return 0; |
385 } | 310 } |
386 | 311 |
387 if (!xf->max_bounds.width) | 312 if (fs && !fs->max_bounds.width) |
388 { | 313 { |
389 /* yes, this has been known to happen. */ | 314 /* yes, this has been known to happen. */ |
390 XFreeFont (dpy, xf); | 315 XFreeFont (dpy, fs); |
316 fs = NULL; | |
391 maybe_signal_error (Qgui_error, "X font is too small", f->name, Qfont, | 317 maybe_signal_error (Qgui_error, "X font is too small", f->name, Qfont, |
392 errb); | 318 errb); |
393 return 0; | 319 if (!rf) |
394 } | 320 return 0; |
395 | 321 } |
396 /* Don't allocate the data until we're sure that we will succeed, | 322 |
397 or the finalize method may get fucked. */ | 323 /* Now that we're sure that we will succeed, we can allocate data without |
324 fear that the finalize method may get fucked. */ | |
398 f->data = xnew (struct x_font_instance_data); | 325 f->data = xnew (struct x_font_instance_data); |
399 FONT_INSTANCE_X_FONT (f) = xf; | 326 |
400 f->ascent = xf->ascent; | 327 #ifdef USE_XFT |
401 f->descent = xf->descent; | 328 FONT_INSTANCE_X_XFTFONT (f) = rf; |
402 f->height = xf->ascent + xf->descent; | 329 if (rf) |
403 { | 330 /* Have an Xft font, initialize font info from it. */ |
404 /* following change suggested by Ted Phelps <phelps@dstc.edu.au> */ | 331 { |
405 int def_char = 'n'; /*xf->default_char;*/ | 332 DEBUG_XFT4 (2, "pre-initial ascent %d descent %d width %d height %d\n", |
406 int byte1, byte2; | 333 f->ascent, f->descent, f->width, f->height); |
407 | 334 |
408 once_more: | 335 /* #### This shit is just plain wrong unless we have a character cell |
409 byte1 = def_char >> 8; | 336 font. It really hoses us on large repertoire Unicode fonts with |
410 byte2 = def_char & 0xFF; | 337 "double-width" characters. */ |
411 | 338 f->ascent = rf->ascent; |
412 if (xf->per_char) | 339 f->descent = rf->descent; |
413 { | 340 { |
414 /* Old versions of the R5 font server have garbage (>63k) as | 341 /* This is an approximation that AFAIK only gets used to compute |
415 def_char. 'n' might not be a valid character. */ | 342 cell size for estimating window dimensions. The test_string8 |
416 if (byte1 < (int) xf->min_byte1 || | 343 is an ASCII string whose characters should approximate the |
417 byte1 > (int) xf->max_byte1 || | 344 distribution of widths expected in real text. */ |
418 byte2 < (int) xf->min_char_or_byte2 || | 345 static const char test_string8[] = "Mmneei"; |
419 byte2 > (int) xf->max_char_or_byte2) | 346 static const int len = sizeof (test_string8) - 1; |
420 f->width = 0; | 347 XGlyphInfo glyphinfo; |
348 | |
349 XftTextExtents8 (dpy, rf, test_string8, len, &glyphinfo); | |
350 /* #### maybe should be glyphinfo.xOff - glyphinfo.x? */ | |
351 f->width = (2*glyphinfo.width + len)/(2*len); | |
352 } | |
353 f->height = rf->height; | |
354 f->proportional_p = 1; /* we can't recognize monospaced fonts! */ | |
355 | |
356 DEBUG_XFT4 (0, "initialized metrics ascent %d descent %d width %d height %d\n", | |
357 f->ascent, f->descent, f->width, f->height); | |
358 /* we also output on initialization of any font below */ | |
359 DEBUG_XFT1 (2, "initialized Xft font %s\n", XSTRING_DATA(f->name)); | |
360 fs = NULL; /* we don' need no steenkin' X font */ | |
361 } | |
362 else | |
363 { | |
364 DEBUG_XFT1 (0, "couldn't initialize Xft font %s\n", | |
365 XSTRING_DATA(f->name)); | |
366 } | |
367 #endif | |
368 | |
369 FONT_INSTANCE_X_FONT (f) = fs; | |
370 if (fs) | |
371 /* Have to use a core font, initialize font info from it. */ | |
372 { | |
373 f->ascent = fs->ascent; | |
374 f->descent = fs->descent; | |
375 f->height = fs->ascent + fs->descent; | |
376 { | |
377 /* following change suggested by Ted Phelps <phelps@dstc.edu.au> */ | |
378 int def_char = 'n'; /*fs->default_char;*/ | |
379 int byte1, byte2; | |
380 | |
381 once_more: | |
382 byte1 = def_char >> 8; | |
383 byte2 = def_char & 0xFF; | |
384 | |
385 if (fs->per_char) | |
386 { | |
387 /* Old versions of the R5 font server have garbage (>63k) as | |
388 def_char. 'n' might not be a valid character. */ | |
389 if (byte1 < (int) fs->min_byte1 || | |
390 byte1 > (int) fs->max_byte1 || | |
391 byte2 < (int) fs->min_char_or_byte2 || | |
392 byte2 > (int) fs->max_char_or_byte2) | |
393 f->width = 0; | |
394 else | |
395 f->width = fs->per_char[(byte1 - fs->min_byte1) * | |
396 (fs->max_char_or_byte2 - | |
397 fs->min_char_or_byte2 + 1) + | |
398 (byte2 - fs->min_char_or_byte2)].width; | |
399 } | |
421 else | 400 else |
422 f->width = xf->per_char[(byte1 - xf->min_byte1) * | 401 f->width = fs->max_bounds.width; |
423 (xf->max_char_or_byte2 - | 402 |
424 xf->min_char_or_byte2 + 1) + | 403 /* Some fonts have a default char whose width is 0. This is no good. |
425 (byte2 - xf->min_char_or_byte2)].width; | 404 If that's the case, first try 'n' as the default char, and if n has |
426 } | 405 0 width too (unlikely) then just use the max width. */ |
427 else | 406 if (f->width == 0) |
428 f->width = xf->max_bounds.width; | |
429 | |
430 /* Some fonts have a default char whose width is 0. This is no good. | |
431 If that's the case, first try 'n' as the default char, and if n has | |
432 0 width too (unlikely) then just use the max width. */ | |
433 if (f->width == 0) | |
434 { | |
435 if (def_char == (int) xf->default_char) | |
436 f->width = xf->max_bounds.width; | |
437 else | |
438 { | 407 { |
439 def_char = xf->default_char; | 408 if (def_char == (int) fs->default_char) |
440 goto once_more; | 409 f->width = fs->max_bounds.width; |
410 else | |
411 { | |
412 def_char = fs->default_char; | |
413 goto once_more; | |
414 } | |
441 } | 415 } |
442 } | 416 } |
443 } | 417 |
444 /* If all characters don't exist then there could potentially be | 418 /* If all characters don't exist then there could potentially be |
445 0-width characters lurking out there. Not setting this flag | 419 0-width characters lurking out there. Not setting this flag |
446 trips an optimization that would make them appear to have width | 420 trips an optimization that would make them appear to have width |
447 to redisplay. This is bad. So we set it if not all characters | 421 to redisplay. This is bad. So we set it if not all characters |
448 have the same width or if not all characters are defined. | 422 have the same width or if not all characters are defined. */ |
449 */ | 423 /* #### This sucks. There is a measurable performance increase |
450 /* #### This sucks. There is a measurable performance increase | 424 when using proportional width fonts if this flag is not set. |
451 when using proportional width fonts if this flag is not set. | 425 Unfortunately so many of the fucking X fonts are not fully |
452 Unfortunately so many of the fucking X fonts are not fully | 426 defined that we could almost just get rid of this damn flag and |
453 defined that we could almost just get rid of this damn flag and | 427 make it an assertion. */ |
454 make it an assertion. */ | 428 f->proportional_p = (fs->min_bounds.width != fs->max_bounds.width || |
455 f->proportional_p = (xf->min_bounds.width != xf->max_bounds.width || | 429 (x_handle_non_fully_specified_fonts && |
456 (x_handle_non_fully_specified_fonts && | 430 !fs->all_chars_exist)); |
457 !xf->all_chars_exist)); | 431 } |
432 | |
433 #ifdef USE_XFT | |
434 if (debug_xft > 0) | |
435 { | |
436 int n = 3, d = 5; | |
437 /* check for weirdness */ | |
438 if (n * f->height < d * f->width) | |
439 stderr_out ("font %s: width:height is %d:%d, larger than %d:%d\n", | |
440 XSTRING_DATA(f->name), f->width, f->height, n, d); | |
441 if (f->height <= 0 || f->width <= 0) | |
442 stderr_out ("bogus dimensions of font %s: width = %d, height = %d\n", | |
443 XSTRING_DATA(f->name), f->width, f->height); | |
444 stderr_out ("initialized font %s\n", XSTRING_DATA(f->name)); | |
445 } | |
446 #else | |
447 #undef rf | |
448 #endif | |
458 | 449 |
459 return 1; | 450 return 1; |
460 } | 451 } |
461 | 452 |
462 static void | 453 static void |
463 x_print_font_instance (Lisp_Font_Instance *f, | 454 x_print_font_instance (Lisp_Font_Instance *f, |
464 Lisp_Object printcharfun, | 455 Lisp_Object printcharfun, |
465 int UNUSED (escapeflag)) | 456 int UNUSED (escapeflag)) |
466 { | 457 { |
467 write_fmt_string (printcharfun, " 0x%lx", | 458 if (FONT_INSTANCE_X_FONT (f)) |
468 (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); | 459 write_fmt_string (printcharfun, " font id: 0x%lx", |
460 (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); | |
461 #ifdef USE_XFT | |
462 /* #### What should we do here? For now, print the address. */ | |
463 if (FONT_INSTANCE_X_XFTFONT (f)) | |
464 write_fmt_string (printcharfun, " xft font: 0x%lx", | |
465 (unsigned long) FONT_INSTANCE_X_XFTFONT (f)); | |
466 #endif | |
469 } | 467 } |
470 | 468 |
471 static void | 469 static void |
472 x_finalize_font_instance (Lisp_Font_Instance *f) | 470 x_finalize_font_instance (Lisp_Font_Instance *f) |
473 { | 471 { |
472 | |
473 #ifdef USE_XFT | |
474 DEBUG_XFT1 (0, "finalizing %s\n", (STRINGP (f->name) | |
475 ? (char *) XSTRING_DATA (f->name) | |
476 : "(unnamed font)")); | |
477 #endif | |
474 | 478 |
475 if (f->data) | 479 if (f->data) |
476 { | 480 { |
477 if (DEVICE_LIVE_P (XDEVICE (f->device))) | 481 if (DEVICE_LIVE_P (XDEVICE (f->device))) |
478 { | 482 { |
479 Display *dpy = DEVICE_X_DISPLAY (XDEVICE (f->device)); | 483 Display *dpy = DEVICE_X_DISPLAY (XDEVICE (f->device)); |
480 | 484 |
481 XFreeFont (dpy, FONT_INSTANCE_X_FONT (f)); | 485 if (FONT_INSTANCE_X_FONT (f)) |
486 XFreeFont (dpy, FONT_INSTANCE_X_FONT (f)); | |
487 #ifdef USE_XFT | |
488 if (FONT_INSTANCE_X_XFTFONT (f)) | |
489 XftFontClose (dpy, FONT_INSTANCE_X_XFTFONT (f)); | |
490 #endif | |
482 } | 491 } |
483 xfree (f->data, void *); | 492 xfree (f->data, void *); |
484 f->data = 0; | 493 f->data = 0; |
485 } | 494 } |
486 } | 495 } |
487 | 496 |
488 /* Determining the truename of a font is hard. (Big surprise.) | 497 /* Determining the truename of a font is hard. (Big surprise.) |
498 | |
499 This is not true for fontconfig. Each font has a (nearly) canonical | |
500 representation up to permutation of the order of properties. It is | |
501 possible to construct a name which exactly identifies the properties of | |
502 the current font. However, it is theoretically possible that there exists | |
503 another font with a super set of those properties that would happen to get | |
504 selected. -- sjt | |
489 | 505 |
490 By "truename" we mean an XLFD-form name which contains no wildcards, yet | 506 By "truename" we mean an XLFD-form name which contains no wildcards, yet |
491 which resolves to *exactly* the same font as the one which we already have | 507 which resolves to *exactly* the same font as the one which we already have |
492 the (probably wildcarded) name and `XFontStruct' of. | 508 the (probably wildcarded) name and `XFontStruct' of. |
493 | 509 |
693 names = XListFonts (dpy, font_name, 1, &count); | 709 names = XListFonts (dpy, font_name, 1, &count); |
694 if (count) result = names [0]; | 710 if (count) result = names [0]; |
695 #else | 711 #else |
696 /* But the world I live in is much more perverse. */ | 712 /* But the world I live in is much more perverse. */ |
697 names = XListFonts (dpy, font_name, MAX_FONT_COUNT, &count); | 713 names = XListFonts (dpy, font_name, MAX_FONT_COUNT, &count); |
714 /* Find the lexicographic minimum of names[]. | |
715 (#### Should we be comparing case-insensitively?) */ | |
698 while (count--) | 716 while (count--) |
699 /* !!#### Not Mule-friendly */ | 717 /* [[ !!#### Not Mule-friendly ]] |
700 /* If names[count] is lexicographically less than result, use it. | 718 Doesn't matter, XLFDs are HPC (old) or Latin1 (modern). If they |
701 (#### Should we be comparing case-insensitively?) */ | 719 aren't, who knows what they are? -- sjt */ |
702 if (result == 0 || (strcmp (result, names [count]) < 0)) | 720 if (result == 0 || (strcmp (result, names [count]) < 0)) |
703 result = names [count]; | 721 result = names [count]; |
704 #endif | 722 #endif |
705 | 723 |
706 if (result) | 724 if (result) |
771 | 789 |
772 static Lisp_Object | 790 static Lisp_Object |
773 x_font_instance_truename (Lisp_Font_Instance *f, Error_Behavior errb) | 791 x_font_instance_truename (Lisp_Font_Instance *f, Error_Behavior errb) |
774 { | 792 { |
775 struct device *d = XDEVICE (f->device); | 793 struct device *d = XDEVICE (f->device); |
794 Display *dpy = DEVICE_X_DISPLAY (d); | |
795 Extbyte *nameext; | |
796 char* xlfd; | |
797 | |
798 /* #### restructure this so that we return a valid truename at the end, | |
799 and otherwise only return when we return something desperate that | |
800 doesn't get stored for future use. */ | |
801 | |
802 #ifdef USE_XFT | |
803 /* First, try an Xft font. */ | |
804 if (NILP (FONT_INSTANCE_TRUENAME (f)) && FONT_INSTANCE_X_XFTFONT (f)) | |
805 { | |
806 /* The font is already open, we just unparse. */ | |
807 FcChar8 *res = FcNameUnparse (FONT_INSTANCE_X_XFTFONT (f)->pattern); | |
808 if (res) | |
809 { | |
810 FONT_INSTANCE_TRUENAME (f) = make_string (res, strlen (res)); | |
811 free (res); | |
812 return FONT_INSTANCE_TRUENAME (f); | |
813 } | |
814 else | |
815 { | |
816 maybe_signal_error (Qgui_error, | |
817 "Couldn't unparse Xft font to truename", | |
818 Qnil, Qfont, errb); | |
819 /* used to return Qnil here */ | |
820 } | |
821 } | |
822 #endif /* USE_XFT */ | |
823 | |
824 /* OK, fall back to core font. */ | |
825 if (NILP (FONT_INSTANCE_TRUENAME (f)) | |
826 && FONT_INSTANCE_X_FONT (f)) | |
827 { | |
828 nameext = &xlfd[0]; | |
829 LISP_STRING_TO_EXTERNAL (f->name, nameext, Qx_font_name_encoding); | |
830 | |
831 FONT_INSTANCE_TRUENAME (f) = | |
832 x_font_truename (dpy, nameext, FONT_INSTANCE_X_FONT (f)); | |
833 } | |
776 | 834 |
777 if (NILP (FONT_INSTANCE_TRUENAME (f))) | 835 if (NILP (FONT_INSTANCE_TRUENAME (f))) |
778 { | 836 { |
779 Display *dpy = DEVICE_X_DISPLAY (d); | 837 /* Urk, no luck. Whine about our bad luck and exit. */ |
780 { | 838 Lisp_Object font_instance = wrap_font_instance (f); |
781 Extbyte *nameext; | 839 |
782 | 840 |
783 LISP_STRING_TO_EXTERNAL (f->name, nameext, Qx_font_name_encoding); | 841 maybe_signal_error (Qgui_error, "Couldn't determine font truename", |
784 FONT_INSTANCE_TRUENAME (f) = | 842 font_instance, Qfont, errb); |
785 x_font_truename (dpy, nameext, FONT_INSTANCE_X_FONT (f)); | 843 /* Ok, just this once, return the font name as the truename. |
786 } | 844 (This is only used by Fequal() right now.) */ |
787 if (NILP (FONT_INSTANCE_TRUENAME (f))) | 845 return f->name; |
788 { | 846 } |
789 Lisp_Object font_instance = wrap_font_instance (f); | 847 |
790 | 848 /* Return what we found. */ |
791 | |
792 maybe_signal_error (Qgui_error, "Couldn't determine font truename", | |
793 font_instance, Qfont, errb); | |
794 /* Ok, just this once, return the font name as the truename. | |
795 (This is only used by Fequal() right now.) */ | |
796 return f->name; | |
797 } | |
798 } | |
799 return FONT_INSTANCE_TRUENAME (f); | 849 return FONT_INSTANCE_TRUENAME (f); |
800 } | 850 } |
801 | 851 |
802 static Lisp_Object | 852 static Lisp_Object |
803 x_font_instance_properties (Lisp_Font_Instance *f) | 853 x_font_instance_properties (Lisp_Font_Instance *f) |
804 { | 854 { |
805 struct device *d = XDEVICE (f->device); | 855 struct device *d = XDEVICE (f->device); |
806 int i; | 856 int i; |
807 Lisp_Object result = Qnil; | 857 Lisp_Object result = Qnil; |
808 Display *dpy = DEVICE_X_DISPLAY (d); | 858 Display *dpy = DEVICE_X_DISPLAY (d); |
809 XFontProp *props = FONT_INSTANCE_X_FONT (f)->properties; | 859 XFontProp *props = NULL; |
810 | 860 |
861 /* #### really should hack Xft fonts, too | |
862 Strategy: fontconfig must have an iterator for this purpose. */ | |
863 if (! FONT_INSTANCE_X_FONT (f)) return result; | |
864 | |
865 props = FONT_INSTANCE_X_FONT (f)->properties; | |
811 for (i = FONT_INSTANCE_X_FONT (f)->n_properties - 1; i >= 0; i--) | 866 for (i = FONT_INSTANCE_X_FONT (f)->n_properties - 1; i >= 0; i--) |
812 { | 867 { |
813 Lisp_Object name, value; | 868 Lisp_Object name, value; |
814 Atom atom = props [i].name; | 869 Atom atom = props [i].name; |
815 Ibyte *name_str = 0; | 870 Ibyte *name_str = 0; |
885 } | 940 } |
886 | 941 |
887 #ifdef MULE | 942 #ifdef MULE |
888 | 943 |
889 static int | 944 static int |
890 x_font_spec_matches_charset (struct device *UNUSED (d), Lisp_Object charset, | 945 x_font_spec_matches_charset (struct device * USED_IF_XFT (d), |
946 Lisp_Object charset, | |
891 const Ibyte *nonreloc, Lisp_Object reloc, | 947 const Ibyte *nonreloc, Lisp_Object reloc, |
892 Bytecount offset, Bytecount length, | 948 Bytecount offset, Bytecount length, |
893 int stage) | 949 int stage) |
894 { | 950 { |
895 if (stage) | 951 if (stage) |
952 #ifdef USE_XFT | |
953 { | |
954 Display *dpy = DEVICE_X_DISPLAY (d); | |
955 Extbyte *extname; | |
956 XftFont *rf; | |
957 const Ibyte *the_nonreloc; | |
958 | |
959 if (!NILP(reloc)) | |
960 { | |
961 the_nonreloc = XSTRING_DATA (reloc); | |
962 LISP_STRING_TO_EXTERNAL (reloc, extname, Qx_font_name_encoding); | |
963 rf = xft_open_font_by_name (dpy, extname); | |
964 return 0; /* #### maybe this will compile and run ;) */ | |
965 } | |
966 } | |
967 #else | |
896 return 0; | 968 return 0; |
969 #endif | |
897 | 970 |
898 if (UNBOUNDP (charset)) | 971 if (UNBOUNDP (charset)) |
899 return 1; | 972 return 1; |
900 /* Hack! Short font names don't have the registry in them, | 973 /* Hack! Short font names don't have the registry in them, |
901 so we just assume the user knows what they're doing in the | 974 so we just assume the user knows what they're doing in the |
902 case of ASCII. For other charsets, you gotta give the | 975 case of ASCII. For other charsets, you gotta give the |
903 long form; sorry buster. | 976 long form; sorry buster. |
977 #### FMH: this screws fontconfig/Xft? | |
978 STRATEGY: use fontconfig's ability to hack languages and character | |
979 sets (lang and charset properties). | |
980 #### Maybe we can use the fontconfig model to eliminate the difference | |
981 between faces and fonts? No - it looks like that would be an abuse | |
982 (fontconfig doesn't know about colors, although Xft does). | |
904 */ | 983 */ |
905 if (EQ (charset, Vcharset_ascii)) | 984 if (EQ (charset, Vcharset_ascii)) |
906 { | 985 { |
907 const Ibyte *the_nonreloc = nonreloc; | 986 const Ibyte *the_nonreloc = nonreloc; |
908 int i; | 987 int i; |
937 return (fast_string_match (XCHARSET_REGISTRY (charset), | 1016 return (fast_string_match (XCHARSET_REGISTRY (charset), |
938 nonreloc, reloc, offset, length, 1, | 1017 nonreloc, reloc, offset, length, 1, |
939 ERROR_ME, 0) >= 0); | 1018 ERROR_ME, 0) >= 0); |
940 } | 1019 } |
941 | 1020 |
1021 #ifdef USE_XFT | |
1022 /* #### debug functions: find a better place for us */ | |
1023 const char *FcResultToString (FcResult r); | |
1024 const char * | |
1025 FcResultToString (FcResult r) | |
1026 { | |
1027 static char buffer[256]; | |
1028 switch (r) | |
1029 { | |
1030 case FcResultMatch: | |
1031 return "FcResultMatch"; | |
1032 case FcResultNoMatch: | |
1033 return "FcResultNoMatch"; | |
1034 case FcResultTypeMismatch: | |
1035 return "FcResultTypeMismatch"; | |
1036 case FcResultNoId: | |
1037 return "FcResultNoId"; | |
1038 default: | |
1039 snprintf (buffer, 255, "FcResultUndocumentedValue (%d)", r); | |
1040 return buffer; | |
1041 } | |
1042 } | |
1043 | |
1044 const char *FcTypeOfValueToString (FcValue v); | |
1045 const char * | |
1046 FcTypeOfValueToString (FcValue v) | |
1047 { | |
1048 static char buffer[256]; | |
1049 switch (v.type) | |
1050 { | |
1051 case FcTypeMatrix: | |
1052 return "FcTypeMatrix"; | |
1053 case FcTypeString: | |
1054 return "FcTypeString"; | |
1055 case FcTypeVoid: | |
1056 return "FcTypeVoid"; | |
1057 case FcTypeDouble: | |
1058 return "FcTypeDouble"; | |
1059 case FcTypeInteger: | |
1060 return "FcTypeInteger"; | |
1061 case FcTypeBool: | |
1062 return "FcTypeBool"; | |
1063 case FcTypeCharSet: | |
1064 return "FcTypeCharSet"; | |
1065 case FcTypeLangSet: | |
1066 return "FcTypeLangSet"; | |
1067 /* #### There is no union member of this type, but there are void* and | |
1068 FcPattern* members, as of fontconfig.h FC_VERSION 10002 */ | |
1069 case FcTypeFTFace: | |
1070 return "FcTypeFTFace"; | |
1071 default: | |
1072 snprintf (buffer, 255, "FcTypeUndocumentedType (%d)", v.type); | |
1073 return buffer; | |
1074 } | |
1075 } | |
1076 | |
1077 static FcCharSet * | |
1078 mule_to_fc_charset (Lisp_Object cs) | |
1079 { | |
1080 int ucode, i, j; | |
1081 FcCharSet *fccs; | |
1082 | |
1083 CHECK_CHARSET (cs); | |
1084 fccs = FcCharSetCreate (); | |
1085 /* #### do we also need to deal with 94 vs. 96 charsets? | |
1086 ie, how are SP and DEL treated in ASCII? non-graphic should return -1 */ | |
1087 if (1 == XCHARSET_DIMENSION (cs)) | |
1088 /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ | |
1089 for (i = 0; i < 96; i++) | |
1090 { | |
1091 ucode = ((int *) XCHARSET_TO_UNICODE_TABLE (cs))[i]; | |
1092 if (ucode >= 0) | |
1093 /* #### should check for allocation failure */ | |
1094 FcCharSetAddChar (fccs, (FcChar32) ucode); | |
1095 } | |
1096 else if (2 == XCHARSET_DIMENSION (cs)) | |
1097 /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ | |
1098 for (i = 0; i < 96; i++) | |
1099 for (j = 0; j < 96; j++) | |
1100 { | |
1101 ucode = ((int **) XCHARSET_TO_UNICODE_TABLE (cs))[i][j]; | |
1102 if (ucode >= 0) | |
1103 /* #### should check for allocation failure */ | |
1104 FcCharSetAddChar (fccs, (FcChar32) ucode); | |
1105 } | |
1106 else | |
1107 { | |
1108 FcCharSetDestroy (fccs); | |
1109 fccs = NULL; | |
1110 } | |
1111 return fccs; | |
1112 } | |
1113 | |
1114 struct charset_reporter { | |
1115 Lisp_Object *charset; | |
1116 /* This is a debug facility, require ASCII. */ | |
1117 Extbyte *language; /* ASCII, please */ | |
1118 FcChar8 *rfc3066; /* ASCII, please */ | |
1119 }; | |
1120 | |
1121 static struct charset_reporter charset_table[] = | |
1122 { | |
1123 /* #### It's my branch, my favorite charsets get checked first! | |
1124 That's a joke, Son. | |
1125 Ie, I don't know what I'm doing, so my charsets first is as good as | |
1126 any other arbitrary order. If you have a better idea, speak up! */ | |
1127 { &Vcharset_ascii, "English", "en" }, | |
1128 { &Vcharset_japanese_jisx0208, "Japanese", "ja" }, | |
1129 { &Vcharset_japanese_jisx0212, "Japanese", "ja" }, | |
1130 { &Vcharset_katakana_jisx0201, "Japanese", "ja" }, | |
1131 { &Vcharset_latin_jisx0201, "Japanese", "ja" }, | |
1132 { &Vcharset_japanese_jisx0208_1978, "Japanese", "ja" }, | |
1133 { &Vcharset_greek_iso8859_7, "Greek", "el" }, | |
1134 /* #### all the Chinese need checking | |
1135 Damn the blood-sucking ISO anyway. */ | |
1136 { &Vcharset_chinese_gb2312, "simplified Chinese", "zh-CN" }, | |
1137 { &Vcharset_korean_ksc5601, "Korean", "ko" }, | |
1138 { &Vcharset_chinese_cns11643_1, "traditional Chinese", "zh-TW" }, | |
1139 { &Vcharset_chinese_cns11643_2, "traditional Chinese", "zh-TW" }, | |
1140 { &Vcharset_latin_iso8859_1, NULL, NULL }, | |
1141 { &Vcharset_latin_iso8859_2, NULL, NULL }, | |
1142 { &Vcharset_latin_iso8859_3, NULL, NULL }, | |
1143 { &Vcharset_latin_iso8859_4, NULL, NULL }, | |
1144 { &Vcharset_latin_iso8859_9, NULL, NULL }, | |
1145 { &Vcharset_latin_iso8859_15, NULL, NULL }, | |
1146 { &Vcharset_thai_tis620, NULL, NULL }, | |
1147 { &Vcharset_arabic_iso8859_6, NULL, NULL }, | |
1148 { &Vcharset_hebrew_iso8859_8, "Hebrew", "he" }, | |
1149 { &Vcharset_cyrillic_iso8859_5, NULL, NULL }, | |
1150 /* #### these probably are not quite right */ | |
1151 { &Vcharset_chinese_big5_1, "traditional Chinese", "zh-TW" }, | |
1152 { &Vcharset_chinese_big5_2, "traditional Chinese", "zh-TW" }, | |
1153 { NULL, NULL, NULL } | |
1154 }; | |
1155 | |
1156 /* Choose appropriate font name for debug messages. | |
1157 Use only in the top half of next function (enforced with #undef). */ | |
1158 #define SET_DEBUG_FONTNAME(name) \ | |
1159 do { name = \ | |
1160 debug_xft > 2 ? eistr_fullname \ | |
1161 : debug_xft > 1 ? eistr_longname \ | |
1162 : eistr_shortname } while (0) | |
1163 | |
1164 #endif /* USE_XFT */ | |
1165 | |
942 /* find a font spec that matches font spec FONT and also matches | 1166 /* find a font spec that matches font spec FONT and also matches |
943 (the registry of) CHARSET. */ | 1167 (the registry of) CHARSET. */ |
944 static Lisp_Object | 1168 static Lisp_Object |
945 x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, | 1169 x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, |
946 int stage) | 1170 int stage) |
947 { | 1171 { |
948 Extbyte **names; | 1172 Extbyte **names; |
949 int count = 0; | 1173 int count = 0; |
950 Lisp_Object result = Qnil; | |
951 const Extbyte *patternext; | 1174 const Extbyte *patternext; |
1175 Lisp_Object result = Qunbound; | |
952 int i; | 1176 int i; |
953 | 1177 |
1178 /* #### with Xft need to handle second stage here -- sjt | |
1179 Hm. Or maybe not. That would be cool. :-) */ | |
954 if (stage) | 1180 if (stage) |
955 return Qnil; | 1181 return Qnil; |
956 | 1182 |
1183 #ifdef USE_XFT | |
1184 /* Fontconfig converts all FreeType names to UTF-8 before passing them | |
1185 back to callers---see fcfreetype.c (FcFreeTypeQuery). | |
1186 I don't believe this is documented. */ | |
1187 | |
1188 DEBUG_XFT1 (1, "confirming charset for font instance %s\n", | |
1189 XSTRING_DATA(font)); | |
1190 | |
1191 /* #### this looks like a fair amount of work, but the basic design | |
1192 has never been rethought, and it should be | |
1193 | |
1194 what really should happen here is that we use FcFontSort (FcFontList?) | |
1195 to get a list of matching fonts, then pick the first (best) one that | |
1196 gives language or repertoire coverage. | |
1197 */ | |
1198 | |
1199 FcInit (); /* No-op if already initialized. | |
1200 In fontconfig 2.3.2, this cannot return | |
1201 failure, but that looks like a bug. We | |
1202 check for it with FcGetCurrentConfig(), | |
1203 which *can* fail. */ | |
1204 if (!FcConfigGetCurrent()) /* #### We should expose FcInit* interfaces | |
1205 to LISP and decide when to reinitialize | |
1206 intelligently. */ | |
1207 stderr_out ("Failed fontconfig initialization\n"); | |
1208 else | |
1209 { | |
1210 FcPattern *fontxft; /* long-lived, freed at end of this block */ | |
1211 FcResult fcresult; | |
1212 FcConfig *fcc; | |
1213 FcChar8 *lang = "en"; /* #### fix this bogus hack! */ | |
1214 FcCharSet *fccs = NULL; | |
1215 DECLARE_EISTRING (eistr_shortname); /* user-friendly nickname */ | |
1216 DECLARE_EISTRING (eistr_longname); /* omit FC_LANG and FC_CHARSET */ | |
1217 DECLARE_EISTRING (eistr_fullname); /* everything */ | |
1218 | |
1219 LISP_STRING_TO_EXTERNAL (font, patternext, Qxft_font_name_encoding); | |
1220 fcc = FcConfigGetCurrent (); | |
1221 | |
1222 /* parse the name, do the substitutions, and match the font */ | |
1223 | |
1224 { | |
1225 FcPattern *p = FcNameParse (patternext); | |
1226 PRINT_XFT_PATTERN (3, "FcNameParse'ed name is %s\n", p); | |
1227 /* #### Next two return FcBool, but what does the return mean? */ | |
1228 /* The order is correct according the fontconfig docs. */ | |
1229 FcConfigSubstitute (fcc, p, FcMatchPattern); | |
1230 PRINT_XFT_PATTERN (2, "FcConfigSubstitute'ed name is %s\n", p); | |
1231 FcDefaultSubstitute (p); | |
1232 PRINT_XFT_PATTERN (3, "FcDefaultSubstitute'ed name is %s\n", p); | |
1233 /* #### check fcresult of following match? */ | |
1234 fontxft = FcFontMatch (fcc, p, &fcresult); | |
1235 /* this prints the long fontconfig name */ | |
1236 PRINT_XFT_PATTERN (1, "FcFontMatch'ed name is %s\n", fontxft); | |
1237 FcPatternDestroy (p); | |
1238 } | |
1239 | |
1240 /* heuristic to give reasonable-length names for debug reports | |
1241 | |
1242 I considered #ifdef SUPPORT_FULL_FONTCONFIG_NAME etc but that's | |
1243 pointless. We're just going to remove this code once the font/ | |
1244 face refactoring is done, but until then it could be very useful. | |
1245 */ | |
1246 { | |
1247 FcPattern *p = FcFontRenderPrepare (fcc, fontxft, fontxft); | |
1248 FcChar8 *name; | |
1249 | |
1250 /* full name, including language coverage and repertoire */ | |
1251 name = FcNameUnparse (p); | |
1252 eicpy_ext (eistr_fullname, name, Qxft_font_name_encoding); | |
1253 free (name); | |
1254 | |
1255 /* long name, omitting coverage and repertoire, plus a number | |
1256 of rarely useful properties */ | |
1257 FcPatternDel (p, FC_CHARSET); | |
1258 FcPatternDel (p, FC_LANG); | |
1259 FcPatternDel (p, FC_WIDTH); | |
1260 FcPatternDel (p, FC_SPACING); | |
1261 FcPatternDel (p, FC_HINTING); | |
1262 FcPatternDel (p, FC_VERTICAL_LAYOUT); | |
1263 FcPatternDel (p, FC_AUTOHINT); | |
1264 FcPatternDel (p, FC_GLOBAL_ADVANCE); | |
1265 FcPatternDel (p, FC_INDEX); | |
1266 FcPatternDel (p, FC_SCALE); | |
1267 FcPatternDel (p, FC_FONTVERSION); | |
1268 name = FcNameUnparse (p); | |
1269 eicpy_ext (eistr_longname, name, Qxft_font_name_encoding); | |
1270 free (name); | |
1271 | |
1272 /* nickname, just family and size, but | |
1273 "family" names usually have style, slant, and weight */ | |
1274 FcPatternDel (p, FC_FOUNDRY); | |
1275 FcPatternDel (p, FC_STYLE); | |
1276 FcPatternDel (p, FC_SLANT); | |
1277 FcPatternDel (p, FC_WEIGHT); | |
1278 FcPatternDel (p, FC_PIXEL_SIZE); | |
1279 FcPatternDel (p, FC_OUTLINE); | |
1280 FcPatternDel (p, FC_SCALABLE); | |
1281 FcPatternDel (p, FC_DPI); | |
1282 name = FcNameUnparse (p); | |
1283 eicpy_ext (eistr_shortname, name, Qxft_font_name_encoding); | |
1284 free (name); | |
1285 | |
1286 FcPatternDestroy (p); | |
1287 } | |
1288 | |
1289 /* The language approach may better in the long run, but we can't use | |
1290 it based on Mule charsets; fontconfig doesn't provide a way to test | |
1291 for unions of languages, etc. That will require support from the | |
1292 text module. | |
1293 | |
1294 Optimization: cache the generated FcCharSet in the Mule charset. | |
1295 Don't forget to destroy it if the Mule charset gets deallocated. */ | |
1296 | |
1297 struct charset_reporter *cr; | |
1298 for (cr = charset_table; | |
1299 cr->charset && !EQ (*(cr->charset), charset); | |
1300 cr++) | |
1301 ; | |
1302 | |
1303 if (cr->rfc3066) | |
1304 { | |
1305 if (debug_xft > 0) | |
1306 { | |
1307 SET_DEBUG_FONTNAME (name); | |
1308 CHECKING_LANG (0, eidata(name), cr->language); | |
1309 } | |
1310 lang = cr->rfc3066; | |
1311 } | |
1312 else if (cr->charset) | |
1313 { | |
1314 /* what the hey, build 'em on the fly */ | |
1315 /* #### in the case of error this could return NULL! */ | |
1316 fccs = mule_to_fc_charset (charset); | |
1317 lang = XSTRING_DATA (XSYMBOL (XCHARSET_NAME (charset))-> name); | |
1318 } | |
1319 else | |
1320 { | |
1321 /* OK, we fell off the end of the table */ | |
1322 warn_when_safe_lispobj (intern ("xft"), intern ("alert"), | |
1323 list2 (build_string ("unchecked charset"), | |
1324 charset)); | |
1325 /* default to "en" | |
1326 #### THIS IS WRONG, WRONG, WRONG!! | |
1327 It is why we never fall through to XLFD-checking. */ | |
1328 } | |
1329 | |
1330 ASSERT_ASCTEXT_ASCII(lang); | |
1331 | |
1332 if (fccs) | |
1333 { | |
1334 /* check for character set coverage */ | |
1335 int i = 0; | |
1336 FcCharSet *v; | |
1337 FcResult r = FcPatternGetCharSet (fontxft, FC_CHARSET, i, &v); | |
1338 | |
1339 if (r == FcResultTypeMismatch) | |
1340 { | |
1341 DEBUG_XFT0 (0, "Unexpected type return in charset value\n"); | |
1342 result = Qnil; | |
1343 } | |
1344 else if (r == FcResultMatch && FcCharSetIsSubset (fccs, v)) | |
1345 { | |
1346 /* The full pattern with the bitmap coverage is massively | |
1347 unwieldy, but the shorter names are's just *wrong*. We | |
1348 should have the full thing internally as truename, and | |
1349 filter stuff the client doesn't want to see on output. | |
1350 Should we just store it into the truename right here? */ | |
1351 if (debug_xft > 0) | |
1352 { | |
1353 SET_DEBUG_FONTNAME (name); | |
1354 DEBUG_XFT2 (0, "Xft font %s supports %s\n", | |
1355 eidata(name), lang); | |
1356 } | |
1357 #ifdef RETURN_LONG_FONTCONFIG_NAMES | |
1358 result = eimake_string(eistr_fullname); | |
1359 #else | |
1360 result = eimake_string(eistr_longname); | |
1361 #endif | |
1362 } | |
1363 else | |
1364 { | |
1365 if (debug_xft > 0) | |
1366 { | |
1367 SET_DEBUG_FONTNAME (name); | |
1368 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", | |
1369 eidata(name), lang); | |
1370 } | |
1371 result = Qnil; | |
1372 } | |
1373 | |
1374 /* clean up */ | |
1375 FcCharSetDestroy (fccs); | |
1376 } | |
1377 else | |
1378 { | |
1379 /* check for language coverage */ | |
1380 int i = 0; | |
1381 FcValue v; | |
1382 /* the main event */ | |
1383 FcResult r = FcPatternGet (fontxft, FC_LANG, i, &v); | |
1384 | |
1385 if (r == FcResultMatch) | |
1386 { | |
1387 if (v.type != FcTypeLangSet) /* excessive paranoia */ | |
1388 { | |
1389 ASSERT_ASCTEXT_ASCII(FcTypeOfValueToString(v)); | |
1390 /* Urk! Fall back and punt to core font. */ | |
1391 DEBUG_XFT1 (0, "Unexpected type of lang value (%s)\n", | |
1392 FcTypeOfValueToString (v)); | |
1393 result = Qnil; | |
1394 } | |
1395 else if (FcLangSetHasLang (v.u.l, lang) != FcLangDifferentLang) | |
1396 { | |
1397 if (debug_xft > 0) | |
1398 { | |
1399 SET_DEBUG_FONTNAME (name); | |
1400 DEBUG_XFT2 (0, "Xft font %s supports %s\n", | |
1401 eidata(name), lang); | |
1402 } | |
1403 #ifdef RETURN_LONG_FONTCONFIG_NAMES | |
1404 result = eimake_string(eistr_fullname); | |
1405 #else | |
1406 result = eimake_string(eistr_longname); | |
1407 #endif | |
1408 } | |
1409 else | |
1410 { | |
1411 if (debug_xft > 0) | |
1412 { | |
1413 SET_DEBUG_FONTNAME (name); | |
1414 DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", | |
1415 eidata(name), lang); | |
1416 } | |
1417 result = Qnil; | |
1418 } | |
1419 } | |
1420 else | |
1421 { | |
1422 ASSERT_ASCTEXT_ASCII(FcResultToString(r)); | |
1423 DEBUG_XFT1 (0, "Getting lang: unexpected result=%s\n", | |
1424 FcResultToString (r)); | |
1425 result = Qnil; | |
1426 } | |
1427 } | |
1428 | |
1429 /* clean up and maybe return */ | |
1430 FcPatternDestroy (fontxft); | |
1431 if (!UNBOUNDP (result)) | |
1432 return result; | |
1433 } | |
1434 | |
1435 DEBUG_XFT1 (0, "shit happens, try X11 charset match for %s\n", | |
1436 XSTRING_DATA(font)); | |
1437 #undef SET_DEBUG_FONTNAME | |
1438 #endif /* USE_XFT */ | |
1439 | |
957 LISP_STRING_TO_EXTERNAL (font, patternext, Qx_font_name_encoding); | 1440 LISP_STRING_TO_EXTERNAL (font, patternext, Qx_font_name_encoding); |
958 | |
959 names = XListFonts (DEVICE_X_DISPLAY (XDEVICE (device)), | 1441 names = XListFonts (DEVICE_X_DISPLAY (XDEVICE (device)), |
960 patternext, MAX_FONT_COUNT, &count); | 1442 patternext, MAX_FONT_COUNT, &count); |
961 /* #### This code seems awfully bogus -- mrb */ | 1443 /* #### This code seems awfully bogus -- mrb */ |
1444 /* #### fontconfig does it better -- sjt */ | |
962 for (i = 0; i < count; i ++) | 1445 for (i = 0; i < count; i ++) |
963 { | 1446 { |
964 const Ibyte *intname; | 1447 const Ibyte *intname; |
965 Bytecount intlen; | 1448 Bytecount intlen; |
966 | 1449 |
1039 circumstances, it also causes a noticeable performance hit when using | 1522 circumstances, it also causes a noticeable performance hit when using |
1040 fixed-width fonts. Since most people don't use characters which could | 1523 fixed-width fonts. Since most people don't use characters which could |
1041 cause problems this is set to nil by default. | 1524 cause problems this is set to nil by default. |
1042 */ ); | 1525 */ ); |
1043 x_handle_non_fully_specified_fonts = 0; | 1526 x_handle_non_fully_specified_fonts = 0; |
1527 | |
1528 #ifdef USE_XFT | |
1529 Fprovide (intern ("xft-fonts")); | |
1530 #endif | |
1044 } | 1531 } |
1045 | 1532 |
1046 void | 1533 void |
1047 Xatoms_of_objects_x (struct device *d) | 1534 Xatoms_of_objects_x (struct device *d) |
1048 { | 1535 { |