summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/font/font_sdl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/font/font_sdl.cpp')
-rw-r--r--src/osd/modules/font/font_sdl.cpp150
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 */