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