From be60cf8978007e8757c828c99b5c7f59ed6de53f Mon Sep 17 00:00:00 2001 From: kaetemi Date: Tue, 3 Nov 2020 08:04:28 +0800 Subject: [PATCH 1/2] Localizable font families, start font name with ui to get a \n-separated font list from uxt, close ryzom/ryzomcore#623 --- nel/include/nel/3d/font_generator.h | 5 +- nel/src/3d/font_generator.cpp | 190 ++++++++++++------ nel/src/gui/view_renderer.cpp | 2 +- .../build_gamedata/processes/font/1_export.py | 1 + .../processes/font/3_install.py | 1 + ryzom/client/src/global.cpp | 2 +- 6 files changed, 130 insertions(+), 71 deletions(-) diff --git a/nel/include/nel/3d/font_generator.h b/nel/include/nel/3d/font_generator.h index eca05d456..f79b3c109 100644 --- a/nel/include/nel/3d/font_generator.h +++ b/nel/include/nel/3d/font_generator.h @@ -36,7 +36,7 @@ typedef struct FT_FaceRec_* FT_Face; #include "nel/misc/types_nl.h" #include - +#include namespace NL3D { @@ -88,6 +88,7 @@ private: static uint32 _FontGeneratorCounterUID; uint32 _UID; std::string _FontFileName; + std::vector _FontFileNames; #ifndef NL_DONT_USE_EXTERNAL_CODE const char *getFT2Error(FT_Error fte); @@ -95,7 +96,7 @@ private: static FT_Library _Library; static uint _LibraryInit; - FT_Face _Face; + std::vector _Faces; #else // NL_DONT_USE_EXTERNAL_CODE #endif // NL_DONT_USE_EXTERNAL_CODE diff --git a/nel/src/3d/font_generator.cpp b/nel/src/3d/font_generator.cpp index 06ccd3a8b..8cc24c4b6 100644 --- a/nel/src/3d/font_generator.cpp +++ b/nel/src/3d/font_generator.cpp @@ -26,6 +26,7 @@ #include "nel/misc/common.h" #include "nel/misc/path.h" #include "nel/misc/file.h" +#include "nel/misc/i18n.h" #include "nel/3d/font_generator.h" @@ -190,6 +191,20 @@ CFontGenerator::CFontGenerator (const std::string &fontFileName, const std::stri _FontGeneratorCounterUID++; _FontFileName = fontFileName; + if (NLMISC::startsWith(fontFileName, "ui")) + { + std::string nameList = CI18N::get(fontFileName); + NLMISC::explode(nameList, string("\n"), _FontFileNames, true); + for (std::vector::iterator it(_FontFileNames.begin()), end(_FontFileNames.end()); it != end; ++it) + { + *it = CPath::lookup(*it); + } + } + else + { + _FontFileNames.push_back(fontFileName); + } + FT_Error error; if (!_LibraryInit) @@ -202,49 +217,66 @@ CFontGenerator::CFontGenerator (const std::string &fontFileName, const std::stri } ++_LibraryInit; - FT_Open_Args args; - - if (!createFreetypeStream(fontFileName, args)) + for (std::vector::iterator it(_FontFileNames.begin()), end(_FontFileNames.end()); it != end; ++it) { - nlerror ("createFreetypeStream failed with file '%s'", fontFileName.c_str()); - } + FT_Open_Args args; + const std::string &fileName = *it; - error = FT_Open_Face(_Library, &args, 0, &_Face); - if (error) - { - nlerror ("FT_New_Face() failed with file '%s': %s", fontFileName.c_str(), getFT2Error(error)); - } + if (!createFreetypeStream(fileName, args)) + { + nlerror("createFreetypeStream failed with file '%s'", fileName.c_str()); + } - string fontEx = fontExFileName; - if (fontEx.empty()) - { - // try to see if the ex filename exists based on the fontExFileName - fontEx = CPath::lookup(CFile::getFilenameWithoutExtension (fontFileName)+".afm", false, false); - } + FT_Face face; + error = FT_Open_Face(_Library, &args, 0, &face); + if (error) + { + nlerror("FT_New_Face() failed with file '%s': %s", fileName.c_str(), getFT2Error(error)); + } - if (!fontEx.empty()) - { - if (!createFreetypeStream(fontEx, args)) + string fontEx = fontExFileName; + if (fontEx.empty()) + { + // try to see if the ex filename exists based on the fontExFileName + fontEx = CPath::lookup(CFile::getFilenameWithoutExtension(fileName) + ".afm", false, false); + } + + if (!fontEx.empty()) { - nlerror ("createFreetypeStream failed with file '%s'", fontFileName.c_str()); + if (!createFreetypeStream(fontEx, args)) + { + nlerror("createFreetypeStream failed with file '%s'", fileName.c_str()); + FT_Done_Face(face); + continue; + } + + error = FT_Attach_Stream(face, &args); + if (error) + { + nlwarning("FT_Attach_File() failed with file '%s': %s", fontEx.c_str(), getFT2Error(error)); + FT_Done_Face(face); + continue; + } } - error = FT_Attach_Stream(_Face, &args); + error = FT_Select_Charmap(face, ft_encoding_unicode); if (error) { - nlwarning ("FT_Attach_File() failed with file '%s': %s", fontEx.c_str(), getFT2Error(error)); + nlerror("FT_Select_Charmap() failed with file '%s': %s", fileName.c_str(), getFT2Error(error)); + FT_Done_Face(face); + continue; } - } - error = FT_Select_Charmap (_Face, ft_encoding_unicode); - if (error) - { - nlerror ("FT_Select_Charmap() failed with file '%s': %s", fontFileName.c_str(), getFT2Error(error)); + _Faces.push_back(face); } } CFontGenerator::~CFontGenerator () { + for (std::vector::iterator it(_Faces.begin()), end(_Faces.end()); it != end; ++it) + FT_Done_Face(*it); + _Faces.clear(); + // important: destroying and creating your last font generator // will also reload the freetype library nlassert(_LibraryInit); @@ -259,30 +291,41 @@ CFontGenerator::~CFontGenerator () void CFontGenerator::getSizes (u32char c, uint32 size, uint32 &width, uint32 &height) { FT_Error error; + FT_Face face; + FT_UInt glyph_index = 0; - error = FT_Set_Pixel_Sizes (_Face, size, size); - if (error) + if (!_Faces.size()) { - nlerror ("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error)); + nlerror("No faces loaded"); + return; } - // retrieve glyph index from character code - FT_UInt glyph_index = FT_Get_Char_Index (_Face, c); - - if (glyph_index == 0) + for (std::vector::iterator it(_Faces.begin()), end(_Faces.end()); it != end; ++it) { - // no glyph available, replace with a dot - glyph_index = FT_Get_Char_Index (_Face, u32char('.')); + face = *it; + error = FT_Set_Pixel_Sizes(face, size, size); + if (error) + { + nlerror("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error)); + continue; + } + + // retrieve glyph index from character code + glyph_index = FT_Get_Char_Index(face, c); + + // found glyph + if (glyph_index) + break; } // load glyph image into the slot (erase previous one) - error = FT_Load_Glyph (_Face, glyph_index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) { // use fallback for glyph/character errors (composite char limit for example) nlwarning ("FT_Load_Glyph() failed: %s", getFT2Error(error)); - error = FT_Load_Glyph (_Face, 0, FT_LOAD_DEFAULT); + error = FT_Load_Glyph(face, 0, FT_LOAD_DEFAULT); if (error) { nlerror("FT_Load_Glyph() fallback failed: %s", getFT2Error(error)); @@ -290,39 +333,48 @@ void CFontGenerator::getSizes (u32char c, uint32 size, uint32 &width, uint32 &he } // convert 24.6 fixed point into integer - width = _Face->glyph->metrics.width >> 6; - height = _Face->glyph->metrics.height >> 6; + width = face->glyph->metrics.width >> 6; + height = face->glyph->metrics.height >> 6; } uint8 *CFontGenerator::getBitmap (u32char c, uint32 size, bool embolden, bool oblique, uint32 &width, uint32 &height, uint32 &pitch, sint32 &left, sint32 &top, sint32 &advx, uint32 &glyphIndex) { FT_Error error; + FT_Face face; + FT_UInt glyph_index = 0; - error = FT_Set_Pixel_Sizes (_Face, size, size); - if (error) + if (!_Faces.size()) { - nlerror ("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error)); + nlerror("No faces loaded"); + return NULL; } - // retrieve glyph index from character code - FT_UInt glyph_index = FT_Get_Char_Index (_Face, c); - - /* - if (glyph_index == 0) + for (std::vector::iterator it(_Faces.begin()), end(_Faces.end()); it != end; ++it) { - // no glyph available, replace with a dot - glyph_index = FT_Get_Char_Index (_Face, u32char('.')); + face = *it; + error = FT_Set_Pixel_Sizes(face, size, size); + if (error) + { + nlerror("FT_Set_Pixel_Sizes() failed: %s", getFT2Error(error)); + continue; + } + + // retrieve glyph index from character code + glyph_index = FT_Get_Char_Index(face, c); + + // found glyph + if (glyph_index) + break; } - */ // load glyph image into the slot (erase previous one) - error = FT_Load_Glyph (_Face, glyph_index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); if (error) { // use fallback for glyph/character errors (composite char limit for example) nlwarning ("FT_Load_Glyph() failed: %s", getFT2Error(error)); - error = FT_Load_Glyph (_Face, 0, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (face, 0, FT_LOAD_DEFAULT); if (error) { nlerror("FT_Load_Glyph() fallback failed: %s", getFT2Error(error)); @@ -343,47 +395,49 @@ uint8 *CFontGenerator::getBitmap (u32char c, uint32 size, bool embolden, bool ob if (embolden) { - FT_GlyphSlot_Embolden(_Face->glyph); + FT_GlyphSlot_Embolden(face->glyph); } if (oblique) { - FT_GlyphSlot_Oblique(_Face->glyph); + FT_GlyphSlot_Oblique(face->glyph); } // convert to an anti-aliased bitmap - error = FT_Render_Glyph (_Face->glyph, ft_render_mode_normal); + error = FT_Render_Glyph (face->glyph, ft_render_mode_normal); if (error) { nlerror ("FT_Render_Glyph() failed: %s", getFT2Error(error)); } - width = _Face->glyph->bitmap.width; - height = _Face->glyph->bitmap.rows; - pitch = _Face->glyph->bitmap.pitch; + width = face->glyph->bitmap.width; + height = face->glyph->bitmap.rows; + pitch = face->glyph->bitmap.pitch; - left = _Face->glyph->bitmap_left; - top = _Face->glyph->bitmap_top; + left = face->glyph->bitmap_left; + top = face->glyph->bitmap_top; - advx = _Face->glyph->advance.x >> 6; + advx = face->glyph->advance.x >> 6; glyphIndex = glyph_index; - return (uint8 *) _Face->glyph->bitmap.buffer; + return (uint8 *) face->glyph->bitmap.buffer; } void CFontGenerator::getKerning (u32char left, u32char right, sint32 &kernx) { - if (!FT_HAS_KERNING(_Face)) + if (!FT_HAS_KERNING(_Faces[0])) { kernx = 0; } else { + // This is currently not used... + FT_Vector kerning; - FT_Error error = FT_Get_Kerning (_Face, left, right, ft_kerning_default, &kerning); + FT_Error error = FT_Get_Kerning (_Faces[0], left, right, ft_kerning_default, &kerning); if (error) { nlerror ("FT_Get_Kerning() failed: %s", getFT2Error(error)); @@ -396,12 +450,14 @@ void CFontGenerator::getKerning (u32char left, u32char right, sint32 &kernx) uint32 CFontGenerator::getCharIndex (u32char c) { - uint32 ret = FT_Get_Char_Index(_Face, c); + // This is currently not used... + + uint32 ret = FT_Get_Char_Index(_Faces[0], c); if (ret == 0) { // no glyph available, replace with a dot - ret = FT_Get_Char_Index (_Face, u32char('.')); + ret = FT_Get_Char_Index (_Faces[0], u32char('.')); } return ret; diff --git a/nel/src/gui/view_renderer.cpp b/nel/src/gui/view_renderer.cpp index 38e20f3f6..66aea4cfb 100644 --- a/nel/src/gui/view_renderer.cpp +++ b/nel/src/gui/view_renderer.cpp @@ -312,7 +312,7 @@ namespace NLGUI if (fonts.count(name) > 0) driver->deleteTextContext(fonts[name]); - std::string fontFile = CPath::lookup(font, false); + std::string fontFile = NLMISC::startsWith(font, "ui") ? font : CPath::lookup(font, false); if (fontFile.empty()) { nlwarning("Font file '%s' not found", font.c_str()); diff --git a/nel/tools/build_gamedata/processes/font/1_export.py b/nel/tools/build_gamedata/processes/font/1_export.py index f97d3375e..5e3f23439 100755 --- a/nel/tools/build_gamedata/processes/font/1_export.py +++ b/nel/tools/build_gamedata/processes/font/1_export.py @@ -49,6 +49,7 @@ mkPath(log, fontExportDir) for dir in FontSourceDirectories: mkPath(log, DatabaseDirectory + "/" + dir) copyFilesExtNoTreeIfNeeded(log, DatabaseDirectory + "/" + dir, fontExportDir, ".ttf") + copyFilesExtNoTreeIfNeeded(log, DatabaseDirectory + "/" + dir, fontExportDir, ".otf") copyFilesExtNoTreeIfNeeded(log, DatabaseDirectory + "/" + dir, fontExportDir, ".afm") copyFilesExtNoTreeIfNeeded(log, DatabaseDirectory + "/" + dir, fontExportDir, ".pfb") copyFilesExtNoTreeIfNeeded(log, DatabaseDirectory + "/" + dir, fontExportDir, ".pfm") diff --git a/nel/tools/build_gamedata/processes/font/3_install.py b/nel/tools/build_gamedata/processes/font/3_install.py index c18ae12e3..11e74ccfe 100755 --- a/nel/tools/build_gamedata/processes/font/3_install.py +++ b/nel/tools/build_gamedata/processes/font/3_install.py @@ -50,6 +50,7 @@ mkPath(log, fontExportDir) printLog(log, ">>> Install font <<<") copyFilesExtNoTreeIfNeeded(log, fontExportDir, installPath, ".ttf") +copyFilesExtNoTreeIfNeeded(log, fontExportDir, installPath, ".otf") copyFilesExtNoTreeIfNeeded(log, fontExportDir, installPath, ".afm") copyFilesExtNoTreeIfNeeded(log, fontExportDir, installPath, ".pfb") copyFilesExtNoTreeIfNeeded(log, fontExportDir, installPath, ".pfm") diff --git a/ryzom/client/src/global.cpp b/ryzom/client/src/global.cpp index 6e8bc4534..22a568306 100644 --- a/ryzom/client/src/global.cpp +++ b/ryzom/client/src/global.cpp @@ -90,7 +90,7 @@ void resetTextContext (const char *font, bool resetInterfaceManager) { if (TextContext != NULL) Driver->deleteTextContext(TextContext); - TextContext = Driver->createTextContext(CPath::lookup(font)); + TextContext = Driver->createTextContext(NLMISC::startsWith(font, "ui") ? font : CPath::lookup(font)); if (TextContext != NULL) TextContext->setKeep800x600Ratio(false); else From 91bceae90265921efeb1b815313d62de7d93a215 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Tue, 3 Nov 2020 08:55:45 +0800 Subject: [PATCH 2/2] Fix UTF-16 character input pair events --- nel/include/nel/misc/win_event_emitter.h | 3 ++- nel/src/misc/win_event_emitter.cpp | 27 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/nel/include/nel/misc/win_event_emitter.h b/nel/include/nel/misc/win_event_emitter.h index d23d9d040..ee709ec04 100644 --- a/nel/include/nel/misc/win_event_emitter.h +++ b/nel/include/nel/misc/win_event_emitter.h @@ -36,7 +36,7 @@ namespace NLMISC { class CWinEventEmitter : public IEventEmitter { public: - CWinEventEmitter () : _MouseEventsEnabled(true), _KeyboardEventsEnabled(true), _IMEEventsEnabled(true) + CWinEventEmitter () : _Utf16Pair(0), _MouseEventsEnabled(true), _KeyboardEventsEnabled(true), _IMEEventsEnabled(true) { _HWnd=NULL; resetButtonFlagState (); @@ -106,6 +106,7 @@ public: private: CWinEventServer _InternalServer; HWND _HWnd; + wchar_t _Utf16Pair; public: // private: may need to be in sync with direct input flags however... bool _CtrlButton; diff --git a/nel/src/misc/win_event_emitter.cpp b/nel/src/misc/win_event_emitter.cpp index dfc385bd9..939ad0477 100644 --- a/nel/src/misc/win_event_emitter.cpp +++ b/nel/src/misc/win_event_emitter.cpp @@ -24,6 +24,7 @@ #include "nel/misc/event_emitter.h" #include "nel/misc/win_event_emitter.h" #include "nel/misc/event_server.h" +#include "nel/misc/utf_string_view.h" #ifdef NL_OS_WINDOWS #include @@ -177,10 +178,28 @@ bool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPA { //if (wParam < KeyCount) //nlinfo("WM_CHAR with %u", wParam); -#ifndef WM_UNICHAR - // FIXME: Combine UTF-16 pairs -#endif - server->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this)); + wchar_t c = (wchar_t)wParam; + if ((c & 0xFC00) == 0xD800) + { + _Utf16Pair = c; + } + else if (_Utf16Pair && (c & 0xFC00) == 0xDC00) + { + wchar_t cc[] = { _Utf16Pair, c, 0 }; + _Utf16Pair = 0; + CUtfStringView cv = CUtfStringView(cc); + for (CUtfStringView::iterator it(cv.begin()), end(cv.end()); it != end; ++it) + server->postEvent(new CEventChar(*it, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this)); + } + else + { + if (_Utf16Pair) + { + server->postEvent(new CEventChar(_Utf16Pair, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this)); + _Utf16Pair = 0; + } + server->postEvent(new CEventChar(c, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this)); + } } break; /*case WM_IME_CHAR: