+#include "wx/fontmap.h"
+#include "wx/tokenzr.h"
+#include "wx/fontenum.h"
+
+#if wxUSE_PANGO
+
+#include "pango/pango.h"
+
+#ifdef __WXGTK20__
+ #include "wx/gtk/private.h"
+ extern GtkWidget *wxGetRootWindow();
+
+ #define wxPANGO_CONV wxGTK_CONV_SYS
+ #define wxPANGO_CONV_BACK wxGTK_CONV_BACK_SYS
+#else
+ #include "wx/x11/private.h"
+ #include "wx/gtk/private/string.h"
+
+ #define wxPANGO_CONV(s) s.utf8_str()
+ #define wxPANGO_CONV_BACK(s) wxString::FromUTF8Unchecked(s)
+#endif
+
+// ----------------------------------------------------------------------------
+// wxNativeFontInfo
+// ----------------------------------------------------------------------------
+
+void wxNativeFontInfo::Init()
+{
+ description = NULL;
+ m_underlined = false;
+ m_strikethrough = false;
+}
+
+void wxNativeFontInfo::Init(const wxNativeFontInfo& info)
+{
+ if (info.description)
+ {
+ description = pango_font_description_copy(info.description);
+ m_underlined = info.GetUnderlined();
+ m_strikethrough = info.GetStrikethrough();
+ }
+ else
+ {
+ description = NULL;
+ m_underlined = false;
+ m_strikethrough = false;
+ }
+}
+
+void wxNativeFontInfo::Free()
+{
+ if (description)
+ pango_font_description_free(description);
+}
+
+int wxNativeFontInfo::GetPointSize() const
+{
+ return pango_font_description_get_size( description ) / PANGO_SCALE;
+}
+
+wxFontStyle wxNativeFontInfo::GetStyle() const
+{
+ wxFontStyle m_style = wxFONTSTYLE_NORMAL;
+
+ switch (pango_font_description_get_style( description ))
+ {
+ case PANGO_STYLE_NORMAL:
+ m_style = wxFONTSTYLE_NORMAL;
+ break;
+ case PANGO_STYLE_ITALIC:
+ m_style = wxFONTSTYLE_ITALIC;
+ break;
+ case PANGO_STYLE_OBLIQUE:
+ m_style = wxFONTSTYLE_SLANT;
+ break;
+ }
+
+ return m_style;
+}
+
+wxFontWeight wxNativeFontInfo::GetWeight() const
+{
+ // We seem to currently initialize only by string.
+ // In that case PANGO_FONT_MASK_WEIGHT is always set.
+ // if (!(pango_font_description_get_set_fields(description) & PANGO_FONT_MASK_WEIGHT))
+ // return wxFONTWEIGHT_NORMAL;
+
+ PangoWeight pango_weight = pango_font_description_get_weight( description );
+
+ // Until the API can be changed the following ranges of weight values are used:
+ // wxFONTWEIGHT_LIGHT: 100 .. 349 - range of 250
+ // wxFONTWEIGHT_NORMAL: 350 .. 599 - range of 250
+ // wxFONTWEIGHT_BOLD: 600 .. 900 - range of 301 (600 is "semibold" already)
+
+ if (pango_weight >= 600)
+ return wxFONTWEIGHT_BOLD;
+
+ if (pango_weight < 350)
+ return wxFONTWEIGHT_LIGHT;
+
+ return wxFONTWEIGHT_NORMAL;
+}
+
+bool wxNativeFontInfo::GetUnderlined() const
+{
+ return m_underlined;
+}
+
+bool wxNativeFontInfo::GetStrikethrough() const
+{
+ return m_strikethrough;
+}
+
+wxString wxNativeFontInfo::GetFaceName() const
+{
+ // the Pango "family" is the wx "face name"
+ return wxPANGO_CONV_BACK(pango_font_description_get_family(description));
+}
+
+wxFontFamily wxNativeFontInfo::GetFamily() const
+{
+ wxFontFamily ret = wxFONTFAMILY_UNKNOWN;
+
+ const char *family_name = pango_font_description_get_family( description );
+
+ // note: not passing -1 as the 2nd parameter to g_ascii_strdown to work
+ // around a bug in the 64-bit glib shipped with solaris 10, -1 causes it
+ // to try to allocate 2^32 bytes.
+ if ( !family_name )
+ return ret;
+ wxGtkString family_text(g_ascii_strdown(family_name, strlen(family_name)));
+
+ // Check for some common fonts, to salvage what we can from the current
+ // win32 centric wxFont API:
+ if (wxStrnicmp( family_text, "monospace", 9 ) == 0)
+ ret = wxFONTFAMILY_TELETYPE; // begins with "Monospace"
+ else if (wxStrnicmp( family_text, "courier", 7 ) == 0)
+ ret = wxFONTFAMILY_TELETYPE; // begins with "Courier"
+#if defined(__WXGTK20__) || defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
+ else
+ {
+ PangoFontFamily **families;
+ PangoFontFamily *family = NULL;
+ int n_families;
+ pango_context_list_families(
+#ifdef __WXGTK20__
+ gtk_widget_get_pango_context( wxGetRootWindow() ),
+#else
+ wxTheApp->GetPangoContext(),
+#endif
+ &families, &n_families);
+
+ for (int i = 0; i < n_families; ++i)
+ {
+ if (g_ascii_strcasecmp(pango_font_family_get_name( families[i] ),
+ pango_font_description_get_family( description )) == 0 )
+ {
+ family = families[i];
+ break;
+ }
+ }
+
+ g_free(families);
+
+ // Some gtk+ systems might query for a non-existing font from
+ // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) on initialization,
+ // don't assert until wxSystemSettings::GetFont is checked for this - MR
+ // wxASSERT_MSG( family, "No appropriate PangoFontFamily found for ::description" );
+
+ if (family != NULL && pango_font_family_is_monospace( family ))
+ ret = wxFONTFAMILY_TELETYPE; // is deemed a monospace font by pango
+ }
+#endif // GTK+ 2 || HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE
+
+ if (ret == wxFONTFAMILY_UNKNOWN)
+ {
+ if (strstr( family_text, "sans" ) != NULL || strstr( family_text, "Sans" ) != NULL)
+ // checked before serif, so that "* Sans Serif" fonts are detected correctly
+ ret = wxFONTFAMILY_SWISS; // contains "Sans"
+ else if (strstr( family_text, "serif" ) != NULL || strstr( family_text, "Serif" ) != NULL)
+ ret = wxFONTFAMILY_ROMAN; // contains "Serif"
+ else if (wxStrnicmp( family_text, "times", 5 ) == 0)
+ ret = wxFONTFAMILY_ROMAN; // begins with "Times"
+ else if (wxStrnicmp( family_text, "old", 3 ) == 0)
+ ret = wxFONTFAMILY_DECORATIVE; // begins with "Old" - "Old English", "Old Town"
+ }
+
+ return ret;
+}
+
+wxFontEncoding wxNativeFontInfo::GetEncoding() const
+{
+ return wxFONTENCODING_SYSTEM;
+}
+
+void wxNativeFontInfo::SetPointSize(int pointsize)
+{
+ pango_font_description_set_size( description, pointsize * PANGO_SCALE );
+}
+
+void wxNativeFontInfo::SetStyle(wxFontStyle style)
+{
+ switch (style)
+ {
+ case wxFONTSTYLE_ITALIC:
+ pango_font_description_set_style( description, PANGO_STYLE_ITALIC );
+ break;
+ case wxFONTSTYLE_SLANT:
+ pango_font_description_set_style( description, PANGO_STYLE_OBLIQUE );
+ break;
+ default:
+ wxFAIL_MSG( "unknown font style" );
+ // fall through
+ case wxFONTSTYLE_NORMAL:
+ pango_font_description_set_style( description, PANGO_STYLE_NORMAL );
+ break;
+ }
+}
+
+void wxNativeFontInfo::SetWeight(wxFontWeight weight)
+{
+ switch (weight)
+ {
+ case wxFONTWEIGHT_BOLD:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
+ break;
+ case wxFONTWEIGHT_LIGHT:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_LIGHT);
+ break;
+ default:
+ wxFAIL_MSG( "unknown font weight" );
+ // fall through
+ case wxFONTWEIGHT_NORMAL:
+ pango_font_description_set_weight(description, PANGO_WEIGHT_NORMAL);
+ }
+}
+
+void wxNativeFontInfo::SetUnderlined(bool underlined)
+{
+ // Pango doesn't have the underlined attribute so we store it separately
+ // (and handle it specially in wxWindowDCImpl::DoDrawText()).
+ m_underlined = underlined;
+}
+
+void wxNativeFontInfo::SetStrikethrough(bool strikethrough)
+{
+ // As with the underlined attribute above, we handle this one separately as
+ // Pango doesn't support it as part of the font description.
+ m_strikethrough = strikethrough;
+}
+
+bool wxNativeFontInfo::SetFaceName(const wxString& facename)
+{
+ pango_font_description_set_family(description, wxPANGO_CONV(facename));
+
+ // we return true because Pango doesn't tell us if the call failed or not;
+ // instead on wxGTK wxFont::SetFaceName() will call wxFontBase::SetFaceName()
+ // which does the check
+ return true;
+}
+
+void wxNativeFontInfo::SetFamily(wxFontFamily family)
+{
+ wxArrayString facename;
+
+ // the list of fonts associated with a family was partially
+ // taken from http://www.codestyle.org/css/font-family
+
+ switch ( family )
+ {
+ case wxFONTFAMILY_SCRIPT:
+ // corresponds to the cursive font family in the page linked above
+ facename.Add(wxS("URW Chancery L"));
+ facename.Add(wxS("Comic Sans MS"));
+ break;
+
+ case wxFONTFAMILY_DECORATIVE:
+ // corresponds to the fantasy font family in the page linked above
+ facename.Add(wxS("Impact"));
+ break;
+
+ case wxFONTFAMILY_ROMAN:
+ // corresponds to the serif font family in the page linked above
+ facename.Add(wxS("Serif"));
+ facename.Add(wxS("DejaVu Serif"));
+ facename.Add(wxS("DejaVu LGC Serif"));
+ facename.Add(wxS("Bitstream Vera Serif"));
+ facename.Add(wxS("Liberation Serif"));
+ facename.Add(wxS("FreeSerif"));
+ facename.Add(wxS("Luxi Serif"));
+ facename.Add(wxS("Times New Roman"));
+ facename.Add(wxS("Century Schoolbook L"));
+ facename.Add(wxS("URW Bookman L"));
+ facename.Add(wxS("URW Palladio L"));
+ facename.Add(wxS("Times"));
+ break;
+
+ case wxFONTFAMILY_TELETYPE:
+ case wxFONTFAMILY_MODERN:
+ // corresponds to the monospace font family in the page linked above
+ facename.Add(wxS("Monospace"));
+ facename.Add(wxS("DejaVu Sans Mono"));
+ facename.Add(wxS("DejaVu LGC Sans Mono"));
+ facename.Add(wxS("Bitstream Vera Sans Mono"));
+ facename.Add(wxS("Liberation Mono"));
+ facename.Add(wxS("FreeMono"));
+ facename.Add(wxS("Luxi Mono"));
+ facename.Add(wxS("Courier New"));
+ facename.Add(wxS("Lucida Sans Typewriter"));
+ facename.Add(wxS("Nimbus Mono L"));
+ facename.Add(wxS("Andale Mono"));
+ facename.Add(wxS("Courier"));
+ break;
+
+ case wxFONTFAMILY_SWISS:
+ case wxFONTFAMILY_DEFAULT:
+ default:
+ // corresponds to the sans-serif font family in the page linked above
+ facename.Add(wxS("Sans"));
+ facename.Add(wxS("DejaVu Sans"));
+ facename.Add(wxS("DejaVu LGC Sans"));
+ facename.Add(wxS("Bitstream Vera Sans"));
+ facename.Add(wxS("Liberation Sans"));
+ facename.Add(wxS("FreeSans"));
+ facename.Add(wxS("Luxi Sans"));
+ facename.Add(wxS("Arial"));
+ facename.Add(wxS("Lucida Sans"));
+ facename.Add(wxS("Nimbus Sans L"));
+ facename.Add(wxS("URW Gothic L"));
+ break;
+ }
+
+ SetFaceName(facename);
+}
+
+void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding))
+{
+ wxFAIL_MSG( "not implemented: Pango encoding is always UTF8" );
+}
+
+bool wxNativeFontInfo::FromString(const wxString& s)
+{
+ wxString str(s);
+
+ // Pango font description doesn't have 'underlined' or 'strikethrough'
+ // attributes, so we handle them specially by extracting them from the
+ // string before passing it to Pango.
+ m_underlined = str.StartsWith(wxS("underlined "), &str);
+ m_strikethrough = str.StartsWith(wxS("strikethrough "), &str);
+
+ if (description)
+ pango_font_description_free( description );
+
+ // there is a bug in at least pango <= 1.13 which makes it (or its backends)
+ // segfault for very big point sizes and for negative point sizes.
+ // To workaround that bug for pango <= 1.13
+ // (see http://bugzilla.gnome.org/show_bug.cgi?id=340229)
+ // we do the check on the size here using same (arbitrary) limits used by
+ // pango > 1.13. Note that the segfault could happen also for pointsize
+ // smaller than this limit !!
+ const size_t pos = str.find_last_of(wxS(" "));
+ double size;
+ if ( pos != wxString::npos && wxString(str, pos + 1).ToDouble(&size) )
+ {
+ wxString sizeStr;
+ if ( size < 1 )
+ sizeStr = wxS("1");
+ else if ( size >= 1E6 )
+ sizeStr = wxS("1E6");
+
+ if ( !sizeStr.empty() )
+ {
+ // replace the old size with the adjusted one
+ str = wxString(s, 0, pos) + sizeStr;
+ }
+ }
+
+ description = pango_font_description_from_string(wxPANGO_CONV(str));
+
+#if wxUSE_FONTENUM
+ // ensure a valid facename is selected
+ if (!wxFontEnumerator::IsValidFacename(GetFaceName()))
+ SetFaceName(wxNORMAL_FONT->GetFaceName());
+#endif // wxUSE_FONTENUM
+
+ return true;
+}
+
+wxString wxNativeFontInfo::ToString() const
+{
+ wxGtkString str(pango_font_description_to_string( description ));
+ wxString desc = wxPANGO_CONV_BACK(str);
+
+ // Augment the string with the attributes not handled by Pango.
+ //
+ // Notice that we must add them in the same order they are extracted in
+ // FromString() above.
+ if (m_strikethrough)
+ desc.insert(0, wxS("strikethrough "));
+ if (m_underlined)
+ desc.insert(0, wxS("underlined "));
+
+ return desc;
+}
+
+bool wxNativeFontInfo::FromUserString(const wxString& s)
+{
+ return FromString( s );
+}
+
+wxString wxNativeFontInfo::ToUserString() const
+{
+ return ToString();
+}
+
+#else // GTK+ 1.x
+