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