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