///////////////////////////////////////////////////////////////////////////// // Name: font.cpp // Purpose: // Author: Robert Roebling // Id: $id$ // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "font.h" #endif #include "wx/font.h" #include "wx/utils.h" #include //----------------------------------------------------------------------------- // local data //----------------------------------------------------------------------------- extern wxFontNameDirectory *wxTheFontNameDirectory; //----------------------------------------------------------------------------- // wxFont //----------------------------------------------------------------------------- class wxFontRefData: public wxObjectRefData { public: wxFontRefData(void); ~wxFontRefData(void); wxList m_scaled_xfonts; int m_pointSize; int m_family, m_style, m_weight; bool m_underlined; int m_fontId; char* m_faceName; bool m_byXFontName; GdkFont *m_font; friend wxFont; }; wxFontRefData::wxFontRefData(void) : m_scaled_xfonts(wxKEY_INTEGER) { m_byXFontName = FALSE; m_pointSize = 12; m_family = wxSWISS; m_style = wxNORMAL; m_weight = wxNORMAL; m_underlined = FALSE; m_fontId = 0; m_faceName = (char *) NULL; m_font = (GdkFont *) NULL; } wxFontRefData::~wxFontRefData(void) { wxNode *node = m_scaled_xfonts.First(); while (node) { GdkFont *font = (GdkFont*)node->Data(); wxNode *next = node->Next(); gdk_font_unref( font ); node = next; } if (m_faceName) { delete m_faceName; m_faceName = (char *) NULL; } if (m_font) gdk_font_unref( m_font ); } //----------------------------------------------------------------------------- #define M_FONTDATA ((wxFontRefData *)m_refData) IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject) wxFont::wxFont(void) { if (wxTheFontList) wxTheFontList->Append( this ); } wxFont::wxFont( char *xFontName ) { if (!xFontName) return; m_refData = new wxFontRefData(); M_FONTDATA->m_byXFontName = TRUE; M_FONTDATA->m_font = gdk_font_load( xFontName ); } wxFont::wxFont(int PointSize, int FontIdOrFamily, int Style, int Weight, bool Underlined, const char* Face) { m_refData = new wxFontRefData(); if ((M_FONTDATA->m_faceName = (Face) ? copystring(Face) : (char*)NULL) ) { M_FONTDATA->m_fontId = wxTheFontNameDirectory->FindOrCreateFontId( Face, FontIdOrFamily ); M_FONTDATA->m_family = wxTheFontNameDirectory->GetFamily( FontIdOrFamily ); } else { M_FONTDATA->m_fontId = FontIdOrFamily; M_FONTDATA->m_family = wxTheFontNameDirectory->GetFamily( FontIdOrFamily ); } if (Style == wxDEFAULT) Style = wxSWISS; M_FONTDATA->m_style = Style; if (Weight == wxDEFAULT) Weight = wxNORMAL; M_FONTDATA->m_weight = Weight; if (PointSize == wxDEFAULT) PointSize = 10; M_FONTDATA->m_pointSize = PointSize; M_FONTDATA->m_underlined = Underlined; if (wxTheFontList) wxTheFontList->Append( this ); } wxFont::wxFont(int PointSize, const char *Face, int Family, int Style, int Weight, bool Underlined) { m_refData = new wxFontRefData(); M_FONTDATA->m_fontId = wxTheFontNameDirectory->FindOrCreateFontId( Face, Family ); M_FONTDATA->m_faceName = (Face) ? copystring(Face) : (char*)NULL; M_FONTDATA->m_family = wxTheFontNameDirectory->GetFamily( M_FONTDATA->m_fontId ); M_FONTDATA->m_style = Style; M_FONTDATA->m_weight = Weight; M_FONTDATA->m_pointSize = PointSize; M_FONTDATA->m_underlined = Underlined; if (wxTheFontList) wxTheFontList->Append( this ); } wxFont::wxFont( const wxFont& font ) { Ref( font ); if (wxTheFontList) wxTheFontList->Append( this ); } wxFont::wxFont( const wxFont* font ) { UnRef(); if (font) Ref( *font ); if (wxTheFontList) wxTheFontList->Append( this ); } wxFont::~wxFont(void) { if (wxTheFontList) wxTheFontList->DeleteObject( this ); } wxFont& wxFont::operator = ( const wxFont& font ) { if (*this == font) return (*this); Ref( font ); return *this; } bool wxFont::operator == ( const wxFont& font ) { return m_refData == font.m_refData; } bool wxFont::operator != ( const wxFont& font ) { return m_refData != font.m_refData; } bool wxFont::Ok() const { return (m_refData != NULL); } int wxFont::GetPointSize(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return 0; } return M_FONTDATA->m_pointSize; } wxString wxFont::GetFaceString(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return ""; } wxString s = wxTheFontNameDirectory->GetFontName( M_FONTDATA->m_fontId ); return s; } wxString wxFont::GetFaceName(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return ""; } wxString s = wxTheFontNameDirectory->GetFontName( M_FONTDATA->m_fontId ); return s; } int wxFont::GetFamily(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return 0; } return M_FONTDATA->m_family; } wxString wxFont::GetFamilyString(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return "wxDEFAULT"; } switch (M_FONTDATA->m_family) { case wxDECORATIVE: return wxString("wxDECORATIVE"); case wxROMAN: return wxString("wxROMAN"); case wxSCRIPT: return wxString("wxSCRIPT"); case wxSWISS: return wxString("wxSWISS"); case wxMODERN: return wxString("wxMODERN"); case wxTELETYPE: return wxString("wxTELETYPE"); default: return "wxDEFAULT"; } return "wxDEFAULT"; } int wxFont::GetFontId(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return 0; } return M_FONTDATA->m_fontId; // stub } int wxFont::GetStyle(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return 0; } return M_FONTDATA->m_style; } wxString wxFont::GetStyleString(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return "wxDEFAULT"; } switch (M_FONTDATA->m_style) { case wxNORMAL: return wxString("wxNORMAL"); case wxSLANT: return wxString("wxSLANT"); case wxITALIC: return wxString("wxITALIC"); default: return wxString("wxDEFAULT"); } return wxString("wxDEFAULT"); } int wxFont::GetWeight(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return 0; } return M_FONTDATA->m_weight; } wxString wxFont::GetWeightString(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return "wxDEFAULT"; } switch (M_FONTDATA->m_weight) { case wxNORMAL: return wxString("wxNORMAL"); case wxBOLD: return wxString("wxBOLD"); case wxLIGHT: return wxString("wxLIGHT"); default: return wxString("wxDEFAULT"); } return wxString("wxDEFAULT"); } bool wxFont::GetUnderlined(void) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return FALSE; } return M_FONTDATA->m_underlined; } //----------------------------------------------------------------------------- // get internal representation of font //----------------------------------------------------------------------------- // local help function static GdkFont *wxLoadQueryNearestFont(int point_size, int fontid, int style, int weight, bool underlined); GdkFont *wxFont::GetInternalFont(float scale) const { if (!Ok()) { wxFAIL_MSG( "invalid font" ); return (GdkFont*) NULL; } if (M_FONTDATA->m_byXFontName) return M_FONTDATA->m_font; long int_scale = long(scale * 100.0 + 0.5); // key for fontlist int point_scale = (M_FONTDATA->m_pointSize * 10 * int_scale) / 100; GdkFont *font = (GdkFont *) NULL; wxNode *node = M_FONTDATA->m_scaled_xfonts.Find(int_scale); if (node) { font = (GdkFont*)node->Data(); } else { font = wxLoadQueryNearestFont( point_scale, M_FONTDATA->m_fontId, M_FONTDATA->m_style, M_FONTDATA->m_weight, M_FONTDATA->m_underlined ); M_FONTDATA->m_scaled_xfonts.Append( int_scale, (wxObject*)font ); } if (!font) printf("could not load any font"); // wxError("could not load any font", "wxFont"); return font; } //----------------------------------------------------------------------------- // local utilities to find a X font //----------------------------------------------------------------------------- static GdkFont *wxLoadQueryFont(int point_size, int fontid, int style, int weight, bool WXUNUSED(underlined)) { char buffer[512]; char *name = wxTheFontNameDirectory->GetScreenName( fontid, weight, style ); if (!name) name = "-*-*-*-*-*-*-*-%d-*-*-*-*-*-*"; sprintf(buffer, name, point_size); return gdk_font_load( buffer ); } static GdkFont *wxLoadQueryNearestFont(int point_size, int fontid, int style, int weight, bool underlined) { GdkFont *font; font = wxLoadQueryFont( point_size, fontid, style, weight, underlined ); if (!font) { // search up and down by stepsize 10 int max_size = point_size + 20 * (1 + (point_size/180)); int min_size = point_size - 20 * (1 + (point_size/180)); int i; // Search for smaller size (approx.) for (i=point_size-10; !font && i >= 10 && i >= min_size; i -= 10) font = wxLoadQueryFont(i, fontid, style, weight, underlined); // Search for larger size (approx.) for (i=point_size+10; !font && i <= max_size; i += 10) font = wxLoadQueryFont(i, fontid, style, weight, underlined); // Try default family if (!font && fontid != wxDEFAULT) font = wxLoadQueryFont(point_size, wxDEFAULT, style, weight, underlined); // Bogus font if (!font) font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL, underlined); } return font; } //----------------------------------------------------------------------------- // face names and index functions //----------------------------------------------------------------------------- static char *font_defaults[] = { "FamilyDefault", "Default", "FamilyRoman", "Roman", "FamilyDecorative", "Decorative", "FamilyModern", "Modern", "FamilyTeletype", "Teletype", "FamilySwiss", "Swiss", "FamilyScript", "Script", "AfmMedium", "", "AfmBold", "Bo", "AfmLight", "", "AfmStraight", "", "AfmItalic", "${AfmSlant}", "AfmSlant", "O", "AfmRoman", "Ro", "AfmTimes", "Times", "AfmHelvetica", "Helv", "AfmCourier", "Cour", "Afm___", "${AfmTimes,$[weight],$[style]}", "AfmTimes__", "${AfmTimes}${Afm$[weight]}${Afm$[style]}", "AfmTimesMediumStraight", "${AfmTimes}${AfmRoman}", "AfmTimesLightStraight", "${AfmTimes}${AfmRoman}", "AfmTimes_Italic", "${AfmTimes}$[weight]${AfmItalic}", "AfmTimes_Slant", "${AfmTimes}$[weight]${AfmItalic}", "AfmSwiss__", "${AfmHelvetica}${Afm$[weight]}${Afm$[style]}", "AfmModern__", "${AfmCourier}${Afm$[weight]}${Afm$[style]}", "AfmTeletype__", "${AfmModern,$[weight],$[style]}", "PostScriptMediumStraight", "", "PostScriptMediumItalic", "-Oblique", "PostScriptMediumSlant", "-Oblique", "PostScriptLightStraight", "", "PostScriptLightItalic", "-Oblique", "PostScriptLightSlant", "-Oblique", "PostScriptBoldStraight", "-Bold", "PostScriptBoldItalic", "-BoldOblique", "PostScriptBoldSlant", "-BoldOblique", #if WX_NORMALIZED_PS_FONTS "PostScript___", "${PostScriptTimes,$[weight],$[style]}", #else "PostScriptRoman__", "${PostScriptTimes,$[weight],$[style]}", "PostScript___", "LucidaSans${PostScript$[weight]$[style]}", #endif "PostScriptTimesMedium", "", "PostScriptTimesLight", "", "PostScriptTimesBold", "Bold", "PostScriptTimes__", "Times${PostScript$[weight]$[style]}", "PostScriptTimesMediumStraight", "Times-Roman", "PostScriptTimesLightStraight", "Times-Roman", "PostScriptTimes_Slant", "Times-${PostScriptTimes$[weight]}Italic", "PostScriptTimes_Italic", "Times-${PostScriptTimes$[weight]}Italic", "PostScriptSwiss__", "Helvetica${PostScript$[weight]$[style]}", "PostScriptModern__", "Courier${PostScript$[weight]$[style]}", "PostScriptTeletype__", "${PostScriptModern,$[weight],$[style]}", #if !WX_NORMALIZED_PS_FONTS "PostScriptScript__", "Zapf-Chancery-MediumItalic", #endif "ScreenMedium", "medium", "ScreenBold", "bold", "ScreenLight", "light", "ScreenStraight", "r", "ScreenItalic", "i", "ScreenSlant", "o", "ScreenDefaultBase", "misc-fixed", "ScreenRomanBase", "*-times", "ScreenDecorativeBase", "*-helvetica", "ScreenModernBase", "*-courier", "ScreenTeletypeBase", "*-lucidatypewriter", "ScreenSwissBase", "*-lucida", "ScreenScriptBase", "*-zapfchancery", "ScreenStdSuffix", "-${Screen$[weight]}-${Screen$[style]}" "-normal-*-*-%d-*-*-*-*-*-*", "Screen___", "-${ScreenDefaultBase}${ScreenStdSuffix}", "ScreenRoman__", "-${ScreenRomanBase}${ScreenStdSuffix}", "ScreenDecorative__", "-${ScreenDecorativeBase}${ScreenStdSuffix}", "ScreenModern__", "-${ScreenModernBase}${ScreenStdSuffix}", "ScreenTeletype__", "-${ScreenTeletypeBase}${ScreenStdSuffix}", "ScreenSwiss__", "-${ScreenSwissBase}${ScreenStdSuffix}", "ScreenScript__", "-${ScreenScriptBase}${ScreenStdSuffix}", (char *) NULL }; enum {wxWEIGHT_NORMAL, wxWEIGHT_BOLD, wxWEIGHT_LIGHT, wxNUM_WEIGHTS}; enum {wxSTYLE_NORMAL, wxSTYLE_ITALIC, wxSTYLE_SLANT, wxNUM_STYLES}; static int WCoordinate(int w) { switch (w) { case wxBOLD: return wxWEIGHT_BOLD; case wxLIGHT: return wxWEIGHT_LIGHT; case wxNORMAL: default: return wxWEIGHT_NORMAL; } }; static int SCoordinate(int s) { switch (s) { case wxITALIC: return wxSTYLE_ITALIC; case wxSLANT: return wxSTYLE_SLANT; case wxNORMAL: default: return wxSTYLE_NORMAL; } }; //----------------------------------------------------------------------------- // wxSuffixMap //----------------------------------------------------------------------------- class wxSuffixMap { public: ~wxSuffixMap(void); inline char *GetName(int weight, int style) { return ( map [WCoordinate(weight)] [SCoordinate(style)] ); } char *map[wxNUM_WEIGHTS][wxNUM_STYLES]; void Initialize(const char *, const char *); }; //#if !USE_RESOURCES #define wxGetResource(a, b, c) 0 //#endif static void SearchResource(const char *prefix, const char **names, int count, char **v) { int k, i, j; char resource[1024], **defaults, *internal; k = 1 << count; *v = (char *) NULL; internal = (char *) NULL; for (i = 0; i < k; i++) { strcpy(resource, prefix); for (j = 0; j < count; j++) { if (!(i & (1 << j))) strcat(resource, names[j]); else strcat(resource, "_"); } if (wxGetResource(wxAPP_CLASS, (char *)resource, v)) return; if (!internal) { defaults = font_defaults; while (*defaults) { if (!strcmp(*defaults, resource)) { internal = defaults[1]; break; } defaults += 2; } } } if (internal) *v = copystring(internal); } wxSuffixMap::~wxSuffixMap(void) { int k, j; for (k = 0; k < wxNUM_WEIGHTS; ++k) for (j = 0; j < wxNUM_STYLES; ++j) if (map[k][j]) { delete[] map[k][j]; map[k][j] = (char *) NULL; } } void wxSuffixMap::Initialize(const char *resname, const char *devresname) { const char *weight, *style; char *v; int i, j, k; const char *names[3]; for (k = 0; k < wxNUM_WEIGHTS; k++) { switch (k) { case wxWEIGHT_NORMAL: weight = "Medium"; break; case wxWEIGHT_LIGHT: weight = "Light"; break; case wxWEIGHT_BOLD: default: weight = "Bold"; } for (j = 0; j < wxNUM_STYLES; j++) { switch (j) { case wxSTYLE_NORMAL: style = "Straight"; break; case wxSTYLE_ITALIC: style = "Italic"; break; case wxSTYLE_SLANT: default: style = "Slant"; } names[0] = resname; names[1] = weight; names[2] = style; SearchResource(devresname, names, 3, &v); /* Expand macros in the found string: */ found: int len, closer = 0, startpos = 0; len = (v ? strlen(v) : 0); for (i = 0; i < len; i++) { if (v[i] == '$' && ((v[i+1] == '[') || (v[i+1] == '{'))) { startpos = i; closer = (v[i+1] == '[') ? ']' : '}'; ++i; } else if (v[i] == closer) { int newstrlen; const char *r = (char *) NULL; bool delete_r = FALSE; char *name; name = v + startpos + 2; v[i] = 0; if (closer == '}') { int i, count, len; char **names; for (i = 0, count = 1; name[i]; i++) if (name[i] == ',') count++; len = i; names = new char*[count]; names[0] = name; for (i = 0, count = 1; i < len; i++) if (name[i] == ',') { names[count++] = name + i + 1; name[i] = 0; } SearchResource("", (const char **)names, count, (char **)&r); delete_r = (r != 0); delete[] names; if (!r) { for (i = 0; i < len; i++) if (!name[i]) name[i] = ','; r = ""; printf("Bad resource name \"%s\" in font lookup\n", name); } } else if (!strcmp(name, "weight")) { r = weight; } else if (!strcmp(name, "style")) { r = style; } else if (!strcmp(name, "family")) { r = resname; } else { r = ""; printf("Bad font macro name \"%s\"\n", name); } // add r to v newstrlen = strlen(r); char *naya = new char[startpos + newstrlen + len - i]; memcpy(naya, v, startpos); memcpy(naya + startpos, r, newstrlen); memcpy(naya + startpos + newstrlen, v + i + 1, len - i); if (delete_r) delete[] (char*)r; delete[] v; v = naya; goto found; } } /* We have a final value: */ map[k][j] = v; } } } //----------------------------------------------------------------------------- // wxFontNameItem //----------------------------------------------------------------------------- class wxFontNameItem : public wxObject { DECLARE_DYNAMIC_CLASS(wxFontNameItem) public: wxFontNameItem(const char *name, int id, int family); ~wxFontNameItem(); inline char* GetScreenName(int w, int s) {return screen.GetName(w, s);} inline char* GetPostScriptName(int w, int s) {return printing.GetName(w, s);} inline char* GetAFMName(int w, int s) {return afm.GetName(w, s);} inline char* GetName(void) {return name;} inline int GetFamily(void) {return family;} inline int GetId(void) {return id;} inline bool IsRoman(void) {return isroman;} #if WXDEBUG void Dump(ostream& str); #endif int id; int family; char *name; wxSuffixMap screen, printing, afm; bool isroman; }; IMPLEMENT_ABSTRACT_CLASS(wxFontNameItem, wxObject) wxFontNameItem::wxFontNameItem(const char *Name, int Id, int Family) { name = copystring(Name); id = Id; family = Family; screen. Initialize(name, "Screen"); printing.Initialize(name, "PostScript"); afm. Initialize(name, "Afm"); } wxFontNameItem::~wxFontNameItem(void) { if (name) delete[] name; name = (char *) NULL; } #if WXDEBUG void wxFontNameItem::Dump(ostream& str) { str << "wxFontNameItem(" << name << ")"; } #endif //----------------------------------------------------------------------------- // wxFontDirectory //----------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS(wxFontNameDirectory, wxObject) wxFontNameDirectory::wxFontNameDirectory(void) { table = new wxHashTable(wxKEY_INTEGER, 20); nextFontId = -1; } wxFontNameDirectory::~wxFontNameDirectory() { // Cleanup wxFontNameItems allocated table->BeginFind(); wxNode *node = table->Next(); while (node) { wxFontNameItem *item = (wxFontNameItem*)node->Data(); delete item; node = table->Next(); } delete table; } int wxFontNameDirectory::GetNewFontId(void) { return (nextFontId--); } void wxFontNameDirectory::Initialize() { Initialize(wxDEFAULT, wxDEFAULT, "Default"); Initialize(wxDECORATIVE, wxDECORATIVE, "Decorative"); Initialize(wxROMAN, wxROMAN, "Roman"); Initialize(wxMODERN, wxMODERN, "Modern"); Initialize(wxTELETYPE, wxTELETYPE, "Teletype"); Initialize(wxSWISS, wxSWISS, "Swiss"); Initialize(wxSCRIPT, wxSCRIPT, "Script"); } void wxFontNameDirectory::Initialize(int fontid, int family, const char *resname) { char *fam, resource[256]; sprintf(resource, "Family%s", resname); SearchResource((const char *)resource, (const char **) NULL, 0, (char **)&fam); if (fam) { if (!strcmp(fam, "Default")) family = wxDEFAULT; else if (!strcmp(fam, "Roman")) family = wxROMAN; else if (!strcmp(fam, "Decorative")) family = wxDECORATIVE; else if (!strcmp(fam, "Modern")) family = wxMODERN; else if (!strcmp(fam, "Teletype")) family = wxTELETYPE; else if (!strcmp(fam, "Swiss")) family = wxSWISS; else if (!strcmp(fam, "Script")) family = wxSCRIPT; delete[] fam; // free resource } table->Put(fontid, new wxFontNameItem(resname, fontid, family)); } int wxFontNameDirectory::FindOrCreateFontId(const char *name, int family) { int id; // font exists -> return id if ( (id = GetFontId(name)) ) return id; // create new font Initialize(id=GetNewFontId(), family, name); return id; } char *wxFontNameDirectory::GetScreenName(int fontid, int weight, int style) { wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font if (item) return item->GetScreenName(weight, style); // font does not exist return (char *) NULL; } char *wxFontNameDirectory::GetPostScriptName(int fontid, int weight, int style) { wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font if (item) return item->GetPostScriptName(weight, style); // font does not exist return (char *) NULL; } char *wxFontNameDirectory::GetAFMName(int fontid, int weight, int style) { wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font if (item) return item->GetAFMName(weight, style); // font does not exist return (char *) NULL; } char *wxFontNameDirectory::GetFontName(int fontid) { wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font if (item) return item->GetName(); // font does not exist return (char *) NULL; } int wxFontNameDirectory::GetFontId(const char *name) { wxNode *node; table->BeginFind(); while ( (node = table->Next()) ) { wxFontNameItem *item = (wxFontNameItem*)node->Data(); if (!strcmp(name, item->name)) return item->id; } // font does not exist return 0; } int wxFontNameDirectory::GetFamily(int fontid) { wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); if (item) return item->family; // font does not exist return wxDEFAULT; }