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