some stupid attempts to make utf8 work - it doesn't, but the code does no harm and...
[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 wxString* xFontName);
100
101 // ============================================================================
102 // implementation
103 // ============================================================================
104
105 // ----------------------------------------------------------------------------
106 // wxNativeEncodingInfo
107 // ----------------------------------------------------------------------------
108
109 // convert to/from the string representation: format is
110 // encodingid;registry;encoding[;facename]
111 bool wxNativeEncodingInfo::FromString(const wxString& s)
112 {
113 // use ";", not "-" because it may be part of encoding name
114 wxStringTokenizer tokenizer(s, _T(";"));
115
116 wxString encid = tokenizer.GetNextToken();
117 long enc;
118 if ( !encid.ToLong(&enc) )
119 return FALSE;
120 encoding = (wxFontEncoding)enc;
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
136 wxString wxNativeEncodingInfo::ToString() const
137 {
138 wxString s;
139 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
140 if ( !!facename )
141 {
142 s << _T(';') << facename;
143 }
144
145 return s;
146 }
147
148 // ----------------------------------------------------------------------------
149 // common functions
150 // ----------------------------------------------------------------------------
151
152 bool 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:
175 case wxFONTENCODING_ISO8859_12:
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
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
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 =
217 info->xencoding = wxT("*");
218 break;
219
220 default:
221 // don't know how to translate this encoding into X fontspec
222 return FALSE;
223 }
224
225 info->encoding = encoding;
226
227 return TRUE;
228 }
229
230 bool 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
245 wxNativeFont wxLoadQueryNearestFont(int pointSize,
246 int family,
247 int style,
248 int weight,
249 bool underlined,
250 const wxString &facename,
251 wxFontEncoding encoding,
252 wxString* xFontName)
253 {
254 if ( encoding == wxFONTENCODING_DEFAULT )
255 {
256 encoding = wxFont::GetDefaultEncoding();
257 }
258
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;
263 if ( encoding == wxFONTENCODING_SYSTEM )
264 {
265 // This will always work so we don't test to save time
266 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
267 }
268 else
269 {
270 if ( !wxGetNativeFontEncoding(encoding, &info) ||
271 !wxTestFontEncoding(info) )
272 {
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 }
282 }
283 }
284
285 // OK, we have the correct xregistry/xencoding in info structure
286 wxNativeFont font = 0;
287
288 // if we already have the X font name, try to use it
289 if( xFontName && !xFontName->IsEmpty() )
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 }
312
313 if( !font )
314 font = wxLoadQueryFont( pointSize, family, style, weight,
315 underlined, facename,
316 info.xregistry, info.xencoding,
317 xFontName );
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,
331 facename, info.xregistry, info.xencoding,
332 xFontName);
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,
339 facename, info.xregistry, info.xencoding,
340 xFontName);
341 }
342
343 // Try default family
344 if ( !font && family != wxDEFAULT )
345 {
346 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
347 underlined, facename,
348 info.xregistry, info.xencoding,
349 xFontName );
350 }
351
352 // Bogus font I
353 if ( !font )
354 {
355 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
356 underlined, facename,
357 info.xregistry, info.xencoding,
358 xFontName);
359 }
360
361 // Bogus font II
362 if ( !font )
363 {
364 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
365 underlined, wxEmptyString,
366 info.xregistry, info.xencoding,
367 xFontName);
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
379 static bool wxTestFontSpec(const wxString& fontspec)
380 {
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
388 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
389 if (test)
390 {
391 return TRUE;
392 }
393
394 test = wxLoadFont(fontspec);
395 g_fontHash->Put( fontspec, (wxObject*) test );
396
397 if ( test )
398 {
399 wxFreeFont(test);
400
401 return TRUE;
402 }
403 else
404 {
405 return FALSE;
406 }
407 }
408
409 static 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,
416 const wxString& xencoding,
417 wxString* xFontName)
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 {
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;
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
591 if( xFontName )
592 *xFontName = fontSpec;
593
594 return wxLoadFont(fontSpec);
595 }
596
597 // ----------------------------------------------------------------------------
598 // wxFontModule
599 // ----------------------------------------------------------------------------
600
601 class wxFontModule : public wxModule
602 {
603 public:
604 bool OnInit();
605 void OnExit();
606
607 private:
608 DECLARE_DYNAMIC_CLASS(wxFontModule)
609 };
610
611 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
612
613 bool wxFontModule::OnInit()
614 {
615 g_fontHash = new wxHashTable( wxKEY_STRING );
616
617 return TRUE;
618 }
619
620 void wxFontModule::OnExit()
621 {
622 delete g_fontHash;
623
624 g_fontHash = (wxHashTable *)NULL;
625 }