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