]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/unix/fontutil.cpp
Unicode compilation fixes
[wxWidgets.git] / src / unix / fontutil.cpp
... / ...
CommitLineData
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
62void wxNativeFontInfo::Init()
63{
64 description = NULL;
65}
66
67void
68wxNativeFontInfo::Init(const wxNativeFontInfo& info)
69{
70 if (info.description)
71 description = pango_font_description_copy(info.description);
72 else
73 description = NULL;
74}
75
76void wxNativeFontInfo::Free()
77{
78 if (description)
79 pango_font_description_free(description);
80}
81
82int wxNativeFontInfo::GetPointSize() const
83{
84 return pango_font_description_get_size( description ) / PANGO_SCALE;
85}
86
87wxFontStyle 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
107wxFontWeight 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
132bool wxNativeFontInfo::GetUnderlined() const
133{
134 return false;
135}
136
137wxString wxNativeFontInfo::GetFaceName() const
138{
139 return wxGTK_CONV_BACK_SYS(pango_font_description_get_family(description));
140}
141
142wxFontFamily 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
214wxFontEncoding wxNativeFontInfo::GetEncoding() const
215{
216 return wxFONTENCODING_SYSTEM;
217}
218
219
220void wxNativeFontInfo::SetPointSize(int pointsize)
221{
222 pango_font_description_set_size( description, pointsize * PANGO_SCALE );
223}
224
225void 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
244void 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
262void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
263{
264 wxFAIL_MSG( _T("not implemented") );
265}
266
267bool wxNativeFontInfo::SetFaceName(const wxString& facename)
268{
269 pango_font_description_set_family(description, wxPANGO_CONV(facename));
270 return true;
271}
272
273void wxNativeFontInfo::SetFamily(wxFontFamily WXUNUSED(family))
274{
275 wxFAIL_MSG( _T("not implemented") );
276}
277
278void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding))
279{
280 wxFAIL_MSG( _T("not implemented") );
281}
282
283
284
285bool 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
324wxString wxNativeFontInfo::ToString() const
325{
326 wxGtkString str(pango_font_description_to_string( description ));
327
328 return wxGTK_CONV_BACK_SYS(str);
329}
330
331bool wxNativeFontInfo::FromUserString(const wxString& s)
332{
333 return FromString( s );
334}
335
336wxString 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
369static 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
406static bool wxTestFontSpec(const wxString& fontspec);
407
408static 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]
428bool 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
453wxString 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
469void wxNativeFontInfo::Init()
470{
471 m_isDefault = true;
472}
473
474bool 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
492wxString wxNativeFontInfo::ToString() const
493{
494 // 0 is the version
495 return wxString::Format(_T("%d;%s"), 0, GetXFontName().c_str());
496}
497
498bool wxNativeFontInfo::FromUserString(const wxString& s)
499{
500 return FromXFontName(s);
501}
502
503wxString wxNativeFontInfo::ToUserString() const
504{
505 return GetXFontName();
506}
507
508bool 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
515wxString 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
529bool 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
565wxString 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
587void
588wxNativeFontInfo::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
613void 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
623int 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
632wxFontStyle 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
659wxFontWeight 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
670bool wxNativeFontInfo::GetUnderlined() const
671{
672 // X fonts are never underlined
673 return false;
674}
675
676wxString wxNativeFontInfo::GetFaceName() const
677{
678 // wxWidgets facename probably more accurately corresponds to X family
679 return GetXFontComponent(wxXLFD_FAMILY);
680}
681
682wxFontFamily 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
691wxFontEncoding 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
699void wxNativeFontInfo::SetPointSize(int pointsize)
700{
701 SetXFontComponent(wxXLFD_POINTSIZE, wxString::Format(_T("%d"), pointsize));
702}
703
704void 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
728void 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
753void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
754{
755 // can't do this under X
756}
757
758bool wxNativeFontInfo::SetFaceName(const wxString& facename)
759{
760 SetXFontComponent(wxXLFD_FAMILY, facename);
761 return true;
762}
763
764void wxNativeFontInfo::SetFamily(wxFontFamily WXUNUSED(family))
765{
766 // wxFontFamily -> X foundry, anyone?
767 wxFAIL_MSG( _T("not implemented") );
768
769 // SetXFontComponent(wxXLFD_FOUNDRY, ...);
770}
771
772void 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
786bool 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
874bool 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
889wxNativeFont 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
1078static 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
1108static 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
1383class wxFontModule : public wxModule
1384{
1385public:
1386 bool OnInit();
1387 void OnExit();
1388
1389private:
1390 DECLARE_DYNAMIC_CLASS(wxFontModule)
1391};
1392
1393IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
1394
1395bool wxFontModule::OnInit()
1396{
1397 g_fontHash = new wxHashTable( wxKEY_STRING );
1398
1399 return true;
1400}
1401
1402void wxFontModule::OnExit()
1403{
1404 delete g_fontHash;
1405
1406 g_fontHash = (wxHashTable *)NULL;
1407}
1408
1409#endif // GTK 2.0/1.x