]> git.saurik.com Git - wxWidgets.git/blob - src/unix/fontutil.cpp
oops, forgot to fix wxHtmlTag dtor
[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 wxUSE_FONTMAP
282 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
283 #endif // wxUSE_FONTMAP
284 {
285 // unspported encoding - replace it with the default
286 //
287 // NB: we can't just return 0 from here because wxGTK code doesn't
288 // check for it (i.e. it supposes that we'll always succeed),
289 // so it would provoke a crash
290 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
291 }
292 }
293 }
294
295 // OK, we have the correct xregistry/xencoding in info structure
296 wxNativeFont font = 0;
297
298 // if we already have the X font name, try to use it
299 if( xFontName && !xFontName->IsEmpty() )
300 {
301 //
302 // Make sure point size is correct for scale factor.
303 //
304 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
305 wxString newFontName;
306
307 for(int i = 0; i < 8; i++)
308 newFontName += tokenizer.NextToken();
309
310 (void) tokenizer.NextToken();
311
312 newFontName += wxString::Format("%d-", pointSize);
313
314 while(tokenizer.HasMoreTokens())
315 newFontName += tokenizer.GetNextToken();
316
317 font = wxLoadFont(newFontName);
318
319 if(font)
320 *xFontName = newFontName;
321 }
322
323 // try to load exactly the font requested first
324 if( !font )
325 {
326 font = wxLoadQueryFont( pointSize, family, style, weight,
327 underlined, facename,
328 info.xregistry, info.xencoding,
329 xFontName );
330 }
331
332 if ( !font )
333 {
334 // search up and down by stepsize 10
335 int max_size = pointSize + 20 * (1 + (pointSize/180));
336 int min_size = pointSize - 20 * (1 + (pointSize/180));
337
338 int i;
339
340 // Search for smaller size (approx.)
341 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
342 {
343 font = wxLoadQueryFont(i, family, style, weight, underlined,
344 facename, info.xregistry, info.xencoding,
345 xFontName);
346 }
347
348 // Search for larger size (approx.)
349 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
350 {
351 font = wxLoadQueryFont(i, family, style, weight, underlined,
352 facename, info.xregistry, info.xencoding,
353 xFontName);
354 }
355
356 // Try default family
357 if ( !font && family != wxDEFAULT )
358 {
359 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
360 underlined, facename,
361 info.xregistry, info.xencoding,
362 xFontName );
363 }
364
365 // ignore size, family, style and weight but try to find font with the
366 // given facename and encoding
367 if ( !font )
368 {
369 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
370 underlined, facename,
371 info.xregistry, info.xencoding,
372 xFontName);
373
374 // ignore family as well
375 if ( !font )
376 {
377 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
378 underlined, wxEmptyString,
379 info.xregistry, info.xencoding,
380 xFontName);
381
382 // if it still failed, try to get the font of any size but
383 // with the requested encoding: this can happen if the
384 // encoding is only available in one size which happens to be
385 // different from 120
386 if ( !font )
387 {
388 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
389 FALSE, wxEmptyString,
390 info.xregistry, info.xencoding,
391 xFontName);
392
393 // this should never happen as we had tested for it in the
394 // very beginning, but if it does, do return something non
395 // NULL or we'd crash in wxFont code
396 if ( !font )
397 {
398 wxFAIL_MSG( _T("this encoding should be available!") );
399
400 font = wxLoadQueryFont(-1,
401 wxDEFAULT, wxNORMAL, wxNORMAL,
402 FALSE, wxEmptyString,
403 _T("*"), _T("*"),
404 xFontName);
405 }
406 }
407 }
408 }
409 }
410
411 return font;
412 }
413
414 // ----------------------------------------------------------------------------
415 // private functions
416 // ----------------------------------------------------------------------------
417
418 // returns TRUE if there are any fonts matching this font spec
419 static bool wxTestFontSpec(const wxString& fontspec)
420 {
421 // some X servers will fail to load this font because there are too many
422 // matches so we must test explicitly for this
423 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
424 {
425 return TRUE;
426 }
427
428 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
429 if (test)
430 {
431 return TRUE;
432 }
433
434 test = wxLoadFont(fontspec);
435 g_fontHash->Put( fontspec, (wxObject*) test );
436
437 if ( test )
438 {
439 wxFreeFont(test);
440
441 return TRUE;
442 }
443 else
444 {
445 return FALSE;
446 }
447 }
448
449 static wxNativeFont wxLoadQueryFont(int pointSize,
450 int family,
451 int style,
452 int weight,
453 bool WXUNUSED(underlined),
454 const wxString& facename,
455 const wxString& xregistry,
456 const wxString& xencoding,
457 wxString* xFontName)
458 {
459 wxString xfamily;
460 switch (family)
461 {
462 case wxDECORATIVE: xfamily = wxT("lucida"); break;
463 case wxROMAN: xfamily = wxT("times"); break;
464 case wxMODERN: xfamily = wxT("courier"); break;
465 case wxSWISS: xfamily = wxT("helvetica"); break;
466 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
467 case wxSCRIPT: xfamily = wxT("utopia"); break;
468 default: xfamily = wxT("*");
469 }
470
471 wxString fontSpec;
472 if (!facename.IsEmpty())
473 {
474 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
475 facename.c_str());
476
477 if ( wxTestFontSpec(fontSpec) )
478 {
479 xfamily = facename;
480 }
481 //else: no such family, use default one instead
482 }
483
484 wxString xstyle;
485 switch (style)
486 {
487 case wxSLANT:
488 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
489 xfamily.c_str());
490 if ( wxTestFontSpec(fontSpec) )
491 {
492 xstyle = wxT("o");
493 break;
494 }
495 // fall through - try wxITALIC now
496
497 case wxITALIC:
498 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
499 xfamily.c_str());
500 if ( wxTestFontSpec(fontSpec) )
501 {
502 xstyle = wxT("i");
503 }
504 else if ( style == wxITALIC ) // and not wxSLANT
505 {
506 // try wxSLANT
507 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
508 xfamily.c_str());
509 if ( wxTestFontSpec(fontSpec) )
510 {
511 xstyle = wxT("o");
512 }
513 else
514 {
515 // no italic, no slant - leave default
516 xstyle = wxT("*");
517 }
518 }
519 break;
520
521 default:
522 wxFAIL_MSG(_T("unknown font style"));
523 // fall back to normal
524
525 case wxNORMAL:
526 xstyle = wxT("r");
527 break;
528 }
529
530 wxString xweight;
531 switch (weight)
532 {
533 case wxBOLD:
534 {
535 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
536 xfamily.c_str());
537 if ( wxTestFontSpec(fontSpec) )
538 {
539 xweight = wxT("bold");
540 break;
541 }
542 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
543 xfamily.c_str());
544 if ( wxTestFontSpec(fontSpec) )
545 {
546 xweight = wxT("heavy");
547 break;
548 }
549 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
550 xfamily.c_str());
551 if ( wxTestFontSpec(fontSpec) )
552 {
553 xweight = wxT("extrabold");
554 break;
555 }
556 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
557 xfamily.c_str());
558 if ( wxTestFontSpec(fontSpec) )
559 {
560 xweight = wxT("demibold");
561 break;
562 }
563 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
564 xfamily.c_str());
565 if ( wxTestFontSpec(fontSpec) )
566 {
567 xweight = wxT("black");
568 break;
569 }
570 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
571 xfamily.c_str());
572 if ( wxTestFontSpec(fontSpec) )
573 {
574 xweight = wxT("ultrablack");
575 break;
576 }
577 }
578 break;
579 case wxLIGHT:
580 {
581 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
582 xfamily.c_str());
583 if ( wxTestFontSpec(fontSpec) )
584 {
585 xweight = wxT("light");
586 break;
587 }
588 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
589 xfamily.c_str());
590 if ( wxTestFontSpec(fontSpec) )
591 {
592 xweight = wxT("thin");
593 break;
594 }
595 }
596 break;
597 case wxNORMAL:
598 {
599 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
600 xfamily.c_str());
601 if ( wxTestFontSpec(fontSpec) )
602 {
603 xweight = wxT("medium");
604 break;
605 }
606 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
607 xfamily.c_str());
608 if ( wxTestFontSpec(fontSpec) )
609 {
610 xweight = wxT("normal");
611 break;
612 }
613 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
614 xfamily.c_str());
615 if ( wxTestFontSpec(fontSpec) )
616 {
617 xweight = wxT("regular");
618 break;
619 }
620 xweight = wxT("*");
621 }
622 break;
623 default: xweight = wxT("*"); break;
624 }
625
626 // if pointSize is -1, don't specify any
627 wxString sizeSpec;
628 if ( fontSpec == -1 )
629 {
630 sizeSpec = _T('*');
631 }
632 else
633 {
634 sizeSpec.Printf(_T("%d"), pointSize);
635 }
636
637 // construct the X font spec from our data
638 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
639 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
640 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
641
642 if( xFontName )
643 *xFontName = fontSpec;
644
645 return wxLoadFont(fontSpec);
646 }
647
648 // ----------------------------------------------------------------------------
649 // wxFontModule
650 // ----------------------------------------------------------------------------
651
652 class wxFontModule : public wxModule
653 {
654 public:
655 bool OnInit();
656 void OnExit();
657
658 private:
659 DECLARE_DYNAMIC_CLASS(wxFontModule)
660 };
661
662 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
663
664 bool wxFontModule::OnInit()
665 {
666 g_fontHash = new wxHashTable( wxKEY_STRING );
667
668 return TRUE;
669 }
670
671 void wxFontModule::OnExit()
672 {
673 delete g_fontHash;
674
675 g_fontHash = (wxHashTable *)NULL;
676 }