fixes for wxFontMapper endless recursion
[wxWidgets.git] / src / unix / fontutil.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: unix/fontutil.cpp
3 // Purpose: Font helper functions for X11 (GDK/X)
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05.11.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "fontutil.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #endif // PCH
33
34 #ifdef __X__
35 #include <X11/Xlib.h>
36
37 #include "wx/utils.h" // for wxGetDisplay()
38 #elif defined(__WXGTK__)
39 #include "gdk/gdk.h"
40 #endif
41
42 #include "wx/fontutil.h"
43 #include "wx/fontmap.h"
44 #include "wx/tokenzr.h"
45
46 // ----------------------------------------------------------------------------
47 // private functions
48 // ----------------------------------------------------------------------------
49
50 // define the functions to create and destroy native fonts for this toolkit
51 #ifdef __X__
52 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
53 {
54 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
55 }
56
57 static inline void wxFreeFont(wxNativeFont font)
58 {
59 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
60 }
61 #elif defined(__WXGTK__)
62 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
63 {
64 return gdk_font_load( wxConvertWX2MB(fontSpec) );
65 }
66
67 static inline void wxFreeFont(wxNativeFont font)
68 {
69 gdk_font_unref(font);
70 }
71 #else
72 #error "Unknown GUI toolkit"
73 #endif
74
75 static bool wxTestFontSpec(const wxString& fontspec);
76
77 static wxNativeFont wxLoadQueryFont(int pointSize,
78 int family,
79 int style,
80 int weight,
81 bool underlined,
82 const wxString& facename,
83 const wxString& xregistry,
84 const wxString& xencoding);
85
86 // ============================================================================
87 // implementation
88 // ============================================================================
89
90 // ----------------------------------------------------------------------------
91 // wxNativeEncodingInfo
92 // ----------------------------------------------------------------------------
93
94 // convert to/from the string representation: format is
95 // registry-encoding[-facename]
96 bool wxNativeEncodingInfo::FromString(const wxString& s)
97 {
98 wxStringTokenizer tokenizer(s, _T("-"));
99
100 xregistry = tokenizer.GetNextToken();
101 if ( !xregistry )
102 return FALSE;
103
104 xencoding = tokenizer.GetNextToken();
105 if ( !xencoding )
106 return FALSE;
107
108 // ok even if empty
109 facename = tokenizer.GetNextToken();
110
111 return TRUE;
112 }
113
114 wxString wxNativeEncodingInfo::ToString() const
115 {
116 wxString s;
117 s << xregistry << _T('-') << xencoding;
118 if ( !!facename )
119 {
120 s << _T('-') << facename;
121 }
122
123 return s;
124 }
125
126 // ----------------------------------------------------------------------------
127 // common functions
128 // ----------------------------------------------------------------------------
129
130 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
131 wxNativeEncodingInfo *info)
132 {
133 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
134
135 if ( encoding == wxFONTENCODING_DEFAULT )
136 {
137 encoding = wxFont::GetDefaultEncoding();
138 }
139
140 switch ( encoding )
141 {
142 case wxFONTENCODING_ISO8859_1:
143 case wxFONTENCODING_ISO8859_2:
144 case wxFONTENCODING_ISO8859_3:
145 case wxFONTENCODING_ISO8859_4:
146 case wxFONTENCODING_ISO8859_5:
147 case wxFONTENCODING_ISO8859_6:
148 case wxFONTENCODING_ISO8859_7:
149 case wxFONTENCODING_ISO8859_8:
150 case wxFONTENCODING_ISO8859_9:
151 case wxFONTENCODING_ISO8859_10:
152 case wxFONTENCODING_ISO8859_11:
153 case wxFONTENCODING_ISO8859_13:
154 case wxFONTENCODING_ISO8859_14:
155 case wxFONTENCODING_ISO8859_15:
156 {
157 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
158 info->xregistry = wxT("iso8859");
159 info->xencoding.Printf(wxT("%d"), cp);
160 }
161 break;
162
163 case wxFONTENCODING_KOI8:
164 info->xregistry = wxT("koi8");
165
166 // we don't make distinction between koi8-r and koi8-u (so far)
167 info->xencoding = wxT("*");
168 break;
169
170 case wxFONTENCODING_CP1250:
171 case wxFONTENCODING_CP1251:
172 case wxFONTENCODING_CP1252:
173 case wxFONTENCODING_CP1253:
174 case wxFONTENCODING_CP1254:
175 case wxFONTENCODING_CP1255:
176 case wxFONTENCODING_CP1256:
177 case wxFONTENCODING_CP1257:
178 {
179 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
180 info->xregistry = wxT("microsoft");
181 info->xencoding.Printf(wxT("cp%d"), cp);
182 }
183 break;
184
185 case wxFONTENCODING_SYSTEM:
186 info->xregistry =
187 info->xencoding = wxT("*");
188 break;
189
190 default:
191 // don't know how to translate this encoding into X fontspec
192 return FALSE;
193 }
194
195 return TRUE;
196 }
197
198 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
199 {
200 wxString fontspec;
201 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
202 !info.facename ? _T("*") : info.facename.c_str(),
203 info.xregistry.c_str(),
204 info.xencoding.c_str());
205
206 return wxTestFontSpec(fontspec);
207 }
208
209 // ----------------------------------------------------------------------------
210 // X-specific functions
211 // ----------------------------------------------------------------------------
212
213 wxNativeFont wxLoadQueryNearestFont(int pointSize,
214 int family,
215 int style,
216 int weight,
217 bool underlined,
218 const wxString &facename,
219 wxFontEncoding encoding)
220 {
221 if ( encoding == wxFONTENCODING_DEFAULT )
222 {
223 encoding = wxFont::GetDefaultEncoding();
224 }
225
226 // first determine the encoding - if the font doesn't exist at all in this
227 // encoding, it's useless to do all other approximations (i.e. size,
228 // family &c don't matter much)
229 wxNativeEncodingInfo info;
230 if ( encoding == wxFONTENCODING_SYSTEM )
231 {
232 // This will always work so we don't test to save time
233 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
234 }
235 else
236 {
237 if ( !wxGetNativeFontEncoding(encoding, &info) ||
238 !wxTestFontEncoding(info) )
239 {
240 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
241 {
242 // unspported encoding - replace it with the default
243 //
244 // NB: we can't just return 0 from here because wxGTK code doesn't
245 // check for it (i.e. it supposes that we'll always succeed),
246 // so it would provoke a crash
247 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
248 }
249 }
250 }
251
252 // OK, we have the correct xregistry/xencoding in info structure
253 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
254 underlined, facename,
255 info.xregistry, info.xencoding );
256
257 if ( !font )
258 {
259 // search up and down by stepsize 10
260 int max_size = pointSize + 20 * (1 + (pointSize/180));
261 int min_size = pointSize - 20 * (1 + (pointSize/180));
262
263 int i;
264
265 // Search for smaller size (approx.)
266 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
267 {
268 font = wxLoadQueryFont(i, family, style, weight, underlined,
269 facename, info.xregistry, info.xencoding);
270 }
271
272 // Search for larger size (approx.)
273 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
274 {
275 font = wxLoadQueryFont(i, family, style, weight, underlined,
276 facename, info.xregistry, info.xencoding);
277 }
278
279 // Try default family
280 if ( !font && family != wxDEFAULT )
281 {
282 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
283 underlined, facename,
284 info.xregistry, info.xencoding );
285 }
286
287 // Bogus font I
288 if ( !font )
289 {
290 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
291 underlined, facename,
292 info.xregistry, info.xencoding);
293 }
294
295 // Bogus font II
296 if ( !font )
297 {
298 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
299 underlined, wxEmptyString,
300 info.xregistry, info.xencoding);
301 }
302 }
303
304 return font;
305 }
306
307 // ----------------------------------------------------------------------------
308 // private functions
309 // ----------------------------------------------------------------------------
310
311 // returns TRUE if there are any fonts matching this font spec
312 static bool wxTestFontSpec(const wxString& fontspec)
313 {
314 // some X servers will fail to load this font because there are too many
315 // matches so we must test explicitly for this
316 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
317 {
318 return TRUE;
319 }
320
321 wxNativeFont test = wxLoadFont(fontspec);
322 if ( test )
323 {
324 wxFreeFont(test);
325
326 return TRUE;
327 }
328 else
329 {
330 return FALSE;
331 }
332 }
333
334 static wxNativeFont wxLoadQueryFont(int pointSize,
335 int family,
336 int style,
337 int weight,
338 bool WXUNUSED(underlined),
339 const wxString& facename,
340 const wxString& xregistry,
341 const wxString& xencoding)
342 {
343 wxString xfamily;
344 switch (family)
345 {
346 case wxDECORATIVE: xfamily = wxT("lucida"); break;
347 case wxROMAN: xfamily = wxT("times"); break;
348 case wxMODERN: xfamily = wxT("courier"); break;
349 case wxSWISS: xfamily = wxT("helvetica"); break;
350 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
351 case wxSCRIPT: xfamily = wxT("utopia"); break;
352 default: xfamily = wxT("*");
353 }
354
355 wxString fontSpec;
356 if (!facename.IsEmpty())
357 {
358 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
359 facename.c_str());
360
361 if ( wxTestFontSpec(fontSpec) )
362 {
363 xfamily = facename;
364 }
365 //else: no such family, use default one instead
366 }
367
368 wxString xstyle;
369 switch (style)
370 {
371 case wxITALIC: xstyle = wxT("i"); break;
372 case wxSLANT: xstyle = wxT("o"); break;
373 case wxNORMAL: xstyle = wxT("r"); break;
374 default: xstyle = wxT("*"); break;
375 }
376
377 wxString xweight;
378 switch (weight)
379 {
380 case wxBOLD:
381 {
382 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
383 xfamily.c_str());
384 if ( wxTestFontSpec(fontSpec) )
385 {
386 xweight = wxT("bold");
387 break;
388 }
389 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
390 xfamily.c_str());
391 if ( wxTestFontSpec(fontSpec) )
392 {
393 xweight = wxT("heavy");
394 break;
395 }
396 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
397 xfamily.c_str());
398 if ( wxTestFontSpec(fontSpec) )
399 {
400 xweight = wxT("extrabold");
401 break;
402 }
403 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
404 xfamily.c_str());
405 if ( wxTestFontSpec(fontSpec) )
406 {
407 xweight = wxT("demibold");
408 break;
409 }
410 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
411 xfamily.c_str());
412 if ( wxTestFontSpec(fontSpec) )
413 {
414 xweight = wxT("black");
415 break;
416 }
417 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
418 xfamily.c_str());
419 if ( wxTestFontSpec(fontSpec) )
420 {
421 xweight = wxT("ultrablack");
422 break;
423 }
424 }
425 break;
426 case wxLIGHT:
427 {
428 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
429 xfamily.c_str());
430 if ( wxTestFontSpec(fontSpec) )
431 {
432 xweight = wxT("light");
433 break;
434 }
435 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
436 xfamily.c_str());
437 if ( wxTestFontSpec(fontSpec) )
438 {
439 xweight = wxT("thin");
440 break;
441 }
442 }
443 break;
444 case wxNORMAL:
445 {
446 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
447 xfamily.c_str());
448 if ( wxTestFontSpec(fontSpec) )
449 {
450 xweight = wxT("medium");
451 break;
452 }
453 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
454 xfamily.c_str());
455 if ( wxTestFontSpec(fontSpec) )
456 {
457 xweight = wxT("normal");
458 break;
459 }
460 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
461 xfamily.c_str());
462 if ( wxTestFontSpec(fontSpec) )
463 {
464 xweight = wxT("regular");
465 break;
466 }
467 xweight = wxT("*");
468 }
469 break;
470 default: xweight = wxT("*"); break;
471 }
472
473 // construct the X font spec from our data
474 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
475 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
476 pointSize, xregistry.c_str(), xencoding.c_str());
477
478 return wxLoadFont(fontSpec);
479 }
480