1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        common/fontmap.cpp 
   3 // Purpose:     wxFontMapper class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) Vadim Zeitlin 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "fontmap.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  37 #include "wx/fontmap.h" 
  40     #include "wx/config.h" 
  41     #include "wx/memconf.h" 
  45     #include "wx/msgdlg.h" 
  46     #include "wx/fontdlg.h" 
  47     #include "wx/choicdlg.h" 
  50 #include "wx/encconv.h" 
  52 // ---------------------------------------------------------------------------- 
  54 // ---------------------------------------------------------------------------- 
  56 // the config paths we use 
  57 static const wxChar
* FONTMAPPER_ROOT_PATH 
= wxT("wxWindows/FontMapper"); 
  58 static const wxChar
* FONTMAPPER_CHARSET_PATH 
= wxT("Charsets"); 
  59 static const wxChar
* FONTMAPPER_CHARSET_ALIAS_PATH 
= wxT("Aliases"); 
  61     static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH 
= wxT("Encodings"); 
  64 // encodings supported by GetEncodingDescription 
  65 static wxFontEncoding gs_encodings
[] = 
  67     wxFONTENCODING_ISO8859_1
, 
  68     wxFONTENCODING_ISO8859_2
, 
  69     wxFONTENCODING_ISO8859_3
, 
  70     wxFONTENCODING_ISO8859_4
, 
  71     wxFONTENCODING_ISO8859_5
, 
  72     wxFONTENCODING_ISO8859_6
, 
  73     wxFONTENCODING_ISO8859_7
, 
  74     wxFONTENCODING_ISO8859_8
, 
  75     wxFONTENCODING_ISO8859_9
, 
  76     wxFONTENCODING_ISO8859_10
, 
  77     wxFONTENCODING_ISO8859_11
, 
  78     wxFONTENCODING_ISO8859_12
, 
  79     wxFONTENCODING_ISO8859_13
, 
  80     wxFONTENCODING_ISO8859_14
, 
  81     wxFONTENCODING_ISO8859_15
, 
  83     wxFONTENCODING_CP1250
, 
  84     wxFONTENCODING_CP1251
, 
  85     wxFONTENCODING_CP1252
, 
  86     wxFONTENCODING_CP1253
, 
  87     wxFONTENCODING_CP1254
, 
  88     wxFONTENCODING_CP1255
, 
  89     wxFONTENCODING_CP1256
, 
  90     wxFONTENCODING_CP1257
, 
  94 // the descriptions for them 
  95 static const wxChar
* gs_encodingDescs
[] = 
  97     wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ), 
  98     wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ), 
  99     wxTRANSLATE( "Esperanto (ISO-8859-3)" ), 
 100     wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ), 
 101     wxTRANSLATE( "Cyrillic (Latin 5)" ), 
 102     wxTRANSLATE( "Arabic (ISO-8859-6)" ), 
 103     wxTRANSLATE( "Greek (ISO-8859-7)" ), 
 104     wxTRANSLATE( "Hebrew (ISO-8859-8)" ), 
 105     wxTRANSLATE( "Turkish (ISO-8859-9)" ), 
 106     wxTRANSLATE( "Nordic (ISO-8859-10)" ), 
 107     wxTRANSLATE( "Thai (ISO-8859-11)" ), 
 108     wxTRANSLATE( "ISO-8859-12" ), 
 109     wxTRANSLATE( "Baltic (ISO-8859-13)" ), 
 110     wxTRANSLATE( "ISO-8859-14" ), 
 111     wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ), 
 112     wxTRANSLATE( "KOI8-R" ), 
 113     wxTRANSLATE( "Windows Latin 2 (CP 1250)" ), 
 114     wxTRANSLATE( "Windows Cyrillic (CP 1251)" ), 
 115     wxTRANSLATE( "Windows Latin 1 (CP 1252)" ), 
 116     wxTRANSLATE( "Windows Greek (CP 1253)" ), 
 117     wxTRANSLATE( "Windows Turkish (CP 1254)" ), 
 118     wxTRANSLATE( "Windows Hebrew (CP 1255)" ), 
 119     wxTRANSLATE( "Windows Arabic (CP 1256)" ), 
 120     wxTRANSLATE( "Windows Baltic (CP 1257)" ), 
 121     wxTRANSLATE( "Windows/DOS OEM (CP 437)" ), 
 124 // and the internal names 
 125 static const wxChar
* gs_encodingNames
[] = 
 143     wxT( "windows1250" ), 
 144     wxT( "windows1251" ), 
 145     wxT( "windows1252" ), 
 146     wxT( "windows1253" ), 
 147     wxT( "windows1254" ), 
 148     wxT( "windows1255" ), 
 149     wxT( "windows1256" ), 
 150     wxT( "windows1257" ), 
 154 // ---------------------------------------------------------------------------- 
 156 // ---------------------------------------------------------------------------- 
 159 static wxFontMapper gs_fontMapper
; 
 161 // and public pointer 
 162 wxFontMapper 
* wxTheFontMapper 
= &gs_fontMapper
; 
 164 // ---------------------------------------------------------------------------- 
 166 // ---------------------------------------------------------------------------- 
 168 // change the config path during the lifetime of this object 
 169 class wxFontMapperPathChanger
 
 172     wxFontMapperPathChanger(wxFontMapper 
*fontMapper
, const wxString
& path
) 
 174         m_fontMapper 
= fontMapper
; 
 175         m_ok 
= m_fontMapper
->ChangePath(path
, &m_pathOld
); 
 178     bool IsOk() const { return m_ok
; } 
 180     ~wxFontMapperPathChanger() 
 183             m_fontMapper
->RestorePath(m_pathOld
); 
 187     wxFontMapper 
*m_fontMapper
; 
 192 // ============================================================================ 
 194 // ============================================================================ 
 196 // ---------------------------------------------------------------------------- 
 198 // ---------------------------------------------------------------------------- 
 200 wxFontMapper::wxFontMapper() 
 204 #endif // wxUSE_CONFIG 
 207     m_windowParent 
= NULL
; 
 211 wxFontMapper::~wxFontMapper() 
 215 // ---------------------------------------------------------------------------- 
 217 // ---------------------------------------------------------------------------- 
 221 /* static */ const wxChar 
*wxFontMapper::GetDefaultConfigPath() 
 223     return FONTMAPPER_ROOT_PATH
; 
 226 void wxFontMapper::SetConfigPath(const wxString
& prefix
) 
 228     wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
, 
 229                  wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") ); 
 231     m_configRootPath 
= prefix
; 
 234 // ---------------------------------------------------------------------------- 
 235 // get config object and path for it 
 236 // ---------------------------------------------------------------------------- 
 238 wxConfigBase 
*wxFontMapper::GetConfig() 
 243         m_config 
= wxConfig::Get(FALSE 
/*don't create on demand*/ ); 
 247             // we still want to have a config object because otherwise we would 
 248             // keep asking the user the same questions in the interactive mode, 
 249             // so create a dummy config which won't write to any files/registry 
 250             // but will allow us to remember the results of the questions at 
 251             // least during this run 
 252             m_config 
= new wxMemoryConfig
; 
 253             wxConfig::Set(m_config
); 
 260 const wxString
& wxFontMapper::GetConfigPath() 
 262     if ( !m_configRootPath 
) 
 265         m_configRootPath 
= GetDefaultConfigPath(); 
 268     return m_configRootPath
; 
 272 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString 
*pathOld
) 
 275     wxConfigBase 
*config 
= GetConfig(); 
 279     *pathOld 
= config
->GetPath(); 
 281     wxString path 
= GetConfigPath(); 
 282     if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR 
) 
 284         path 
+= wxCONFIG_PATH_SEPARATOR
; 
 287     wxASSERT_MSG( !pathNew 
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
), 
 288                   wxT("should be a relative path") ); 
 292     config
->SetPath(path
); 
 300 void wxFontMapper::RestorePath(const wxString
& pathOld
) 
 303     GetConfig()->SetPath(pathOld
); 
 308 // ---------------------------------------------------------------------------- 
 309 // charset/encoding correspondence 
 310 // ---------------------------------------------------------------------------- 
 313 wxString 
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
) 
 315     size_t count 
= WXSIZEOF(gs_encodingDescs
); 
 317     wxASSERT_MSG( count 
== WXSIZEOF(gs_encodings
), 
 318                   wxT("inconsitency detected - forgot to update one of the arrays?") ); 
 320     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 322         if ( gs_encodings
[i
] == encoding 
) 
 324             return wxGetTranslation(gs_encodingDescs
[i
]); 
 329     str
.Printf(_("Unknown encoding (%d)"), encoding
); 
 335 wxString 
wxFontMapper::GetEncodingName(wxFontEncoding encoding
) 
 337     size_t count 
= WXSIZEOF(gs_encodingNames
); 
 339     wxASSERT_MSG( count 
== WXSIZEOF(gs_encodings
), 
 340                   wxT("inconsistency detected - forgot to update one of the arrays?") ); 
 342     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 344         if ( gs_encodings
[i
] == encoding 
) 
 346             return wxGetTranslation(gs_encodingNames
[i
]); 
 351     str
.Printf(_("unknown-%d"), encoding
); 
 356 wxFontEncoding 
wxFontMapper::CharsetToEncoding(const wxString
& charset
, 
 359     wxFontEncoding encoding 
= wxFONTENCODING_SYSTEM
; 
 361     // we're going to modify it, make a copy 
 362     wxString cs 
= charset
; 
 365     // first try the user-defined settings 
 367     if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) ) 
 369         wxConfigBase 
*config 
= GetConfig(); 
 371         // do we have an encoding for this charset? 
 372         long value 
= config
->Read(charset
, -1l); 
 375             if ( value 
>= 0 && value 
<= wxFONTENCODING_MAX 
) 
 377                 encoding 
= (wxFontEncoding
)value
; 
 381                 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"), 
 382                            value
, charset
.c_str()); 
 386         if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 388             // may be we have an alias? 
 389             config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
); 
 391             wxString alias 
= config
->Read(charset
); 
 394                 // yes, we do - use it instead 
 399         RestorePath(pathOld
); 
 403     // if didn't find it there, try to reckognise it ourselves 
 404     if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 408         if ( !cs 
|| cs 
== wxT("US-ASCII") ) 
 409             encoding 
= wxFONTENCODING_DEFAULT
; 
 410         else if ( cs 
== wxT("KOI8-R") || cs 
== wxT("KOI8-U") ) 
 411             encoding 
= wxFONTENCODING_KOI8
; 
 412         else if ( cs
.Left(3) == wxT("ISO") ) 
 414             // the dash is optional (or, to be exact, it is not, but 
 415             // several brokenmails "forget" it) 
 416             const wxChar 
*p 
= cs
.c_str() + 3; 
 417             if ( *p 
== wxT('-') ) 
 421             if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 ) 
 423                 if ( value 
< wxFONTENCODING_ISO8859_MAX 
- 
 424                              wxFONTENCODING_ISO8859_1 
) 
 426                     // it's a valid ISO8859 encoding 
 427                     value 
+= wxFONTENCODING_ISO8859_1 
- 1; 
 428                     encoding 
= (wxFontEncoding
)value
; 
 432         else if ( cs
.Left(8) == wxT("WINDOWS-") ) 
 435             if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 ) 
 440                     if ( value 
< wxFONTENCODING_CP12_MAX 
- 
 441                                  wxFONTENCODING_CP1250 
- 1 ) 
 443                         // a valid Windows code page 
 444                         value 
+= wxFONTENCODING_CP1250
; 
 445                         encoding 
= (wxFontEncoding
)value
; 
 454     // if still no luck, ask the user - unless disabled 
 455     if ( (encoding 
== wxFONTENCODING_SYSTEM
) && interactive 
) 
 457         // prepare the dialog data 
 460         wxString 
title(m_titleDialog
); 
 462             title 
<< wxTheApp
->GetAppName() << _(": unknown charset"); 
 466         msg
.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset
.c_str()); 
 468         // the list of choices 
 469         size_t count 
= WXSIZEOF(gs_encodingDescs
); 
 471         wxASSERT_MSG( count 
== WXSIZEOF(gs_encodings
), 
 472                       wxT("inconsitency detected - forgot to update one of the arrays?") ); 
 474         wxString 
*encodingNamesTranslated 
= new wxString
[count
]; 
 476         for ( size_t i 
= 0; i 
< count
; i
++ ) 
 478             encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]); 
 482         wxWindow 
*parent 
= m_windowParent
; 
 484             parent 
= wxTheApp
->GetTopWindow(); 
 486         // do ask the user and get back the index in encodings table 
 487         int n 
= wxGetSingleChoiceIndex(msg
, title
, 
 489                                        encodingNamesTranslated
, 
 492         delete [] encodingNamesTranslated
; 
 496             encoding 
= gs_encodings
[n
]; 
 499         // save the result in the config now 
 500             if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) ) 
 502                 wxConfigBase 
*config 
= GetConfig(); 
 504                 // remember the alt encoding for this charset 
 505                 if ( !config
->Write(charset
, (long)encoding
) ) 
 507                     wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str()); 
 510                 RestorePath(pathOld
); 
 512 #endif // wxUSE_CONFIG 
 521 // ---------------------------------------------------------------------------- 
 522 // support for unknown encodings: we maintain a map between the 
 523 // (platform-specific) strings identifying them and our wxFontEncodings they 
 524 // correspond to which is used by GetFontForEncoding() function 
 525 // ---------------------------------------------------------------------------- 
 529 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
, 
 530                                    wxFontEncoding encReplacement
, 
 531                                    wxNativeEncodingInfo 
*info
) 
 533     if ( wxGetNativeFontEncoding(encReplacement
, info
) && 
 534          wxTestFontEncoding(*info
) ) 
 537         // remember the mapping in the config 
 538         wxFontMapperPathChanger 
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 542             GetConfig()->Write(configEntry
, info
->ToString()); 
 544 #endif // wxUSE_CONFIG 
 552 class ReentrancyBlocker
 
 555     ReentrancyBlocker(bool& b
) : m_b(b
) { m_b 
= TRUE
; } 
 556     ~ReentrancyBlocker() { m_b 
= FALSE
; } 
 563 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 564                                      wxNativeEncodingInfo 
*info
, 
 565                                      const wxString
& facename
, 
 569     // we need a flag to prevent infinite recursion which happens, for 
 570     // example, when GetAltForEncoding() is called from an OnPaint() handler: 
 571     // in this case, wxYield() which is called from wxMessageBox() we use here 
 572     // will lead to another call of OnPaint() and hence to another call of 
 573     // GetAltForEncoding() - and it is impossible to catch this from the user 
 574     // code because we are called from wxFont ctor implicitly. 
 576     // assume we're always called from the main thread, so that it is safe to 
 578     static bool s_inGetAltForEncoding 
= FALSE
; 
 580     if ( interactive 
&& s_inGetAltForEncoding 
) 
 583     ReentrancyBlocker 
blocker(s_inGetAltForEncoding
); 
 586     wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") ); 
 588     info
->facename 
= facename
; 
 590     if ( encoding 
== wxFONTENCODING_DEFAULT 
) 
 592         encoding 
= wxFont::GetDefaultEncoding(); 
 595     // if we failed to load the system default encoding, something is really 
 596     // wrong and we'd better stop now - otherwise we will go into endless 
 597     // recursion trying to create the font in the msg box with the error 
 599     if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 601         wxFatalError(_("can't load any font, aborting")); 
 603         // wxFatalError doesn't return 
 606     wxString configEntry
, encName 
= GetEncodingName(encoding
); 
 609         configEntry 
= facename 
+ _T("_"); 
 611     configEntry 
+= encName
; 
 614     // do we have a font spec for this encoding? 
 616     if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) ) 
 618         wxConfigBase 
*config 
= GetConfig(); 
 620         wxString fontinfo 
= config
->Read(configEntry
); 
 622         RestorePath(pathOld
); 
 624         if ( !!fontinfo 
&& !!facename 
) 
 626             // we tried to find a match with facename - now try without it 
 627             fontinfo 
= config
->Read(encName
); 
 632             if ( info
->FromString(fontinfo
) ) 
 634                 if ( wxTestFontEncoding(*info
) ) 
 639                 //else: no such fonts, look for something else 
 643                 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo
.c_str()); 
 646         //else: there is no information in config about this encoding 
 648 #endif // wxUSE_CONFIG 
 653         wxString 
title(m_titleDialog
); 
 655             title 
<< wxTheApp
->GetAppName() << _(": unknown encoding"); 
 659         msg
.Printf(_("The encoding '%s' is unknown.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), 
 660                      GetEncodingDescription(encoding
).c_str()); 
 662         wxWindow 
*parent 
= m_windowParent
; 
 664             parent 
= wxTheApp
->GetTopWindow(); 
 666         if ( wxMessageBox(msg
, title
, 
 667                           wxICON_QUESTION 
| wxYES_NO
, parent
) == wxYES 
) 
 670             data
.SetEncoding(encoding
); 
 671             data
.EncodingInfo() = *info
; 
 672             wxFontDialog 
dialog(parent
, &data
); 
 673             if ( dialog
.ShowModal() == wxID_OK 
) 
 675                 wxFontData retData 
= dialog
.GetFontData(); 
 676                 wxFont font 
= retData
.GetChosenFont(); 
 678                 *info 
= retData
.EncodingInfo(); 
 679                 info 
-> encoding 
= retData
.GetEncoding(); 
 682             // remember this in the config 
 683                 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) ) 
 685                     GetConfig()->Write(configEntry
, info
->ToString()); 
 687                     RestorePath(pathOld
); 
 693             //else: the user canceled the font selection dialog 
 695         //else: the user doesn't want to select a font 
 697     //else: we're in non-interactive mode 
 699     // now try the default mappings: 
 700     wxFontEncodingArray equiv 
= wxEncodingConverter::GetAllEquivalents(encoding
); 
 701     size_t count 
= equiv
.GetCount(); 
 702     for ( size_t i 
= (equiv
[0] == encoding
) ? 1 : 0; i 
< count
; i
++ ) 
 704         if ( TestAltEncoding(configEntry
, equiv
[i
], info
) ) 
 711 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 712                                      wxFontEncoding 
*alt_encoding
, 
 713                                      const wxString
& facename
, 
 716     wxNativeEncodingInfo info
; 
 717     bool r 
= GetAltForEncoding(encoding
, &info
, facename
, interactive
); 
 718     *alt_encoding 
= info
.encoding
; 
 722 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
, 
 723                                        const wxString
& facename
) 
 725     wxNativeEncodingInfo info
; 
 727     if (wxGetNativeFontEncoding(encoding
, &info
)) 
 729         info
.facename 
= facename
; 
 730         return wxTestFontEncoding(info
);