1. added a brief overview of Unicode support
[wxWidgets.git] / src / gtk1 / font.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: font.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #ifdef __GNUG__
19 #pragma implementation "font.h"
20 #endif
21
22 #include "wx/font.h"
23 #include "wx/utils.h"
24 #include "wx/log.h"
25 #include "wx/gdicmn.h"
26 #include "wx/tokenzr.h"
27
28 #include <strings.h>
29
30 #include "gdk/gdk.h"
31
32 // ----------------------------------------------------------------------------
33 // local data
34 // ----------------------------------------------------------------------------
35
36 #if wxUSE_FONTNAMEDIRECTORY
37 extern wxFontNameDirectory *wxTheFontNameDirectory;
38 #endif
39
40 // ----------------------------------------------------------------------------
41 // private functions
42 // ----------------------------------------------------------------------------
43
44 // returns TRUE if there are any fonts matching this font spec
45 static bool wxTestFontSpec(const wxString& fontspec);
46
47 static GdkFont *wxLoadQueryFont( int pointSize,
48 int family,
49 int style,
50 int weight,
51 bool underlined,
52 const wxString &facename,
53 wxFontEncoding encoding );
54
55 static GdkFont *wxLoadQueryNearestFont( int pointSize,
56 int family,
57 int style,
58 int weight,
59 bool underlined,
60 const wxString &facename,
61 wxFontEncoding encoding);
62
63 // ----------------------------------------------------------------------------
64 // wxFontRefData
65 // ----------------------------------------------------------------------------
66
67 class wxFontRefData : public wxObjectRefData
68 {
69 public:
70 wxFontRefData(int size = wxDEFAULT,
71 int family = wxDEFAULT,
72 int style = wxDEFAULT,
73 int weight = wxDEFAULT,
74 bool underlined = FALSE,
75 const wxString& faceName = wxEmptyString,
76 wxFontEncoding encoding = wxFONTENCODING_DEFAULT)
77 : m_scaled_xfonts(wxKEY_INTEGER)
78 {
79 Init(size, family, style, weight, underlined, faceName, encoding);
80 }
81
82 wxFontRefData( const wxFontRefData& data );
83
84 virtual ~wxFontRefData();
85
86 protected:
87 // common part of all ctors
88 void Init(int pointSize,
89 int family,
90 int style,
91 int weight,
92 bool underlined,
93 const wxString& faceName,
94 wxFontEncoding encoding);
95
96 private:
97 wxList m_scaled_xfonts;
98
99 int m_pointSize;
100 int m_family,
101 m_style,
102 m_weight;
103 bool m_underlined;
104 wxString m_faceName;
105 wxFontEncoding m_encoding;
106
107 bool m_byXFontName;
108 GdkFont *m_font;
109
110 friend wxFont;
111 };
112
113 // ============================================================================
114 // implementation
115 // ============================================================================
116
117 // ----------------------------------------------------------------------------
118 // wxFontRefData
119 // ----------------------------------------------------------------------------
120
121 void wxFontRefData::Init(int pointSize,
122 int family,
123 int style,
124 int weight,
125 bool underlined,
126 const wxString& faceName,
127 wxFontEncoding encoding)
128 {
129 if (family == wxDEFAULT)
130 m_family = wxSWISS;
131 else
132 m_family = family;
133
134 m_faceName = faceName;
135
136 if (style == wxDEFAULT)
137 m_style = wxNORMAL;
138 else
139 m_style = style;
140
141 if (weight == wxDEFAULT)
142 m_weight = wxNORMAL;
143 else
144 m_weight = weight;
145
146 if (pointSize == wxDEFAULT)
147 m_pointSize = 12;
148 else
149 m_pointSize = pointSize;
150
151 m_underlined = underlined;
152 m_encoding = encoding;
153
154 m_byXFontName = FALSE;
155 m_font = (GdkFont *) NULL;
156 }
157
158 wxFontRefData::wxFontRefData( const wxFontRefData& data )
159 : m_scaled_xfonts(wxKEY_INTEGER)
160 {
161 Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight,
162 data.m_underlined, data.m_faceName, data.m_encoding);
163
164 if (data.m_font)
165 m_font = gdk_font_ref( data.m_font );
166 }
167
168 wxFontRefData::~wxFontRefData()
169 {
170 wxNode *node = m_scaled_xfonts.First();
171 while (node)
172 {
173 GdkFont *font = (GdkFont*)node->Data();
174 wxNode *next = node->Next();
175 gdk_font_unref( font );
176 node = next;
177 }
178
179 if (m_font)
180 gdk_font_unref( m_font );
181 }
182
183 // ----------------------------------------------------------------------------
184 // wxFont
185 // ----------------------------------------------------------------------------
186
187 IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject)
188
189 void wxFont::Init()
190 {
191 if (wxTheFontList)
192 wxTheFontList->Append( this );
193 }
194
195 wxFont::wxFont( GdkFont *font, char *xFontName )
196 {
197 if (!xFontName)
198 return;
199
200 // VZ: this ctor ddidn't append the font to wxTheFontList before, but
201 // there is no reason to not do it, is there?
202 Init();
203
204 m_refData = new wxFontRefData();
205
206 // M_FONTDATA->m_byXFontName = TRUE;
207 M_FONTDATA->m_font = font;
208
209 wxString tmp;
210
211 wxString fontname( xFontName );
212 wxStringTokenizer tn( fontname, _T("-") );
213
214 tn.GetNextToken(); // foundry
215
216 M_FONTDATA->m_faceName = tn.GetNextToken(); // courier
217
218 tmp = tn.GetNextToken().MakeUpper();
219 if (tmp == _T("BOLD")) M_FONTDATA->m_weight = wxBOLD;
220
221 tmp = tn.GetNextToken().MakeUpper();
222 if (tmp == _T("I")) M_FONTDATA->m_style = wxITALIC;
223 if (tmp == _T("O")) M_FONTDATA->m_style = wxITALIC;
224
225 tn.GetNextToken(); // set width
226 tn.GetNextToken(); // ?
227 tn.GetNextToken(); // pixel size
228
229 tmp = tn.GetNextToken(); // pointsize
230 int num = wxStrtol (tmp.c_str(), (wxChar **) NULL, 10);
231 M_FONTDATA->m_pointSize = num / 10;
232
233 tn.GetNextToken(); // x-res
234 tn.GetNextToken(); // y-res
235
236 tmp = tn.GetNextToken().MakeUpper();
237 if (tmp == _T("M")) M_FONTDATA->m_family = wxMODERN;
238 else if (M_FONTDATA->m_faceName == _T("TIMES")) M_FONTDATA->m_family = wxROMAN;
239 else if (M_FONTDATA->m_faceName == _T("HELVETICA")) M_FONTDATA->m_family = wxSWISS;
240 else if (M_FONTDATA->m_faceName == _T("LUCIDATYPEWRITER")) M_FONTDATA->m_family = wxTELETYPE;
241 else if (M_FONTDATA->m_faceName == _T("LUCIDA")) M_FONTDATA->m_family = wxDECORATIVE;
242 else if (M_FONTDATA->m_faceName == _T("UTOPIA")) M_FONTDATA->m_family = wxSCRIPT;
243 }
244
245 bool wxFont::Create( int pointSize,
246 int family,
247 int style,
248 int weight,
249 bool underlined,
250 const wxString& face,
251 wxFontEncoding encoding )
252 {
253 m_refData = new wxFontRefData(pointSize, family, style, weight,
254 underlined, face, encoding);
255
256 Init();
257
258 return TRUE;
259 }
260
261 void wxFont::Unshare()
262 {
263 if (!m_refData)
264 {
265 m_refData = new wxFontRefData();
266 }
267 else
268 {
269 wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData);
270 UnRef();
271 m_refData = ref;
272 }
273 }
274
275 wxFont::~wxFont()
276 {
277 if (wxTheFontList)
278 wxTheFontList->DeleteObject( this );
279 }
280
281 // ----------------------------------------------------------------------------
282 // accessors
283 // ----------------------------------------------------------------------------
284
285 int wxFont::GetPointSize() const
286 {
287 wxCHECK_MSG( Ok(), 0, _T("invalid font") );
288
289 return M_FONTDATA->m_pointSize;
290 }
291
292 wxString wxFont::GetFaceName() const
293 {
294 wxCHECK_MSG( Ok(), _T(""), _T("invalid font") );
295
296 return M_FONTDATA->m_faceName;
297 }
298
299 int wxFont::GetFamily() const
300 {
301 wxCHECK_MSG( Ok(), 0, _T("invalid font") );
302
303 return M_FONTDATA->m_family;
304 }
305
306 int wxFont::GetStyle() const
307 {
308 wxCHECK_MSG( Ok(), 0, _T("invalid font") );
309
310 return M_FONTDATA->m_style;
311 }
312
313 int wxFont::GetWeight() const
314 {
315 wxCHECK_MSG( Ok(), 0, _T("invalid font") );
316
317 return M_FONTDATA->m_weight;
318 }
319
320 bool wxFont::GetUnderlined() const
321 {
322 wxCHECK_MSG( Ok(), FALSE, _T("invalid font") );
323
324 return M_FONTDATA->m_underlined;
325 }
326
327
328 wxFontEncoding wxFont::GetEncoding() const
329 {
330 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, _T("invalid font") );
331
332 return M_FONTDATA->m_encoding;
333 }
334
335 // ----------------------------------------------------------------------------
336 // change font attributes
337 // ----------------------------------------------------------------------------
338
339 void wxFont::SetPointSize(int pointSize)
340 {
341 Unshare();
342
343 M_FONTDATA->m_pointSize = pointSize;
344 }
345
346 void wxFont::SetFamily(int family)
347 {
348 Unshare();
349
350 M_FONTDATA->m_family = family;
351 }
352
353 void wxFont::SetStyle(int style)
354 {
355 Unshare();
356
357 M_FONTDATA->m_style = style;
358 }
359
360 void wxFont::SetWeight(int weight)
361 {
362 Unshare();
363
364 M_FONTDATA->m_weight = weight;
365 }
366
367 void wxFont::SetFaceName(const wxString& faceName)
368 {
369 Unshare();
370
371 M_FONTDATA->m_faceName = faceName;
372 }
373
374 void wxFont::SetUnderlined(bool underlined)
375 {
376 Unshare();
377
378 M_FONTDATA->m_underlined = underlined;
379 }
380
381 void wxFont::SetEncoding(wxFontEncoding encoding)
382 {
383 Unshare();
384
385 M_FONTDATA->m_encoding = encoding;
386 }
387
388 // ----------------------------------------------------------------------------
389 // get internal representation of font
390 // ----------------------------------------------------------------------------
391
392 GdkFont *wxFont::GetInternalFont( float scale ) const
393 {
394 if (!Ok())
395 {
396 wxFAIL_MSG( _T("invalid font") );
397
398 return (GdkFont*) NULL;
399 }
400
401 /* short cut if the special X font constructor has been used */
402 if (M_FONTDATA->m_byXFontName)
403 return M_FONTDATA->m_font;
404
405 long int_scale = long(scale * 100.0 + 0.5); /* key for fontlist */
406 int point_scale = (M_FONTDATA->m_pointSize * 10 * int_scale) / 100;
407 GdkFont *font = (GdkFont *) NULL;
408
409 wxNode *node = M_FONTDATA->m_scaled_xfonts.Find(int_scale);
410 if (node)
411 {
412 font = (GdkFont*)node->Data();
413 }
414 else
415 {
416 #if 0
417 if ((int_scale == 100) &&
418 (M_FONTDATA->m_family == wxSWISS) &&
419 (M_FONTDATA->m_style == wxNORMAL) &&
420 (M_FONTDATA->m_pointSize == 12) &&
421 (M_FONTDATA->m_weight == wxNORMAL) &&
422 (M_FONTDATA->m_underlined == FALSE))
423 {
424 font = gdk_font_load( "-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*" );
425 }
426 else
427 #endif // 0
428 {
429 font = wxLoadQueryNearestFont( point_scale,
430 M_FONTDATA->m_family,
431 M_FONTDATA->m_style,
432 M_FONTDATA->m_weight,
433 M_FONTDATA->m_underlined,
434 M_FONTDATA->m_faceName,
435 M_FONTDATA->m_encoding );
436 }
437
438 M_FONTDATA->m_scaled_xfonts.Append( int_scale, (wxObject*)font );
439 }
440
441 if (!font)
442 {
443 wxLogError(_T("could not load any font"));
444 }
445
446 return font;
447 }
448
449 //-----------------------------------------------------------------------------
450 // local utilities to find a X font
451 //-----------------------------------------------------------------------------
452
453 // returns TRUE if there are any fonts matching this font spec
454 static bool wxTestFontSpec(const wxString& fontSpec)
455 {
456 GdkFont *test = gdk_font_load( wxConvCurrent->cWX2MB(fontSpec) );
457 if ( test )
458 {
459 gdk_font_unref( test );
460
461 return TRUE;
462 }
463 else
464 {
465 return FALSE;
466 }
467 }
468
469 static GdkFont *wxLoadQueryFont( int pointSize,
470 int family,
471 int style,
472 int weight,
473 bool WXUNUSED(underlined),
474 const wxString &facename,
475 wxFontEncoding encoding )
476 {
477 wxString xfamily;
478 switch (family)
479 {
480 case wxDECORATIVE: xfamily = _T("lucida"); break;
481 case wxROMAN: xfamily = _T("times"); break;
482 case wxMODERN: xfamily = _T("courier"); break;
483 case wxSWISS: xfamily = _T("helvetica"); break;
484 case wxTELETYPE: xfamily = _T("lucidatypewriter"); break;
485 case wxSCRIPT: xfamily = _T("utopia"); break;
486 default: xfamily = _T("*");
487 }
488
489 wxString fontSpec;
490 if (!facename.IsEmpty())
491 {
492 fontSpec.Printf(_T("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
493 facename.c_str());
494
495 if ( wxTestFontSpec(fontSpec) )
496 {
497 xfamily = facename;
498 }
499 //else: no such family, use default one instead
500 }
501
502 wxString xstyle;
503 switch (style)
504 {
505 case wxITALIC: xstyle = _T("i"); break;
506 case wxSLANT: xstyle = _T("o"); break;
507 case wxNORMAL: xstyle = _T("r"); break;
508 default: xstyle = _T("*"); break;
509 }
510
511 wxString xweight;
512 switch (weight)
513 {
514 case wxBOLD: xweight = _T("bold"); break;
515 case wxLIGHT:
516 case wxNORMAL: xweight = _T("medium"); break;
517 default: xweight = _T("*"); break;
518 }
519
520 wxString xregistry, xencoding;
521 if ( encoding == wxFONTENCODING_DEFAULT )
522 {
523 // use the apps default
524 encoding = wxFont::GetDefaultEncoding();
525 }
526
527 bool test = TRUE; // should we test for availability of encoding?
528 switch ( encoding )
529 {
530 case wxFONTENCODING_ISO8859_1:
531 case wxFONTENCODING_ISO8859_2:
532 case wxFONTENCODING_ISO8859_3:
533 case wxFONTENCODING_ISO8859_4:
534 case wxFONTENCODING_ISO8859_5:
535 case wxFONTENCODING_ISO8859_6:
536 case wxFONTENCODING_ISO8859_7:
537 case wxFONTENCODING_ISO8859_8:
538 case wxFONTENCODING_ISO8859_9:
539 case wxFONTENCODING_ISO8859_10:
540 case wxFONTENCODING_ISO8859_11:
541 case wxFONTENCODING_ISO8859_13:
542 case wxFONTENCODING_ISO8859_14:
543 case wxFONTENCODING_ISO8859_15:
544 {
545 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
546 xregistry = _T("iso8859");
547 xencoding.Printf(_T("%d"), cp);
548 }
549 break;
550
551 case wxFONTENCODING_KOI8:
552 xregistry = _T("koi8");
553 if ( wxTestFontSpec(_T("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) )
554 {
555 xencoding = _T("1");
556
557 // test passed, no need to do it once more
558 test = FALSE;
559 }
560 else
561 {
562 xencoding = _T("*");
563 }
564 break;
565
566 case wxFONTENCODING_CP1250:
567 case wxFONTENCODING_CP1251:
568 case wxFONTENCODING_CP1252:
569 {
570 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
571 fontSpec.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"),
572 cp);
573 if ( wxTestFontSpec(fontSpec) )
574 {
575 xregistry = _T("microsoft");
576 xencoding.Printf(_T("cp%d"), cp);
577
578 // test passed, no need to do it once more
579 test = FALSE;
580 }
581 else
582 {
583 // fall back to LatinX
584 xregistry = _T("iso8859");
585 xencoding.Printf(_T("%d"), cp - 1249);
586 }
587 }
588 break;
589
590 case wxFONTENCODING_SYSTEM:
591 default:
592 test = FALSE;
593 xregistry =
594 xencoding = _T("*");
595 }
596
597 if ( test )
598 {
599 fontSpec.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"),
600 xregistry.c_str(), xencoding.c_str());
601 if ( !wxTestFontSpec(fontSpec) )
602 {
603 // this encoding isn't available - what to do?
604 xregistry =
605 xencoding = _T("*");
606 }
607 }
608
609 // construct the X font spec from our data
610 fontSpec.Printf(_T("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
611 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
612 pointSize, xregistry.c_str(), xencoding.c_str());
613
614 return gdk_font_load( wxConvCurrent->cWX2MB(fontSpec) );
615 }
616
617 static GdkFont *wxLoadQueryNearestFont( int pointSize,
618 int family,
619 int style,
620 int weight,
621 bool underlined,
622 const wxString &facename,
623 wxFontEncoding encoding )
624 {
625 GdkFont *font = wxLoadQueryFont( pointSize, family, style, weight,
626 underlined, facename, encoding );
627
628 if (!font)
629 {
630 /* search up and down by stepsize 10 */
631 int max_size = pointSize + 20 * (1 + (pointSize/180));
632 int min_size = pointSize - 20 * (1 + (pointSize/180));
633
634 int i;
635
636 /* Search for smaller size (approx.) */
637 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
638 {
639 font = wxLoadQueryFont(i, family, style, weight, underlined,
640 facename, encoding );
641 }
642
643 /* Search for larger size (approx.) */
644 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
645 {
646 font = wxLoadQueryFont( i, family, style, weight, underlined,
647 facename, encoding );
648 }
649
650 /* Try default family */
651 if ( !font && family != wxDEFAULT )
652 {
653 font = wxLoadQueryFont( pointSize, wxDEFAULT, style, weight,
654 underlined, facename, encoding );
655 }
656
657 /* Bogus font */
658 if ( !font )
659 {
660 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
661 underlined, facename, encoding );
662 }
663 }
664
665 return font;
666 }
667
668 // wow, what's this stuff? Is it used/useful? (VZ)
669 #if 0
670
671 //-----------------------------------------------------------------------------
672 // face names and index functions
673 //-----------------------------------------------------------------------------
674
675 static char *font_defaults[] = {
676 "FamilyDefault", "Default",
677 "FamilyRoman", "Roman",
678 "FamilyDecorative", "Decorative",
679 "FamilyModern", "Modern",
680 "FamilyTeletype", "Teletype",
681 "FamilySwiss", "Swiss",
682 "FamilyScript", "Script",
683
684 "AfmMedium", "",
685 "AfmBold", "Bo",
686 "AfmLight", "",
687 "AfmStraight", "",
688 "AfmItalic", "${AfmSlant}",
689 "AfmSlant", "O",
690 "AfmRoman", "Ro",
691 "AfmTimes", "Times",
692 "AfmHelvetica", "Helv",
693 "AfmCourier", "Cour",
694
695 "Afm___", "${AfmTimes,$[weight],$[style]}",
696
697 "AfmTimes__", "${AfmTimes}${Afm$[weight]}${Afm$[style]}",
698 "AfmTimesMediumStraight", "${AfmTimes}${AfmRoman}",
699 "AfmTimesLightStraight", "${AfmTimes}${AfmRoman}",
700 "AfmTimes_Italic", "${AfmTimes}$[weight]${AfmItalic}",
701 "AfmTimes_Slant", "${AfmTimes}$[weight]${AfmItalic}",
702
703 "AfmSwiss__", "${AfmHelvetica}${Afm$[weight]}${Afm$[style]}",
704 "AfmModern__", "${AfmCourier}${Afm$[weight]}${Afm$[style]}",
705
706 "AfmTeletype__", "${AfmModern,$[weight],$[style]}",
707
708 "PostScriptMediumStraight", "",
709 "PostScriptMediumItalic", "-Oblique",
710 "PostScriptMediumSlant", "-Oblique",
711 "PostScriptLightStraight", "",
712 "PostScriptLightItalic", "-Oblique",
713 "PostScriptLightSlant", "-Oblique",
714 "PostScriptBoldStraight", "-Bold",
715 "PostScriptBoldItalic", "-BoldOblique",
716 "PostScriptBoldSlant", "-BoldOblique",
717
718 #if WX_NORMALIZED_PS_FONTS
719 "PostScript___", "${PostScriptTimes,$[weight],$[style]}",
720 #else
721 "PostScriptRoman__", "${PostScriptTimes,$[weight],$[style]}",
722 "PostScript___", "LucidaSans${PostScript$[weight]$[style]}",
723 #endif
724
725 "PostScriptTimesMedium", "",
726 "PostScriptTimesLight", "",
727 "PostScriptTimesBold", "Bold",
728
729 "PostScriptTimes__", "Times${PostScript$[weight]$[style]}",
730 "PostScriptTimesMediumStraight", "Times-Roman",
731 "PostScriptTimesLightStraight", "Times-Roman",
732 "PostScriptTimes_Slant", "Times-${PostScriptTimes$[weight]}Italic",
733 "PostScriptTimes_Italic", "Times-${PostScriptTimes$[weight]}Italic",
734
735 "PostScriptSwiss__", "Helvetica${PostScript$[weight]$[style]}",
736 "PostScriptModern__", "Courier${PostScript$[weight]$[style]}",
737
738 "PostScriptTeletype__", "${PostScriptModern,$[weight],$[style]}",
739
740 #if !WX_NORMALIZED_PS_FONTS
741 "PostScriptScript__", "Zapf-Chancery-MediumItalic",
742 #endif
743
744 "ScreenMedium", "medium",
745 "ScreenBold", "bold",
746 "ScreenLight", "light",
747 "ScreenStraight", "r",
748 "ScreenItalic", "i",
749 "ScreenSlant", "o",
750
751 "ScreenDefaultBase", "*-times",
752
753 "ScreenRomanBase", "*-times",
754 "ScreenDecorativeBase", "*-helvetica",
755 "ScreenModernBase", "*-courier",
756 "ScreenTeletypeBase", "*-lucidatypewriter",
757 "ScreenSwissBase", "*-lucida",
758 "ScreenScriptBase", "*-zapfchancery",
759
760 "ScreenStdSuffix", "-${Screen$[weight]}-${Screen$[style]}"
761 "-normal-*-*-%d-*-*-*-*-*-*",
762
763 "Screen___",
764 "-${ScreenDefaultBase}${ScreenStdSuffix}",
765 "ScreenRoman__",
766 "-${ScreenRomanBase}${ScreenStdSuffix}",
767 "ScreenDecorative__",
768 "-${ScreenDecorativeBase}${ScreenStdSuffix}",
769 "ScreenModern__",
770 "-${ScreenModernBase}${ScreenStdSuffix}",
771 "ScreenTeletype__",
772 "-${ScreenTeletypeBase}${ScreenStdSuffix}",
773 "ScreenSwiss__",
774 "-${ScreenSwissBase}${ScreenStdSuffix}",
775 "ScreenScript__",
776 "-${ScreenScriptBase}${ScreenStdSuffix}",
777 (char *) NULL
778 };
779
780 enum {wxWEIGHT_NORMAL, wxWEIGHT_BOLD, wxWEIGHT_LIGHT, wxNUM_WEIGHTS};
781 enum {wxSTYLE_NORMAL, wxSTYLE_ITALIC, wxSTYLE_SLANT, wxNUM_STYLES};
782
783 static int WCoordinate(int w)
784 {
785 switch (w)
786 {
787 case wxBOLD: return wxWEIGHT_BOLD;
788 case wxLIGHT: return wxWEIGHT_LIGHT;
789 case wxNORMAL:
790 default: return wxWEIGHT_NORMAL;
791 }
792 };
793
794 static int SCoordinate(int s)
795 {
796 switch (s)
797 {
798 case wxITALIC: return wxSTYLE_ITALIC;
799 case wxSLANT: return wxSTYLE_SLANT;
800 case wxNORMAL:
801 default: return wxSTYLE_NORMAL;
802 }
803 };
804
805 //-----------------------------------------------------------------------------
806 // wxSuffixMap
807 //-----------------------------------------------------------------------------
808
809 class wxSuffixMap
810 {
811 public:
812 ~wxSuffixMap();
813
814 inline char *GetName(int weight, int style)
815 {
816 return ( map [WCoordinate(weight)] [SCoordinate(style)] );
817 }
818
819 char *map[wxNUM_WEIGHTS][wxNUM_STYLES];
820 void Initialize(const char *, const char *);
821 };
822
823 static void SearchResource(const char *prefix, const char **names, int count, char **v)
824 {
825 int k, i, j;
826 char resource[1024], **defaults, *internal;
827
828 k = 1 << count;
829
830 *v = (char *) NULL;
831 internal = (char *) NULL;
832
833 for (i = 0; i < k; i++)
834 {
835 strcpy(resource, prefix);
836 for (j = 0; j < count; j++)
837 {
838 // upon failure to find a matching fontname
839 // in the default fonts above, we substitute more
840 // and more values by _ so that at last ScreenMyFontBoldNormal
841 // would turn into Screen___ and this will then get
842 // converted to -${ScreenDefaultBase}${ScreenStdSuffix}
843
844 if (!(i & (1 << j)))
845 strcat(resource, names[j]);
846 else
847 strcat(resource, "_");
848 }
849
850 // we previously search the Xt-resources here
851
852 if (!internal)
853 {
854 defaults = font_defaults;
855 while (*defaults)
856 {
857 if (!strcmp(*defaults, resource))
858 {
859 internal = defaults[1];
860 break;
861 }
862 defaults += 2;
863 }
864 }
865 }
866
867 if (internal)
868 {
869 if ((strcmp(internal,"-${ScreenDefaultBase}${ScreenStdSuffix}") == 0) &&
870 (strcmp(names[0], "Default") != 0))
871 {
872 // we did not find any font name in the standard list.
873 // this can (hopefully does) mean that someone supplied
874 // the facename in the wxFont constructor so we insert
875 // it here
876
877 strcpy( resource,"-*-" ); // any producer
878 strcat( resource, names[0] ); // facename
879 strcat( resource, "${ScreenStdSuffix}" ); // add size params later on
880 *v = copystring(resource);
881 }
882 else
883 {
884 *v = copystring(internal);
885 }
886 }
887 }
888
889 wxSuffixMap::~wxSuffixMap()
890 {
891 int k, j;
892
893 for (k = 0; k < wxNUM_WEIGHTS; ++k)
894 for (j = 0; j < wxNUM_STYLES; ++j)
895 if (map[k][j])
896 {
897 delete[] map[k][j];
898 map[k][j] = (char *) NULL;
899 }
900 }
901
902 void wxSuffixMap::Initialize(const char *resname, const char *devresname)
903 {
904 const char *weight, *style;
905 char *v;
906 int i, j, k;
907 const char *names[3];
908
909 for (k = 0; k < wxNUM_WEIGHTS; k++)
910 {
911 switch (k)
912 {
913 case wxWEIGHT_NORMAL: weight = "Medium"; break;
914 case wxWEIGHT_LIGHT: weight = "Light"; break;
915 case wxWEIGHT_BOLD:
916 default: weight = "Bold";
917 }
918 for (j = 0; j < wxNUM_STYLES; j++)
919 {
920 switch (j)
921 {
922 case wxSTYLE_NORMAL: style = "Straight"; break;
923 case wxSTYLE_ITALIC: style = "Italic"; break;
924 case wxSTYLE_SLANT:
925 default: style = "Slant";
926 }
927 names[0] = resname;
928 names[1] = weight;
929 names[2] = style;
930
931 SearchResource(devresname, names, 3, &v);
932
933 // Expand macros in the found string:
934 found:
935 int len, closer = 0, startpos = 0;
936
937 len = (v ? strlen(v) : 0);
938 for (i = 0; i < len; i++)
939 {
940 if (v[i] == '$' && ((v[i+1] == '[') || (v[i+1] == '{')))
941 {
942 startpos = i;
943 closer = (v[i+1] == '[') ? ']' : '}';
944 ++i;
945 }
946 else if (v[i] == closer)
947 {
948 int newstrlen;
949 const char *r = (char *) NULL; bool delete_r = FALSE;
950 char *name;
951
952 name = v + startpos + 2;
953 v[i] = 0;
954
955 if (closer == '}')
956 {
957 int i, count, len;
958 char **names;
959
960 for (i = 0, count = 1; name[i]; i++)
961 if (name[i] == ',')
962 count++;
963
964 len = i;
965
966 names = new char*[count];
967 names[0] = name;
968 for (i = 0, count = 1; i < len; i++)
969 if (name[i] == ',')
970 {
971 names[count++] = name + i + 1;
972 name[i] = 0;
973 }
974
975 SearchResource("", (const char **)names, count, (char **)&r);
976 delete_r = (r != 0);
977 delete[] names;
978
979 if (!r)
980 {
981 for (i = 0; i < len; i++)
982 if (!name[i])
983 name[i] = ',';
984 r = "";
985 wxLogError( "Bad resource name in font lookup." );
986 }
987 } else if (!strcmp(name, "weight")) {
988 r = weight;
989 } else if (!strcmp(name, "style")) {
990 r = style;
991 } else if (!strcmp(name, "family")) {
992 r = resname;
993 } else {
994 r = "";
995 wxLogError( "Bad font macro name." );
996 }
997
998 // add r to v
999 newstrlen = strlen(r);
1000 char *naya = new char[startpos + newstrlen + len - i];
1001 memcpy(naya, v, startpos);
1002 memcpy(naya + startpos, r, newstrlen);
1003 memcpy(naya + startpos + newstrlen, v + i + 1, len - i);
1004 if (delete_r)
1005 delete[] (char*)r;
1006 delete[] v;
1007 v = naya;
1008
1009 goto found;
1010 }
1011 }
1012 // We have a final value:
1013 map[k][j] = v;
1014 }
1015 }
1016 }
1017
1018 //-----------------------------------------------------------------------------
1019 // wxFontNameItem
1020 //-----------------------------------------------------------------------------
1021
1022 class wxFontNameItem : public wxObject
1023 {
1024 DECLARE_DYNAMIC_CLASS(wxFontNameItem)
1025 public:
1026 wxFontNameItem(const char *name, int id, int family);
1027 ~wxFontNameItem();
1028
1029 inline char* GetScreenName(int w, int s) {return screen.GetName(w, s);}
1030 inline char* GetPostScriptName(int w, int s) {return printing.GetName(w, s);}
1031 inline char* GetAFMName(int w, int s) {return afm.GetName(w, s);}
1032 inline char* GetName() {return name;}
1033 inline int GetFamily() {return family;}
1034 inline int GetId() {return id;}
1035 inline bool IsRoman() {return isroman;}
1036 #if defined(__WXDEBUG__)
1037 void Dump(ostream& str);
1038 #endif
1039
1040 int id;
1041 int family;
1042 char *name;
1043 wxSuffixMap screen, printing, afm;
1044 bool isroman;
1045 };
1046
1047 IMPLEMENT_ABSTRACT_CLASS(wxFontNameItem, wxObject)
1048
1049 wxFontNameItem::wxFontNameItem(const char *Name, int Id, int Family)
1050 {
1051 name = copystring(Name);
1052 id = Id;
1053 family = Family;
1054
1055 screen. Initialize(name, "Screen");
1056 printing.Initialize(name, "PostScript");
1057 afm. Initialize(name, "Afm");
1058 }
1059
1060 wxFontNameItem::~wxFontNameItem()
1061 {
1062 if (name)
1063 delete[] name;
1064 name = (char *) NULL;
1065 }
1066
1067 #if defined(__WXDEBUG__)
1068 void wxFontNameItem::Dump(ostream& str)
1069 {
1070 str << "wxFontNameItem(" << name << ")";
1071 }
1072 #endif
1073
1074 //-----------------------------------------------------------------------------
1075 // wxFontDirectory
1076 //-----------------------------------------------------------------------------
1077
1078 IMPLEMENT_DYNAMIC_CLASS(wxFontNameDirectory, wxObject)
1079
1080 wxFontNameDirectory::wxFontNameDirectory()
1081 {
1082 table = new wxHashTable(wxKEY_INTEGER, 20);
1083 nextFontId = -1;
1084 }
1085
1086 wxFontNameDirectory::~wxFontNameDirectory()
1087 {
1088 // Cleanup wxFontNameItems allocated
1089 table->BeginFind();
1090 wxNode *node = table->Next();
1091 while (node)
1092 {
1093 wxFontNameItem *item = (wxFontNameItem*)node->Data();
1094 delete item;
1095 node = table->Next();
1096 }
1097 delete table;
1098 }
1099
1100 int wxFontNameDirectory::GetNewFontId()
1101 {
1102 return (nextFontId--);
1103 }
1104
1105 void wxFontNameDirectory::Initialize()
1106 {
1107 Initialize(wxDEFAULT, wxDEFAULT, "Default");
1108 Initialize(wxDECORATIVE, wxDECORATIVE, "Decorative");
1109 Initialize(wxROMAN, wxROMAN, "Roman");
1110 Initialize(wxMODERN, wxMODERN, "Modern");
1111 Initialize(wxTELETYPE, wxTELETYPE, "Teletype");
1112 Initialize(wxSWISS, wxSWISS, "Swiss");
1113 Initialize(wxSCRIPT, wxSCRIPT, "Script");
1114 }
1115
1116 void wxFontNameDirectory::Initialize(int fontid, int family, const char *resname)
1117 {
1118 char *fam, resource[256];
1119
1120 sprintf(resource, "Family%s", resname);
1121 SearchResource((const char *)resource, (const char **) NULL, 0, (char **)&fam);
1122
1123 if (fam)
1124 {
1125 if (!strcmp(fam, "Default")) family = wxDEFAULT;
1126 else if (!strcmp(fam, "Roman")) family = wxROMAN;
1127 else if (!strcmp(fam, "Decorative")) family = wxDECORATIVE;
1128 else if (!strcmp(fam, "Modern")) family = wxMODERN;
1129 else if (!strcmp(fam, "Teletype")) family = wxTELETYPE;
1130 else if (!strcmp(fam, "Swiss")) family = wxSWISS;
1131 else if (!strcmp(fam, "Script")) family = wxSCRIPT;
1132 delete[] fam; // free resource
1133 }
1134 table->Put(fontid, new wxFontNameItem(resname, fontid, family));
1135 }
1136
1137 int wxFontNameDirectory::FindOrCreateFontId(const char *name, int family)
1138 {
1139 int id;
1140
1141 // font exists -> return id
1142 if ( (id = GetFontId(name)) ) return id;
1143
1144 // create new font
1145 Initialize(id=GetNewFontId(), family, name);
1146 return id;
1147 }
1148
1149 char *wxFontNameDirectory::GetScreenName(int fontid, int weight, int style)
1150 {
1151 wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font
1152 if (item)
1153 return item->GetScreenName(weight, style);
1154
1155 // font does not exist
1156 return (char *) NULL;
1157 }
1158
1159 char *wxFontNameDirectory::GetPostScriptName(int fontid, int weight, int style)
1160 {
1161 wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font
1162 if (item)
1163 return item->GetPostScriptName(weight, style);
1164
1165 // font does not exist
1166 return (char *) NULL;
1167 }
1168
1169 char *wxFontNameDirectory::GetAFMName(int fontid, int weight, int style)
1170 {
1171 wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font
1172 if (item)
1173 return item->GetAFMName(weight, style);
1174 // font does not exist
1175 return (char *) NULL;
1176 }
1177
1178 char *wxFontNameDirectory::GetFontName(int fontid)
1179 {
1180 wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font
1181 if (item)
1182 return item->GetName();
1183
1184 // font does not exist
1185 return (char *) NULL;
1186 }
1187
1188 int wxFontNameDirectory::GetFontId(const char *name)
1189 {
1190 wxNode *node;
1191
1192 table->BeginFind();
1193
1194 while ( (node = table->Next()) )
1195 {
1196 wxFontNameItem *item = (wxFontNameItem*)node->Data();
1197 if (!strcmp(name, item->name))
1198 return item->id;
1199 }
1200
1201 // font does not exist
1202 return 0;
1203 }
1204
1205 int wxFontNameDirectory::GetFamily(int fontid)
1206 {
1207 wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid);
1208
1209 if (item)
1210 return item->family;
1211
1212 // font does not exist
1213 return wxDEFAULT;
1214 }
1215
1216 #endif // 0