From f58ce6c7181d08caa60b71e45ed8f8c8fd7a2aaf Mon Sep 17 00:00:00 2001 From: Jonas Fink Date: Thu, 24 Oct 2024 21:38:58 +0200 Subject: [PATCH] Add callback to get missing fonts --- include/lunasvg.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ source/graphics.cpp | 31 ++++++++++++++++++++++++++++++- source/graphics.h | 5 +++++ source/lunasvg.cpp | 12 ++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/include/lunasvg.h b/include/lunasvg.h index 3e062e9..16f0b14 100644 --- a/include/lunasvg.h +++ b/include/lunasvg.h @@ -27,6 +27,7 @@ #include #include #include +#include #if !defined(LUNASVG_BUILD_STATIC) && (defined(_WIN32) || defined(__CYGWIN__)) #define LUNASVG_EXPORT __declspec(dllexport) @@ -129,6 +130,50 @@ LUNASVG_API bool lunasvg_add_font_face_from_data(const char* family, bool bold, namespace lunasvg { +/** + * @brief A callback function type to handle missing fonts. + * @param family The name of the font family. + * @param bold Use `true` for bold, `false` otherwise. + * @param italic Use `true` for italic, `false` otherwise. + * @return The path to the font file or an empty string if the font is not found. + */ +typedef std::function MissingFontCallback; + +/** + * @brief Allows to user to load custom fonts. + */ +namespace LUNASVG_API FontManager { + /** + * @brief Add a font face from a file to the cache. + * @param family The name of the font family. If an empty string is provided, the font will act as a fallback. + * @param bold Use `true` for bold, `false` otherwise. + * @param italic Use `true` for italic, `false` otherwise. + * @param filename The path to the font file. + * @return `true` if the font face was successfully added to the cache, `false` otherwise. + */ + bool addFromFile(const std::string& family, bool bold, bool italic, const std::string& filename); + + /** + * @brief Add a font face from memory to the cache. + * @param family The name of the font family. If an empty string is provided, the font will act as a fallback. + * @param bold Use `true` for bold, `false` otherwise. + * @param italic Use `true` for italic, `false` otherwise. + * @param data A pointer to the memory buffer containing the font data. + * @param length The size of the memory buffer in bytes. + * @param destroy_func Callback function to free the memory buffer when it is no longer needed. + * @param closure User-defined pointer passed to the `destroy_func` callback. + * @return `true` if the font face was successfully added to the cache, `false` otherwise. + */ + bool addFromData(const std::string& family, bool bold, bool italic, const void* data, size_t length, lunasvg_destroy_func_t destroy_func, void* closure); + + + /** + * @brief Registers a callback function to handle missing fonts. + * @param callback The callback function to register. + */ + void registerMissingFontCalback(MissingFontCallback callback); +} + /** * @note Bitmap pixel format is ARGB32_Premultiplied. */ diff --git a/source/graphics.cpp b/source/graphics.cpp index c5eb3be..81dcca5 100644 --- a/source/graphics.cpp +++ b/source/graphics.cpp @@ -417,11 +417,35 @@ bool FontFaceCache::addFontFace(const std::string& family, bool bold, bool itali return !face.isNull(); } +void FontFaceCache::registerMissingFontCallback(const std::function& callback) +{ + m_callback = callback; +} + +FontFace FontFaceCache::tryRequestFontFace(const std::string_view& family, bool bold, bool italic) +{ + if (m_callback == nullptr) { + return FontFace(); + } + std::string filename = m_callback(std::string(family), bold, italic); + if (filename.empty()) { + return FontFace(); + } + auto face = FontFace(filename.c_str()); + if(!face.isNull()) { + addFontFace(std::string(family), bold, italic, face); + return face; + } + else { + return FontFace(); + } +} + FontFace FontFaceCache::getFontFace(const std::string_view& family, bool bold, bool italic) { auto it = m_table.find(family); if(it == m_table.end()) { - return FontFace(); + return tryRequestFontFace(family, bold, italic); } auto select = [bold, italic](const FontFaceEntry& a, const FontFaceEntry& b) { @@ -439,6 +463,11 @@ FontFace FontFaceCache::getFontFace(const std::string_view& family, bool bold, b entry = select(entry, item); } + if(bold != std::get<0>(entry) || italic != std::get<1>(entry)) { + return tryRequestFontFace(family, bold, italic); + } + + return std::get<2>(entry); } diff --git a/source/graphics.h b/source/graphics.h index 9291bb8..83aa86b 100644 --- a/source/graphics.h +++ b/source/graphics.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace lunasvg { @@ -421,12 +422,16 @@ class FontFaceCache { public: bool addFontFace(const std::string& family, bool bold, bool italic, const FontFace& face); FontFace getFontFace(const std::string_view& family, bool bold, bool italic); + void registerMissingFontCallback(const std::function& callback); private: FontFaceCache(); using FontFaceEntry = std::tuple; std::map, std::less<>> m_table; + std::function m_callback = nullptr; friend FontFaceCache* fontFaceCache(); + + FontFace tryRequestFontFace(const std::string_view& family, bool bold, bool italic); }; FontFaceCache* fontFaceCache(); diff --git a/source/lunasvg.cpp b/source/lunasvg.cpp index 2cb72d1..6a39e53 100644 --- a/source/lunasvg.cpp +++ b/source/lunasvg.cpp @@ -29,6 +29,18 @@ bool lunasvg_add_font_face_from_data(const char* family, bool bold, bool italic, namespace lunasvg { +bool FontManager::addFromFile(const std::string& family, bool bold, bool italic, const std::string& filename) { + return lunasvg_add_font_face_from_file(family.c_str(), bold, italic, filename.c_str()); +} + +bool FontManager::addFromData(const std::string& family, bool bold, bool italic, const void* data, size_t length, lunasvg_destroy_func_t destroy_func, void* closure) { + return lunasvg_add_font_face_from_data(family.c_str(), bold, italic, data, length, destroy_func, closure); +} + +void FontManager::registerMissingFontCalback(std::function callback) { + fontFaceCache()->registerMissingFontCallback(callback); +} + Bitmap::Bitmap(int width, int height) : m_surface(plutovg_surface_create(width, height)) {