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