diff options
Diffstat (limited to 'src/osd/modules/font/font_sdl.cpp')
-rw-r--r-- | src/osd/modules/font/font_sdl.cpp | 150 |
1 files changed, 84 insertions, 66 deletions
diff --git a/src/osd/modules/font/font_sdl.cpp b/src/osd/modules/font/font_sdl.cpp index 3c8a69d5d63..bfe3013032e 100644 --- a/src/osd/modules/font/font_sdl.cpp +++ b/src/osd/modules/font/font_sdl.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb /* * font_sdl.c * @@ -8,15 +8,19 @@ #include "font_module.h" #include "modules/osdmodule.h" -#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) +#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU) #include "corestr.h" #include "corealloc.h" #include "fileio.h" #include "unicode.h" +#ifdef SDLMAME_EMSCRIPTEN +#include <SDL_ttf.h> +#else #include <SDL2/SDL_ttf.h> -#ifndef SDLMAME_HAIKU +#endif +#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) #include <fontconfig/fontconfig.h> #endif @@ -52,11 +56,11 @@ private: static constexpr double POINT_SIZE = 144.0; -#ifndef SDLMAME_HAIKU - TTF_Font_ptr search_font_config(std::string const &name, bool bold, bool italic, bool underline, bool &bakedstyles); +#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) + TTF_Font_ptr search_font_config(std::string const &family, std::string const &style, bool &bakedstyles); #endif bool BDF_Check_Magic(std::string const &name); - TTF_Font_ptr TTF_OpenFont_Magic(std::string const &name, int fsize); + TTF_Font_ptr TTF_OpenFont_Magic(std::string const &name, int fsize, long index); TTF_Font_ptr m_font; }; @@ -65,42 +69,42 @@ bool osd_font_sdl::open(std::string const &font_path, std::string const &_name, { bool bakedstyles = false; - // accept qualifiers from the name std::string name(_name); if (name.compare("default") == 0) { - name = "Liberation Sans"; + name = "Liberation Sans|Regular"; } - bool const bold = (strreplace(name, "[B]", "") + strreplace(name, "[b]", "") > 0); - bool const italic = (strreplace(name, "[I]", "") + strreplace(name, "[i]", "") > 0); + // accept qualifiers from the name bool const underline = (strreplace(name, "[U]", "") + strreplace(name, "[u]", "") > 0); bool const strike = (strreplace(name, "[S]", "") + strreplace(name, "[s]", "") > 0); + std::string::size_type const separator = name.rfind('|'); + std::string const family(name.substr(0, separator)); + std::string const style((std::string::npos != separator) ? name.substr(separator + 1) : std::string()); // first up, try it as a filename - TTF_Font_ptr font = TTF_OpenFont_Magic(name, POINT_SIZE); + TTF_Font_ptr font = TTF_OpenFont_Magic(family, POINT_SIZE, 0); // if no success, try the font path - if (!font) { - osd_printf_verbose("Searching font %s in -%s\n", name.c_str(), OPTION_FONTPATH); + osd_printf_verbose("Searching font %s in -%s\n", family.c_str(), OPTION_FONTPATH); //emu_file file(options().font_path(), OPEN_FLAG_READ); emu_file file(font_path.c_str(), OPEN_FLAG_READ); - if (file.open(name.c_str()) == osd_file::error::NONE) + if (file.open(family.c_str()) == osd_file::error::NONE) { std::string full_name = file.fullpath(); - font = TTF_OpenFont_Magic(full_name, POINT_SIZE); + font = TTF_OpenFont_Magic(full_name, POINT_SIZE, 0); if (font) osd_printf_verbose("Found font %s\n", full_name.c_str()); } } // if that didn't work, crank up the FontConfig database -#ifndef SDLMAME_HAIKU +#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) if (!font) { - font = search_font_config(name, bold, italic, underline, bakedstyles); + font = search_font_config(family, style, bakedstyles); } #endif @@ -114,21 +118,21 @@ bool osd_font_sdl::open(std::string const &font_path, std::string const &_name, } // apply styles - int style = 0; + int styleflags = 0; if (!bakedstyles) { - style |= bold ? TTF_STYLE_BOLD : 0; - style |= italic ? TTF_STYLE_ITALIC : 0; + if ((style.find("Bold") != std::string::npos) || (style.find("Black") != std::string::npos)) styleflags |= TTF_STYLE_BOLD; + if ((style.find("Italic") != std::string::npos) || (style.find("Oblique") != std::string::npos)) styleflags |= TTF_STYLE_ITALIC; } - style |= underline ? TTF_STYLE_UNDERLINE : 0; + styleflags |= underline ? TTF_STYLE_UNDERLINE : 0; // SDL_ttf 2.0.9 and earlier does not define TTF_STYLE_STRIKETHROUGH #if SDL_VERSIONNUM(TTF_MAJOR_VERSION, TTF_MINOR_VERSION, TTF_PATCHLEVEL) > SDL_VERSIONNUM(2,0,9) - style |= strike ? TTF_STYLE_STRIKETHROUGH : 0; + styleflags |= strike ? TTF_STYLE_STRIKETHROUGH : 0; #else if (strike) osd_printf_warning("Ignoring strikethrough for SDL_TTF older than 2.0.10\n"); #endif // PATCHLEVEL - TTF_SetFontStyle(font.get(), style); + TTF_SetFontStyle(font.get(), styleflags); height = TTF_FontLineSkip(font.get()); @@ -157,9 +161,9 @@ void osd_font_sdl::close() bool osd_font_sdl::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, std::int32_t &width, std::int32_t &xoffs, std::int32_t &yoffs) { SDL_Color const fcol = { 0xff, 0xff, 0xff }; - std::uint16_t ustr[16]; - ustr[utf16_from_uchar(ustr, ARRAY_LENGTH(ustr), chnum)] = 0; - std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> const drawsurf(TTF_RenderUNICODE_Solid(m_font.get(), ustr, fcol), &SDL_FreeSurface); + char ustr[16]; + ustr[utf8_from_uchar(ustr, ARRAY_LENGTH(ustr), chnum)] = '\0'; + std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> const drawsurf(TTF_RenderUTF8_Solid(m_font.get(), ustr, fcol), &SDL_FreeSurface); // was nothing returned? if (drawsurf) @@ -187,18 +191,26 @@ bool osd_font_sdl::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, std::in return bitmap.valid(); } -osd_font_sdl::TTF_Font_ptr osd_font_sdl::TTF_OpenFont_Magic(std::string const &name, int fsize) +osd_font_sdl::TTF_Font_ptr osd_font_sdl::TTF_OpenFont_Magic(std::string const &name, int fsize, long index) { emu_file file(OPEN_FLAG_READ); if (file.open(name.c_str()) == osd_file::error::NONE) { - unsigned char const magic[] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; - unsigned char buffer[sizeof(magic)] = { 0xff, 0xff, 0xff, 0xff, 0xff }; - if ((sizeof(magic) != file.read(buffer, sizeof(magic))) || memcmp(buffer, magic, sizeof(magic))) - return TTF_Font_ptr(nullptr, &TTF_CloseFont); + unsigned char const ttf_magic[] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; + unsigned char const ttc1_magic[] = { 0x74, 0x74, 0x63, 0x66, 0x00, 0x01, 0x00, 0x00 }; + unsigned char const ttc2_magic[] = { 0x74, 0x74, 0x63, 0x66, 0x00, 0x02, 0x00, 0x00 }; + unsigned char buffer[std::max({ sizeof(ttf_magic), sizeof(ttc1_magic), sizeof(ttc2_magic) })]; + auto const bytes_read = file.read(buffer, sizeof(buffer)); file.close(); + + if ((bytes_read >= sizeof(ttf_magic)) && !std::memcmp(buffer, ttf_magic, sizeof(ttf_magic))) + return TTF_Font_ptr(TTF_OpenFont(name.c_str(), POINT_SIZE), &TTF_CloseFont); + + if (((bytes_read >= sizeof(ttc1_magic)) && !std::memcmp(buffer, ttc1_magic, sizeof(ttc1_magic))) || + ((bytes_read >= sizeof(ttc2_magic)) && !std::memcmp(buffer, ttc2_magic, sizeof(ttc2_magic)))) + return TTF_Font_ptr(TTF_OpenFontIndex(name.c_str(), POINT_SIZE, index), &TTF_CloseFont); } - return TTF_Font_ptr(TTF_OpenFont(name.c_str(), POINT_SIZE), &TTF_CloseFont); + return TTF_Font_ptr(nullptr, &TTF_CloseFont); } bool osd_font_sdl::BDF_Check_Magic(std::string const &name) @@ -214,36 +226,24 @@ bool osd_font_sdl::BDF_Check_Magic(std::string const &name) return false; } -#ifndef SDLMAME_HAIKU -osd_font_sdl::TTF_Font_ptr osd_font_sdl::search_font_config(std::string const &name, bool bold, bool italic, bool underline, bool &bakedstyles) +#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) +osd_font_sdl::TTF_Font_ptr osd_font_sdl::search_font_config(std::string const &family, std::string const &style, bool &bakedstyles) { TTF_Font_ptr font(nullptr, &TTF_CloseFont); FcConfig *const config = FcConfigGetCurrent(); std::unique_ptr<FcPattern, void (*)(FcPattern *)> pat(FcPatternCreate(), &FcPatternDestroy); std::unique_ptr<FcObjectSet, void (*)(FcObjectSet *)> os(FcObjectSetCreate(), &FcObjectSetDestroy); - FcPatternAddString(pat.get(), FC_FAMILY, (const FcChar8 *)name.c_str()); + FcPatternAddString(pat.get(), FC_FAMILY, (const FcChar8 *)family.c_str()); // try and get a font with the requested styles baked-in - if (bold) - { - if (italic) - FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)"Bold Italic"); - else - FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)"Bold"); - } - else if (italic) - { - FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)"Italic"); - } - else - { - FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)"Regular"); - } + if (!style.empty()) + FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)style.c_str()); FcPatternAddString(pat.get(), FC_FONTFORMAT, (const FcChar8 *)"TrueType"); FcObjectSetAdd(os.get(), FC_FILE); + FcObjectSetAdd(os.get(), FC_INDEX); std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontset(FcFontList(config, pat.get(), os.get()), &FcFontSetDestroy); for (int i = 0; (i < fontset->nfont) && !font; i++) @@ -253,8 +253,9 @@ osd_font_sdl::TTF_Font_ptr osd_font_sdl::search_font_config(std::string const &n { osd_printf_verbose("Matching font: %s\n", val.u.s); - std::string match_name((const char*)val.u.s); - font = TTF_OpenFont_Magic(match_name, POINT_SIZE); + std::string const match_name((const char*)val.u.s); + long const index = ((FcPatternGet(fontset->fonts[i], FC_INDEX, 0, &val) == FcResultMatch) && (val.type == FcTypeInteger)) ? val.u.i : 0; + font = TTF_OpenFont_Magic(match_name, POINT_SIZE, index); if (font) bakedstyles = true; @@ -262,12 +263,11 @@ osd_font_sdl::TTF_Font_ptr osd_font_sdl::search_font_config(std::string const &n } // didn't get a font above? try again with no baked-in styles - if (!font) + // note that this simply returns the first match for the family name, which could be regular if you're lucky, but it could be bold oblique or something + if (!font && !style.empty()) { pat.reset(FcPatternCreate()); - FcPatternAddString(pat.get(), FC_FAMILY, (const FcChar8 *)name.c_str()); - //Quite a lot of fonts don't have a "Regular" font type attribute - //FcPatternAddString(pat.get(), FC_STYLE, (const FcChar8 *)"Regular"); + FcPatternAddString(pat.get(), FC_FAMILY, (const FcChar8 *)family.c_str()); FcPatternAddString(pat.get(), FC_FONTFORMAT, (const FcChar8 *)"TrueType"); fontset.reset(FcFontList(config, pat.get(), os.get())); @@ -278,8 +278,12 @@ osd_font_sdl::TTF_Font_ptr osd_font_sdl::search_font_config(std::string const &n { osd_printf_verbose("Matching unstyled font: %s\n", val.u.s); - std::string const match_name((const char *)val.u.s); - font = TTF_OpenFont_Magic(match_name, POINT_SIZE); + std::string const match_name((const char*)val.u.s); + long const index = ((FcPatternGet(fontset->fonts[i], FC_INDEX, 0, &val) == FcResultMatch) && (val.type == FcTypeInteger)) ? val.u.i : 0; + font = TTF_OpenFont_Magic(match_name, POINT_SIZE, index); + + if (font) + bakedstyles = false; } } } @@ -296,12 +300,12 @@ public: { } - osd_font::ptr font_alloc() + osd_font::ptr font_alloc() override { return std::make_unique<osd_font_sdl>(); } - virtual int init(const osd_options &options) + virtual int init(const osd_options &options) override { if (TTF_Init() == -1) { @@ -311,7 +315,7 @@ public: return 0; } - virtual void exit() + virtual void exit() override { TTF_Quit(); } @@ -326,6 +330,7 @@ bool font_sdl::get_font_families(std::string const &font_path, std::vector<std:: // TODO: enumerate TTF files in font path, since we can load them, too +#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN) FcConfig *const config = FcConfigGetCurrent(); std::unique_ptr<FcPattern, void (*)(FcPattern *)> pat(FcPatternCreate(), &FcPatternDestroy); FcPatternAddString(pat.get(), FC_FONTFORMAT, (const FcChar8 *)"TrueType"); @@ -333,6 +338,7 @@ bool font_sdl::get_font_families(std::string const &font_path, std::vector<std:: std::unique_ptr<FcObjectSet, void (*)(FcObjectSet *)> os(FcObjectSetCreate(), &FcObjectSetDestroy); FcObjectSetAdd(os.get(), FC_FAMILY); FcObjectSetAdd(os.get(), FC_FILE); + FcObjectSetAdd(os.get(), FC_STYLE); std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontset(FcFontList(config, pat.get(), os.get()), &FcFontSetDestroy); for (int i = 0; (i < fontset->nfont); i++) @@ -345,18 +351,30 @@ bool font_sdl::get_font_families(std::string const &font_path, std::vector<std:: { auto const compare_fonts = [](std::pair<std::string, std::string> const &a, std::pair<std::string, std::string> const &b) -> bool { - int const first = core_stricmp(a.first.c_str(), b.first.c_str()); - if (first < 0) return true; - else if (first > 0) return false; - else return core_stricmp(b.second.c_str(), b.second.c_str()) < 0; + int const second = core_stricmp(a.second.c_str(), b.second.c_str()); + if (second < 0) return true; + else if (second > 0) return false; + else return core_stricmp(b.first.c_str(), b.first.c_str()) < 0; }; - std::pair<std::string, std::string> font((const char *)val.u.s, (const char *)val.u.s); + std::string config((const char *)val.u.s); + std::string display(config); + if ((FcPatternGet(fontset->fonts[i], FC_STYLE, 0, &val) == FcResultMatch) && (val.type == FcTypeString)) + { + config.push_back('|'); + config.append((const char *)val.u.s); + display.push_back(' '); + display.append((const char *)val.u.s); + } + std::pair<std::string, std::string> font(std::move(config), std::move(display)); auto const pos = std::lower_bound(result.begin(), result.end(), font, compare_fonts); if ((result.end() == pos) || (pos->first != font.first)) result.emplace(pos, std::move(font)); } } return true; +#else + return false; +#endif } #else /* SDLMAME_UNIX */ |