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