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