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