diff --git a/libraries/ZWidget/include/zwidget/core/resourcedata.h b/libraries/ZWidget/include/zwidget/core/resourcedata.h index 5eaedcfae..17627dabe 100644 --- a/libraries/ZWidget/include/zwidget/core/resourcedata.h +++ b/libraries/ZWidget/include/zwidget/core/resourcedata.h @@ -7,8 +7,7 @@ struct SingleFontData { std::vector fontdata; - std::vector> ranges; - int language = -1; // mainly useful if we start supporting Chinese so that we can use another font there than for Japanese. + std::string language; }; std::vector LoadWidgetFontData(const std::string& name); diff --git a/libraries/ZWidget/src/core/canvas.cpp b/libraries/ZWidget/src/core/canvas.cpp index 571266408..95890f7c7 100644 --- a/libraries/ZWidget/src/core/canvas.cpp +++ b/libraries/ZWidget/src/core/canvas.cpp @@ -47,7 +47,8 @@ class CanvasFont public: CanvasFont(const std::string& fontname, double height, std::vector& _data) : fontname(fontname), height(height) { - ttf = std::make_unique(std::make_shared(_data)); + auto tdata = std::make_shared(_data); + ttf = std::make_unique(tdata); textmetrics = ttf->GetTextMetrics(height); } @@ -58,6 +59,7 @@ public: CanvasGlyph* getGlyph(uint32_t utfchar) { uint32_t glyphIndex = ttf->GetGlyphIndex(utfchar); + if (glyphIndex == 0) return nullptr; auto& glyph = glyphs[glyphIndex]; if (glyph) @@ -266,8 +268,7 @@ public: struct SingleFont { std::unique_ptr font; - std::vector> ranges; - int language; // mainly useful if we start supporting Chinese so that we can use another font there than for Japanese. + std::string language; }; CanvasFontGroup(const std::string& fontname, double height) : height(height) { @@ -276,34 +277,22 @@ public: for (size_t i = 0; i < fonts.size(); i++) { fonts[i].font = std::make_unique(fontname, height, fontdata[i].fontdata); - fonts[i].ranges = std::move(fontdata[i].ranges); fonts[i].language = fontdata[i].language; } } - CanvasGlyph* getGlyph(uint32_t utfchar) + CanvasGlyph* getGlyph(uint32_t utfchar, const char* lang = nullptr) { - if (utfchar >= 0x530 && utfchar < 0x590) + for (int i = 0; i < 2; i++) { - int a = 0; - } - for (auto& fd : fonts) - { - bool get = false; - if (fd.ranges.size() == 0) get = true; - else for (auto r : fd.ranges) + for (auto& fd : fonts) { - if (utfchar >= r.first && utfchar <= r.second) + if (i == 1 || lang == nullptr || *lang == 0 || fd.language.empty() || fd.language == lang) { - get = true; - break; + auto g = fd.font->getGlyph(utfchar); + if (g) return g; } } - if (get) - { - auto g = fd.font->getGlyph(utfchar); - if (g) return g; - } } return nullptr; @@ -371,6 +360,8 @@ public: int getClipMaxX() const; int getClipMaxY() const; + void setLanguage(const char* lang) { language = lang; } + std::unique_ptr createTexture(int width, int height, const void* pixels, ImageFormat format = ImageFormat::B8G8R8A8); template @@ -390,6 +381,7 @@ public: std::vector pixels; std::unordered_map, std::unique_ptr> imageTextures; + std::string language; }; BitmapCanvas::BitmapCanvas(DisplayWindow* window) : window(window) @@ -557,8 +549,8 @@ void BitmapCanvas::drawText(const Point& pos, const Colorf& color, const std::st UTF8Reader reader(text.data(), text.size()); while (!reader.is_end()) { - CanvasGlyph* glyph = font->getGlyph(reader.character()); - if (!glyph->texture) + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) { glyph = font->getGlyph(32); } @@ -583,8 +575,8 @@ Rect BitmapCanvas::measureText(const std::string& text) UTF8Reader reader(text.data(), text.size()); while (!reader.is_end()) { - CanvasGlyph* glyph = font->getGlyph(reader.character()); - if (!glyph->texture) + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) { glyph = font->getGlyph(32); } diff --git a/src/common/widgets/widgetresourcedata.cpp b/src/common/widgets/widgetresourcedata.cpp index fd416e1d1..1b04e66fc 100644 --- a/src/common/widgets/widgetresourcedata.cpp +++ b/src/common/widgets/widgetresourcedata.cpp @@ -2,6 +2,12 @@ #include #include "filesystem.h" #include "printf.h" +#include "zstring.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif FResourceFile* WidgetResources; @@ -17,11 +23,11 @@ void CloseWidgetResources() if (WidgetResources) delete WidgetResources; } -static std::vector LoadFile(const std::string& name) +static std::vector LoadFile(const char* name) { - auto lump = WidgetResources->FindEntry(name.c_str()); + auto lump = WidgetResources->FindEntry(name); if (lump == -1) - I_FatalError("Unable to find %s", name.c_str()); + I_FatalError("Unable to find %s", name); auto reader = WidgetResources->GetEntryReader(lump, FileSys::READER_SHARED); std::vector buffer(reader.GetLength()); @@ -29,31 +35,53 @@ static std::vector LoadFile(const std::string& name) return buffer; } +// this must be allowed to fail without throwing. +static std::vector LoadDiskFile(const char* name) +{ + std::vector buffer; + FileSys::FileReader lump; + if (lump.OpenFile(name)) + { + buffer.resize(lump.GetLength()); + lump.Read(buffer.data(), buffer.size()); + } + return buffer; +} + // This interface will later require some significant redesign. std::vector LoadWidgetFontData(const std::string& name) { std::vector 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 + returnv.resize(5); + returnv[0].fontdata = LoadFile("widgets/noto/notosans-regular.ttf"); + returnv[1].fontdata = LoadFile("widgets/noto/notosansarmenian-regular.ttf"); + returnv[2].fontdata = LoadFile("widgets/noto/notosansgeorgian-regular.ttf"); +#ifdef _WIN32 + wchar_t wbuffer[256]; + if (GetWindowsDirectoryW(wbuffer, 256)) + { + FString windir(wbuffer); + returnv[3].fontdata = LoadDiskFile((windir + "/fonts/yugothm.ttc").GetChars()); + returnv[3].language = "ja"; + returnv[4].fontdata = LoadDiskFile((windir + "/fonts/malgun.ttf").GetChars()); + returnv[4].language = "ko"; + // Don't fail if these cannot be found + if (returnv[4].fontdata.size() == 0) returnv.erase(returnv.begin() + 4); + if (returnv[3].fontdata.size() == 0) returnv.erase(returnv.begin() + 3); + } +#endif return returnv; } returnv.resize(1); std::string fn = "widgets/font/" +name + ".ttf"; - returnv[0].fontdata = LoadFile(fn); + returnv[0].fontdata = LoadFile(fn.c_str()); return returnv; } std::vector LoadWidgetImageData(const std::string& name) { - return LoadFile(name); + return LoadFile(name.c_str()); }