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