///////////////////////////////////////////////////////////////////////////// // Name: src/mgl/fontutil.cpp // Purpose: Font helper functions for MGL // Author: Vaclav Slavik // Created: 2001/04/29 // RCS-ID: $Id$ // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/hash.h" #include "wx/log.h" #endif #include "wx/fontutil.h" #include "wx/encinfo.h" #include "wx/fontmap.h" #include "wx/tokenzr.h" #include "wx/listimpl.cpp" #include "wx/sysopt.h" #include "wx/mgl/private.h" #include // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // wxNativeEncodingInfo // ---------------------------------------------------------------------------- // convert to/from the string representation: format is // encoding[;facename] bool wxNativeEncodingInfo::FromString(const wxString& s) { wxStringTokenizer tokenizer(s, _T(";")); wxString encid = tokenizer.GetNextToken(); long enc; if ( !encid.ToLong(&enc) ) return false; encoding = (wxFontEncoding)enc; // ok even if empty facename = tokenizer.GetNextToken(); return true; } wxString wxNativeEncodingInfo::ToString() const { wxString s; s << (long)encoding; if ( !facename.empty() ) { s << _T(';') << facename; } return s; } // ---------------------------------------------------------------------------- // common functions // ---------------------------------------------------------------------------- bool wxGetNativeFontEncoding(wxFontEncoding encoding, wxNativeEncodingInfo *info) { wxCHECK_MSG( info, false, _T("bad pointer in wxGetNativeFontEncoding") ); if ( encoding == wxFONTENCODING_DEFAULT ) { encoding = wxFont::GetDefaultEncoding(); } switch ( encoding ) { case wxFONTENCODING_ISO8859_1: case wxFONTENCODING_ISO8859_2: case wxFONTENCODING_ISO8859_3: case wxFONTENCODING_ISO8859_4: case wxFONTENCODING_ISO8859_5: case wxFONTENCODING_ISO8859_6: case wxFONTENCODING_ISO8859_7: case wxFONTENCODING_ISO8859_8: case wxFONTENCODING_ISO8859_9: case wxFONTENCODING_ISO8859_10: case wxFONTENCODING_ISO8859_11: case wxFONTENCODING_ISO8859_13: case wxFONTENCODING_ISO8859_14: case wxFONTENCODING_ISO8859_15: info->mglEncoding = MGL_ENCODING_ISO8859_1 + (encoding - wxFONTENCODING_ISO8859_1); break; case wxFONTENCODING_KOI8: info->mglEncoding = MGL_ENCODING_KOI8; break; case wxFONTENCODING_CP1250: case wxFONTENCODING_CP1251: case wxFONTENCODING_CP1252: case wxFONTENCODING_CP1253: case wxFONTENCODING_CP1254: case wxFONTENCODING_CP1255: case wxFONTENCODING_CP1256: case wxFONTENCODING_CP1257: info->mglEncoding = MGL_ENCODING_CP1250 + (encoding - wxFONTENCODING_CP1250); break; case wxFONTENCODING_SYSTEM: info->mglEncoding = MGL_ENCODING_ASCII; break; default: // encoding not known to MGL return false; } info->encoding = encoding; return true; } bool wxTestFontEncoding(const wxNativeEncodingInfo& info) { if ( !info.facename ) return true; wxMGLFontFamily *family = wxTheFontsManager->GetFamily(info.facename); if ( !family ) return false; if ( family->GetInfo()->fontLibType == MGL_BITMAPFONT_LIB ) return (info.mglEncoding == MGL_ENCODING_ASCII || info.mglEncoding == MGL_ENCODING_ISO8859_1 || info.mglEncoding == MGL_ENCODING_ISO8859_15 || info.mglEncoding == MGL_ENCODING_CP1252); else return true; } // ---------------------------------------------------------------------------- // wxFontFamily, wxMGLFontInstance, wxMGLFontLibrary // ---------------------------------------------------------------------------- WX_DECLARE_LIST(wxMGLFontInstance, wxMGLFontInstanceList); WX_DEFINE_LIST(wxMGLFontInstanceList) WX_DEFINE_LIST(wxMGLFontFamilyList) wxMGLFontInstance::wxMGLFontInstance(wxMGLFontLibrary *fontLib, float pt, bool slant, bool aa) { m_fontLib = fontLib; m_font = NULL; m_pt = pt; m_slant = slant; m_aa = aa; float slantAngle = m_slant ? 15.0 : 0.0; wxLogTrace("mgl_font", "loading instance of '%s' slant=%i pt=%0.1f aa=%i", m_fontLib->GetMGLfont_lib_t()->name, m_slant, m_pt, m_aa); m_font = MGL_loadFontInstance(m_fontLib->GetMGLfont_lib_t(), m_pt, slantAngle, 0.0, aa); wxASSERT_MSG( m_font, wxT("Cannot create font instance.") ); } wxMGLFontInstance::~wxMGLFontInstance() { wxLogTrace("mgl_font", "unloading instance of '%s' slant=%i pt=%0.1f aa=%i", m_fontLib->GetMGLfont_lib_t()->name, m_slant, m_pt, m_aa); if ( m_font ) MGL_unloadFontInstance(m_font); } wxMGLFontLibrary::wxMGLFontLibrary(const wxString& filename, int type, wxMGLFontFamily *parentFamily) { m_family = parentFamily; m_type = type; m_fileName = filename; m_refs = 0; m_fontLib = NULL; m_instances = new wxMGLFontInstanceList; m_instances->DeleteContents(true); } wxMGLFontLibrary::~wxMGLFontLibrary() { wxLogTrace("mgl_font", "font library dtor '%s'", m_fileName.mb_str()); delete m_instances; } void wxMGLFontLibrary::IncRef() { wxLogTrace("mgl_font", "incRef(%u) '%s'", m_refs, m_fileName.c_str()); if ( m_refs++ == 0 ) { wxLogTrace("mgl_font", "opening library '%s'", m_fileName.mb_str()); m_fontLib = MGL_openFontLib(m_fileName.mb_str()); } } void wxMGLFontLibrary::DecRef() { wxLogTrace("mgl_font", "decRef(%u) '%s'", m_refs, m_fileName.c_str()); if ( --m_refs == 0 ) { wxLogTrace("mgl_font", "killing instances of '%s'", m_fileName.mb_str()); m_instances->Clear(); wxLogTrace("mgl_font", "closing library '%s'", m_fileName.mb_str()); MGL_closeFontLib(m_fontLib); m_fontLib = NULL; } } static int gs_antialiasingThreshold = -1; wxMGLFontInstance *wxMGLFontLibrary::GetFontInstance(wxFont *font, float scale, bool aa) { wxASSERT_MSG(m_refs > 0 && m_fontLib, wxT("font library not loaded!")); wxString facename; float pt = (float)font->GetPointSize() * scale; if ( gs_antialiasingThreshold == -1 ) { gs_antialiasingThreshold = 10; #if wxUSE_SYSTEM_OPTIONS if ( wxSystemOptions::HasOption(wxT("mgl.aa-threshold")) ) gs_antialiasingThreshold = wxSystemOptions::GetOptionInt(wxT("mgl.aa-threshold")); wxLogTrace("mgl_font", "AA threshold set to %i", gs_antialiasingThreshold); #endif } // Small characters don't look good when antialiased with the algorithm // that FreeType uses (mere 2x2 supersampling), so lets disable it AA // completely for small fonts. bool antialiased = false; if (( pt > gs_antialiasingThreshold ) && ( m_fontLib->fontLibType != MGL_BITMAPFONT_LIB ) ) antialiased = aa; bool slant = (((m_type & wxFONTFACE_ITALIC) == 0) && (font->GetStyle() == wxSLANT || font->GetStyle() == wxITALIC)); // FIXME_MGL -- MGL does not yet support slant, although the API is there slant = false; wxLogTrace("mgl_font", "requested instance of '%s' slant=%i pt=%0.1f aa=%i", m_fileName.mb_str(), slant, pt, antialiased); wxMGLFontInstance *i; wxMGLFontInstanceList::Node *node; for (node = m_instances->GetFirst(); node; node = node->GetNext()) { i = node->GetData(); if ( i->GetPt() == pt && i->GetSlant() == slant && i->GetAA() == antialiased ) { wxLogTrace("mgl_font", " got from cache: slant=%i pt=%0.1f aa=%i", i->GetSlant(), i->GetPt(), i->GetAA()); return i; } } i = new wxMGLFontInstance(this, pt, slant, antialiased); m_instances->Append(i); return i; } wxMGLFontFamily::wxMGLFontFamily(const font_info_t *info) { m_name = info->familyName; m_fontInfo = info; if ( info->regularFace[0] == '\0' ) m_fontLibs[wxFONTFACE_REGULAR] = NULL; else m_fontLibs[wxFONTFACE_REGULAR] = new wxMGLFontLibrary(info->regularFace, wxFONTFACE_REGULAR, this); if ( info->italicFace[0] == '\0' ) m_fontLibs[wxFONTFACE_ITALIC] = NULL; else m_fontLibs[wxFONTFACE_ITALIC] = new wxMGLFontLibrary(info->italicFace, wxFONTFACE_ITALIC, this); if ( info->boldFace[0] == '\0' ) m_fontLibs[wxFONTFACE_BOLD] = NULL; else m_fontLibs[wxFONTFACE_BOLD] = new wxMGLFontLibrary(info->boldFace, wxFONTFACE_BOLD, this); if ( info->boldItalicFace[0] == '\0' ) m_fontLibs[wxFONTFACE_BOLD_ITALIC] = NULL; else m_fontLibs[wxFONTFACE_BOLD_ITALIC] = new wxMGLFontLibrary(info->boldItalicFace, wxFONTFACE_BOLD_ITALIC, this); wxLogTrace("mgl_font", "new family '%s' (r=%s, i=%s, b=%s, bi=%s)\n", info->familyName, info->regularFace, info->italicFace, info->boldFace, info->boldItalicFace); } wxMGLFontFamily::~wxMGLFontFamily() { for (size_t i = 0; i < wxFONTFACE_MAX; i++) delete m_fontLibs[i]; } bool wxMGLFontFamily::HasFace(int type) const { return (m_fontLibs[type] != NULL); } // ---------------------------------------------------------------------------- // wxFontsManager // ---------------------------------------------------------------------------- wxMGLFontLibrary *wxFontsManager::GetFontLibrary(wxFont *font) { wxMGLFontFamily *family; int type; wxString facename = font->GetFaceName(); if ( !facename.empty() ) family = GetFamily(facename); else family = NULL; if ( !family ) { facename.Empty(); switch (font->GetFamily()) { case wxSCRIPT: facename = wxT("Script"); break; case wxDECORATIVE: facename = wxT("Charter"); break; case wxROMAN: facename = wxT("Times"); break; case wxTELETYPE: case wxMODERN: facename = wxT("Courier"); break; case wxSWISS: facename = wxT("Helvetica"); break; case wxDEFAULT: default: facename = wxT("Helvetica"); break; } family = GetFamily(facename); if ( !family ) { if ( m_list->GetFirst() ) family = m_list->GetFirst()->GetData(); else wxFAIL_MSG(wxT("Fatal error, no fonts available!")); } } type = wxFONTFACE_REGULAR; if ( font->GetWeight() == wxBOLD ) type |= wxFONTFACE_BOLD; // FIXME_MGL -- this should read "if ( font->GetStyle() == wxITALIC )", // but since MGL does not yet support slant, we try to display it with // italic face (better than nothing...) if ( font->GetStyle() == wxITALIC || font->GetStyle() == wxSLANT ) { if ( family->HasFace(type | wxFONTFACE_ITALIC) ) type |= wxFONTFACE_ITALIC; } if ( !family->HasFace(type) ) { for (int i = 0; i < wxFONTFACE_MAX; i++) if ( family->HasFace(i) ) { type = i; break; } } return family->GetLibrary(type); } static ibool MGLAPI enum_callback(const font_info_t *info, void *cookie) { wxFontsManager *db = (wxFontsManager*)cookie; db->AddFamily(info); return TRUE; } wxFontsManager::wxFontsManager() { m_hash = new wxHashTable(wxKEY_STRING); m_hash->DeleteContents(false); m_list = new wxMGLFontFamilyList; m_list->DeleteContents(true); MGL_enumerateFonts(enum_callback, (void*)this); } wxFontsManager::~wxFontsManager() { delete m_hash; delete m_list; } void wxFontsManager::AddFamily(const font_info_t *info) { wxMGLFontFamily *f = new wxMGLFontFamily(info); m_hash->Put(f->GetName().Lower(), f); m_list->Append(f); } wxMGLFontFamily *wxFontsManager::GetFamily(const wxString& name) const { return (wxMGLFontFamily*)m_hash->Get(name.Lower()); } wxFontsManager *wxTheFontsManager = NULL;