/* -*- C++ -*- * * Purpose: wxWindows font name handling * * Authors: Markus Holzem, Julian Smart, and Matthew Flatt * * Copyright: (C) 2004-2009 PLT Scheme Inc. * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian) * Copyright: (C) 1995, GNU (Markus) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA. */ #pragma implementation #ifdef wx_xt # define Uses_wxApp # define Uses_wxFontNameDirectory # include "wx.h" # include #endif char *font_defaults[] = { "PostScriptMediumStraight", "", "PostScriptMediumItalic", "-Oblique", "PostScriptMediumSlant", "-Oblique", "PostScriptLightStraight", "", "PostScriptLightItalic", "-Oblique", "PostScriptLightSlant", "-Oblique", "PostScriptBoldStraight", "-Bold", "PostScriptBoldItalic", "-BoldOblique", "PostScriptBoldSlant", "-BoldOblique", "PostScript___", "${PostScript$[family],$[weight],$[style]}", "PostScriptSystem__", "${PostScriptTimes,$[weight],$[style]}", "PostScriptRoman__", "${PostScriptTimes,$[weight],$[style]}", "PostScriptScript__", "ZapfChancery-MediumItalic", "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", "PostScriptDefault__", "Helvetica${PostScript$[weight]$[style]}", "PostScriptSwiss__", "Helvetica${PostScript$[weight]$[style]}", "PostScriptDecorative__", "Helvetica${PostScript$[weight]$[style]}", "PostScriptModern__", "Courier${PostScript$[weight]$[style]}", "PostScriptSymbol__", "Symbol", "PostScriptTeletype__", "${PostScriptModern,$[weight],$[style]}", #ifdef wx_x "ScreenMedium", "medium", "ScreenBold", "bold", "ScreenLight", "light", "ScreenStraight", "r", "ScreenItalic", "i", "ScreenSlant", "o", "ScreenSystemBase", "*-lucida", "ScreenDefaultBase", "*-lucida", "ScreenRomanBase", "*-times", "ScreenDecorativeBase", "*-helvetica", "ScreenModernBase", "*-courier", "ScreenTeletypeBase", "*-lucidatypewriter", "ScreenSwissBase", "*-lucida", "ScreenScriptBase", "*-zapf chancery", "ScreenSymbolBase", "*-symbol", "ScreenStdSuffix", "-${Screen$[weight]}-${Screen$[style]}" "-normal-*-*-%d-*-*-*-*-*-*", "ScreenSystem__", "+-${ScreenSystemBase}${ScreenStdSuffix}", "ScreenDefault__", "+-${ScreenDefaultBase}${ScreenStdSuffix}", "ScreenRoman__", "+-${ScreenRomanBase}${ScreenStdSuffix}", "ScreenDecorative__", "+-${ScreenDecorativeBase}${ScreenStdSuffix}", "ScreenModern__", "+-${ScreenModernBase}${ScreenStdSuffix}", "ScreenTeletype__", "+-${ScreenTeletypeBase}${ScreenStdSuffix}", "ScreenSwiss__", "+-${ScreenSwissBase}${ScreenStdSuffix}", "ScreenScript__", "+-${ScreenScriptBase}-medium-i-normal-*-*-%d-*-*-*-*-*-*", "ScreenSymbol__", "+-${ScreenSymbolBase}-medium-r-normal-*-*-%d-*-*-*-*-*-*", #endif #ifdef wx_msw "ScreenSystem__", "MS Sans Serif", /* maybe changed by Adjust */ "ScreenDefault__", "MS Sans Serif", /* maybe changed by Adjust */ "ScreenRoman__", "Times New Roman", "ScreenDecorative__", "Arial", "ScreenModern__", "Courier New", "ScreenTeletype__", "${ScreenModern$[weight];$[style]}", "ScreenSwiss__", "Arial", "ScreenScript__", "Arial", "ScreenSymbol__", "Symbol", #endif #ifdef wx_mac # ifdef OS_X "ScreenDefault__", "Lucida Grande", "ScreenSystem__", "Lucida Grande", "ScreenDecorative__", "Arial", /* "Geneva" looks bad at 12pt in Quartz with QD spacing */ "ScreenModern__", "Courier New", /* "Courier" is worse without Quartz */ "ScreenScript__", "Apple Chancery", # else "ScreenDefault__", "applicationfont", "ScreenSystem__", "systemfont", "ScreenDecorative__", "Geneva", "ScreenModern__", "Monaco", /* "courier" is also good */ "ScreenScript__", "Zapf Chancery", # endif "ScreenRoman__", "Times", "ScreenTeletype__", "${ScreenModern,$[weight],$[style]}", "ScreenSwiss__", "Helvetica", "ScreenSymbol__", "Symbol", #endif NULL }; #ifdef wx_msw static int CALLBACK check_font_here(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam) { *(int *)lParam = 1; return 0; } int check_avail(char *name) { int present = 0; LOGFONT lf; HDC dc; lf.lfCharSet = DEFAULT_CHARSET; strcpy(lf.lfFaceName, name); lf.lfPitchAndFamily = 0; dc = GetDC(NULL); EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)check_font_here, (LPARAM)&present, 0); ReleaseDC(NULL, dc); return present; } #endif #ifdef WX_USE_XFT extern int wxXRenderHere(void); #endif static void AdjustFontDefaults(void) { #ifdef wx_xt # ifdef WX_USE_XFT if (wxXRenderHere()) { int i; for (i = 0; font_defaults[i]; i += 2) { if (!strcmp(font_defaults[i], "ScreenSystem__")) { font_defaults[i + 1] = " Sans"; } else if (!strcmp(font_defaults[i], "ScreenDefault__")) { font_defaults[i + 1] = " Sans"; } else if (!strcmp(font_defaults[i], "ScreenRoman__")) { font_defaults[i + 1] = " Serif"; } else if (!strcmp(font_defaults[i], "ScreenDecorative__")) { font_defaults[i + 1] = " Nimbus Sans L"; } else if (!strcmp(font_defaults[i], "ScreenModern__")) { font_defaults[i + 1] = " Monospace"; } else if (!strcmp(font_defaults[i], "ScreenTeletype__")) { font_defaults[i + 1] = " Monospace"; } else if (!strcmp(font_defaults[i], "ScreenSwiss__")) { font_defaults[i + 1] = " Nimbus Sans L"; } else if (!strcmp(font_defaults[i], "ScreenScript__")) { font_defaults[i + 1] = " URW Chancery L"; } else if (!strcmp(font_defaults[i], "ScreenSymbol__")) { font_defaults[i + 1] = " Standard Symbols L,Nimbus Sans L"; } } } # endif #endif #ifdef wx_msw int i; for (i = 0; font_defaults[i]; i += 2) { if (!strcmp(font_defaults[i], "ScreenDefault__")) { /* We'd prefer to use "Microsoft Sans Serif", instead, in XP, because that's an outline font. */ if (check_avail("Microsoft Sans Serif")) { font_defaults[i + 1] = "Microsoft Sans Serif"; } } else if (!strcmp(font_defaults[i], "ScreenSystem__")) { /* 2000 and XP use Tahoma by default for controls */ static int known = 0, present = 0; if (check_avail("Tahoma")) { font_defaults[i+1] = "Tahoma"; } } } #endif } wxFontNameDirectory *wxTheFontNameDirectory; enum { wxWEIGHT_NORMAL, wxWEIGHT_BOLD, wxWEIGHT_LIGHT, wxNUM_WEIGHTS }; enum { wxSTYLE_NORMAL, wxSTYLE_ITALIC, wxSTYLE_SLANT, wxNUM_STYLES }; class wxSuffixMap { public: char *map[wxNUM_WEIGHTS][wxNUM_STYLES]; void Initialize(const char *, const char *, int weight, int style, int fam); wxSuffixMap(); #ifdef MZ_PRECISE_GC void gcMark(); void gcFixup(); #endif }; #ifdef MZ_PRECISE_GC START_XFORM_SKIP; void wxSuffixMap::gcMark() { int i, j; for (i = 0; i < wxNUM_WEIGHTS; i++) for (j = 0; j < wxNUM_STYLES; j++) { gcMARK_TYPED(char *, map[i][j]); } } void wxSuffixMap::gcFixup() { int i, j; for (i = 0; i < wxNUM_WEIGHTS; i++) for (j = 0; j < wxNUM_STYLES; j++) { gcFIXUP_TYPED(char *, map[i][j]); } } END_XFORM_SKIP; #endif wxSuffixMap::wxSuffixMap() { int i, j; for (i = 0; i < wxNUM_WEIGHTS; i++) { for (j = 0; j < wxNUM_STYLES; j++) { map[i][j] = NULL; } } } class wxFontNameItem : public wxObject { public: int id; int family; char *name; wxSuffixMap *screen, *printing; Bool isfamily; wxFontNameItem(); }; wxFontNameItem::wxFontNameItem() : wxObject(WXGC_NO_CLEANUP) { screen = new WXGC_PTRS wxSuffixMap; printing = new WXGC_PTRS wxSuffixMap; } 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; } } wxFontNameDirectory::wxFontNameDirectory(void) { wxHashTable *ht; ht = new WXGC_PTRS wxHashTable(wxKEY_INTEGER, 20); table = ht; nextFontId = 100; /* Larger than all family ids */ } wxFontNameDirectory::~wxFontNameDirectory() { DELETE_OBJ table; } int wxFontNameDirectory::GetNewFontId(void) { return (nextFontId++); } int wxGetPreference(const char *name, char *res, long len); static char pref_buf[1024]; static void SearchResource(const char *prefix, const char **names, int count, char **v) { int k, i, j; char resource[1024], *internal; GC_CAN_IGNORE char **defaults; k = 1 << count; *v = NULL; internal = 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 (wxGetPreference((char *)resource, pref_buf, 1024) && *pref_buf) { *v = pref_buf; return; } if (!internal) { defaults = font_defaults; while (*defaults) { if (!strcmp(*defaults, resource)) { internal = defaults[1]; break; } defaults += 2; } } } if (internal) { char *s; s = copystring(internal); *v = s; } } void wxInitializeFontNameDirectory(void) { AdjustFontDefaults(); wxREGGLOB(wxTheFontNameDirectory); wxTheFontNameDirectory = new WXGC_PTRS wxFontNameDirectory; wxTheFontNameDirectory->Initialize(wxSYSTEM, wxSYSTEM, "System"); wxTheFontNameDirectory->Initialize(wxDEFAULT, wxDEFAULT, "Default"); wxTheFontNameDirectory->Initialize(wxDECORATIVE, wxDECORATIVE, "Decorative"); wxTheFontNameDirectory->Initialize(wxROMAN, wxROMAN, "Roman"); wxTheFontNameDirectory->Initialize(wxMODERN, wxMODERN, "Modern"); wxTheFontNameDirectory->Initialize(wxTELETYPE, wxTELETYPE, "Teletype"); wxTheFontNameDirectory->Initialize(wxSWISS, wxSWISS, "Swiss"); wxTheFontNameDirectory->Initialize(wxSCRIPT, wxSCRIPT, "Script"); wxTheFontNameDirectory->Initialize(wxSYMBOL, wxSYMBOL, "Symbol"); } void wxSuffixMap::Initialize(const char *resname, const char *devresname, int wt, int st, int fam) { const char *weight, *style; char *v = NULL; int i, drn; { switch (wt) { case wxWEIGHT_NORMAL: weight = "Medium"; break; case wxWEIGHT_LIGHT: weight = "Light"; break; case wxWEIGHT_BOLD: default: weight = "Bold"; } { int len, closer = 0, startpos = 0; const char *rnames[3]; switch (st) { case wxSTYLE_NORMAL: style = "Straight"; break; case wxSTYLE_ITALIC: style = "Italic"; break; case wxSTYLE_SLANT: default: style = "Slant"; } rnames[0] = resname; rnames[1] = weight; rnames[2] = style; SearchResource(devresname, rnames, 3, &v); /* Expand macros in the found string: */ found: len = (v ? strlen(v) : 0); for (i = 0; i < len; i++) { if (v[i] == '$' && ((v[i+1] == '[') || (v[i+1] == '{'))) { startpos = i; if (v[i+1] == '[') closer = ']'; else closer = '}'; i++; } else if (v[i] == closer) { int newstrlen, noff; const char *r = NULL; char *naya, *name; noff = startpos + 2; name = v; v[i] = 0; if (closer == '}') { int i, count, len; char **names; for (i = 0, count = 1; name[i + noff]; i++) { if (name[i + noff] == ',') { count++; name[i + noff] = 0; } } len = i; names = new WXGC_PTRS char*[count]; { char *cs; cs = COPYSTRING_TO_ALIGNED(name, noff); names[0] = cs; } for (i = 0, count = 1; i < len; i++) { if (!name[i + noff]) { { char *cs; cs = COPYSTRING_TO_ALIGNED(name, i + 1 + noff); names[count++] = cs; } } } SearchResource("", (const char **)names, count, (char **)&r); if (!r) { for (i = 0; i < len; i++) { if (!name[i + noff]) name[i + noff] = ','; } r = ""; printf("Bad resource name \"%s\" in font lookup\n", name + noff); } } else if (!strcmp(name + noff, "weight")) { r = weight; } else if (!strcmp(name + noff, "style")) { r = style; } else if (!strcmp(name + noff, "family")) { switch (fam) { case wxSYSTEM: r = "System"; break; case wxDECORATIVE: r = "Decorative"; break; case wxROMAN: r = "Roman"; break; case wxMODERN: r = "Modern"; break; case wxTELETYPE: r = "Teletype"; break; case wxSWISS: r = "Swiss"; break; case wxSCRIPT: r = "Script"; break; case wxSYMBOL: r = "Symbol"; break; default: r = "Default"; } } else { r = ""; printf("Bad font macro name \"%s\"\n", name + noff); } newstrlen = strlen(r); naya = new WXGC_ATOMIC char[len + newstrlen + 1]; memcpy(naya, v, startpos); memcpy(naya + startpos, r, newstrlen); memcpy(naya + startpos + newstrlen, v + i + 1, len - i + 1); v = naya; goto found; } } drn = ((resname[0] == '@') ? 1 : 0); #if defined(wx_msw) || defined(wx_mac) if (!v) v = copystring(resname + drn); #endif #ifdef wx_x if (!strcmp(devresname, "Screen")) { if (v && (v[0] == '+')) { memmove(v, v + 1, strlen(v)); } else { int len, ds; char *src; char *normalcy; /* Build name using special heuristics: -([^-]*) => -*-\1--