use a more complete font did some primitive font substitution logic.

NotoSans was chosen because it contains all Latin, Cyrillic and Greek characters in one file.
To test the substitution the separate font files for Armenian and Georgian were also added, even though the languages have not been translated.
This commit is contained in:
Christoph Oelckers 2024-01-02 18:58:39 +01:00
parent 3caca15c61
commit f5c4964902
11 changed files with 107 additions and 24 deletions

View file

@ -256,7 +256,7 @@ if( MSVC )
# String pooling
# Function-level linking
# Disable run-time type information
set( ALL_C_FLAGS "/GF /Gy /permissive-" )
set( ALL_C_FLAGS "/GF /Gy /permissive- /utf-8" )
if ( HAVE_VULKAN )
set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_VULKAN" )

View file

@ -4,5 +4,12 @@
#include <cstdint>
#include <string>
std::vector<uint8_t> LoadWidgetFontData(const std::string& name);
struct SingleFontData
{
std::vector<uint8_t> fontdata;
std::vector<std::pair<uint32_t, uint32_t>> ranges;
int language = -1; // mainly useful if we start supporting Chinese so that we can use another font there than for Japanese.
};
std::vector<SingleFontData> LoadWidgetFontData(const std::string& name);
std::vector<uint8_t> LoadWidgetImageData(const std::string& name);

View file

@ -149,7 +149,7 @@ private:
bool select_all_on_focus_gain = false;
std::shared_ptr<Font> font = Font::Create("Segoe UI", 12.0);
std::shared_ptr<Font> font = Font::Create("NotoSans", 12.0);
template<typename T>
static T clamp(T val, T minval, T maxval) { return std::max<T>(std::min<T>(val, maxval), minval); }

View file

@ -36,9 +36,9 @@ public:
class CanvasFont
{
public:
CanvasFont(const std::string& fontname, double height) : fontname(fontname), height(height)
CanvasFont(const std::string& fontname, double height, std::vector<uint8_t>& _data) : fontname(fontname), height(height)
{
data = LoadWidgetFontData(fontname);
data = std::move(_data);
loadFont(data.data(), data.size());
try
@ -152,6 +152,65 @@ private:
std::vector<uint8_t> data;
};
class CanvasFontGroup
{
public:
struct SingleFont
{
std::unique_ptr<CanvasFont> font;
std::vector<std::pair<uint32_t, uint32_t>> ranges;
int language; // mainly useful if we start supporting Chinese so that we can use another font there than for Japanese.
};
CanvasFontGroup(const std::string& fontname, double height) : height(height)
{
auto fontdata = LoadWidgetFontData(fontname);
fonts.resize(fontdata.size());
for (size_t i = 0; i < fonts.size(); i++)
{
fonts[i].font = std::make_unique<CanvasFont>(fontname, height, fontdata[i].fontdata);
fonts[i].ranges = std::move(fontdata[i].ranges);
fonts[i].language = fontdata[i].language;
}
}
CanvasGlyph* getGlyph(uint32_t utfchar)
{
if (utfchar >= 0x530 && utfchar < 0x590)
{
int a = 0;
}
for (auto& fd : fonts)
{
bool get = false;
if (fd.ranges.size() == 0) get = true;
else for (auto r : fd.ranges)
{
if (utfchar >= r.first && utfchar <= r.second)
{
get = true;
break;
}
}
if (get)
{
auto g = fd.font->getGlyph(utfchar);
if (g) return g;
}
}
return nullptr;
}
SFT_LMetrics& GetTextMetrics()
{
return fonts[0].font->textmetrics;
}
double height;
std::vector<SingleFont> fonts;
};
class BitmapCanvas : public Canvas
{
public:
@ -211,7 +270,7 @@ public:
DisplayWindow* window = nullptr;
std::unique_ptr<CanvasFont> font;
std::unique_ptr<CanvasFontGroup> font;
std::unique_ptr<CanvasTexture> whiteTexture;
Point origin;
@ -230,7 +289,7 @@ BitmapCanvas::BitmapCanvas(DisplayWindow* window) : window(window)
uiscale = window->GetDpiScale();
uint32_t white = 0xffffffff;
whiteTexture = createTexture(1, 1, &white);
font = std::make_unique<CanvasFont>("Segoe UI", 13.0*uiscale);
font = std::make_unique<CanvasFontGroup>("NotoSans", 13.0*uiscale);
}
BitmapCanvas::~BitmapCanvas()
@ -411,7 +470,7 @@ void BitmapCanvas::drawText(const Point& pos, const Colorf& color, const std::st
Rect BitmapCanvas::measureText(const std::string& text)
{
double x = 0.0;
double y = font->textmetrics.ascender - font->textmetrics.descender;
double y = font->GetTextMetrics().ascender - font->GetTextMetrics().descender;
UTF8Reader reader(text.data(), text.size());
while (!reader.is_end())
@ -433,8 +492,9 @@ VerticalTextPosition BitmapCanvas::verticalTextAlign()
{
VerticalTextPosition align;
align.top = 0.0f;
align.baseline = font->textmetrics.ascender / uiscale;
align.bottom = (font->textmetrics.ascender - font->textmetrics.descender) / uiscale;
auto tm = font->GetTextMetrics();
align.baseline = tm.ascender / uiscale;
align.bottom = (tm.ascender - tm.descender) / uiscale;
return align;
}

View file

@ -1,4 +1,3 @@
#include "launcherwindow.h"
#include "v_video.h"
#include "version.h"

View file

@ -12,19 +12,7 @@ void InitWidgetResources(const char* filename)
I_FatalError("Unable to open %s", filename);
}
std::vector<uint8_t> LoadWidgetFontData(const std::string& name)
{
auto lump = WidgetResources->FindEntry("widgets/poppins/poppins-regular.ttf");
if (lump == -1)
I_FatalError("Unable to find %s", name.c_str());
auto reader = WidgetResources->GetEntryReader(lump, FileSys::READER_SHARED);
std::vector<uint8_t> buffer(reader.GetLength());
reader.Read(buffer.data(), buffer.size());
return buffer;
}
std::vector<uint8_t> LoadWidgetImageData(const std::string& name)
static std::vector<uint8_t> LoadFile(const std::string& name)
{
auto lump = WidgetResources->FindEntry(name.c_str());
if (lump == -1)
@ -35,3 +23,32 @@ std::vector<uint8_t> LoadWidgetImageData(const std::string& name)
reader.Read(buffer.data(), buffer.size());
return buffer;
}
// This interface will later require some significant redesign.
std::vector<SingleFontData> LoadWidgetFontData(const std::string& name)
{
std::vector<SingleFontData> returnv;
if (!stricmp(name.c_str(), "notosans"))
{
returnv.resize(3);
returnv[2].fontdata = LoadFile("widgets/noto/notosans-regular.ttf");
returnv[0].fontdata = LoadFile("widgets/noto/notosansarmenian-regular.ttf");
returnv[1].fontdata = LoadFile("widgets/noto/notosansgeorgian-regular.ttf");
returnv[0].ranges.push_back(std::make_pair(0x531, 0x58f));
returnv[1].ranges.push_back(std::make_pair(0x10a0, 0x10ff));
returnv[1].ranges.push_back(std::make_pair(0x1c90, 0x1cbf));
returnv[1].ranges.push_back(std::make_pair(0x2d00, 0x2d2f));
// todo: load system CJK fonts here
return returnv;
}
returnv.resize(1);
std::string fn = "widgets/font/" +name + ".ttf";
returnv[0].fontdata = LoadFile(fn);
return returnv;
}
std::vector<uint8_t> LoadWidgetImageData(const std::string& name)
{
return LoadFile(name);
}

Binary file not shown.