]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fontcmn.cpp
Update version to 2.9.4 in version.bkl too and rebake everything.
[wxWidgets.git] / src / common / fontcmn.cpp
index f83bb4701fa6cf4c603f37bf97c91b33d15eb362..d54521c449fa92cf323fa2c009eb4f2dd5ca09c6 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef WX_PRECOMP
     #include "wx/dc.h"
     #include "wx/intl.h"
+    #include "wx/math.h"
     #include "wx/dcscreen.h"
     #include "wx/log.h"
     #include "wx/gdicmn.h"
 
 #include "wx/tokenzr.h"
 
+// debugger helper: this function can be called from a debugger to show what
+// the date really is
+extern const char *wxDumpFont(const wxFont *font)
+{
+    static char buf[256];
+
+    const wxFontWeight weight = font->GetWeight();
+
+    wxString s;
+    s.Printf(wxS("%s-%s-%s-%d-%d"),
+             font->GetFaceName(),
+             weight == wxFONTWEIGHT_NORMAL
+                ? wxT("normal")
+                : weight == wxFONTWEIGHT_BOLD
+                    ? wxT("bold")
+                    : wxT("light"),
+             font->GetStyle() == wxFONTSTYLE_NORMAL
+                ? wxT("regular")
+                : wxT("italic"),
+             font->GetPointSize(),
+             font->GetEncoding());
+
+    wxStrlcpy(buf, s.mb_str(), WXSIZEOF(buf));
+    return buf;
+}
+
+// ----------------------------------------------------------------------------
+// XTI
+// ----------------------------------------------------------------------------
+
+wxBEGIN_ENUM( wxFontFamily )
+wxENUM_MEMBER( wxFONTFAMILY_DEFAULT )
+wxENUM_MEMBER( wxFONTFAMILY_DECORATIVE )
+wxENUM_MEMBER( wxFONTFAMILY_ROMAN )
+wxENUM_MEMBER( wxFONTFAMILY_SCRIPT )
+wxENUM_MEMBER( wxFONTFAMILY_SWISS )
+wxENUM_MEMBER( wxFONTFAMILY_MODERN )
+wxENUM_MEMBER( wxFONTFAMILY_TELETYPE )
+wxEND_ENUM( wxFontFamily )
+
+wxBEGIN_ENUM( wxFontStyle )
+wxENUM_MEMBER( wxFONTSTYLE_NORMAL )
+wxENUM_MEMBER( wxFONTSTYLE_ITALIC )
+wxENUM_MEMBER( wxFONTSTYLE_SLANT )
+wxEND_ENUM( wxFontStyle )
+
+wxBEGIN_ENUM( wxFontWeight )
+wxENUM_MEMBER( wxFONTWEIGHT_NORMAL )
+wxENUM_MEMBER( wxFONTWEIGHT_LIGHT )
+wxENUM_MEMBER( wxFONTWEIGHT_BOLD )
+wxEND_ENUM( wxFontWeight )
+
+wxIMPLEMENT_DYNAMIC_CLASS_WITH_COPY_XTI(wxFont, wxGDIObject, "wx/font.h")
+
+//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxFont>)
+
+wxBEGIN_PROPERTIES_TABLE(wxFont)
+wxPROPERTY( Size,int, SetPointSize, GetPointSize, 12, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Family, wxFontFamily , SetFamily, GetFamily, (wxFontFamily)wxDEFAULT, \
+           0 /*flags*/, wxT("Helpstring"), wxT("group")) // wxFontFamily
+wxPROPERTY( Style, wxFontStyle, SetStyle, GetStyle, (wxFontStyle)wxNORMAL, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group")) // wxFontStyle
+wxPROPERTY( Weight, wxFontWeight, SetWeight, GetWeight, (wxFontWeight)wxNORMAL, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group")) // wxFontWeight
+wxPROPERTY( Underlined, bool, SetUnderlined, GetUnderlined, false, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Face, wxString, SetFaceName, GetFaceName, wxEMPTY_PARAMETER_VALUE, \
+           0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Encoding, wxFontEncoding, SetEncoding, GetEncoding, \
+           wxFONTENCODING_DEFAULT, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxEND_PROPERTIES_TABLE()
+
+wxCONSTRUCTOR_6( wxFont, int, Size, wxFontFamily, Family, wxFontStyle, Style, wxFontWeight, Weight, \
+                bool, Underlined, wxString, Face )
+
+wxEMPTY_HANDLERS_TABLE(wxFont)
+
 // ============================================================================
 // implementation
 // ============================================================================
 // helper functions
 // ----------------------------------------------------------------------------
 
-static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize)
+static inline int flags2Style(int flags)
 {
-    int currentSize = 0;
-    int largestGood = 0;
-    int smallestBad = 0;
-
-    bool initialGoodFound = false;
-    bool initialBadFound = false;
-
-    // NB: this assignment was separated from the variable definition
-    // in order to fix a gcc v3.3.3 compiler crash
-    currentSize = font.GetPointSize();
-    while (currentSize > 0)
-    {
-        dc.SetFont(font);
-
-        // if currentSize (in points) results in a font that is smaller
-        // than required by pixelSize it is considered a good size
-        if (dc.GetCharHeight() <= pixelSize.GetHeight() &&
-                (!pixelSize.GetWidth() ||
-                 dc.GetCharWidth() <= pixelSize.GetWidth()))
-        {
-            largestGood = currentSize;
-            initialGoodFound = true;
-        }
-        else
-        {
-            smallestBad = currentSize;
-            initialBadFound = true;
-        }
-        if (!initialGoodFound)
-        {
-            currentSize /= 2;
-        }
-        else if (!initialBadFound)
-        {
-            currentSize *= 2;
-        }
-        else
-        {
-            int distance = smallestBad - largestGood;
-            if (distance == 1)
-                break;
-
-            currentSize = largestGood + distance / 2;
-        }
+    return flags & wxFONTFLAG_ITALIC
+                    ? wxFONTSTYLE_ITALIC
+                    : flags & wxFONTFLAG_SLANT
+                        ? wxFONTSTYLE_SLANT
+                        : wxFONTSTYLE_NORMAL;
+}
 
-        font.SetPointSize(currentSize);
-    }
+static inline int flags2Weight(int flags)
+{
+    return flags & wxFONTFLAG_LIGHT
+                    ? wxFONTWEIGHT_LIGHT
+                    : flags & wxFONTFLAG_BOLD
+                        ? wxFONTWEIGHT_BOLD
+                        : wxFONTWEIGHT_NORMAL;
+}
 
-    if (currentSize != largestGood)
-        font.SetPointSize(largestGood);
+static inline bool flags2Underlined(int flags)
+{
+    return (flags & wxFONTFLAG_UNDERLINED) != 0;
 }
 
 // ----------------------------------------------------------------------------
@@ -119,7 +167,7 @@ void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding)
     // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT
     // and, besides, using this value here doesn't make any sense
     wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT,
-                 _T("can't set default encoding to wxFONTENCODING_DEFAULT") );
+                 wxT("can't set default encoding to wxFONTENCODING_DEFAULT") );
 
     ms_encodingDefault = encoding;
 }
@@ -131,9 +179,9 @@ wxFontBase::~wxFontBase()
 
 /* static */
 wxFont *wxFontBase::New(int size,
-                        int family,
-                        int style,
-                        int weight,
+                        wxFontFamily family,
+                        wxFontStyle style,
+                        wxFontWeight weight,
                         bool underlined,
                         const wxString& face,
                         wxFontEncoding encoding)
@@ -141,27 +189,17 @@ wxFont *wxFontBase::New(int size,
     return new wxFont(size, family, style, weight, underlined, face, encoding);
 }
 
-static inline int flags2Style(int flags)
-{
-    return flags & wxFONTFLAG_ITALIC
-                    ? wxFONTSTYLE_ITALIC
-                    : flags & wxFONTFLAG_SLANT
-                        ? wxFONTSTYLE_SLANT
-                        : wxFONTSTYLE_NORMAL;
-}
-
-static inline int flags2Weight(int flags)
-{
-    return flags & wxFONTFLAG_LIGHT
-                    ? wxFONTWEIGHT_LIGHT
-                    : flags & wxFONTFLAG_BOLD
-                        ? wxFONTWEIGHT_BOLD
-                        : wxFONTWEIGHT_NORMAL;
-}
-
-static inline bool flags2Underlined(int flags)
+/* static */
+wxFont *wxFontBase::New(const wxSize& pixelSize,
+                        wxFontFamily family,
+                        wxFontStyle style,
+                        wxFontWeight weight,
+                        bool underlined,
+                        const wxString& face,
+                        wxFontEncoding encoding)
 {
-    return (flags & wxFONTFLAG_UNDERLINED) != 0;
+    return new wxFont(pixelSize, family, style, weight, underlined,
+                      face, encoding);
 }
 
 /* static */
@@ -175,26 +213,6 @@ wxFont *wxFontBase::New(int pointSize,
                flags2Underlined(flags), face, encoding);
 }
 
-/* static */
-wxFont *wxFontBase::New(const wxSize& pixelSize,
-                        int family,
-                        int style,
-                        int weight,
-                        bool underlined,
-                        const wxString& face,
-                        wxFontEncoding encoding)
-{
-#if defined(__WXMSW__)
-    return new wxFont(pixelSize, family, style, weight, underlined,
-                      face, encoding);
-#else
-    wxFont *self = New(10, family, style, weight, underlined, face, encoding);
-    wxScreenDC dc;
-    AdjustFontSize(*(wxFont *)self, dc, pixelSize);
-    return self;
-#endif
-}
-
 /* static */
 wxFont *wxFontBase::New(const wxSize& pixelSize,
                         wxFontFamily family,
@@ -206,24 +224,6 @@ wxFont *wxFontBase::New(const wxSize& pixelSize,
                flags2Underlined(flags), face, encoding);
 }
 
-wxSize wxFontBase::GetPixelSize() const
-{
-    wxScreenDC dc;
-    dc.SetFont(*(wxFont *)this);
-    return wxSize(dc.GetCharWidth(), dc.GetCharHeight());
-}
-
-bool wxFontBase::IsUsingSizeInPixels() const
-{
-    return false;
-}
-
-void wxFontBase::SetPixelSize( const wxSize& pixelSize )
-{
-    wxScreenDC dc;
-    AdjustFontSize(*(wxFont *)this, dc, pixelSize);
-}
-
 /* static */
 wxFont *wxFontBase::New(const wxNativeFontInfo& info)
 {
@@ -245,6 +245,81 @@ bool wxFontBase::IsFixedWidth() const
     return GetFamily() == wxFONTFAMILY_TELETYPE;
 }
 
+wxSize wxFontBase::GetPixelSize() const
+{
+    wxScreenDC dc;
+    dc.SetFont(*(wxFont *)this);
+    return wxSize(dc.GetCharWidth(), dc.GetCharHeight());
+}
+
+bool wxFontBase::IsUsingSizeInPixels() const
+{
+    return false;
+}
+
+void wxFontBase::SetPixelSize( const wxSize& pixelSize )
+{
+    wxCHECK_RET( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0,
+                 "Negative values for the pixel size or zero pixel height are not allowed" );
+
+    wxScreenDC dc;
+
+    // NOTE: this algorithm for adjusting the font size is used by all
+    //       implementations of wxFont except under wxMSW and wxGTK where
+    //       native support to font creation using pixel-size is provided.
+
+    int largestGood = 0;
+    int smallestBad = 0;
+
+    bool initialGoodFound = false;
+    bool initialBadFound = false;
+
+    // NB: this assignment was separated from the variable definition
+    // in order to fix a gcc v3.3.3 compiler crash
+    int currentSize = GetPointSize();
+    while (currentSize > 0)
+    {
+        dc.SetFont(*static_cast<wxFont*>(this));
+
+        // if currentSize (in points) results in a font that is smaller
+        // than required by pixelSize it is considered a good size
+        // NOTE: the pixel size width may be zero
+        if (dc.GetCharHeight() <= pixelSize.GetHeight() &&
+                (pixelSize.GetWidth() == 0 ||
+                 dc.GetCharWidth() <= pixelSize.GetWidth()))
+        {
+            largestGood = currentSize;
+            initialGoodFound = true;
+        }
+        else
+        {
+            smallestBad = currentSize;
+            initialBadFound = true;
+        }
+        if (!initialGoodFound)
+        {
+            currentSize /= 2;
+        }
+        else if (!initialBadFound)
+        {
+            currentSize *= 2;
+        }
+        else
+        {
+            int distance = smallestBad - largestGood;
+            if (distance == 1)
+                break;
+
+            currentSize = largestGood + distance / 2;
+        }
+
+        SetPointSize(currentSize);
+    }
+
+    if (currentSize != largestGood)
+        SetPointSize(largestGood);
+}
+
 void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info)
 {
 #ifdef wxNO_NATIVE_FONTINFO
@@ -262,6 +337,8 @@ void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info)
 
 wxString wxFontBase::GetNativeFontInfoDesc() const
 {
+    wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
+
     wxString fontDesc;
     const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
     if ( fontInfo )
@@ -279,6 +356,8 @@ wxString wxFontBase::GetNativeFontInfoDesc() const
 
 wxString wxFontBase::GetNativeFontInfoUserDesc() const
 {
+    wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
+
     wxString fontDesc;
     const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
     if ( fontInfo )
@@ -303,7 +382,6 @@ bool wxFontBase::SetNativeFontInfo(const wxString& info)
         return true;
     }
 
-    UnRef();
     return false;
 }
 
@@ -316,7 +394,6 @@ bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info)
         return true;
     }
 
-    UnRef();
     return false;
 }
 
@@ -324,9 +401,9 @@ bool wxFontBase::operator==(const wxFont& font) const
 {
     // either it is the same font, i.e. they share the same common data or they
     // have different ref datas but still describe the same font
-    return GetFontData() == font.GetFontData() ||
+    return IsSameAs(font) ||
            (
-            Ok() == font.Ok() &&
+            IsOk() == font.IsOk() &&
             GetPointSize() == font.GetPointSize() &&
             // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses
             // operator==() resulting in infinite recursion so we can't use it
@@ -343,72 +420,161 @@ bool wxFontBase::operator==(const wxFont& font) const
            );
 }
 
-bool wxFontBase::operator!=(const wxFont& font) const
+wxFontFamily wxFontBase::GetFamily() const
 {
-    return !(*this == font);
+    wxCHECK_MSG( IsOk(), wxFONTFAMILY_UNKNOWN, wxS("invalid font") );
+
+    // Don't return wxFONTFAMILY_UNKNOWN from here because it prevents the code
+    // like wxFont(size, wxNORMAL_FONT->GetFamily(), ...) from working (see
+    // #12330). This is really just a hack but it allows to keep compatibility
+    // and doesn't really have any bad drawbacks so do this until someone comes
+    // up with a better idea.
+    const wxFontFamily family = DoGetFamily();
+
+    return family == wxFONTFAMILY_UNKNOWN ? wxFONTFAMILY_DEFAULT : family;
 }
 
 wxString wxFontBase::GetFamilyString() const
 {
-    wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
+    wxCHECK_MSG( IsOk(), "wxFONTFAMILY_DEFAULT", "invalid font" );
 
     switch ( GetFamily() )
     {
-        case wxDECORATIVE:   return wxT("wxDECORATIVE");
-        case wxROMAN:        return wxT("wxROMAN");
-        case wxSCRIPT:       return wxT("wxSCRIPT");
-        case wxSWISS:        return wxT("wxSWISS");
-        case wxMODERN:       return wxT("wxMODERN");
-        case wxTELETYPE:     return wxT("wxTELETYPE");
-        default:             return wxT("wxDEFAULT");
+        case wxFONTFAMILY_DECORATIVE:   return "wxFONTFAMILY_DECORATIVE";
+        case wxFONTFAMILY_ROMAN:        return "wxFONTFAMILY_ROMAN";
+        case wxFONTFAMILY_SCRIPT:       return "wxFONTFAMILY_SCRIPT";
+        case wxFONTFAMILY_SWISS:        return "wxFONTFAMILY_SWISS";
+        case wxFONTFAMILY_MODERN:       return "wxFONTFAMILY_MODERN";
+        case wxFONTFAMILY_TELETYPE:     return "wxFONTFAMILY_TELETYPE";
+        case wxFONTFAMILY_UNKNOWN:      return "wxFONTFAMILY_UNKNOWN";
+        default:                        return "wxFONTFAMILY_DEFAULT";
     }
 }
 
 wxString wxFontBase::GetStyleString() const
 {
-    wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
+    wxCHECK_MSG( IsOk(), "wxFONTSTYLE_DEFAULT", "invalid font" );
 
     switch ( GetStyle() )
     {
-        case wxNORMAL:   return wxT("wxNORMAL");
-        case wxSLANT:    return wxT("wxSLANT");
-        case wxITALIC:   return wxT("wxITALIC");
-        default:         return wxT("wxDEFAULT");
+        case wxFONTSTYLE_NORMAL:   return "wxFONTSTYLE_NORMAL";
+        case wxFONTSTYLE_SLANT:    return "wxFONTSTYLE_SLANT";
+        case wxFONTSTYLE_ITALIC:   return "wxFONTSTYLE_ITALIC";
+        default:                   return "wxFONTSTYLE_DEFAULT";
     }
 }
 
 wxString wxFontBase::GetWeightString() const
 {
-    wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
+    wxCHECK_MSG( IsOk(), "wxFONTWEIGHT_DEFAULT", "invalid font" );
 
     switch ( GetWeight() )
     {
-        case wxNORMAL:   return wxT("wxNORMAL");
-        case wxBOLD:     return wxT("wxBOLD");
-        case wxLIGHT:    return wxT("wxLIGHT");
-        default:         return wxT("wxDEFAULT");
+        case wxFONTWEIGHT_NORMAL:   return "wxFONTWEIGHT_NORMAL";
+        case wxFONTWEIGHT_BOLD:     return "wxFONTWEIGHT_BOLD";
+        case wxFONTWEIGHT_LIGHT:    return "wxFONTWEIGHT_LIGHT";
+        default:                    return "wxFONTWEIGHT_DEFAULT";
     }
 }
 
-bool wxFontBase::SetFaceName(const wxString &facename)
+bool wxFontBase::SetFaceName(const wxStringfacename)
 {
+#if wxUSE_FONTENUM
     if (!wxFontEnumerator::IsValidFacename(facename))
     {
-        UnRef();        // make Ok() return false
+        UnRef();        // make IsOk() return false
         return false;
     }
+#else // !wxUSE_FONTENUM
+    wxUnusedVar(facename);
+#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
 
     return true;
 }
 
+void wxFontBase::SetSymbolicSize(wxFontSymbolicSize size)
+{
+    SetSymbolicSizeRelativeTo(size, wxNORMAL_FONT->GetPointSize());
+}
+
+/* static */
+int wxFontBase::AdjustToSymbolicSize(wxFontSymbolicSize size, int base)
+{
+    // Using a fixed factor (1.2, from CSS2) is a bad idea as explained at
+    // http://www.w3.org/TR/CSS21/fonts.html#font-size-props so use the values
+    // from http://style.cleverchimp.com/font_size_intervals/altintervals.html
+    // instead.
+    static const float factors[] = { 0.60f, 0.75f, 0.89f, 1.f, 1.2f, 1.5f, 2.f };
+
+    wxCOMPILE_TIME_ASSERT
+    (
+        WXSIZEOF(factors) == wxFONTSIZE_XX_LARGE - wxFONTSIZE_XX_SMALL + 1,
+        WrongFontSizeFactorsSize
+    );
+
+    return wxRound(factors[size - wxFONTSIZE_XX_SMALL]*base);
+}
+
+wxFont& wxFont::MakeBold()
+{
+    SetWeight(wxFONTWEIGHT_BOLD);
+    return *this;
+}
+
+wxFont wxFont::Bold() const
+{
+    wxFont font(*this);
+    font.MakeBold();
+    return font;
+}
+
+wxFont& wxFont::MakeItalic()
+{
+    SetStyle(wxFONTSTYLE_ITALIC);
+    return *this;
+}
+
+wxFont wxFont::Italic() const
+{
+    wxFont font(*this);
+    font.MakeItalic();
+    return font;
+}
+
+wxFont& wxFont::MakeUnderlined()
+{
+    SetUnderlined(true);
+    return *this;
+}
+
+wxFont wxFont::Underlined() const
+{
+    wxFont font(*this);
+    font.MakeUnderlined();
+    return font;
+}
+
+wxFont& wxFont::Scale(float x)
+{
+    SetPointSize(int(x*GetPointSize() + 0.5));
+    return *this;
+}
+
+wxFont wxFont::Scaled(float x) const
+{
+    wxFont font(*this);
+    font.Scale(x);
+    return font;
+}
 
 // ----------------------------------------------------------------------------
 // wxNativeFontInfo
 // ----------------------------------------------------------------------------
 
 // Up to now, there are no native implementations of this function:
-void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames)
+void wxNativeFontInfo::SetFaceName(const wxArrayStringfacenames)
 {
+#if wxUSE_FONTENUM
     for (size_t i=0; i < facenames.GetCount(); i++)
     {
         if (wxFontEnumerator::IsValidFacename(facenames[i]))
@@ -422,6 +588,9 @@ void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames)
     wxString validfacename = wxFontEnumerator::GetFacenames().Item(0);
     wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str());
     SetFaceName(validfacename);
+#else // !wxUSE_FONTENUM
+    SetFaceName(facenames[0]);
+#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
 }
 
 
@@ -436,7 +605,7 @@ bool wxNativeFontInfo::FromString(const wxString& s)
 {
     long l;
 
-    wxStringTokenizer tokenizer(s, _T(";"));
+    wxStringTokenizer tokenizer(s, wxT(";"));
 
     wxString token = tokenizer.GetNextToken();
     //
@@ -487,7 +656,7 @@ wxString wxNativeFontInfo::ToString() const
 {
     wxString s;
 
-    s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"),
+    s.Printf(wxT("%d;%d;%d;%d;%d;%d;%s;%d"),
              0,                                 // version
              pointSize,
              family,
@@ -589,7 +758,7 @@ void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_)
 // format there anyhow (but there is a well-defined standard for X11 fonts used
 // by wxGTK and wxMotif)
 
-#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__)
+#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__) || defined(__WXOSX__)
 
 wxString wxNativeFontInfo::ToUserString() const
 {
@@ -605,7 +774,7 @@ wxString wxNativeFontInfo::ToUserString() const
     switch ( GetWeight() )
     {
         default:
-            wxFAIL_MSG( _T("unknown font weight") );
+            wxFAIL_MSG( wxT("unknown font weight") );
             // fall through
 
         case wxFONTWEIGHT_NORMAL:
@@ -623,7 +792,7 @@ wxString wxNativeFontInfo::ToUserString() const
     switch ( GetStyle() )
     {
         default:
-            wxFAIL_MSG( _T("unknown font style") );
+            wxFAIL_MSG( wxT("unknown font style") );
             // fall through
 
         case wxFONTSTYLE_NORMAL:
@@ -639,20 +808,74 @@ wxString wxNativeFontInfo::ToUserString() const
     wxString face = GetFaceName();
     if ( !face.empty() )
     {
-        desc << _T(' ') << face;
+        if (face.Contains(' ') || face.Contains(';') || face.Contains(','))
+        {
+            face.Replace("'", "");
+                // eventually remove quote characters: most systems do not
+                // allow them in a facename anyway so this usually does nothing
+
+            // make it possible for FromUserString() function to understand
+            // that the different words which compose this facename are
+            // not different adjectives or other data but rather all parts
+            // of the facename
+            desc << wxT(" '") << face << _("'");
+        }
+        else
+            desc << wxT(' ') << face;
+    }
+    else // no face name specified
+    {
+        // use the family
+        wxString familyStr;
+        switch ( GetFamily() )
+        {
+            case wxFONTFAMILY_DECORATIVE:
+                familyStr = "decorative";
+                break;
+
+            case wxFONTFAMILY_ROMAN:
+                familyStr = "roman";
+                break;
+
+            case wxFONTFAMILY_SCRIPT:
+                familyStr = "script";
+                break;
+
+            case wxFONTFAMILY_SWISS:
+                familyStr = "swiss";
+                break;
+
+            case wxFONTFAMILY_MODERN:
+                familyStr = "modern";
+                break;
+
+            case wxFONTFAMILY_TELETYPE:
+                familyStr = "teletype";
+                break;
+
+            case wxFONTFAMILY_DEFAULT:
+            case wxFONTFAMILY_UNKNOWN:
+                break;
+
+            default:
+                wxFAIL_MSG( "unknown font family" );
+        }
+
+        if ( !familyStr.empty() )
+            desc << " '" << familyStr << " family'";
     }
 
     int size = GetPointSize();
     if ( size != wxNORMAL_FONT->GetPointSize() )
     {
-        desc << _T(' ') << size;
+        desc << wxT(' ') << size;
     }
 
 #if wxUSE_FONTMAP
     wxFontEncoding enc = GetEncoding();
     if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM )
     {
-        desc << _T(' ') << wxFontMapper::GetEncodingName(enc);
+        desc << wxT(' ') << wxFontMapper::GetEncodingName(enc);
     }
 #endif // wxUSE_FONTMAP
 
@@ -664,10 +887,13 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
     // reset to the default state
     Init();
 
+    // ToUserString() will quote the facename if it contains spaces, commas
+    // or semicolons: we must be able to understand that quoted text is
+    // a single token:
+    wxString toparse(s);
+
     // parse a more or less free form string
-    //
-    // TODO: we should handle at least the quoted facenames
-    wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK);
+    wxStringTokenizer tokenizer(toparse, wxT(";, "), wxTOKEN_STRTOK);
 
     wxString face;
     unsigned long size;
@@ -675,6 +901,7 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
 #if wxUSE_FONTMAP
     bool encodingfound = false;
 #endif
+    bool insideQuotes = false;
 
     while ( tokenizer.HasMoreTokens() )
     {
@@ -682,23 +909,51 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
 
         // normalize it
         token.Trim(true).Trim(false).MakeLower();
+        if (insideQuotes)
+        {
+            if (token.StartsWith("'") ||
+                token.EndsWith("'"))
+            {
+                insideQuotes = false;
+
+                // add this last token to the facename:
+                face += " " + token;
+
+                // normalize facename:
+                face = face.Trim(true).Trim(false);
+                face.Replace("'", "");
+
+                continue;
+            }
+        }
+        else
+        {
+            if (token.StartsWith("'"))
+                insideQuotes = true;
+        }
 
         // look for the known tokens
-        if ( token == _T("underlined") || token == _("underlined") )
+        if ( insideQuotes )
+        {
+            // only the facename may be quoted:
+            face += " " + token;
+            continue;
+        }
+        if ( token == wxT("underlined") || token == _("underlined") )
         {
             SetUnderlined(true);
         }
-        else if ( token == _T("light") || token == _("light") )
+        else if ( token == wxT("light") || token == _("light") )
         {
             SetWeight(wxFONTWEIGHT_LIGHT);
             weightfound = true;
         }
-        else if ( token == _T("bold") || token == _("bold") )
+        else if ( token == wxT("bold") || token == _("bold") )
         {
             SetWeight(wxFONTWEIGHT_BOLD);
             weightfound = true;
         }
-        else if ( token == _T("italic") || token == _("italic") )
+        else if ( token == wxT("italic") || token == _("italic") )
         {
             SetStyle(wxFONTSTYLE_ITALIC);
         }
@@ -725,7 +980,7 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
                 // assume it is the face name
             if ( !face.empty() )
             {
-                face += _T(' ');
+                face += wxT(' ');
             }
 
             face += token;
@@ -743,12 +998,40 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
         // bar")
         if ( !face.empty() )
         {
+            wxString familyStr;
+            if ( face.EndsWith(" family", &familyStr) )
+            {
+                // it's not a facename but rather a font family
+                wxFontFamily family;
+                if ( familyStr == "decorative" )
+                    family = wxFONTFAMILY_DECORATIVE;
+                else if ( familyStr == "roman" )
+                    family = wxFONTFAMILY_ROMAN;
+                else if ( familyStr == "script" )
+                    family = wxFONTFAMILY_SCRIPT;
+                else if ( familyStr == "swiss" )
+                    family = wxFONTFAMILY_SWISS;
+                else if ( familyStr == "modern" )
+                    family = wxFONTFAMILY_MODERN;
+                else if ( familyStr == "teletype" )
+                    family = wxFONTFAMILY_TELETYPE;
+                else
+                    return false;
+
+                SetFamily(family);
+            }
             // NB: the check on the facename is implemented in wxFontBase::SetFaceName
-            //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+            //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitly
             //     call here wxFontEnumerator::IsValidFacename
-            if (!wxFontEnumerator::IsValidFacename(face) ||
-                !SetFaceName(face))
+            else if (
+#if wxUSE_FONTENUM
+                    !wxFontEnumerator::IsValidFacename(face) ||
+#endif // wxUSE_FONTENUM
+                    !SetFaceName(face) )
+            {
                 SetFaceName(wxNORMAL_FONT->GetFaceName());
+            }
+
             face.clear();
         }
     }
@@ -757,11 +1040,16 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
     if ( !face.empty() )
     {
         // NB: the check on the facename is implemented in wxFontBase::SetFaceName
-        //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+        //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitly
         //     call here wxFontEnumerator::IsValidFacename
-        if (!wxFontEnumerator::IsValidFacename(face) ||
-            !SetFaceName(face))
-            SetFaceName(wxNORMAL_FONT->GetFaceName());
+        if (
+#if wxUSE_FONTENUM
+                !wxFontEnumerator::IsValidFacename(face) ||
+#endif // wxUSE_FONTENUM
+                !SetFaceName(face) )
+            {
+                SetFaceName(wxNORMAL_FONT->GetFaceName());
+            }
     }
 
     // set point size to default value if size was not given
@@ -782,3 +1070,26 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
 }
 
 #endif // generic or wxMSW or wxOS2
+
+
+// wxFont <-> wxString utilities, used by wxConfig
+wxString wxToString(const wxFontBase& font)
+{
+    return font.IsOk() ? font.GetNativeFontInfoDesc()
+                       : wxString();
+}
+
+bool wxFromString(const wxString& str, wxFontBase *font)
+{
+    wxCHECK_MSG( font, false, wxT("NULL output parameter") );
+
+    if ( str.empty() )
+    {
+        *font = wxNullFont;
+        return true;
+    }
+
+    return font->SetNativeFontInfo(str);
+}
+
+