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