]> git.saurik.com Git - wxWidgets.git/blame - src/unix/fontutil.cpp
fingers crossed..
[wxWidgets.git] / src / unix / fontutil.cpp
CommitLineData
7beba2fc
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: 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 license
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "fontutil.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32#endif // PCH
33
79e4b627 34#ifdef __X__
4ea45e6b
VZ
35 #ifdef __VMS__
36 #pragma message disable nosimpint
37 #endif
38
39 #include <X11/Xlib.h>
40
41 #ifdef __VMS__
42 #pragma message enable nosimpint
43 #endif
79e4b627
VZ
44
45 #include "wx/utils.h" // for wxGetDisplay()
46#elif defined(__WXGTK__)
4ea45e6b
VZ
47 // we have to declare struct tm to avoid problems with first forward
48 // declaring it in C code (glib.h included from gdk.h does it) and then
49 // defining it when time.h is included from the headers below - this is
50 // known not to work at least with Sun CC 6.01
51 #include <time.h>
52
53 #include <gdk/gdk.h>
79e4b627
VZ
54#endif
55
7beba2fc
VZ
56#include "wx/fontutil.h"
57#include "wx/fontmap.h"
58#include "wx/tokenzr.h"
2e0e025e
RR
59#include "wx/hash.h"
60#include "wx/module.h"
61
62// ----------------------------------------------------------------------------
63// private data
64// ----------------------------------------------------------------------------
65
66static wxHashTable *g_fontHash = (wxHashTable*) NULL;
7beba2fc
VZ
67
68// ----------------------------------------------------------------------------
69// private functions
70// ----------------------------------------------------------------------------
71
72// define the functions to create and destroy native fonts for this toolkit
73#ifdef __X__
74 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
75 {
76 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
77 }
78
79 static inline void wxFreeFont(wxNativeFont font)
80 {
a5fc62a1 81 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
7beba2fc
VZ
82 }
83#elif defined(__WXGTK__)
7beba2fc
VZ
84 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
85 {
97d3f0ee 86 return gdk_font_load( wxConvertWX2MB(fontSpec) );
7beba2fc
VZ
87 }
88
89 static inline void wxFreeFont(wxNativeFont font)
90 {
91 gdk_font_unref(font);
92 }
93#else
94 #error "Unknown GUI toolkit"
95#endif
96
97static bool wxTestFontSpec(const wxString& fontspec);
98
99static wxNativeFont wxLoadQueryFont(int pointSize,
100 int family,
101 int style,
102 int weight,
103 bool underlined,
104 const wxString& facename,
105 const wxString& xregistry,
30764ab5
VZ
106 const wxString& xencoding,
107 wxString* xFontName);
7beba2fc
VZ
108
109// ============================================================================
110// implementation
111// ============================================================================
112
113// ----------------------------------------------------------------------------
114// wxNativeEncodingInfo
115// ----------------------------------------------------------------------------
116
117// convert to/from the string representation: format is
1e1d0be1 118// encodingid;registry;encoding[;facename]
7beba2fc
VZ
119bool wxNativeEncodingInfo::FromString(const wxString& s)
120{
6c49baf2 121 // use ";", not "-" because it may be part of encoding name
1e1d0be1 122 wxStringTokenizer tokenizer(s, _T(";"));
1e1d0be1
VS
123
124 wxString encid = tokenizer.GetNextToken();
125 long enc;
126 if ( !encid.ToLong(&enc) )
127 return FALSE;
128 encoding = (wxFontEncoding)enc;
7beba2fc
VZ
129
130 xregistry = tokenizer.GetNextToken();
131 if ( !xregistry )
132 return FALSE;
133
134 xencoding = tokenizer.GetNextToken();
135 if ( !xencoding )
136 return FALSE;
137
138 // ok even if empty
139 facename = tokenizer.GetNextToken();
140
141 return TRUE;
142}
143
144wxString wxNativeEncodingInfo::ToString() const
145{
146 wxString s;
1e1d0be1 147 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
7beba2fc
VZ
148 if ( !!facename )
149 {
1e1d0be1 150 s << _T(';') << facename;
7beba2fc
VZ
151 }
152
153 return s;
154}
155
156// ----------------------------------------------------------------------------
157// common functions
158// ----------------------------------------------------------------------------
159
160bool wxGetNativeFontEncoding(wxFontEncoding encoding,
161 wxNativeEncodingInfo *info)
162{
163 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
164
165 if ( encoding == wxFONTENCODING_DEFAULT )
166 {
167 encoding = wxFont::GetDefaultEncoding();
168 }
169
170 switch ( encoding )
171 {
172 case wxFONTENCODING_ISO8859_1:
173 case wxFONTENCODING_ISO8859_2:
174 case wxFONTENCODING_ISO8859_3:
175 case wxFONTENCODING_ISO8859_4:
176 case wxFONTENCODING_ISO8859_5:
177 case wxFONTENCODING_ISO8859_6:
178 case wxFONTENCODING_ISO8859_7:
179 case wxFONTENCODING_ISO8859_8:
180 case wxFONTENCODING_ISO8859_9:
181 case wxFONTENCODING_ISO8859_10:
182 case wxFONTENCODING_ISO8859_11:
80a24267 183 case wxFONTENCODING_ISO8859_12:
7beba2fc
VZ
184 case wxFONTENCODING_ISO8859_13:
185 case wxFONTENCODING_ISO8859_14:
186 case wxFONTENCODING_ISO8859_15:
187 {
188 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
189 info->xregistry = wxT("iso8859");
190 info->xencoding.Printf(wxT("%d"), cp);
191 }
192 break;
193
bb84929e
VZ
194 case wxFONTENCODING_UTF8:
195 // FIXME: this is probably false, but this is how they are called on
196 // my system and I don't know what the standard XFLD is (VZ)
197 info->xregistry = wxT("iso646.1991");
198 info->xencoding = wxT("*");
199 break;
200
7beba2fc
VZ
201 case wxFONTENCODING_KOI8:
202 info->xregistry = wxT("koi8");
203
204 // we don't make distinction between koi8-r and koi8-u (so far)
205 info->xencoding = wxT("*");
206 break;
207
208 case wxFONTENCODING_CP1250:
209 case wxFONTENCODING_CP1251:
210 case wxFONTENCODING_CP1252:
211 case wxFONTENCODING_CP1253:
212 case wxFONTENCODING_CP1254:
213 case wxFONTENCODING_CP1255:
214 case wxFONTENCODING_CP1256:
215 case wxFONTENCODING_CP1257:
216 {
217 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
218 info->xregistry = wxT("microsoft");
219 info->xencoding.Printf(wxT("cp%d"), cp);
220 }
221 break;
222
223 case wxFONTENCODING_SYSTEM:
224 info->xregistry =
81c67e27 225 info->xencoding = wxT("*");
7beba2fc
VZ
226 break;
227
228 default:
229 // don't know how to translate this encoding into X fontspec
230 return FALSE;
231 }
232
6b0eebc5
VS
233 info->encoding = encoding;
234
7beba2fc
VZ
235 return TRUE;
236}
237
238bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
239{
240 wxString fontspec;
241 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
242 !info.facename ? _T("*") : info.facename.c_str(),
243 info.xregistry.c_str(),
244 info.xencoding.c_str());
245
246 return wxTestFontSpec(fontspec);
247}
248
249// ----------------------------------------------------------------------------
250// X-specific functions
251// ----------------------------------------------------------------------------
252
253wxNativeFont wxLoadQueryNearestFont(int pointSize,
254 int family,
255 int style,
256 int weight,
257 bool underlined,
258 const wxString &facename,
30764ab5
VZ
259 wxFontEncoding encoding,
260 wxString* xFontName)
7beba2fc 261{
97d3f0ee
VZ
262 if ( encoding == wxFONTENCODING_DEFAULT )
263 {
264 encoding = wxFont::GetDefaultEncoding();
265 }
266
7beba2fc
VZ
267 // first determine the encoding - if the font doesn't exist at all in this
268 // encoding, it's useless to do all other approximations (i.e. size,
269 // family &c don't matter much)
270 wxNativeEncodingInfo info;
97d3f0ee 271 if ( encoding == wxFONTENCODING_SYSTEM )
81c67e27
RR
272 {
273 // This will always work so we don't test to save time
274 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
275 }
276 else
7beba2fc 277 {
81c67e27
RR
278 if ( !wxGetNativeFontEncoding(encoding, &info) ||
279 !wxTestFontEncoding(info) )
7beba2fc 280 {
81c67e27
RR
281 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
282 {
283 // unspported encoding - replace it with the default
284 //
285 // NB: we can't just return 0 from here because wxGTK code doesn't
286 // check for it (i.e. it supposes that we'll always succeed),
287 // so it would provoke a crash
288 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
289 }
97d3f0ee 290 }
7beba2fc 291 }
6c49baf2 292
81c67e27 293 // OK, we have the correct xregistry/xencoding in info structure
30764ab5
VZ
294 wxNativeFont font = 0;
295
296 // if we already have the X font name, try to use it
297 if( xFontName && !xFontName->IsEmpty() )
6c49baf2
VZ
298 {
299 //
300 // Make sure point size is correct for scale factor.
301 //
302 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
303 wxString newFontName;
304
305 for(int i = 0; i < 8; i++)
306 newFontName += tokenizer.NextToken();
307
308 (void) tokenizer.NextToken();
309
310 newFontName += wxString::Format("%d-", pointSize);
311
312 while(tokenizer.HasMoreTokens())
313 newFontName += tokenizer.GetNextToken();
314
315 font = wxLoadFont(newFontName);
316
317 if(font)
318 *xFontName = newFontName;
319 }
30764ab5 320
f139dfe8 321 // try to load exactly the font requested first
30764ab5 322 if( !font )
f139dfe8 323 {
30764ab5 324 font = wxLoadQueryFont( pointSize, family, style, weight,
f139dfe8 325 underlined, facename,
30764ab5
VZ
326 info.xregistry, info.xencoding,
327 xFontName );
f139dfe8 328 }
7beba2fc
VZ
329
330 if ( !font )
331 {
332 // search up and down by stepsize 10
333 int max_size = pointSize + 20 * (1 + (pointSize/180));
334 int min_size = pointSize - 20 * (1 + (pointSize/180));
335
336 int i;
337
338 // Search for smaller size (approx.)
339 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
340 {
341 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
342 facename, info.xregistry, info.xencoding,
343 xFontName);
7beba2fc
VZ
344 }
345
346 // Search for larger size (approx.)
347 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
348 {
349 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
350 facename, info.xregistry, info.xencoding,
351 xFontName);
7beba2fc
VZ
352 }
353
354 // Try default family
355 if ( !font && family != wxDEFAULT )
356 {
357 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
358 underlined, facename,
30764ab5
VZ
359 info.xregistry, info.xencoding,
360 xFontName );
7beba2fc
VZ
361 }
362
f139dfe8
VZ
363 // ignore size, family, style and weight but try to find font with the
364 // given facename and encoding
7beba2fc
VZ
365 if ( !font )
366 {
367 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
368 underlined, facename,
30764ab5
VZ
369 info.xregistry, info.xencoding,
370 xFontName);
7beba2fc 371
f139dfe8
VZ
372 // ignore family as well
373 if ( !font )
374 {
375 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
376 underlined, wxEmptyString,
377 info.xregistry, info.xencoding,
378 xFontName);
379
380 // if it still failed, try to get the font of any size but
381 // with the requested encoding: this can happen if the
382 // encoding is only available in one size which happens to be
383 // different from 120
384 if ( !font )
385 {
386 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
387 FALSE, wxEmptyString,
388 info.xregistry, info.xencoding,
389 xFontName);
390
391 // this should never happen as we had tested for it in the
392 // very beginning, but if it does, do return something non
393 // NULL or we'd crash in wxFont code
394 if ( !font )
395 {
396 wxFAIL_MSG( _T("this encoding should be available!") );
397
398 font = wxLoadQueryFont(-1,
399 wxDEFAULT, wxNORMAL, wxNORMAL,
400 FALSE, wxEmptyString,
401 _T("*"), _T("*"),
402 xFontName);
403 }
404 }
405 }
7beba2fc
VZ
406 }
407 }
408
409 return font;
410}
411
412// ----------------------------------------------------------------------------
413// private functions
414// ----------------------------------------------------------------------------
415
416// returns TRUE if there are any fonts matching this font spec
417static bool wxTestFontSpec(const wxString& fontspec)
418{
97d3f0ee
VZ
419 // some X servers will fail to load this font because there are too many
420 // matches so we must test explicitly for this
421 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
422 {
423 return TRUE;
424 }
425
2e0e025e
RR
426 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
427 if (test)
428 {
2e0e025e
RR
429 return TRUE;
430 }
431
432 test = wxLoadFont(fontspec);
433 g_fontHash->Put( fontspec, (wxObject*) test );
6c49baf2 434
7beba2fc
VZ
435 if ( test )
436 {
437 wxFreeFont(test);
438
439 return TRUE;
440 }
441 else
442 {
443 return FALSE;
444 }
445}
446
447static wxNativeFont wxLoadQueryFont(int pointSize,
448 int family,
449 int style,
450 int weight,
451 bool WXUNUSED(underlined),
452 const wxString& facename,
453 const wxString& xregistry,
30764ab5
VZ
454 const wxString& xencoding,
455 wxString* xFontName)
7beba2fc
VZ
456{
457 wxString xfamily;
458 switch (family)
459 {
460 case wxDECORATIVE: xfamily = wxT("lucida"); break;
461 case wxROMAN: xfamily = wxT("times"); break;
462 case wxMODERN: xfamily = wxT("courier"); break;
463 case wxSWISS: xfamily = wxT("helvetica"); break;
464 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
465 case wxSCRIPT: xfamily = wxT("utopia"); break;
466 default: xfamily = wxT("*");
467 }
468
469 wxString fontSpec;
470 if (!facename.IsEmpty())
471 {
472 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
473 facename.c_str());
474
475 if ( wxTestFontSpec(fontSpec) )
476 {
477 xfamily = facename;
478 }
479 //else: no such family, use default one instead
480 }
481
482 wxString xstyle;
483 switch (style)
484 {
f9dbf34f
VZ
485 case wxSLANT:
486 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
487 xfamily.c_str());
488 if ( wxTestFontSpec(fontSpec) )
489 {
490 xstyle = wxT("o");
491 break;
492 }
493 // fall through - try wxITALIC now
494
495 case wxITALIC:
496 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
497 xfamily.c_str());
498 if ( wxTestFontSpec(fontSpec) )
499 {
500 xstyle = wxT("i");
501 }
502 else if ( style == wxITALIC ) // and not wxSLANT
503 {
504 // try wxSLANT
505 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
506 xfamily.c_str());
507 if ( wxTestFontSpec(fontSpec) )
508 {
509 xstyle = wxT("o");
510 }
511 else
512 {
513 // no italic, no slant - leave default
514 xstyle = wxT("*");
515 }
516 }
517 break;
518
519 default:
520 wxFAIL_MSG(_T("unknown font style"));
521 // fall back to normal
522
523 case wxNORMAL:
524 xstyle = wxT("r");
525 break;
7beba2fc
VZ
526 }
527
528 wxString xweight;
529 switch (weight)
530 {
531 case wxBOLD:
532 {
533 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
534 xfamily.c_str());
535 if ( wxTestFontSpec(fontSpec) )
536 {
537 xweight = wxT("bold");
538 break;
539 }
540 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
541 xfamily.c_str());
542 if ( wxTestFontSpec(fontSpec) )
543 {
544 xweight = wxT("heavy");
545 break;
546 }
547 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
548 xfamily.c_str());
549 if ( wxTestFontSpec(fontSpec) )
550 {
551 xweight = wxT("extrabold");
552 break;
553 }
554 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
555 xfamily.c_str());
556 if ( wxTestFontSpec(fontSpec) )
557 {
558 xweight = wxT("demibold");
559 break;
560 }
561 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
562 xfamily.c_str());
563 if ( wxTestFontSpec(fontSpec) )
564 {
565 xweight = wxT("black");
566 break;
567 }
568 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
569 xfamily.c_str());
570 if ( wxTestFontSpec(fontSpec) )
571 {
572 xweight = wxT("ultrablack");
573 break;
574 }
575 }
576 break;
577 case wxLIGHT:
578 {
579 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
580 xfamily.c_str());
581 if ( wxTestFontSpec(fontSpec) )
582 {
583 xweight = wxT("light");
584 break;
585 }
586 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
587 xfamily.c_str());
588 if ( wxTestFontSpec(fontSpec) )
589 {
590 xweight = wxT("thin");
591 break;
592 }
593 }
594 break;
595 case wxNORMAL:
596 {
597 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
598 xfamily.c_str());
599 if ( wxTestFontSpec(fontSpec) )
600 {
601 xweight = wxT("medium");
602 break;
603 }
604 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
605 xfamily.c_str());
606 if ( wxTestFontSpec(fontSpec) )
607 {
608 xweight = wxT("normal");
609 break;
610 }
611 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
612 xfamily.c_str());
613 if ( wxTestFontSpec(fontSpec) )
614 {
615 xweight = wxT("regular");
616 break;
617 }
618 xweight = wxT("*");
619 }
620 break;
621 default: xweight = wxT("*"); break;
622 }
623
f139dfe8
VZ
624 // if pointSize is -1, don't specify any
625 wxString sizeSpec;
626 if ( fontSpec == -1 )
627 {
628 sizeSpec = _T('*');
629 }
630 else
631 {
632 sizeSpec.Printf(_T("%d"), pointSize);
633 }
634
7beba2fc 635 // construct the X font spec from our data
f139dfe8 636 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
7beba2fc 637 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
f139dfe8 638 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
7beba2fc 639
30764ab5
VZ
640 if( xFontName )
641 *xFontName = fontSpec;
642
7beba2fc
VZ
643 return wxLoadFont(fontSpec);
644}
645
2e0e025e
RR
646// ----------------------------------------------------------------------------
647// wxFontModule
648// ----------------------------------------------------------------------------
649
650class wxFontModule : public wxModule
651{
652public:
653 bool OnInit();
654 void OnExit();
655
656private:
657 DECLARE_DYNAMIC_CLASS(wxFontModule)
658};
659
660IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
661
662bool wxFontModule::OnInit()
663{
664 g_fontHash = new wxHashTable( wxKEY_STRING );
665
666 return TRUE;
667}
668
669void wxFontModule::OnExit()
670{
671 delete g_fontHash;
672
673 g_fontHash = (wxHashTable *)NULL;
674}