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