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