From d8a720fb7e87bbf152962177874a6566d68a357a Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 5 Jun 2024 01:13:59 +0200 Subject: [PATCH] ttf_loader: support loading from memory New text API for loading fonts from memory is introduced. This is necessary to enable embedded fonts support. --- inc/thorvg.h | 30 +++++++++++++++++++++++++++++- src/loaders/ttf/tvgTtfLoader.cpp | 26 ++++++++++++++++++++++++-- src/loaders/ttf/tvgTtfLoader.h | 3 +++ src/renderer/tvgLoader.cpp | 23 +++++++++++++++++++++++ src/renderer/tvgLoader.h | 1 + src/renderer/tvgText.cpp | 15 +++++++++++++++ 6 files changed, 95 insertions(+), 3 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 2bd63d44..f073e812 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -1552,7 +1552,7 @@ public: Result fill(std::unique_ptr f) noexcept; /** - * @brief Loads a scalable font data(ttf) from a file. + * @brief Loads a scalable font data (ttf) from a file. * * ThorVG efficiently caches the loaded data using the specified @p path as a key. * This means that loading the same file again will not result in duplicate operations; @@ -1571,6 +1571,34 @@ public: */ static Result load(const std::string& path) noexcept; + /** + * @brief Loads a scalable font data (ttf) from a memory block of a given size. + * + * ThorVG efficiently caches the loaded font data using the specified @p name as a key. + * This means that loading the same fonts again will not result in duplicate operations. + * Instead, ThorVG will reuse the previously loaded font data. + * + * @param[in] name The name under which the font will be stored and accessible (e.x. in a @p font() API). + * @param[in] data A pointer to a memory location where the content of the font data is stored. + * @param[in] size The size in bytes of the memory occupied by the @p data. + * @param[in] mimeType Mimetype or extension of font data. In case an empty string is provided the loader will be determined automatically. + * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not (default). + * + * @retval Result::Success When succeed. + * @retval Result::InvalidArguments If no name is provided or if @p size is zero while @p data points to a valid memory location. + * @retval Result::NonSupport When trying to load a file with an unsupported extension. + * @retval Result::Unknown If an error occurs at a later stage. + * + * @warning: It's the user responsibility to release the @p data memory. + * + * @note To unload the font data loaded using this API, pass the proper @p name and @c nullptr as @p data. + * @note If you are unsure about the MIME type, you can provide an empty value like @c "", and thorvg will attempt to figure it out. + * @note Experimental API + * + * @see Text::font(const char* name, float size, const char* style) + */ + static Result load(const char* name, const char* data, uint32_t size, const std::string& mimeType = "ttf", bool copy = false) noexcept; + /** * @brief Unloads the specified scalable font data (TTF) that was previously loaded. * diff --git a/src/loaders/ttf/tvgTtfLoader.cpp b/src/loaders/ttf/tvgTtfLoader.cpp index bcff2a0f..6bda38f4 100644 --- a/src/loaders/ttf/tvgTtfLoader.cpp +++ b/src/loaders/ttf/tvgTtfLoader.cpp @@ -193,7 +193,13 @@ static uint32_t* _codepoints(const char* text, size_t n) void TtfLoader::clear() { - _unmap(this); + if (nomap) { + if (freeData) free(reader.data); + reader.data = nullptr; + reader.size = 0; + freeData = false; + nomap = false; + } else _unmap(this); shape = nullptr; } @@ -236,6 +242,22 @@ bool TtfLoader::open(const string& path) } +bool TtfLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) +{ + reader.size = size; + nomap = true; + + if (copy) { + reader.data = (uint8_t*)malloc(size); + if (!reader.data) return false; + memcpy((char*)reader.data, data, reader.size); + freeData = true; + } else reader.data = (uint8_t*)data; + + return reader.header(); +} + + bool TtfLoader::request(Shape* shape, char* text, bool italic) { this->shape = shape; @@ -279,4 +301,4 @@ bool TtfLoader::read() free(code); return true; -} +} \ No newline at end of file diff --git a/src/loaders/ttf/tvgTtfLoader.h b/src/loaders/ttf/tvgTtfLoader.h index d45f86d5..e981921b 100644 --- a/src/loaders/ttf/tvgTtfLoader.h +++ b/src/loaders/ttf/tvgTtfLoader.h @@ -37,12 +37,15 @@ struct TtfLoader : public FontLoader char* text = nullptr; Shape* shape = nullptr; bool italic = false; + bool nomap = false; + bool freeData = false; TtfLoader(); ~TtfLoader(); using FontLoader::open; bool open(const string& path) override; + bool open(const char *data, uint32_t size, const string& rpath, bool copy) override; bool resize(Paint* paint, float w, float h) override; bool request(Shape* shape, char* text, bool italic = false) override; bool read() override; diff --git a/src/renderer/tvgLoader.cpp b/src/renderer/tvgLoader.cpp index eb695b31..80e2bedb 100644 --- a/src/renderer/tvgLoader.cpp +++ b/src/renderer/tvgLoader.cpp @@ -431,5 +431,28 @@ LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool return loader; } delete(loader); + return nullptr; +} + + +//loads fonts from memory - loader is cached (regardless of copy value) in order to access it while setting font +LoadModule* LoaderMgr::loader(const char* name, const char* data, uint32_t size, const string& mimeType, bool copy) +{ + //TODO: add check for mimetype ? + if (auto loader = _findFromCache(name)) return loader; + + if (auto loader = _findByType(mimeType)) { + if (loader->open(data, size, "", copy)) { + loader->hashpath = strdup(name); + loader->pathcache = true; + ScopedLock lock(key); + _activeLoaders.back(loader); + return loader; + } else { + TVGLOG("LOADER", "The font data \"%s\" could not be loaded.", name); + delete(loader); + } + } + return nullptr; } \ No newline at end of file diff --git a/src/renderer/tvgLoader.h b/src/renderer/tvgLoader.h index 86d36db1..76377366 100644 --- a/src/renderer/tvgLoader.h +++ b/src/renderer/tvgLoader.h @@ -32,6 +32,7 @@ struct LoaderMgr static LoadModule* loader(const string& path, bool* invalid); static LoadModule* loader(const char* data, uint32_t size, const string& mimeType, const string& rpath, bool copy); static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy); + static LoadModule* loader(const char* name, const char* data, uint32_t size, const string& mimeType, bool copy); static LoadModule* loader(const char* key); static bool retrieve(const string& path); static bool retrieve(LoadModule* loader); diff --git a/src/renderer/tvgText.cpp b/src/renderer/tvgText.cpp index 1fe244c1..4bd40881 100644 --- a/src/renderer/tvgText.cpp +++ b/src/renderer/tvgText.cpp @@ -71,6 +71,21 @@ Result Text::load(const std::string& path) noexcept } +Result Text::load(const char* name, const char* data, uint32_t size, const string& mimeType, bool copy) noexcept +{ + if (!name || (size == 0 && data)) return Result::InvalidArguments; + + //unload font + if (!data) { + if (LoaderMgr::retrieve(name)) return Result::Success; + return Result::InvalidArguments; + } + + if (!LoaderMgr::loader(name, data, size, mimeType, copy)) return Result::NonSupport; + return Result::Success; +} + + Result Text::unload(const std::string& path) noexcept { if (LoaderMgr::retrieve(path)) return Result::Success;