From f59913e997c9f0eef9ac88f721acd72f5be36c89 Mon Sep 17 00:00:00 2001 From: FRex Date: Sun, 2 Feb 2025 02:27:37 +0100 Subject: [PATCH] Fix opening `sf::Font` from non-ASCII path --- include/SFML/Graphics/Font.hpp | 18 ++- src/SFML/Graphics/Font.cpp | 242 ++++++++++++++------------------- test/Graphics/Font.test.cpp | 8 +- test/Graphics/tuffy-ń.ttf | Bin 0 -> 18444 bytes test/Graphics/tuffy-🐌.ttf | Bin 0 -> 18444 bytes 5 files changed, 117 insertions(+), 151 deletions(-) create mode 100755 test/Graphics/tuffy-ń.ttf create mode 100755 test/Graphics/tuffy-🐌.ttf diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp index 30e1576aa..d1a014011 100644 --- a/include/SFML/Graphics/Font.hpp +++ b/include/SFML/Graphics/Font.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -45,13 +46,6 @@ #include -#ifdef SFML_SYSTEM_ANDROID -namespace sf::priv -{ -class ResourceStream; -} -#endif - namespace sf { class InputStream; @@ -399,6 +393,12 @@ private: //////////////////////////////////////////////////////////// void cleanup(); + //////////////////////////////////////////////////////////// + /// \brief Open from stream and print errors with custom message + /// + //////////////////////////////////////////////////////////// + [[nodiscard]] bool openFromStreamImpl(InputStream& stream, std::string_view type); + //////////////////////////////////////////////////////////// /// \brief Find or create the glyphs page corresponding to the given character size /// @@ -457,9 +457,7 @@ private: Info m_info; //!< Information about the font mutable PageTable m_pages; //!< Table containing the glyphs pages by character size mutable std::vector m_pixelBuffer; //!< Pixel buffer holding a glyph's pixels before being written to the texture -#ifdef SFML_SYSTEM_ANDROID - std::shared_ptr m_stream; //!< Asset file streamer (if loaded from file) -#endif + std::shared_ptr m_stream; //!< Stream for openFromFile and openFromMemory }; } // namespace sf diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp index 71ef0be44..9d553aa83 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -33,7 +33,8 @@ #endif #include #include -#include +#include +#include #include #include @@ -125,7 +126,7 @@ struct Font::FontHandles Font::Font(const std::filesystem::path& filename) { if (!openFromFile(filename)) - throw sf::Exception("Failed to open font from file"); + throw Exception("Failed to open font from file"); } @@ -133,7 +134,7 @@ Font::Font(const std::filesystem::path& filename) Font::Font(const void* data, std::size_t sizeInBytes) { if (!openFromMemory(data, sizeInBytes)) - throw sf::Exception("Failed to open font from memory"); + throw Exception("Failed to open font from memory"); } @@ -141,67 +142,47 @@ Font::Font(const void* data, std::size_t sizeInBytes) Font::Font(InputStream& stream) { if (!openFromStream(stream)) - throw sf::Exception("Failed to open font from stream"); + throw Exception("Failed to open font from stream"); } //////////////////////////////////////////////////////////// bool Font::openFromFile(const std::filesystem::path& filename) { -#ifndef SFML_SYSTEM_ANDROID + using namespace std::string_view_literals; // Cleanup the previous resources cleanup(); - auto fontHandles = std::make_shared(); +#ifndef SFML_SYSTEM_ANDROID - // Initialize FreeType - // Note: we initialize FreeType for every font instance in order to avoid having a single - // global manager that would create a lot of issues regarding creation and destruction order. - if (FT_Init_FreeType(&fontHandles->library) != 0) + // Create the input stream and open the file + const auto stream = std::make_shared(); + const auto type = "file"sv; + if (!stream->open(filename)) { - err() << "Failed to load font (failed to initialize FreeType)\n" << formatDebugPathInfo(filename) << std::endl; - return false; - } - - // Load the new font face from the specified file - FT_Face face = nullptr; - if (FT_New_Face(fontHandles->library, filename.string().c_str(), 0, &face) != 0) - { - err() << "Failed to load font (failed to create the font face)\n" << formatDebugPathInfo(filename) << std::endl; - return false; - } - fontHandles->face = face; - - // Load the stroker that will be used to outline the font - if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0) - { - err() << "Failed to load font (failed to create the stroker)\n" << formatDebugPathInfo(filename) << std::endl; - return false; - } - - // Select the unicode character map - if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) - { - err() << "Failed to load font (failed to set the Unicode character set)\n" + err() << "Failed to load font (failed to open file): " << std::strerror(errno) << '\n' << formatDebugPathInfo(filename) << std::endl; return false; } - // Store the loaded font handles - m_fontHandles = std::move(fontHandles); - - // Store the font information - m_info.family = face->family_name ? face->family_name : std::string(); - - return true; - #else - m_stream = std::make_shared(filename); - return openFromStream(*m_stream); + const auto stream = std::make_shared(filename); + const auto type = "Android resource stream"sv; #endif + + // Open the font, and if succesful save the stream to keep it alive + if (openFromStreamImpl(*stream, type)) + { + m_stream = stream; + return true; + } + + // If loading failed, print filename (after the error message already printed in openFromStreamImpl) + err() << formatDebugPathInfo(filename) << std::endl; + return false; } @@ -211,71 +192,29 @@ bool Font::openFromMemory(const void* data, std::size_t sizeInBytes) // Cleanup the previous resources cleanup(); - auto fontHandles = std::make_shared(); - - // Initialize FreeType - // Note: we initialize FreeType for every font instance in order to avoid having a single - // global manager that would create a lot of issues regarding creation and destruction order. - if (FT_Init_FreeType(&fontHandles->library) != 0) + if (!data) { - err() << "Failed to load font from memory (failed to initialize FreeType)" << std::endl; + err() << "Failed to load font from memory (provided data pointer is null)" << std::endl; return false; } - // Load the new font face from the specified file - FT_Face face = nullptr; - if (FT_New_Memory_Face(fontHandles->library, - reinterpret_cast(data), - static_cast(sizeInBytes), - 0, - &face) != 0) - { - err() << "Failed to load font from memory (failed to create the font face)" << std::endl; - return false; - } - fontHandles->face = face; + // Create memory stream - the memory is owned by the user + const auto memoryStream = std::make_shared(data, sizeInBytes); - // Load the stroker that will be used to outline the font - if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0) + // Open the font, and if succesful save the stream to keep it alive + if (openFromStreamImpl(*memoryStream, "memory")) { - err() << "Failed to load font from memory (failed to create the stroker)" << std::endl; - return false; + m_stream = memoryStream; + return true; } - // Select the Unicode character map - if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) - { - err() << "Failed to load font from memory (failed to set the Unicode character set)" << std::endl; - return false; - } - - // Store the loaded font handles - m_fontHandles = std::move(fontHandles); - - // Store the font information - m_info.family = face->family_name ? face->family_name : std::string(); - - return true; + return false; } //////////////////////////////////////////////////////////// bool Font::openFromStream(InputStream& stream) { - // Cleanup the previous resources - cleanup(); - - auto fontHandles = std::make_shared(); - - // Initialize FreeType - // Note: we initialize FreeType for every font instance in order to avoid having a single - // global manager that would create a lot of issues regarding creation and destruction order. - if (FT_Init_FreeType(&fontHandles->library) != 0) - { - err() << "Failed to load font from stream (failed to initialize FreeType)" << std::endl; - return false; - } - // Make sure that the stream's reading position is at the beginning if (!stream.seek(0).has_value()) { @@ -283,50 +222,8 @@ bool Font::openFromStream(InputStream& stream) return false; } - // Prepare a wrapper for our stream, that we'll pass to FreeType callbacks - fontHandles->streamRec.base = nullptr; - fontHandles->streamRec.size = static_cast(stream.getSize().value()); - fontHandles->streamRec.pos = 0; - fontHandles->streamRec.descriptor.pointer = &stream; - fontHandles->streamRec.read = &read; - fontHandles->streamRec.close = &close; - - // Setup the FreeType callbacks that will read our stream - FT_Open_Args args; - args.flags = FT_OPEN_STREAM; - args.stream = &fontHandles->streamRec; - args.driver = nullptr; - - // Load the new font face from the specified stream - FT_Face face = nullptr; - if (FT_Open_Face(fontHandles->library, &args, 0, &face) != 0) - { - err() << "Failed to load font from stream (failed to create the font face)" << std::endl; - return false; - } - fontHandles->face = face; - - // Load the stroker that will be used to outline the font - if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0) - { - err() << "Failed to load font from stream (failed to create the stroker)" << std::endl; - return false; - } - - // Select the Unicode character map - if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) - { - err() << "Failed to load font from stream (failed to set the Unicode character set)" << std::endl; - return false; - } - - // Store the loaded font handles - m_fontHandles = std::move(fontHandles); - - // Store the font information - m_info.family = face->family_name ? face->family_name : std::string(); - - return true; + // Open the font, do not save the stream in m_stream, its owned by the caller + return openFromStreamImpl(stream, "stream"); } @@ -492,6 +389,73 @@ void Font::cleanup() // Reset members m_pages.clear(); std::vector().swap(m_pixelBuffer); + + // Drop the file stream if we held one due to openFromFile or openFromMemory + m_stream.reset(); +} + + +//////////////////////////////////////////////////////////// +bool Font::openFromStreamImpl(InputStream& stream, std::string_view type) +{ + // Cleanup the previous resources + cleanup(); + + auto fontHandles = std::make_shared(); + + // Initialize FreeType + // Note: we initialize FreeType for every font instance in order to avoid having a single + // global manager that would create a lot of issues regarding creation and destruction order. + if (FT_Init_FreeType(&fontHandles->library) != 0) + { + err() << "Failed to load font from " << type << " (failed to initialize FreeType)" << std::endl; + return false; + } + + // Prepare a wrapper for our stream, that we'll pass to FreeType callbacks + fontHandles->streamRec.base = nullptr; + fontHandles->streamRec.size = static_cast(stream.getSize().value()); + fontHandles->streamRec.pos = 0; + fontHandles->streamRec.descriptor.pointer = &stream; + fontHandles->streamRec.read = &read; + fontHandles->streamRec.close = &close; + + // Setup the FreeType callbacks that will read our stream + FT_Open_Args args; + args.flags = FT_OPEN_STREAM; + args.stream = &fontHandles->streamRec; + args.driver = nullptr; + + // Load the new font face from the specified stream + FT_Face face = nullptr; + if (FT_Open_Face(fontHandles->library, &args, 0, &face) != 0) + { + err() << "Failed to load font from " << type << " (failed to create the font face)" << std::endl; + return false; + } + fontHandles->face = face; + + // Load the stroker that will be used to outline the font + if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0) + { + err() << "Failed to load font from " << type << " (failed to create the stroker)" << std::endl; + return false; + } + + // Select the Unicode character map + if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) + { + err() << "Failed to load font from " << type << " (failed to set the Unicode character set)" << std::endl; + return false; + } + + // Store the loaded font handles + m_fontHandles = std::move(fontHandles); + + // Store the font information + m_info.family = face->family_name ? face->family_name : std::string(); + + return true; } diff --git a/test/Graphics/Font.test.cpp b/test/Graphics/Font.test.cpp index c605ae0e7..271a1fad4 100644 --- a/test/Graphics/Font.test.cpp +++ b/test/Graphics/Font.test.cpp @@ -7,10 +7,10 @@ #include #include +#include #include #include -#include #include TEST_CASE("[Graphics] sf::Font", runDisplayTests()) @@ -146,7 +146,11 @@ TEST_CASE("[Graphics] sf::Font", runDisplayTests()) SECTION("Successful load") { - REQUIRE(font.openFromFile("Graphics/tuffy.ttf")); + const std::u32string filenameSuffix = GENERATE(U"", U"-ń", U"-🐌"); + const std::filesystem::path filename = U"Graphics/tuffy" + filenameSuffix + U".ttf"; + INFO("Filename: " << reinterpret_cast(filename.u8string().c_str())); + + REQUIRE(font.openFromFile(filename)); CHECK(font.getInfo().family == "Tuffy"); const auto& glyph = font.getGlyph(0x45, 16, false); CHECK(glyph.advance == 9); diff --git a/test/Graphics/tuffy-ń.ttf b/test/Graphics/tuffy-ń.ttf new file mode 100755 index 0000000000000000000000000000000000000000..8ea647090f75e7d34bee4c511921299d1f3c1055 GIT binary patch literal 18444 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