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