fixed memory leak in wxNativeFontInfo when using Pango
[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 licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 #include "wx/encinfo.h"
33 #endif // PCH
34
35 #include "wx/fontutil.h"
36 #include "wx/fontmap.h"
37 #include "wx/tokenzr.h"
38 #include "wx/hash.h"
39 #include "wx/module.h"
40
41 #if wxUSE_PANGO
42
43 #include "pango/pango.h"
44
45 #ifdef __WXGTK20__
46 #include "wx/gtk/private.h"
47 #else
48 #include "wx/x11/private.h"
49 #endif
50
51 // ----------------------------------------------------------------------------
52 // wxNativeFontInfo
53 // ----------------------------------------------------------------------------
54
55 void wxNativeFontInfo::Init()
56 {
57 description = NULL;
58 }
59
60 wxNativeFontInfo::wxNativeFontInfo(const wxNativeFontInfo& info)
61 {
62 if (info.description)
63 description = pango_font_description_copy(info.description);
64 else
65 description = NULL;
66 }
67
68 wxNativeFontInfo::~wxNativeFontInfo()
69 {
70 if (description)
71 pango_font_description_free(description);
72 }
73
74 int wxNativeFontInfo::GetPointSize() const
75 {
76 return pango_font_description_get_size( description ) / PANGO_SCALE;
77 }
78
79 wxFontStyle wxNativeFontInfo::GetStyle() const
80 {
81 wxFontStyle m_style = wxFONTSTYLE_NORMAL;
82
83 switch (pango_font_description_get_style( description ))
84 {
85 case PANGO_STYLE_NORMAL:
86 m_style = wxFONTSTYLE_NORMAL;
87 break;
88 case PANGO_STYLE_ITALIC:
89 m_style = wxFONTSTYLE_ITALIC;
90 break;
91 case PANGO_STYLE_OBLIQUE:
92 m_style = wxFONTSTYLE_SLANT;
93 break;
94 }
95
96 return m_style;
97 }
98
99 wxFontWeight wxNativeFontInfo::GetWeight() const
100 {
101 wxFontWeight m_weight = wxFONTWEIGHT_NORMAL;
102
103 switch (pango_font_description_get_weight( description ))
104 {
105 case PANGO_WEIGHT_ULTRALIGHT:
106 m_weight = wxFONTWEIGHT_LIGHT;
107 break;
108 case PANGO_WEIGHT_LIGHT:
109 m_weight = wxFONTWEIGHT_LIGHT;
110 break;
111 case PANGO_WEIGHT_NORMAL:
112 m_weight = wxFONTWEIGHT_NORMAL;
113 break;
114 case PANGO_WEIGHT_BOLD:
115 m_weight = wxFONTWEIGHT_BOLD;
116 break;
117 case PANGO_WEIGHT_ULTRABOLD:
118 m_weight = wxFONTWEIGHT_BOLD;
119 break;
120 case PANGO_WEIGHT_HEAVY:
121 m_weight = wxFONTWEIGHT_BOLD;
122 break;
123 }
124
125 return m_weight;
126 }
127
128 bool wxNativeFontInfo::GetUnderlined() const
129 {
130 return FALSE;
131 }
132
133 wxString wxNativeFontInfo::GetFaceName() const
134 {
135 wxString tmp = wxGTK_CONV_BACK( pango_font_description_get_family( description ) );
136
137 return tmp;
138 }
139
140 wxFontFamily wxNativeFontInfo::GetFamily() const
141 {
142 return wxFONTFAMILY_SWISS;
143 }
144
145 wxFontEncoding wxNativeFontInfo::GetEncoding() const
146 {
147 return wxFONTENCODING_SYSTEM;
148 }
149
150
151 void wxNativeFontInfo::SetPointSize(int WXUNUSED(pointsize))
152 {
153 wxFAIL_MSG( _T("not implemented") );
154 }
155
156 void wxNativeFontInfo::SetStyle(wxFontStyle WXUNUSED(style))
157 {
158 wxFAIL_MSG( _T("not implemented") );
159 }
160
161 void wxNativeFontInfo::SetWeight(wxFontWeight WXUNUSED(weight))
162 {
163 wxFAIL_MSG( _T("not implemented") );
164 }
165
166 void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
167 {
168 wxFAIL_MSG( _T("not implemented") );
169 }
170
171 void wxNativeFontInfo::SetFaceName(wxString WXUNUSED(facename))
172 {
173 wxFAIL_MSG( _T("not implemented") );
174 }
175
176 void wxNativeFontInfo::SetFamily(wxFontFamily WXUNUSED(family))
177 {
178 wxFAIL_MSG( _T("not implemented") );
179 }
180
181 void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding))
182 {
183 wxFAIL_MSG( _T("not implemented") );
184 }
185
186
187
188 bool wxNativeFontInfo::FromString(const wxString& s)
189 {
190 if (description)
191 pango_font_description_free( description );
192
193 description = pango_font_description_from_string( wxGTK_CONV( s ) );
194
195 return TRUE;
196 }
197
198 wxString wxNativeFontInfo::ToString() const
199 {
200 char *str = pango_font_description_to_string( description );
201 wxString tmp = wxGTK_CONV_BACK( str );
202 g_free( str );
203
204 return tmp;
205 }
206
207 bool wxNativeFontInfo::FromUserString(const wxString& s)
208 {
209 return FromString( s );
210 }
211
212 wxString wxNativeFontInfo::ToUserString() const
213 {
214 return ToString();
215 }
216
217 // ----------------------------------------------------------------------------
218 // wxNativeEncodingInfo
219 // ----------------------------------------------------------------------------
220
221 bool wxNativeEncodingInfo::FromString(const wxString& s)
222 {
223 return FALSE;
224 }
225
226 wxString wxNativeEncodingInfo::ToString() const
227 {
228 return wxEmptyString;
229 }
230
231 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
232 {
233 return TRUE;
234 }
235
236 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
237 wxNativeEncodingInfo *info)
238 {
239 return FALSE;
240 }
241
242 #else // GTK+ 1.x
243
244 #ifdef __X__
245 #ifdef __VMS__
246 #pragma message disable nosimpint
247 #endif
248
249 #include <X11/Xlib.h>
250
251 #ifdef __VMS__
252 #pragma message enable nosimpint
253 #endif
254
255 #include "wx/utils.h" // for wxGetDisplay()
256 #elif defined(__WXGTK__)
257 // we have to declare struct tm to avoid problems with first forward
258 // declaring it in C code (glib.h included from gdk.h does it) and then
259 // defining it when time.h is included from the headers below - this is
260 // known not to work at least with Sun CC 6.01
261 #include <time.h>
262
263 #include <gdk/gdk.h>
264 #endif
265
266
267 // ----------------------------------------------------------------------------
268 // private data
269 // ----------------------------------------------------------------------------
270
271 static wxHashTable *g_fontHash = (wxHashTable*) NULL;
272
273 // ----------------------------------------------------------------------------
274 // private functions
275 // ----------------------------------------------------------------------------
276
277 // define the functions to create and destroy native fonts for this toolkit
278 #ifdef __X__
279 wxNativeFont wxLoadFont(const wxString& fontSpec)
280 {
281 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
282 }
283
284 inline void wxFreeFont(wxNativeFont font)
285 {
286 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
287 }
288 #elif defined(__WXGTK__)
289 wxNativeFont wxLoadFont(const wxString& fontSpec)
290 {
291 // VZ: we should use gdk_fontset_load() instead of gdk_font_load()
292 // here to be able to display Japanese fonts correctly (at least
293 // this is what people report) but unfortunately doing it results
294 // in tons of warnings when using GTK with "normal" European
295 // languages and so we can't always do it and I don't know enough
296 // to determine when should this be done... (FIXME)
297 return gdk_font_load( wxConvertWX2MB(fontSpec) );
298 }
299
300 inline void wxFreeFont(wxNativeFont font)
301 {
302 gdk_font_unref(font);
303 }
304 #else
305 #error "Unknown GUI toolkit"
306 #endif
307
308 static bool wxTestFontSpec(const wxString& fontspec);
309
310 static wxNativeFont wxLoadQueryFont(int pointSize,
311 int family,
312 int style,
313 int weight,
314 bool underlined,
315 const wxString& facename,
316 const wxString& xregistry,
317 const wxString& xencoding,
318 wxString* xFontName);
319
320 // ============================================================================
321 // implementation
322 // ============================================================================
323
324 // ----------------------------------------------------------------------------
325 // wxNativeEncodingInfo
326 // ----------------------------------------------------------------------------
327
328 // convert to/from the string representation: format is
329 // encodingid;registry;encoding[;facename]
330 bool wxNativeEncodingInfo::FromString(const wxString& s)
331 {
332 // use ";", not "-" because it may be part of encoding name
333 wxStringTokenizer tokenizer(s, _T(";"));
334
335 wxString encid = tokenizer.GetNextToken();
336 long enc;
337 if ( !encid.ToLong(&enc) )
338 return FALSE;
339 encoding = (wxFontEncoding)enc;
340
341 xregistry = tokenizer.GetNextToken();
342 if ( !xregistry )
343 return FALSE;
344
345 xencoding = tokenizer.GetNextToken();
346 if ( !xencoding )
347 return FALSE;
348
349 // ok even if empty
350 facename = tokenizer.GetNextToken();
351
352 return TRUE;
353 }
354
355 wxString wxNativeEncodingInfo::ToString() const
356 {
357 wxString s;
358 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
359 if ( !!facename )
360 {
361 s << _T(';') << facename;
362 }
363
364 return s;
365 }
366
367 // ----------------------------------------------------------------------------
368 // wxNativeFontInfo
369 // ----------------------------------------------------------------------------
370
371 void wxNativeFontInfo::Init()
372 {
373 m_isDefault = TRUE;
374 }
375
376 bool wxNativeFontInfo::FromString(const wxString& s)
377 {
378 wxStringTokenizer tokenizer(s, _T(";"));
379
380 // check the version
381 wxString token = tokenizer.GetNextToken();
382 if ( token != _T('0') )
383 return FALSE;
384
385 xFontName = tokenizer.GetNextToken();
386
387 // this should be the end
388 if ( tokenizer.HasMoreTokens() )
389 return FALSE;
390
391 return FromXFontName(xFontName);
392 }
393
394 wxString wxNativeFontInfo::ToString() const
395 {
396 // 0 is the version
397 return wxString::Format(_T("%d;%s"), 0, GetXFontName().c_str());
398 }
399
400 bool wxNativeFontInfo::FromUserString(const wxString& s)
401 {
402 return FromXFontName(s);
403 }
404
405 wxString wxNativeFontInfo::ToUserString() const
406 {
407 return GetXFontName();
408 }
409
410 bool wxNativeFontInfo::HasElements() const
411 {
412 // we suppose that the foundry is never empty, so if it is it means that we
413 // had never parsed the XLFD
414 return !fontElements[0].empty();
415 }
416
417 wxString wxNativeFontInfo::GetXFontComponent(wxXLFDField field) const
418 {
419 wxCHECK_MSG( field < wxXLFD_MAX, _T(""), _T("invalid XLFD field") );
420
421 if ( !HasElements() )
422 {
423 // const_cast
424 if ( !((wxNativeFontInfo *)this)->FromXFontName(xFontName) )
425 return _T("");
426 }
427
428 return fontElements[field];
429 }
430
431 bool wxNativeFontInfo::FromXFontName(const wxString& fontname)
432 {
433 // TODO: we should be able to handle the font aliases here, but how?
434 wxStringTokenizer tokenizer(fontname, _T("-"));
435
436 // skip the leading, usually empty field (font name registry)
437 if ( !tokenizer.HasMoreTokens() )
438 return FALSE;
439
440 (void)tokenizer.GetNextToken();
441
442 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
443 {
444 if ( !tokenizer.HasMoreTokens() )
445 {
446 // not enough elements in the XLFD - or maybe an alias
447 return FALSE;
448 }
449
450 wxString field = tokenizer.GetNextToken();
451 if ( !field.empty() && field != _T('*') )
452 {
453 // we're really initialized now
454 m_isDefault = FALSE;
455 }
456
457 fontElements[n] = field;
458 }
459
460 // this should be all
461 if ( tokenizer.HasMoreTokens() )
462 return FALSE;
463
464 return TRUE;
465 }
466
467 wxString wxNativeFontInfo::GetXFontName() const
468 {
469 if ( xFontName.empty() )
470 {
471 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
472 {
473 // replace the non specified elements with '*' except for the
474 // additional style which is usually just omitted
475 wxString elt = fontElements[n];
476 if ( elt.empty() && n != wxXLFD_ADDSTYLE )
477 {
478 elt = _T('*');
479 }
480
481 // const_cast
482 ((wxNativeFontInfo *)this)->xFontName << _T('-') << elt;
483 }
484 }
485
486 return xFontName;
487 }
488
489 void
490 wxNativeFontInfo::SetXFontComponent(wxXLFDField field, const wxString& value)
491 {
492 wxCHECK_RET( field < wxXLFD_MAX, _T("invalid XLFD field") );
493
494 // this class should be initialized with a valid font spec first and only
495 // then the fields may be modified!
496 wxASSERT_MSG( !IsDefault(), _T("can't modify an uninitialized XLFD") );
497
498 if ( !HasElements() )
499 {
500 // const_cast
501 if ( !((wxNativeFontInfo *)this)->FromXFontName(xFontName) )
502 {
503 wxFAIL_MSG( _T("can't set font element for invalid XLFD") );
504
505 return;
506 }
507 }
508
509 fontElements[field] = value;
510
511 // invalidate the XFLD, it doesn't correspond to the font elements any more
512 xFontName.clear();
513 }
514
515 void wxNativeFontInfo::SetXFontName(const wxString& xFontName_)
516 {
517 // invalidate the font elements, GetXFontComponent() will reparse the XLFD
518 fontElements[0].clear();
519
520 xFontName = xFontName_;
521
522 m_isDefault = FALSE;
523 }
524
525 int wxNativeFontInfo::GetPointSize() const
526 {
527 const wxString s = GetXFontComponent(wxXLFD_POINTSIZE);
528
529 // return -1 to indicate that the size is unknown
530 long l;
531 return s.ToLong(&l) ? l : -1;
532 }
533
534 wxFontStyle wxNativeFontInfo::GetStyle() const
535 {
536 const wxString s = GetXFontComponent(wxXLFD_SLANT);
537
538 if ( s.length() != 1 )
539 {
540 // it is really unknown but we don't have any way to return it from
541 // here
542 return wxFONTSTYLE_NORMAL;
543 }
544
545 switch ( s[0] )
546 {
547 default:
548 // again, unknown but consider normal by default
549
550 case _T('r'):
551 return wxFONTSTYLE_NORMAL;
552
553 case _T('i'):
554 return wxFONTSTYLE_ITALIC;
555
556 case _T('o'):
557 return wxFONTSTYLE_SLANT;
558 }
559 }
560
561 wxFontWeight wxNativeFontInfo::GetWeight() const
562 {
563 const wxString s = GetXFontComponent(wxXLFD_WEIGHT).MakeLower();
564 if ( s.find(_T("bold")) != wxString::npos || s == _T("black") )
565 return wxFONTWEIGHT_BOLD;
566 else if ( s == _T("light") )
567 return wxFONTWEIGHT_LIGHT;
568
569 return wxFONTWEIGHT_NORMAL;
570 }
571
572 bool wxNativeFontInfo::GetUnderlined() const
573 {
574 // X fonts are never underlined
575 return FALSE;
576 }
577
578 wxString wxNativeFontInfo::GetFaceName() const
579 {
580 // wxWidgets facename probably more accurately corresponds to X family
581 return GetXFontComponent(wxXLFD_FAMILY);
582 }
583
584 wxFontFamily wxNativeFontInfo::GetFamily() const
585 {
586 // and wxWidgets family -- to X foundry, but we have to translate it to
587 // wxFontFamily somehow...
588 wxFAIL_MSG(_T("not implemented")); // GetXFontComponent(wxXLFD_FOUNDRY);
589
590 return wxFONTFAMILY_DEFAULT;
591 }
592
593 wxFontEncoding wxNativeFontInfo::GetEncoding() const
594 {
595 // we already have the code for this but need to refactor it first
596 wxFAIL_MSG( _T("not implemented") );
597
598 return wxFONTENCODING_MAX;
599 }
600
601 void wxNativeFontInfo::SetPointSize(int pointsize)
602 {
603 SetXFontComponent(wxXLFD_POINTSIZE, wxString::Format(_T("%d"), pointsize));
604 }
605
606 void wxNativeFontInfo::SetStyle(wxFontStyle style)
607 {
608 wxString s;
609 switch ( style )
610 {
611 case wxFONTSTYLE_ITALIC:
612 s = _T('i');
613 break;
614
615 case wxFONTSTYLE_SLANT:
616 s = _T('o');
617 break;
618
619 case wxFONTSTYLE_NORMAL:
620 s = _T('r');
621
622 default:
623 wxFAIL_MSG( _T("unknown wxFontStyle in wxNativeFontInfo::SetStyle") );
624 return;
625 }
626
627 SetXFontComponent(wxXLFD_SLANT, s);
628 }
629
630 void wxNativeFontInfo::SetWeight(wxFontWeight weight)
631 {
632 wxString s;
633 switch ( weight )
634 {
635 case wxFONTWEIGHT_BOLD:
636 s = _T("bold");
637 break;
638
639 case wxFONTWEIGHT_LIGHT:
640 s = _T("light");
641 break;
642
643 case wxFONTWEIGHT_NORMAL:
644 s = _T("medium");
645 break;
646
647 default:
648 wxFAIL_MSG( _T("unknown wxFontWeight in wxNativeFontInfo::SetWeight") );
649 return;
650 }
651
652 SetXFontComponent(wxXLFD_WEIGHT, s);
653 }
654
655 void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
656 {
657 // can't do this under X
658 }
659
660 void wxNativeFontInfo::SetFaceName(wxString facename)
661 {
662 SetXFontComponent(wxXLFD_FAMILY, facename);
663 }
664
665 void wxNativeFontInfo::SetFamily(wxFontFamily family)
666 {
667 // wxFontFamily -> X foundry, anyone?
668 wxFAIL_MSG( _T("not implemented") );
669
670 // SetXFontComponent(wxXLFD_FOUNDRY, ...);
671 }
672
673 void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding)
674 {
675 wxNativeEncodingInfo info;
676 if ( wxGetNativeFontEncoding(encoding, &info) )
677 {
678 SetXFontComponent(wxXLFD_ENCODING, info.xencoding);
679 SetXFontComponent(wxXLFD_REGISTRY, info.xregistry);
680 }
681 }
682
683 // ----------------------------------------------------------------------------
684 // common functions
685 // ----------------------------------------------------------------------------
686
687 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
688 wxNativeEncodingInfo *info)
689 {
690 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
691
692 if ( encoding == wxFONTENCODING_DEFAULT )
693 {
694 encoding = wxFont::GetDefaultEncoding();
695 }
696
697 switch ( encoding )
698 {
699 case wxFONTENCODING_ISO8859_1:
700 case wxFONTENCODING_ISO8859_2:
701 case wxFONTENCODING_ISO8859_3:
702 case wxFONTENCODING_ISO8859_4:
703 case wxFONTENCODING_ISO8859_5:
704 case wxFONTENCODING_ISO8859_6:
705 case wxFONTENCODING_ISO8859_7:
706 case wxFONTENCODING_ISO8859_8:
707 case wxFONTENCODING_ISO8859_9:
708 case wxFONTENCODING_ISO8859_10:
709 case wxFONTENCODING_ISO8859_11:
710 case wxFONTENCODING_ISO8859_12:
711 case wxFONTENCODING_ISO8859_13:
712 case wxFONTENCODING_ISO8859_14:
713 case wxFONTENCODING_ISO8859_15:
714 {
715 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
716 info->xregistry = wxT("iso8859");
717 info->xencoding.Printf(wxT("%d"), cp);
718 }
719 break;
720
721 case wxFONTENCODING_UTF8:
722 info->xregistry = wxT("iso10646");
723 info->xencoding = wxT("*");
724 break;
725
726 case wxFONTENCODING_GB2312:
727 info->xregistry = wxT("GB2312"); // or the otherway round?
728 info->xencoding = wxT("*");
729 break;
730
731 case wxFONTENCODING_KOI8:
732 case wxFONTENCODING_KOI8_U:
733 info->xregistry = wxT("koi8");
734
735 // we don't make distinction between koi8-r, koi8-u and koi8-ru (so far)
736 info->xencoding = wxT("*");
737 break;
738
739 case wxFONTENCODING_CP1250:
740 case wxFONTENCODING_CP1251:
741 case wxFONTENCODING_CP1252:
742 case wxFONTENCODING_CP1253:
743 case wxFONTENCODING_CP1254:
744 case wxFONTENCODING_CP1255:
745 case wxFONTENCODING_CP1256:
746 case wxFONTENCODING_CP1257:
747 {
748 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
749 info->xregistry = wxT("microsoft");
750 info->xencoding.Printf(wxT("cp%d"), cp);
751 }
752 break;
753
754 case wxFONTENCODING_SYSTEM:
755 info->xregistry =
756 info->xencoding = wxT("*");
757 break;
758
759 default:
760 // don't know how to translate this encoding into X fontspec
761 return FALSE;
762 }
763
764 info->encoding = encoding;
765
766 return TRUE;
767 }
768
769 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
770 {
771 wxString fontspec;
772 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
773 !info.facename ? _T("*") : info.facename.c_str(),
774 info.xregistry.c_str(),
775 info.xencoding.c_str());
776
777 return wxTestFontSpec(fontspec);
778 }
779
780 // ----------------------------------------------------------------------------
781 // X-specific functions
782 // ----------------------------------------------------------------------------
783
784 wxNativeFont wxLoadQueryNearestFont(int pointSize,
785 int family,
786 int style,
787 int weight,
788 bool underlined,
789 const wxString &facename,
790 wxFontEncoding encoding,
791 wxString* xFontName)
792 {
793 if ( encoding == wxFONTENCODING_DEFAULT )
794 {
795 encoding = wxFont::GetDefaultEncoding();
796 }
797
798 // first determine the encoding - if the font doesn't exist at all in this
799 // encoding, it's useless to do all other approximations (i.e. size,
800 // family &c don't matter much)
801 wxNativeEncodingInfo info;
802 if ( encoding == wxFONTENCODING_SYSTEM )
803 {
804 // This will always work so we don't test to save time
805 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
806 }
807 else
808 {
809 if ( !wxGetNativeFontEncoding(encoding, &info) ||
810 !wxTestFontEncoding(info) )
811 {
812 #if wxUSE_FONTMAP
813 if ( !wxFontMapper::Get()->GetAltForEncoding(encoding, &info) )
814 #endif // wxUSE_FONTMAP
815 {
816 // unspported encoding - replace it with the default
817 //
818 // NB: we can't just return 0 from here because wxGTK code doesn't
819 // check for it (i.e. it supposes that we'll always succeed),
820 // so it would provoke a crash
821 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
822 }
823 }
824 }
825
826 // OK, we have the correct xregistry/xencoding in info structure
827 wxNativeFont font = 0;
828
829 // if we already have the X font name, try to use it
830 if( xFontName && !xFontName->IsEmpty() )
831 {
832 //
833 // Make sure point size is correct for scale factor.
834 //
835 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
836 wxString newFontName;
837
838 for(int i = 0; i < 8; i++)
839 newFontName += tokenizer.NextToken();
840
841 (void) tokenizer.NextToken();
842
843 newFontName += wxString::Format(wxT("%d-"), pointSize);
844
845 while(tokenizer.HasMoreTokens())
846 newFontName += tokenizer.GetNextToken();
847
848 font = wxLoadFont(newFontName);
849
850 if(font)
851 *xFontName = newFontName;
852 }
853
854 if ( !font )
855 {
856 // search up and down by stepsize 10
857 int max_size = pointSize + 20 * (1 + (pointSize/180));
858 int min_size = pointSize - 20 * (1 + (pointSize/180));
859
860 int i, round; // counters
861
862 // first round: search for equal, then for smaller and for larger size with the given weight and style
863 int testweight = weight;
864 int teststyle = style;
865
866 for ( round = 0; round < 3; round++ )
867 {
868 // second round: use normal weight
869 if ( round == 1 )
870 {
871 if ( testweight != wxNORMAL )
872 {
873 testweight = wxNORMAL;
874 }
875 else
876 {
877 ++round; // fall through to third round
878 }
879 }
880
881 // third round: ... and use normal style
882 if ( round == 2 )
883 {
884 if ( teststyle != wxNORMAL )
885 {
886 teststyle = wxNORMAL;
887 }
888 else
889 {
890 break;
891 }
892 }
893 // Search for equal or smaller size (approx.)
894 for ( i = pointSize; !font && i >= 10 && i >= min_size; i -= 10 )
895 {
896 font = wxLoadQueryFont(i, family, teststyle, testweight, underlined,
897 facename, info.xregistry, info.xencoding,
898 xFontName);
899 }
900
901 // Search for larger size (approx.)
902 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
903 {
904 font = wxLoadQueryFont(i, family, teststyle, testweight, underlined,
905 facename, info.xregistry, info.xencoding,
906 xFontName);
907 }
908 }
909
910 // Try default family
911 if ( !font && family != wxDEFAULT )
912 {
913 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
914 underlined, facename,
915 info.xregistry, info.xencoding,
916 xFontName );
917 }
918
919 // ignore size, family, style and weight but try to find font with the
920 // given facename and encoding
921 if ( !font )
922 {
923 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
924 underlined, facename,
925 info.xregistry, info.xencoding,
926 xFontName);
927
928 // ignore family as well
929 if ( !font )
930 {
931 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
932 underlined, wxEmptyString,
933 info.xregistry, info.xencoding,
934 xFontName);
935
936 // if it still failed, try to get the font of any size but
937 // with the requested encoding: this can happen if the
938 // encoding is only available in one size which happens to be
939 // different from 120
940 if ( !font )
941 {
942 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
943 FALSE, wxEmptyString,
944 info.xregistry, info.xencoding,
945 xFontName);
946
947 // this should never happen as we had tested for it in the
948 // very beginning, but if it does, do return something non
949 // NULL or we'd crash in wxFont code
950 if ( !font )
951 {
952 wxFAIL_MSG( _T("this encoding should be available!") );
953
954 font = wxLoadQueryFont(-1,
955 wxDEFAULT, wxNORMAL, wxNORMAL,
956 FALSE, wxEmptyString,
957 _T("*"), _T("*"),
958 xFontName);
959 }
960 }
961 }
962 }
963 }
964
965 return font;
966 }
967
968 // ----------------------------------------------------------------------------
969 // private functions
970 // ----------------------------------------------------------------------------
971
972 // returns TRUE if there are any fonts matching this font spec
973 static bool wxTestFontSpec(const wxString& fontspec)
974 {
975 // some X servers will fail to load this font because there are too many
976 // matches so we must test explicitly for this
977 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
978 {
979 return TRUE;
980 }
981
982 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
983 if (test)
984 {
985 return TRUE;
986 }
987
988 test = wxLoadFont(fontspec);
989 g_fontHash->Put( fontspec, (wxObject*) test );
990
991 if ( test )
992 {
993 wxFreeFont(test);
994
995 return TRUE;
996 }
997 else
998 {
999 return FALSE;
1000 }
1001 }
1002
1003 static wxNativeFont wxLoadQueryFont(int pointSize,
1004 int family,
1005 int style,
1006 int weight,
1007 bool WXUNUSED(underlined),
1008 const wxString& facename,
1009 const wxString& xregistry,
1010 const wxString& xencoding,
1011 wxString* xFontName)
1012 {
1013 wxString xfamily;
1014 switch (family)
1015 {
1016 case wxDECORATIVE: xfamily = wxT("lucida"); break;
1017 case wxROMAN: xfamily = wxT("times"); break;
1018 case wxMODERN: xfamily = wxT("courier"); break;
1019 case wxSWISS: xfamily = wxT("helvetica"); break;
1020 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
1021 case wxSCRIPT: xfamily = wxT("utopia"); break;
1022 default: xfamily = wxT("*");
1023 }
1024 #if wxUSE_NANOX
1025 int xweight;
1026 switch (weight)
1027 {
1028 case wxBOLD:
1029 {
1030 xweight = MWLF_WEIGHT_BOLD;
1031 break;
1032 }
1033 case wxLIGHT:
1034 {
1035 xweight = MWLF_WEIGHT_LIGHT;
1036 break;
1037 }
1038 case wxNORMAL:
1039 {
1040 xweight = MWLF_WEIGHT_NORMAL;
1041 break;
1042 }
1043
1044 default:
1045 {
1046 xweight = MWLF_WEIGHT_DEFAULT;
1047 break;
1048 }
1049 }
1050 GR_SCREEN_INFO screenInfo;
1051 GrGetScreenInfo(& screenInfo);
1052
1053 int yPixelsPerCM = screenInfo.ydpcm;
1054
1055 // A point is 1/72 of an inch.
1056 // An inch is 2.541 cm.
1057 // So pixelHeight = (pointSize / 72) (inches) * 2.541 (for cm) * yPixelsPerCM (for pixels)
1058 // In fact pointSize is 10 * the normal point size so
1059 // divide by 10.
1060
1061 int pixelHeight = (int) ( (((float)pointSize) / 720.0) * 2.541 * (float) yPixelsPerCM) ;
1062
1063 // An alternative: assume that the screen is 72 dpi.
1064 //int pixelHeight = (int) (((float)pointSize / 720.0) * 72.0) ;
1065 //int pixelHeight = (int) ((float)pointSize / 10.0) ;
1066
1067 GR_LOGFONT logFont;
1068 logFont.lfHeight = pixelHeight;
1069 logFont.lfWidth = 0;
1070 logFont.lfEscapement = 0;
1071 logFont.lfOrientation = 0;
1072 logFont.lfWeight = xweight;
1073 logFont.lfItalic = (style == wxNORMAL ? 0 : 1) ;
1074 logFont.lfUnderline = 0;
1075 logFont.lfStrikeOut = 0;
1076 logFont.lfCharSet = MWLF_CHARSET_DEFAULT; // TODO: select appropriate one
1077 logFont.lfOutPrecision = MWLF_TYPE_DEFAULT;
1078 logFont.lfClipPrecision = 0; // Not used
1079 logFont.lfRoman = (family == wxROMAN ? 1 : 0) ;
1080 logFont.lfSerif = (family == wxSWISS ? 0 : 1) ;
1081 logFont.lfSansSerif = !logFont.lfSerif ;
1082 logFont.lfModern = (family == wxMODERN ? 1 : 0) ;
1083 logFont.lfProportional = (family == wxTELETYPE ? 0 : 1) ;
1084 logFont.lfOblique = 0;
1085 logFont.lfSmallCaps = 0;
1086 logFont.lfPitch = 0; // 0 = default
1087 strcpy(logFont.lfFaceName, facename.c_str());
1088
1089 XFontStruct* fontInfo = (XFontStruct*) malloc(sizeof(XFontStruct));
1090 fontInfo->fid = GrCreateFont((GR_CHAR*) facename.c_str(), pixelHeight, & logFont);
1091 GrGetFontInfo(fontInfo->fid, & fontInfo->info);
1092 return (wxNativeFont) fontInfo;
1093
1094 #else
1095 wxString fontSpec;
1096 if (!facename.IsEmpty())
1097 {
1098 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
1099 facename.c_str());
1100
1101 if ( wxTestFontSpec(fontSpec) )
1102 {
1103 xfamily = facename;
1104 }
1105 //else: no such family, use default one instead
1106 }
1107
1108 wxString xstyle;
1109 switch (style)
1110 {
1111 case wxSLANT:
1112 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1113 xfamily.c_str());
1114 if ( wxTestFontSpec(fontSpec) )
1115 {
1116 xstyle = wxT("o");
1117 break;
1118 }
1119 // fall through - try wxITALIC now
1120
1121 case wxITALIC:
1122 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
1123 xfamily.c_str());
1124 if ( wxTestFontSpec(fontSpec) )
1125 {
1126 xstyle = wxT("i");
1127 }
1128 else if ( style == wxITALIC ) // and not wxSLANT
1129 {
1130 // try wxSLANT
1131 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1132 xfamily.c_str());
1133 if ( wxTestFontSpec(fontSpec) )
1134 {
1135 xstyle = wxT("o");
1136 }
1137 else
1138 {
1139 // no italic, no slant - leave default
1140 xstyle = wxT("*");
1141 }
1142 }
1143 break;
1144
1145 default:
1146 wxFAIL_MSG(_T("unknown font style"));
1147 // fall back to normal
1148
1149 case wxNORMAL:
1150 xstyle = wxT("r");
1151 break;
1152 }
1153
1154 wxString xweight;
1155 switch (weight)
1156 {
1157 case wxBOLD:
1158 {
1159 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
1160 xfamily.c_str());
1161 if ( wxTestFontSpec(fontSpec) )
1162 {
1163 xweight = wxT("bold");
1164 break;
1165 }
1166 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
1167 xfamily.c_str());
1168 if ( wxTestFontSpec(fontSpec) )
1169 {
1170 xweight = wxT("heavy");
1171 break;
1172 }
1173 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
1174 xfamily.c_str());
1175 if ( wxTestFontSpec(fontSpec) )
1176 {
1177 xweight = wxT("extrabold");
1178 break;
1179 }
1180 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
1181 xfamily.c_str());
1182 if ( wxTestFontSpec(fontSpec) )
1183 {
1184 xweight = wxT("demibold");
1185 break;
1186 }
1187 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
1188 xfamily.c_str());
1189 if ( wxTestFontSpec(fontSpec) )
1190 {
1191 xweight = wxT("black");
1192 break;
1193 }
1194 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
1195 xfamily.c_str());
1196 if ( wxTestFontSpec(fontSpec) )
1197 {
1198 xweight = wxT("ultrablack");
1199 break;
1200 }
1201 }
1202 break;
1203 case wxLIGHT:
1204 {
1205 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
1206 xfamily.c_str());
1207 if ( wxTestFontSpec(fontSpec) )
1208 {
1209 xweight = wxT("light");
1210 break;
1211 }
1212 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
1213 xfamily.c_str());
1214 if ( wxTestFontSpec(fontSpec) )
1215 {
1216 xweight = wxT("thin");
1217 break;
1218 }
1219 }
1220 break;
1221 case wxNORMAL:
1222 {
1223 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
1224 xfamily.c_str());
1225 if ( wxTestFontSpec(fontSpec) )
1226 {
1227 xweight = wxT("medium");
1228 break;
1229 }
1230 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
1231 xfamily.c_str());
1232 if ( wxTestFontSpec(fontSpec) )
1233 {
1234 xweight = wxT("normal");
1235 break;
1236 }
1237 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
1238 xfamily.c_str());
1239 if ( wxTestFontSpec(fontSpec) )
1240 {
1241 xweight = wxT("regular");
1242 break;
1243 }
1244 xweight = wxT("*");
1245 }
1246 break;
1247 default: xweight = wxT("*"); break;
1248 }
1249
1250 // if pointSize is -1, don't specify any
1251 wxString sizeSpec;
1252 if ( pointSize == -1 )
1253 {
1254 sizeSpec = _T('*');
1255 }
1256 else
1257 {
1258 sizeSpec.Printf(_T("%d"), pointSize);
1259 }
1260
1261 // construct the X font spec from our data
1262 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
1263 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
1264 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
1265
1266 if( xFontName )
1267 *xFontName = fontSpec;
1268
1269 return wxLoadFont(fontSpec);
1270 #endif
1271 // wxUSE_NANOX
1272 }
1273
1274 // ----------------------------------------------------------------------------
1275 // wxFontModule
1276 // ----------------------------------------------------------------------------
1277
1278 class wxFontModule : public wxModule
1279 {
1280 public:
1281 bool OnInit();
1282 void OnExit();
1283
1284 private:
1285 DECLARE_DYNAMIC_CLASS(wxFontModule)
1286 };
1287
1288 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
1289
1290 bool wxFontModule::OnInit()
1291 {
1292 g_fontHash = new wxHashTable( wxKEY_STRING );
1293
1294 return TRUE;
1295 }
1296
1297 void wxFontModule::OnExit()
1298 {
1299 delete g_fontHash;
1300
1301 g_fontHash = (wxHashTable *)NULL;
1302 }
1303
1304 #endif // GTK 2.0/1.x
1305