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