diff options
Diffstat (limited to 'Src/Wasabi/api/font/font.cpp')
-rw-r--r-- | Src/Wasabi/api/font/font.cpp | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/Src/Wasabi/api/font/font.cpp b/Src/Wasabi/api/font/font.cpp new file mode 100644 index 00000000..e45994ce --- /dev/null +++ b/Src/Wasabi/api/font/font.cpp @@ -0,0 +1,637 @@ +#include "precomp.h" +// ============================================================================================================================================================ +// Font abstract class + statics to install TT fonts and Bitmap fonts +// ============================================================================================================================================================ + +#include <api/font/font.h> +#include <api/font/bitmapfont.h> +#include <bfc/parse/pathparse.h> + +#ifdef WASABI_COMPILE_SKIN + #include <api/skin/skin.h> + #include <api/skin/skinparse.h> +#endif + +#include <tataki/canvas/ifc_canvas.h> +#include <api/wnd/fontdef.h> + +#ifdef WASABI_COMPILE_FONT +#include <api/service/svcs/svc_font.h> +//#include "services/svc_fontmaker.h" +#endif + +#ifdef WASABI_API_CONFIG +#include <api/config/options.h> +#include <api/config/items/attrint.h> +#include <api/config/items/attrstr.h> +#include <api/config/items/attrbool.h> +#endif +#include <api/memmgr/api_memmgr.h> +#include <api/font/FontSvcEnum.h> + +extern _bool cfg_options_usefontmapper; +extern _string cfg_options_ttfoverridefont; +extern _int cfg_options_defaultfontscale; + +PtrList<svc_font> Font::fontlist; +PtrList<FontDef> Font::fontdefs; + +void Font::init() +{ +#ifdef WASABI_API_CONFIG + Wasabi::Std::setDefaultFont(cfg_options_defaultfont.getValue()); + Wasabi::Std::setDefaultFontScale(cfg_options_defaultfontscale.getValueAsInt()); +#endif +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +void Font::dispatchTextOut(ifc_canvas *c, int style, int x, int y, int w, int h, const wchar_t *txt) +{ + int isoverride = 0; + if (WASABI_API_APP->main_isShuttingDown()) return; + + int size = c->getTextSize(); + + svc_font *f = requestSkinFont(c->getTextFont(), &size); + + ASSERT(f != NULL); + + // After we get the font we want, check to see if it is bitmap. + // If bitmap fonts are disallowed, use the truetype override font. + if (f->isBitmap() && useTrueTypeOverride(txt)) + { + int gotdefault=0; + svc_font *ttFont = requestSkinFont(getTrueTypeOverride(), &size, &gotdefault); + if (ttFont != NULL) + { + if (!gotdefault) + isoverride = 1; + f = ttFont; + } + } + + if (isoverride) + { + double f = (double)getTrueTypeOverrideScale() / 100.0f; + size = (int)(size*f); + } + int bold = c->getTextBold(); + int opaque = c->getTextOpaque(); + int underline = c->getTextUnderline(); + int italic = c->getTextItalic(); + int align = c->getTextAlign(); + int antialiased = c->getTextAntialias(); + ARGB32 color = c->getTextColor(); + ARGB32 bkcolor = c->getTextBkColor(); + int xoffset=0, yoffset=0; + c->getOffsets(&xoffset, &yoffset); +/* if (!f->isBitmap() && _intVal(Main::enumRootCfgItem(0), "Force antialias on all TTF")) + antialiased = 1;*/ + switch (style) + { + case WA_FONT_TEXTOUT_NORMAL: + f->textOut(c, x, y, txt, size, bold, opaque, underline, italic, color, bkcolor, xoffset, yoffset, antialiased); + break; + case WA_FONT_TEXTOUT_RECT: + f->textOut(c, x, y, w, h, txt, size, bold, opaque, underline, italic, align, color, bkcolor, xoffset, yoffset, antialiased); + break; + case WA_FONT_TEXTOUT_ELLIPSED: + f->textOutEllipsed(c, x, y, w, h, txt, size, bold, opaque, underline, italic, align, color, bkcolor, xoffset, yoffset, antialiased); + break; + case WA_FONT_TEXTOUT_WRAPPED: + f->textOutWrapped(c, x, y, w, h, txt, size, bold, opaque, underline, italic, align, color, bkcolor, xoffset, yoffset, antialiased); + break; + case WA_FONT_TEXTOUT_WRAPPEDPATHED: + f->textOutWrappedPathed(c, x, y, w, txt, size, bold, opaque, underline, italic, align, color, bkcolor, xoffset, yoffset, antialiased); + break; + case WA_FONT_TEXTOUT_CENTERED: + RECT r; + r.left = x; + r.top = y; + r.right = w; + r.bottom = h; + f->textOutCentered(c, &r, txt, size, bold, opaque, underline, italic, align, color, bkcolor, xoffset, yoffset, antialiased); + break; + } +} + + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +int Font::dispatchGetInfo(ifc_canvas *c, const wchar_t *font, int infoid, const wchar_t *txt, int *w, int *h) +{ + int isoverride = 0; + if (WASABI_API_APP->main_isShuttingDown()) return 0; + // mig: Let's not crash if we want to see how big a NULL pointer is. + if (txt == NULL) { + if ( infoid == WA_FONT_GETINFO_WIDTHHEIGHT ) { + if (w != NULL) { + *w = 0; + } + if (h != NULL) { + *h = 0; + } + } + return 0; + } + + int size = c->getTextSize(); + + svc_font *f = requestSkinFont(font, &size); + ASSERT(f != NULL); + + // After we get the font we want, check to see if it is bitmap. + // If bitmap fonts are disallowed, use the truetype override font. + if (f->isBitmap() && useTrueTypeOverride(txt)) + { + int gotdefault = 0; + svc_font *ttFont = requestSkinFont(getTrueTypeOverride(), &size, &gotdefault); + if (ttFont != NULL) + { + if (!gotdefault) + isoverride = 1; + f = ttFont; + } + } + + if (isoverride) { + double f = (double)getTrueTypeOverrideScale() / 100.0f; + size = (int)(size*f); + } + int bold = c->getTextBold(); + int underline = c->getTextUnderline(); + int italic = c->getTextItalic(); + int antialiased = c->getTextAntialias(); + switch (infoid) { + case WA_FONT_GETINFO_WIDTH: + return f->getTextWidth(c, txt, size, bold, underline, italic, antialiased); + case WA_FONT_GETINFO_HEIGHT: + return f->getTextHeight(c, txt, size, bold, underline, italic, antialiased); + case WA_FONT_GETINFO_WIDTHHEIGHT: + f->getTextExtent(c, txt, w, h, size, bold, underline, italic, antialiased); + return 0; + } + return 0; +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Install a truetype font from its filename and associate a script_id to it +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +svc_font *Font::installTrueTypeFont(const wchar_t *filename, const wchar_t *path, const wchar_t *id, int scriptid, int allowmapping, int isttfreload) { + + if (!isttfreload) + { + FontDef *fd = new FontDef; + fd->filename = filename; + fd->path = path; + fd->id = id; + fd->scriptid = scriptid; + fd->isbitmap = 0; + fd->allowmapping = allowmapping; + fontdefs.addItem(fd); + } + + StringW file; + + OSFILETYPE ff=OPEN_FAILED; + if (wcschr(filename, ':')) + ff = WFOPEN(filename, WF_READONLY_BINARY); + + if (ff == OPEN_FAILED) + { + file = StringPathCombine(path, filename); + ff = WFOPEN(file, WF_READONLY_BINARY); + } +#ifdef WASABI_COMPILE_SKIN + if (ff == OPEN_FAILED) + { + file = StringPathCombine(SkinParser::getXmlRootPath(), filename); + ff = WFOPEN(file, WF_READONLY_BINARY); + if (ff == OPEN_FAILED) + { + file = StringPathCombine(Skin::getDefaultSkinPath(), filename); + ff = WFOPEN(file, WF_READONLY_BINARY); + if (ff == OPEN_FAILED) + { + DebugString("Font not found %s\n", filename); + // todo: do something if still not found + } + } + } +#endif + if (ff == OPEN_FAILED) { + DebugString("Could not install font %s\n", filename); + return 0; + } + + StringW fs = filename; + wchar_t *p = wcschr(fs.getNonConstVal(), '.'); + if (p) + *p = 0; + PathParserW pp(fs); + fs = pp.getLastString(); + + svc_font *f = newTrueTypeFont(); + if (f && f->addFontResource( ff, fs) ) + { + f->setFontId(id); + f->setScriptId(scriptid); + fontlist.addItem(f); + } else { + DebugString("font.cpp ====== CAN'T LOAD FONT FILE.\n"); + } + + FCLOSE(ff); + return f; +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Uninstall all installed fonts +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +void Font::uninstallAll(int ttfreload) { + int i; + // delete all by hand + for (i = 0; i < fontlist.getNumItems(); i++) { + svc_font *f = fontlist.enumItem(i); + if (ttfreload && f->isBitmap()) continue; + deleteFont(f); + fontlist.removeByPos(i); + i--; + } + if (!ttfreload) fontdefs.deleteAll(); +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Uninstall by scriptid +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +void Font::uninstallByScriptId(int scriptid) { + for (int i=0;i<fontlist.getNumItems();i++) { + svc_font *f = fontlist.enumItem(i); + if (f->getScriptId() == scriptid) { + fontlist.removeByPos(i); + deleteFont(f); + i--; + } + } + for (int i=0;i<fontdefs.getNumItems();i++) { + FontDef *fd = fontdefs.enumItem(i); + if (fd->scriptid == scriptid) { + fontdefs.removeByPos(i); + delete fd; + i--; + } + } +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Install a bitmap font and associates a script_id to it +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +void Font::installBitmapFont(const wchar_t *filename, const wchar_t *path, const wchar_t *id, int cw, int ch, int hs, int vs, int scriptid, int allowmapping) +{ + FontDef *fd = new FontDef; + fd->filename = filename; + fd->path = path; + fd->id = id; + fd->scriptid = scriptid; + fd->isbitmap = 1; + fd->allowmapping = allowmapping; + fontdefs.addItem(fd); + + BitmapFont *f = new BitmapFont; + f->setFontBitmap(filename, path); + f->setFontId(id); + f->setFontMetrics(cw, ch, hs, vs); + f->setScriptId(scriptid); + fontlist.addItem(f); +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Requests a Font* from its id +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +svc_font *Font::requestSkinFont(const wchar_t *id, int *size, int *gotdefault) +{ + if (gotdefault) *gotdefault = 0; + int oldsize = size ? *size : -1; + const wchar_t *mapped_id = getFontMapping(id, size); + if (mapped_id != NULL) + id = mapped_id; + + // First try to get a font by that id + foreach_reverse(fontlist) + const wchar_t *thisid = fontlist.getfor()->getFontId(); + if (thisid && !WCSICMP(thisid, id)) + return fontlist.getfor(); + endfor + // if it wasnt found, try to load a wa-installed ttfont with this face name + foreach_reverse(fontlist) + const wchar_t *facename=fontlist.getfor()->getFaceName(); + if (facename && !WCSICMP(facename, id)) return fontlist.getfor(); + endfor + + // not found, try to reload it front the list of fonts defined by the skin + foreach(fontdefs) + FontDef *fd = fontdefs.getfor(); + if (!WCSICMP(fd->id, id)) + { + if (!fd->isbitmap) + { + svc_font *f = installTrueTypeFont(fd->filename, fd->path, fd->id, fd->scriptid, fd->allowmapping, 1); + if (f) return f; + } + } + endfor; + + /* + for (i=fontlist.getNumItems()-1;i>=0;i--) { + const char *thisid = fontlist.enumItem(i)->getFontId(); + if (thisid && STRCASEEQL(thisid, "wasabi.font.ttf.default" )) + return fontlist.enumItem(i); + } + */ + + // not found ? try to find it in the windows fonts directory + { + wchar_t *fp = WMALLOC(WA_MAX_PATH); + Wasabi::Std::getFontPath(WA_MAX_PATH, fp); + StringW file; + file.own(fp); +// FREE(fp); // benski> no need because we now own it + file.AppendPath(StringPrintfW(L"%s%s", id, WCSCASESTR(id, L".ttf") == NULL ? L".ttf":L"")); + + if (!WACCESS(file, 0)) + { + svc_font *f = newTrueTypeFont(); + f->setFontFace(id); + f->setFontId(id); + OSFILETYPE ff = WFOPEN(file, WF_READONLY_BINARY); + if (ff != OPEN_FAILED) + { + if (f->addFontResource(ff, id)) + { + DebugStringW(L"font.cpp ====== FONT FOR ID=%s NOT FOUND. USING WIN FONT FILE:\n%s\n", id, file.getValue()); + fontlist.addItem(f); + } + } else { + DebugStringW(L"font.cpp ====== FONT FOR ID=%s NOT FOUND. CANNOT OPEN WIN FONT FILE:\n%s\n", id, file.getValue()); + delete f; + f = NULL; + } + return f; + } + } + + // not found ? ask the Std:: interface for the folder and the + // default fontname (ie: one you know will always be in the OS) + svc_font *f = newTrueTypeFont(); + if (f) { + if (gotdefault) *gotdefault = 1; + if (oldsize != -1 && size) { + *size = oldsize; + double f = (double)Wasabi::Std::getDefaultFontScale() / 100.0; + *size = (int)(*size*f); + } + // Query Std:: and build the path to the default font file. + wchar_t *fontPath = WMALLOC(WA_MAX_PATH); + Wasabi::Std::getFontPath(WA_MAX_PATH, fontPath); + wchar_t fontFile[WA_MAX_PATH] = {0}; + Wasabi::Std::getDefaultFont(WA_MAX_PATH, fontFile); + StringW defaultFont; + defaultFont.own(fontPath); + defaultFont.AppendPath(fontFile); +// FREE(fontFile); + StringW fs = defaultFont; + wchar_t *p = wcschr(fs.getNonConstVal(), '.'); + if (p) *p = 0; + PathParserW pp(fs); + fs = pp.getLastString(); + f->setFontFace(fs); + f->setFontId(id); + // Open it and load it as the font resource. + OSFILETYPE ff = WFOPEN(defaultFont, WF_READONLY_BINARY); + if (ff != OPEN_FAILED) { + if (f->addFontResource(ff, fs)) + { + DebugStringW(L"font.cpp ====== FONT FOR ID=%s NOT FOUND. USING DEFAULT FONT FILE:\n%s\n", id, defaultFont); + fontlist.addItem(f); + } + } else { + DebugStringW(L"font.cpp ====== FONT FOR ID=%s NOT FOUND. CANNOT OPEN FONT FILE:\n%s\n", id, defaultFont); + delete f; + f = NULL; + } + } else { + DebugString("font.cpp ====== CAN'T GET NEW FONT FILE.\n"); + delete f; + f = NULL; + } + + +#ifdef _WIN32 + if (f == NULL) { + // not found :((((( grab the default font data and use this, whatever it is + f = newTrueTypeFont(); + if (f) + { + HDC dc = GetDC(GetDesktopWindow()); + HDC dc2 = CreateCompatibleDC(dc); + SelectObject(dc2, GetStockObject(DEFAULT_GUI_FONT)); + + int datalen = GetFontData(dc2, 0, 0, NULL, 0); + if (datalen > 0) { + void *mem = WASABI_API_MEMMGR->sysMalloc(datalen+1); // freed by the service !! + ASSERT(mem != NULL); + GetFontData(dc2, 0, 0, mem, datalen); + + f->setFontFace(id); + f->setFontId(id); + f->addFontResource2(mem, datalen, id); + + ReleaseDC(GetDesktopWindow(), dc); + DeleteDC(dc2); + fontlist.addItem(f); + return f; + } + delete f; + f = NULL; + } + } +#else +#warning port me +#endif + + if (f == NULL) { + // ok, NOW I'm getting pissed + wchar_t fp[WA_MAX_PATH] = {0}; + Wasabi::Std::getFontPath(WA_MAX_PATH, fp); +#ifdef _WIN32 + Wasabi::Std::messageBox(StringPrintfW(L"Fatal error trying to load truetype fonts.\n\nYou need arial.ttf at the very least, but it does not appear to be in %s", fp), L"Fatal Error", MB_ICONERROR); +#else +#warning port me +#endif + } + + //if (f == NULL) DebugString("font.cpp ====== FALLBACK FOR FONT %s CANNOT BE FOUND IN OUR LISTS.\n",f->getFontId()); + + return f; +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Intelligently delete the font +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +void Font::deleteFont(svc_font *f) +{ + if (f) + { + if (f->isBitmap()) + { + delete static_cast<BitmapFont *>(f); // we delete our own bitmap fonts. + } + else + { + SvcEnum::release(f); + } + } +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Intelligently make a new truetype font from the service interfaces +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +svc_font *Font::newTrueTypeFont() +{ +/*#ifdef WASABI_COMPILE_CONFIG + const GUID options_guid = + { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; + CfgItem *options = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); +#endif*/ + + svc_font *retval = NULL; + const wchar_t *name = NULL; + +#ifdef WASABI_COMPILE_CONFIG + //const wchar_t *attr = L"Font Renderer"; + // First, try to find a font service that matches the attribute. +// if (options) { +// char buf[256]; // WHEEE for stack arrays +// if (options->getData(attr, buf, sizeof buf)) { + if (WASABI_API_SKIN->skin_getVersion() >= 1.3) // hardcode win32 renderer for v1.3+ skins + retval = FontSvcEnum(L"Win32 TextOut").getFirst(); + else + retval = FontSvcEnum(cfg_options_fontrenderer.getValue()).getFirst(); + +#else +#ifndef WASABI_FONT_RENDERER +#error You need to define WASABI_FONT_RENDERER (ie: #define WASABI_FONT_RENDERER "Freetype") +#endif + retval = FontSvcEnum(WASABI_FONT_RENDERER).getFirst(); +#endif +#ifdef WASABI_COMPILE_CONFIG +// } +// } + + // If we can't find one, fallback and just take the first. + if (!retval) + { + retval = FontSvcEnum().getFirst(); + if (retval != NULL) + name = retval->getFontSvcName(); + } + + // If we had to fallback, remember the fallback service in the attribute. + if (name/* && options*/) + { + //options->setData(attr, name); + cfg_options_fontrenderer.setValue(name); + } +#endif + + return retval; +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Test whether to forbid bitmap fonts. +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +int Font::useTrueTypeOverride(const wchar_t *txt) + +{ + if (cfg_options_no7bitsttfoverride.getValueAsInt()) + { + const wchar_t *p = (const wchar_t *)txt; + while (p && *p) + { + // TODO: benski> some characters above 127 can be handled by the bitmap fonts - it might be worth checking those explicitly + if (*p & 0xFF80) + break; + p++; + } + if (!*p) return 0; + } +#ifdef WASABI_COMPILE_CONFIG +/* // {280876CF-48C0-40bc-8E86-73CE6BB462E5} + const GUID options_guid = + { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; + return !_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid), "Use bitmap fonts (no international support)", 1);*/ + return !cfg_options_allowbitmapfonts.getValueAsInt(); +#else + return WASABI_FONT_TTFOVERRIDE; +#endif +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Get the font to be used to override bitmap fonts. +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +const wchar_t *Font::getTrueTypeOverride() +{ +#ifdef WASABI_COMPILE_CONFIG + return cfg_options_ttfoverridefont.getValue(); +#else + return L"Arial"; +#warning TODO +#endif +} + +int Font::getTrueTypeOverrideScale() +{ +#ifdef WASABI_COMPILE_CONFIG + return cfg_options_ttfoverridescale.getValueAsInt(); +#else + return 1; +#warning TODO +#endif +} + +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Returns the font mapping for this font & skin, if font mapper is on and if there is a mapping, otherwise returns null +// ------------------------------------------------------------------------------------------------------------------------------------------------------------- +const wchar_t *Font::getFontMapping(const wchar_t *id, int *size) +{ + if (cfg_options_usefontmapper.getValueAsInt()) + { + wchar_t t[256]=L""; + StringW tmp; + tmp.printf(L"Skin:%s/Font Mapping/%s",WASABI_API_SKIN->getSkinName(), id); + WASABI_API_CONFIG->getStringPrivate(tmp, t, 256, L""); + + tmp.printf(L"Skin:%s/Font Mapping/%s_scale",WASABI_API_SKIN->getSkinName(), id); + int v = WASABI_API_CONFIG->getIntPrivate(tmp, -1); + if (!*t) + { + tmp.printf(L"Font Mapping/%s", id); + WASABI_API_CONFIG->getStringPrivate(tmp, t, 256, L""); + tmp.printf(L"Font Mapping/%s_scale", id); + v = WASABI_API_CONFIG->getIntPrivate(tmp, -1); + } + mapping = t; + if (mapping.isempty()) return NULL; + if (size != NULL) + { + if (v != -1) + { + double f = (double)v / 100.0; + *size = (int)((double)*size * f); + } + } + return mapping; + } + return NULL; +} + +StringW Font::mapping;
\ No newline at end of file |