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