]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/fontutil.cpp
better learn the operators...
[wxWidgets.git] / src / unix / fontutil.cpp
index 774dd534bd46e8020038e41848d35e0d6572ea2e..f190de22b664af8416feb804b95ac3e6d929c8ef 100644 (file)
 #endif // PCH
 
 #ifdef __X__
 #endif // PCH
 
 #ifdef __X__
+    #ifdef __VMS__
+        #pragma message disable nosimpint
+    #endif
+
     #include <X11/Xlib.h>
 
     #include <X11/Xlib.h>
 
+    #ifdef __VMS__
+        #pragma message enable nosimpint
+    #endif
+
     #include "wx/utils.h"       // for wxGetDisplay()
 #elif defined(__WXGTK__)
     #include "wx/utils.h"       // for wxGetDisplay()
 #elif defined(__WXGTK__)
-    #include "gdk/gdk.h"
+    // we have to declare struct tm to avoid problems with first forward
+    // declaring it in C code (glib.h included from gdk.h does it) and then
+    // defining it when time.h is included from the headers below - this is
+    // known not to work at least with Sun CC 6.01
+    #include <time.h>
+
+    #include <gdk/gdk.h>
 #endif
 
 #include "wx/fontutil.h"
 #include "wx/fontmap.h"
 #include "wx/tokenzr.h"
 #endif
 
 #include "wx/fontutil.h"
 #include "wx/fontmap.h"
 #include "wx/tokenzr.h"
+#include "wx/hash.h"
+#include "wx/module.h"
+
+// ----------------------------------------------------------------------------
+// private data
+// ----------------------------------------------------------------------------
+
+static wxHashTable *g_fontHash = (wxHashTable*) NULL;
 
 // ----------------------------------------------------------------------------
 // private functions
 
 // ----------------------------------------------------------------------------
 // private functions
 
     static inline void wxFreeFont(wxNativeFont font)
     {
 
     static inline void wxFreeFont(wxNativeFont font)
     {
-        XFreeFont((Display *)wxGetDisplay(), font);
+        XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
     }
 #elif defined(__WXGTK__)
     static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
     {
     }
 #elif defined(__WXGTK__)
     static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
     {
-        return gdk_font_load( wxConvertWX2MB(fontSpec) );
+       return gdk_font_load( wxConvertWX2MB(fontSpec) );
     }
 
     static inline void wxFreeFont(wxNativeFont font)
     }
 
     static inline void wxFreeFont(wxNativeFont font)
@@ -81,7 +103,8 @@ static wxNativeFont wxLoadQueryFont(int pointSize,
                                     bool underlined,
                                     const wxString& facename,
                                     const wxString& xregistry,
                                     bool underlined,
                                     const wxString& facename,
                                     const wxString& xregistry,
-                                    const wxString& xencoding);
+                                    const wxString& xencoding,
+                                    wxString* xFontName);
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -92,10 +115,17 @@ static wxNativeFont wxLoadQueryFont(int pointSize,
 // ----------------------------------------------------------------------------
 
 // convert to/from the string representation: format is
 // ----------------------------------------------------------------------------
 
 // convert to/from the string representation: format is
-//      registry-encoding[-facename]
+//      encodingid;registry;encoding[;facename]
 bool wxNativeEncodingInfo::FromString(const wxString& s)
 {
 bool wxNativeEncodingInfo::FromString(const wxString& s)
 {
-    wxStringTokenizer tokenizer(s, _T("-"));
+    // use ";", not "-" because it may be part of encoding name
+    wxStringTokenizer tokenizer(s, _T(";"));
+
+    wxString encid = tokenizer.GetNextToken();
+    long enc;
+    if ( !encid.ToLong(&enc) )
+        return FALSE;
+    encoding = (wxFontEncoding)enc;
 
     xregistry = tokenizer.GetNextToken();
     if ( !xregistry )
 
     xregistry = tokenizer.GetNextToken();
     if ( !xregistry )
@@ -114,10 +144,10 @@ bool wxNativeEncodingInfo::FromString(const wxString& s)
 wxString wxNativeEncodingInfo::ToString() const
 {
     wxString s;
 wxString wxNativeEncodingInfo::ToString() const
 {
     wxString s;
-    s << xregistry << _T('-') << xencoding;
+    s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
     if ( !!facename )
     {
     if ( !!facename )
     {
-        s << _T('-') << facename;
+        s << _T(';') << facename;
     }
 
     return s;
     }
 
     return s;
@@ -150,6 +180,7 @@ bool wxGetNativeFontEncoding(wxFontEncoding encoding,
         case wxFONTENCODING_ISO8859_9:
         case wxFONTENCODING_ISO8859_10:
         case wxFONTENCODING_ISO8859_11:
         case wxFONTENCODING_ISO8859_9:
         case wxFONTENCODING_ISO8859_10:
         case wxFONTENCODING_ISO8859_11:
+        case wxFONTENCODING_ISO8859_12:
         case wxFONTENCODING_ISO8859_13:
         case wxFONTENCODING_ISO8859_14:
         case wxFONTENCODING_ISO8859_15:
         case wxFONTENCODING_ISO8859_13:
         case wxFONTENCODING_ISO8859_14:
         case wxFONTENCODING_ISO8859_15:
@@ -160,10 +191,15 @@ bool wxGetNativeFontEncoding(wxFontEncoding encoding,
             }
             break;
 
             }
             break;
 
+        case wxFONTENCODING_UTF8:
+            info->xregistry = wxT("iso10646");
+            info->xencoding = wxT("*");
+            break;
+
         case wxFONTENCODING_KOI8:
             info->xregistry = wxT("koi8");
 
         case wxFONTENCODING_KOI8:
             info->xregistry = wxT("koi8");
 
-            // we don't make distinction between koi8-r and koi8-u (so far)
+            // we don't make distinction between koi8-r, koi8-u and koi8-ru (so far)
             info->xencoding = wxT("*");
             break;
 
             info->xencoding = wxT("*");
             break;
 
@@ -184,7 +220,7 @@ bool wxGetNativeFontEncoding(wxFontEncoding encoding,
 
         case wxFONTENCODING_SYSTEM:
             info->xregistry =
 
         case wxFONTENCODING_SYSTEM:
             info->xregistry =
-            info->xencoding = wxT('*');
+            info->xencoding = wxT("*");
             break;
 
         default:
             break;
 
         default:
@@ -192,6 +228,8 @@ bool wxGetNativeFontEncoding(wxFontEncoding encoding,
             return FALSE;
     }
 
             return FALSE;
     }
 
+   info->encoding = encoding;
+
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -216,30 +254,78 @@ wxNativeFont wxLoadQueryNearestFont(int pointSize,
                                     int weight,
                                     bool underlined,
                                     const wxString &facename,
                                     int weight,
                                     bool underlined,
                                     const wxString &facename,
-                                    wxFontEncoding encoding)
+                                    wxFontEncoding encoding,
+                                    wxString* xFontName)
 {
 {
+    if ( encoding == wxFONTENCODING_DEFAULT )
+    {
+        encoding = wxFont::GetDefaultEncoding();
+    }
+
     // first determine the encoding - if the font doesn't exist at all in this
     // encoding, it's useless to do all other approximations (i.e. size,
     // family &c don't matter much)
     wxNativeEncodingInfo info;
     // first determine the encoding - if the font doesn't exist at all in this
     // encoding, it's useless to do all other approximations (i.e. size,
     // family &c don't matter much)
     wxNativeEncodingInfo info;
-    if ( !wxGetNativeFontEncoding(encoding, &info) ||
-         !wxTestFontEncoding(info) )
+    if ( encoding == wxFONTENCODING_SYSTEM )
+    {
+        // This will always work so we don't test to save time
+        wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
+    }
+    else
     {
     {
-        if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
+        if ( !wxGetNativeFontEncoding(encoding, &info) ||
+             !wxTestFontEncoding(info) )
         {
         {
-            // unspported encoding - replace it with the default
-            //
-            // NB: we can't just return 0 from here because wxGTK code doesn't
-            //     check for it (i.e. it supposes that we'll always succeed),
-            //     so it would provoke a crash
-            wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
+#if wxUSE_FONTMAP
+            if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
+#endif // wxUSE_FONTMAP
+            {
+                // unspported encoding - replace it with the default
+                //
+                // NB: we can't just return 0 from here because wxGTK code doesn't
+                //     check for it (i.e. it supposes that we'll always succeed),
+                //     so it would provoke a crash
+                wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
+            }
         }
     }
         }
     }
-    //else: we have the correct xregistry/xencoding in info structure
 
 
-    wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
-                                         underlined, facename,
-                                         info.xregistry, info.xencoding );
+    // OK, we have the correct xregistry/xencoding in info structure
+    wxNativeFont font = 0;
+
+    // if we already have the X font name, try to use it
+    if( xFontName && !xFontName->IsEmpty() )
+    {
+        //
+        //  Make sure point size is correct for scale factor.
+        //
+        wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
+        wxString newFontName;
+
+        for(int i = 0; i < 8; i++)
+          newFontName += tokenizer.NextToken();
+
+        (void) tokenizer.NextToken();
+
+        newFontName += wxString::Format("%d-", pointSize);
+
+        while(tokenizer.HasMoreTokens())
+          newFontName += tokenizer.GetNextToken();
+
+        font = wxLoadFont(newFontName);
+
+        if(font)
+          *xFontName = newFontName;
+    }
+
+    // try to load exactly the font requested first
+    if( !font )
+    {
+        font = wxLoadQueryFont( pointSize, family, style, weight,
+                                underlined, facename,
+                                info.xregistry, info.xencoding,
+                                xFontName );
+    }
 
     if ( !font )
     {
 
     if ( !font )
     {
@@ -253,14 +339,16 @@ wxNativeFont wxLoadQueryNearestFont(int pointSize,
         for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
         {
             font = wxLoadQueryFont(i, family, style, weight, underlined,
         for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
         {
             font = wxLoadQueryFont(i, family, style, weight, underlined,
-                                   facename, info.xregistry, info.xencoding);
+                                   facename, info.xregistry, info.xencoding,
+                                   xFontName);
         }
 
         // Search for larger size (approx.)
         for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
         {
             font = wxLoadQueryFont(i, family, style, weight, underlined,
         }
 
         // Search for larger size (approx.)
         for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
         {
             font = wxLoadQueryFont(i, family, style, weight, underlined,
-                                   facename, info.xregistry, info.xencoding);
+                                   facename, info.xregistry, info.xencoding,
+                                   xFontName);
         }
 
         // Try default family
         }
 
         // Try default family
@@ -268,23 +356,53 @@ wxNativeFont wxLoadQueryNearestFont(int pointSize,
         {
             font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
                                    underlined, facename,
         {
             font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
                                    underlined, facename,
-                                   info.xregistry, info.xencoding );
+                                   info.xregistry, info.xencoding,
+                                   xFontName );
         }
 
         }
 
-        // Bogus font I
+        // ignore size, family, style and weight but try to find font with the
+        // given facename and encoding
         if ( !font )
         {
             font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
                                    underlined, facename,
         if ( !font )
         {
             font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
                                    underlined, facename,
-                                   info.xregistry, info.xencoding);
-        }
+                                   info.xregistry, info.xencoding,
+                                   xFontName);
 
 
-        // Bogus font II
-        if ( !font )
-        {
-            font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
-                                   underlined, wxEmptyString,
-                                   info.xregistry, info.xencoding);
+            // ignore family as well
+            if ( !font )
+            {
+                font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
+                                       underlined, wxEmptyString,
+                                       info.xregistry, info.xencoding,
+                                       xFontName);
+
+                // if it still failed, try to get the font of any size but
+                // with the requested encoding: this can happen if the
+                // encoding is only available in one size which happens to be
+                // different from 120
+                if ( !font )
+                {
+                    font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
+                                           FALSE, wxEmptyString,
+                                           info.xregistry, info.xencoding,
+                                           xFontName);
+
+                    // this should never happen as we had tested for it in the
+                    // very beginning, but if it does, do return something non
+                    // NULL or we'd crash in wxFont code
+                    if ( !font )
+                    {
+                        wxFAIL_MSG( _T("this encoding should be available!") );
+
+                        font = wxLoadQueryFont(-1,
+                                               wxDEFAULT, wxNORMAL, wxNORMAL,
+                                               FALSE, wxEmptyString,
+                                               _T("*"), _T("*"),
+                                               xFontName);
+                    }
+                }
+            }
         }
     }
 
         }
     }
 
@@ -298,7 +416,22 @@ wxNativeFont wxLoadQueryNearestFont(int pointSize,
 // returns TRUE if there are any fonts matching this font spec
 static bool wxTestFontSpec(const wxString& fontspec)
 {
 // returns TRUE if there are any fonts matching this font spec
 static bool wxTestFontSpec(const wxString& fontspec)
 {
-    wxNativeFont test = wxLoadFont(fontspec);
+    // some X servers will fail to load this font because there are too many
+    // matches so we must test explicitly for this
+    if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
+    {
+        return TRUE;
+    }
+
+    wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
+    if (test)
+    {
+        return TRUE;
+    }
+
+    test = wxLoadFont(fontspec);
+    g_fontHash->Put( fontspec, (wxObject*) test );
+
     if ( test )
     {
         wxFreeFont(test);
     if ( test )
     {
         wxFreeFont(test);
@@ -318,7 +451,8 @@ static wxNativeFont wxLoadQueryFont(int pointSize,
                                     bool WXUNUSED(underlined),
                                     const wxString& facename,
                                     const wxString& xregistry,
                                     bool WXUNUSED(underlined),
                                     const wxString& facename,
                                     const wxString& xregistry,
-                                    const wxString& xencoding)
+                                    const wxString& xencoding,
+                                    wxString* xFontName)
 {
     wxString xfamily;
     switch (family)
 {
     wxString xfamily;
     switch (family)
@@ -348,10 +482,47 @@ static wxNativeFont wxLoadQueryFont(int pointSize,
     wxString xstyle;
     switch (style)
     {
     wxString xstyle;
     switch (style)
     {
-        case wxITALIC:     xstyle = wxT("i"); break;
-        case wxSLANT:      xstyle = wxT("o"); break;
-        case wxNORMAL:     xstyle = wxT("r"); break;
-        default:           xstyle = wxT("*"); break;
+        case wxSLANT:
+            fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
+                    xfamily.c_str());
+            if ( wxTestFontSpec(fontSpec) )
+            {
+                xstyle = wxT("o");
+                break;
+            }
+            // fall through - try wxITALIC now
+
+        case wxITALIC:
+            fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
+                    xfamily.c_str());
+            if ( wxTestFontSpec(fontSpec) )
+            {
+                xstyle = wxT("i");
+            }
+            else if ( style == wxITALIC ) // and not wxSLANT
+            {
+                // try wxSLANT
+                fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
+                        xfamily.c_str());
+                if ( wxTestFontSpec(fontSpec) )
+                {
+                    xstyle = wxT("o");
+                }
+                else
+                {
+                    // no italic, no slant - leave default
+                    xstyle = wxT("*");
+                }
+            }
+            break;
+
+        default:
+            wxFAIL_MSG(_T("unknown font style"));
+            // fall back to normal
+
+        case wxNORMAL:
+            xstyle = wxT("r");
+            break;
     }
 
     wxString xweight;
     }
 
     wxString xweight;
@@ -450,11 +621,54 @@ static wxNativeFont wxLoadQueryFont(int pointSize,
         default:           xweight = wxT("*"); break;
     }
 
         default:           xweight = wxT("*"); break;
     }
 
+    // if pointSize is -1, don't specify any
+    wxString sizeSpec;
+    if ( fontSpec == -1 )
+    {
+        sizeSpec = _T('*');
+    }
+    else
+    {
+        sizeSpec.Printf(_T("%d"), pointSize);
+    }
+
     // construct the X font spec from our data
     // construct the X font spec from our data
-    fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
+    fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
                     xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
                     xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
-                    pointSize, xregistry.c_str(), xencoding.c_str());
+                    sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
+
+    if( xFontName )
+        *xFontName = fontSpec;
 
     return wxLoadFont(fontSpec);
 }
 
 
     return wxLoadFont(fontSpec);
 }
 
+// ----------------------------------------------------------------------------
+// wxFontModule
+// ----------------------------------------------------------------------------
+
+class wxFontModule : public wxModule
+{
+public:
+    bool OnInit();
+    void OnExit();
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxFontModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
+
+bool wxFontModule::OnInit()
+{
+    g_fontHash = new wxHashTable( wxKEY_STRING );
+
+    return TRUE;
+}
+
+void wxFontModule::OnExit()
+{
+    delete g_fontHash;
+
+    g_fontHash = (wxHashTable *)NULL;
+}