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