fir for Sun CC 6.0 compilation of wxGTK
[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
39 #include <X11/Xlib.h>
40
41 #ifdef __VMS__
42 #pragma message enable nosimpint
43 #endif
44
45 #include "wx/utils.h" // for wxGetDisplay()
46 #elif defined(__WXGTK__)
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>
54 #endif
55
56 #include "wx/fontutil.h"
57 #include "wx/fontmap.h"
58 #include "wx/tokenzr.h"
59 #include "wx/hash.h"
60 #include "wx/module.h"
61
62 // ----------------------------------------------------------------------------
63 // private data
64 // ----------------------------------------------------------------------------
65
66 static wxHashTable *g_fontHash = (wxHashTable*) NULL;
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 {
81 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
82 }
83 #elif defined(__WXGTK__)
84 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
85 {
86 return gdk_font_load( wxConvertWX2MB(fontSpec) );
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
97 static bool wxTestFontSpec(const wxString& fontspec);
98
99 static wxNativeFont wxLoadQueryFont(int pointSize,
100 int family,
101 int style,
102 int weight,
103 bool underlined,
104 const wxString& facename,
105 const wxString& xregistry,
106 const wxString& xencoding,
107 wxString* xFontName);
108
109 // ============================================================================
110 // implementation
111 // ============================================================================
112
113 // ----------------------------------------------------------------------------
114 // wxNativeEncodingInfo
115 // ----------------------------------------------------------------------------
116
117 // convert to/from the string representation: format is
118 // encodingid;registry;encoding[;facename]
119 bool wxNativeEncodingInfo::FromString(const wxString& s)
120 {
121 // use ";", not "-" because it may be part of encoding name
122 wxStringTokenizer tokenizer(s, _T(";"));
123
124 wxString encid = tokenizer.GetNextToken();
125 long enc;
126 if ( !encid.ToLong(&enc) )
127 return FALSE;
128 encoding = (wxFontEncoding)enc;
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
144 wxString wxNativeEncodingInfo::ToString() const
145 {
146 wxString s;
147 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
148 if ( !!facename )
149 {
150 s << _T(';') << facename;
151 }
152
153 return s;
154 }
155
156 // ----------------------------------------------------------------------------
157 // common functions
158 // ----------------------------------------------------------------------------
159
160 bool 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:
183 case wxFONTENCODING_ISO8859_12:
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
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
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 =
225 info->xencoding = wxT("*");
226 break;
227
228 default:
229 // don't know how to translate this encoding into X fontspec
230 return FALSE;
231 }
232
233 info->encoding = encoding;
234
235 return TRUE;
236 }
237
238 bool 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
253 wxNativeFont wxLoadQueryNearestFont(int pointSize,
254 int family,
255 int style,
256 int weight,
257 bool underlined,
258 const wxString &facename,
259 wxFontEncoding encoding,
260 wxString* xFontName)
261 {
262 if ( encoding == wxFONTENCODING_DEFAULT )
263 {
264 encoding = wxFont::GetDefaultEncoding();
265 }
266
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;
271 if ( encoding == wxFONTENCODING_SYSTEM )
272 {
273 // This will always work so we don't test to save time
274 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
275 }
276 else
277 {
278 if ( !wxGetNativeFontEncoding(encoding, &info) ||
279 !wxTestFontEncoding(info) )
280 {
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 }
290 }
291 }
292
293 // OK, we have the correct xregistry/xencoding in info structure
294 wxNativeFont font = 0;
295
296 // if we already have the X font name, try to use it
297 if( xFontName && !xFontName->IsEmpty() )
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 }
320
321 if( !font )
322 font = wxLoadQueryFont( pointSize, family, style, weight,
323 underlined, facename,
324 info.xregistry, info.xencoding,
325 xFontName );
326
327 if ( !font )
328 {
329 // search up and down by stepsize 10
330 int max_size = pointSize + 20 * (1 + (pointSize/180));
331 int min_size = pointSize - 20 * (1 + (pointSize/180));
332
333 int i;
334
335 // Search for smaller size (approx.)
336 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
337 {
338 font = wxLoadQueryFont(i, family, style, weight, underlined,
339 facename, info.xregistry, info.xencoding,
340 xFontName);
341 }
342
343 // Search for larger size (approx.)
344 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
345 {
346 font = wxLoadQueryFont(i, family, style, weight, underlined,
347 facename, info.xregistry, info.xencoding,
348 xFontName);
349 }
350
351 // Try default family
352 if ( !font && family != wxDEFAULT )
353 {
354 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
355 underlined, facename,
356 info.xregistry, info.xencoding,
357 xFontName );
358 }
359
360 // Bogus font I
361 if ( !font )
362 {
363 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
364 underlined, facename,
365 info.xregistry, info.xencoding,
366 xFontName);
367 }
368
369 // Bogus font II
370 if ( !font )
371 {
372 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
373 underlined, wxEmptyString,
374 info.xregistry, info.xencoding,
375 xFontName);
376 }
377 }
378
379 return font;
380 }
381
382 // ----------------------------------------------------------------------------
383 // private functions
384 // ----------------------------------------------------------------------------
385
386 // returns TRUE if there are any fonts matching this font spec
387 static bool wxTestFontSpec(const wxString& fontspec)
388 {
389 // some X servers will fail to load this font because there are too many
390 // matches so we must test explicitly for this
391 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
392 {
393 return TRUE;
394 }
395
396 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
397 if (test)
398 {
399 return TRUE;
400 }
401
402 test = wxLoadFont(fontspec);
403 g_fontHash->Put( fontspec, (wxObject*) test );
404
405 if ( test )
406 {
407 wxFreeFont(test);
408
409 return TRUE;
410 }
411 else
412 {
413 return FALSE;
414 }
415 }
416
417 static wxNativeFont wxLoadQueryFont(int pointSize,
418 int family,
419 int style,
420 int weight,
421 bool WXUNUSED(underlined),
422 const wxString& facename,
423 const wxString& xregistry,
424 const wxString& xencoding,
425 wxString* xFontName)
426 {
427 wxString xfamily;
428 switch (family)
429 {
430 case wxDECORATIVE: xfamily = wxT("lucida"); break;
431 case wxROMAN: xfamily = wxT("times"); break;
432 case wxMODERN: xfamily = wxT("courier"); break;
433 case wxSWISS: xfamily = wxT("helvetica"); break;
434 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
435 case wxSCRIPT: xfamily = wxT("utopia"); break;
436 default: xfamily = wxT("*");
437 }
438
439 wxString fontSpec;
440 if (!facename.IsEmpty())
441 {
442 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
443 facename.c_str());
444
445 if ( wxTestFontSpec(fontSpec) )
446 {
447 xfamily = facename;
448 }
449 //else: no such family, use default one instead
450 }
451
452 wxString xstyle;
453 switch (style)
454 {
455 case wxSLANT:
456 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
457 xfamily.c_str());
458 if ( wxTestFontSpec(fontSpec) )
459 {
460 xstyle = wxT("o");
461 break;
462 }
463 // fall through - try wxITALIC now
464
465 case wxITALIC:
466 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
467 xfamily.c_str());
468 if ( wxTestFontSpec(fontSpec) )
469 {
470 xstyle = wxT("i");
471 }
472 else if ( style == wxITALIC ) // and not wxSLANT
473 {
474 // try wxSLANT
475 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
476 xfamily.c_str());
477 if ( wxTestFontSpec(fontSpec) )
478 {
479 xstyle = wxT("o");
480 }
481 else
482 {
483 // no italic, no slant - leave default
484 xstyle = wxT("*");
485 }
486 }
487 break;
488
489 default:
490 wxFAIL_MSG(_T("unknown font style"));
491 // fall back to normal
492
493 case wxNORMAL:
494 xstyle = wxT("r");
495 break;
496 }
497
498 wxString xweight;
499 switch (weight)
500 {
501 case wxBOLD:
502 {
503 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
504 xfamily.c_str());
505 if ( wxTestFontSpec(fontSpec) )
506 {
507 xweight = wxT("bold");
508 break;
509 }
510 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
511 xfamily.c_str());
512 if ( wxTestFontSpec(fontSpec) )
513 {
514 xweight = wxT("heavy");
515 break;
516 }
517 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
518 xfamily.c_str());
519 if ( wxTestFontSpec(fontSpec) )
520 {
521 xweight = wxT("extrabold");
522 break;
523 }
524 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
525 xfamily.c_str());
526 if ( wxTestFontSpec(fontSpec) )
527 {
528 xweight = wxT("demibold");
529 break;
530 }
531 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
532 xfamily.c_str());
533 if ( wxTestFontSpec(fontSpec) )
534 {
535 xweight = wxT("black");
536 break;
537 }
538 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
539 xfamily.c_str());
540 if ( wxTestFontSpec(fontSpec) )
541 {
542 xweight = wxT("ultrablack");
543 break;
544 }
545 }
546 break;
547 case wxLIGHT:
548 {
549 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
550 xfamily.c_str());
551 if ( wxTestFontSpec(fontSpec) )
552 {
553 xweight = wxT("light");
554 break;
555 }
556 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
557 xfamily.c_str());
558 if ( wxTestFontSpec(fontSpec) )
559 {
560 xweight = wxT("thin");
561 break;
562 }
563 }
564 break;
565 case wxNORMAL:
566 {
567 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
568 xfamily.c_str());
569 if ( wxTestFontSpec(fontSpec) )
570 {
571 xweight = wxT("medium");
572 break;
573 }
574 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
575 xfamily.c_str());
576 if ( wxTestFontSpec(fontSpec) )
577 {
578 xweight = wxT("normal");
579 break;
580 }
581 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
582 xfamily.c_str());
583 if ( wxTestFontSpec(fontSpec) )
584 {
585 xweight = wxT("regular");
586 break;
587 }
588 xweight = wxT("*");
589 }
590 break;
591 default: xweight = wxT("*"); break;
592 }
593
594 // construct the X font spec from our data
595 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
596 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
597 pointSize, xregistry.c_str(), xencoding.c_str());
598
599 if( xFontName )
600 *xFontName = fontSpec;
601
602 return wxLoadFont(fontSpec);
603 }
604
605 // ----------------------------------------------------------------------------
606 // wxFontModule
607 // ----------------------------------------------------------------------------
608
609 class wxFontModule : public wxModule
610 {
611 public:
612 bool OnInit();
613 void OnExit();
614
615 private:
616 DECLARE_DYNAMIC_CLASS(wxFontModule)
617 };
618
619 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
620
621 bool wxFontModule::OnInit()
622 {
623 g_fontHash = new wxHashTable( wxKEY_STRING );
624
625 return TRUE;
626 }
627
628 void wxFontModule::OnExit()
629 {
630 delete g_fontHash;
631
632 g_fontHash = (wxHashTable *)NULL;
633 }