ttf_loader: support loading from memory

New text API for loading fonts from memory
is introduced. This is necessary to enable
embedded fonts support.
This commit is contained in:
Mira Grudzinska 2024-06-05 01:13:59 +02:00 committed by Hermet Park
parent f8626d13d1
commit d8a720fb7e
6 changed files with 95 additions and 3 deletions

View file

@ -1552,7 +1552,7 @@ public:
Result fill(std::unique_ptr<Fill> f) noexcept; Result fill(std::unique_ptr<Fill> 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. * 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; * 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; 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. * @brief Unloads the specified scalable font data (TTF) that was previously loaded.
* *

View file

@ -193,7 +193,13 @@ static uint32_t* _codepoints(const char* text, size_t n)
void TtfLoader::clear() 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; 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) bool TtfLoader::request(Shape* shape, char* text, bool italic)
{ {
this->shape = shape; this->shape = shape;
@ -279,4 +301,4 @@ bool TtfLoader::read()
free(code); free(code);
return true; return true;
} }

View file

@ -37,12 +37,15 @@ struct TtfLoader : public FontLoader
char* text = nullptr; char* text = nullptr;
Shape* shape = nullptr; Shape* shape = nullptr;
bool italic = false; bool italic = false;
bool nomap = false;
bool freeData = false;
TtfLoader(); TtfLoader();
~TtfLoader(); ~TtfLoader();
using FontLoader::open; using FontLoader::open;
bool open(const string& path) override; 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 resize(Paint* paint, float w, float h) override;
bool request(Shape* shape, char* text, bool italic = false) override; bool request(Shape* shape, char* text, bool italic = false) override;
bool read() override; bool read() override;

View file

@ -431,5 +431,28 @@ LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool
return loader; return loader;
} }
delete(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; return nullptr;
} }

View file

@ -32,6 +32,7 @@ struct LoaderMgr
static LoadModule* loader(const string& path, bool* invalid); 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 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 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 LoadModule* loader(const char* key);
static bool retrieve(const string& path); static bool retrieve(const string& path);
static bool retrieve(LoadModule* loader); static bool retrieve(LoadModule* loader);

View file

@ -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 Result Text::unload(const std::string& path) noexcept
{ {
if (LoaderMgr::retrieve(path)) return Result::Success; if (LoaderMgr::retrieve(path)) return Result::Success;