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