mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
common: ++stability of the font cache
Use the font name as the cache key for precise comparison instead of the file path.
This commit is contained in:
parent
384fa7f2cb
commit
9e6a514022
8 changed files with 88 additions and 58 deletions
|
@ -206,6 +206,7 @@ error:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* duplicate(const char *str, size_t n)
|
char* duplicate(const char *str, size_t n)
|
||||||
{
|
{
|
||||||
auto len = strlen(str);
|
auto len = strlen(str);
|
||||||
|
@ -217,6 +218,7 @@ char* duplicate(const char *str, size_t n)
|
||||||
return (char*)memcpy(ret, str, n);
|
return (char*)memcpy(ret, str, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* append(char* lhs, const char* rhs, size_t n)
|
char* append(char* lhs, const char* rhs, size_t n)
|
||||||
{
|
{
|
||||||
if (!rhs) return lhs;
|
if (!rhs) return lhs;
|
||||||
|
@ -225,20 +227,36 @@ char* append(char* lhs, const char* rhs, size_t n)
|
||||||
return strncat(lhs, rhs, n);
|
return strncat(lhs, rhs, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* dirname(const char* path)
|
char* dirname(const char* path)
|
||||||
{
|
{
|
||||||
const char *ptr = strrchr(path, '/');
|
auto ptr = strrchr(path, '/');
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (ptr) ptr = strrchr(ptr + 1, '\\');
|
ptr = strrchr(ptr ? ptr : path, '\\');
|
||||||
#endif
|
#endif
|
||||||
int len = int(ptr + 1 - path); // +1 to include '/'
|
auto len = ptr ? size_t(ptr - path + 1) : SIZE_MAX;
|
||||||
return duplicate(path, len);
|
return duplicate(path, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* fileext(const char* filename)
|
char* filename(const char* path)
|
||||||
{
|
{
|
||||||
auto ext = filename;
|
const char* ptr = strrchr(path, '/');
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto ptr2 = strrchr(ptr ? ptr : path, '\\');
|
||||||
|
if (ptr2) ptr = ptr2;
|
||||||
|
#endif
|
||||||
|
if (ptr) ++ptr;
|
||||||
|
else ptr = path;
|
||||||
|
auto dot = fileext(ptr);
|
||||||
|
auto len = (dot > ptr) ? (size_t)(dot - ptr - 1) : strlen(ptr);
|
||||||
|
return duplicate(ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* fileext(const char* path)
|
||||||
|
{
|
||||||
|
auto ext = path;
|
||||||
while (ext) {
|
while (ext) {
|
||||||
auto p = strchr(ext, '.');
|
auto p = strchr(ext, '.');
|
||||||
if (!p) break;
|
if (!p) break;
|
||||||
|
|
|
@ -37,7 +37,8 @@ float toFloat(const char *str, char **end); //convert to floa
|
||||||
char* duplicate(const char *str, size_t n = SIZE_MAX); //copy the string
|
char* duplicate(const char *str, size_t n = SIZE_MAX); //copy the string
|
||||||
char* append(char* lhs, const char* rhs, size_t n); //append the rhs to the lhs
|
char* append(char* lhs, const char* rhs, size_t n); //append the rhs to the lhs
|
||||||
char* dirname(const char* path); //return the full directory name
|
char* dirname(const char* path); //return the full directory name
|
||||||
const char* fileext(const char* filename); //return the file extension name
|
char* filename(const char* path); //return the file name without extension
|
||||||
|
const char* fileext(const char* path); //return the file extension name
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //_TVG_STR_H_
|
#endif //_TVG_STR_H_
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tvgStr.h"
|
||||||
#include "tvgTtfLoader.h"
|
#include "tvgTtfLoader.h"
|
||||||
|
|
||||||
#if defined(_WIN32) && (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
|
#if defined(_WIN32) && (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
|
||||||
|
@ -208,6 +209,9 @@ void TtfLoader::clear()
|
||||||
_unmap(this);
|
_unmap(this);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tvg::free(name);
|
||||||
|
name = nullptr;
|
||||||
shape = nullptr;
|
shape = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +251,9 @@ bool TtfLoader::open(const char* path)
|
||||||
#ifdef THORVG_FILE_IO_SUPPORT
|
#ifdef THORVG_FILE_IO_SUPPORT
|
||||||
clear();
|
clear();
|
||||||
if (!_map(this, path)) return false;
|
if (!_map(this, path)) return false;
|
||||||
|
|
||||||
|
name = tvg::filename(path);
|
||||||
|
|
||||||
return reader.header();
|
return reader.header();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -33,20 +33,30 @@ struct LoadModule
|
||||||
INLIST_ITEM(LoadModule);
|
INLIST_ITEM(LoadModule);
|
||||||
|
|
||||||
//Use either hashkey(data) or hashpath(path)
|
//Use either hashkey(data) or hashpath(path)
|
||||||
union {
|
uintptr_t hashkey = 0;
|
||||||
uintptr_t hashkey;
|
char* hashpath = nullptr;
|
||||||
char* hashpath = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
FileType type; //current loader file type
|
FileType type; //current loader file type
|
||||||
uint16_t sharing = 0; //reference count
|
uint16_t sharing = 0; //reference count
|
||||||
bool readied = false; //read done already.
|
bool readied = false; //read done already.
|
||||||
bool pathcache = false; //cached by path
|
bool cached = false; //cached for sharing
|
||||||
|
|
||||||
LoadModule(FileType type) : type(type) {}
|
LoadModule(FileType type) : type(type) {}
|
||||||
virtual ~LoadModule()
|
virtual ~LoadModule()
|
||||||
{
|
{
|
||||||
if (pathcache) tvg::free(hashpath);
|
tvg::free(hashpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cache(uintptr_t data)
|
||||||
|
{
|
||||||
|
hashkey = data;
|
||||||
|
cached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cache(char* data)
|
||||||
|
{
|
||||||
|
hashpath = data;
|
||||||
|
cached = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool open(const char* path) { return false; }
|
virtual bool open(const char* path) { return false; }
|
||||||
|
@ -61,12 +71,6 @@ struct LoadModule
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cached()
|
|
||||||
{
|
|
||||||
if (hashkey) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool close()
|
virtual bool close()
|
||||||
{
|
{
|
||||||
if (sharing == 0) return true;
|
if (sharing == 0) return true;
|
||||||
|
@ -99,6 +103,7 @@ struct ImageLoader : LoadModule
|
||||||
struct FontLoader : LoadModule
|
struct FontLoader : LoadModule
|
||||||
{
|
{
|
||||||
float scale = 1.0f;
|
float scale = 1.0f;
|
||||||
|
char* name = nullptr;
|
||||||
|
|
||||||
FontLoader(FileType type) : LoadModule(type) {}
|
FontLoader(FileType type) : LoadModule(type) {}
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ static LoadModule* _findFromCache(const char* filename)
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
|
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
if (loader->pathcache && !strcmp(loader->hashpath, filename)) {
|
if (loader->cached && !strcmp(loader->hashpath, filename)) {
|
||||||
++loader->sharing;
|
++loader->sharing;
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ bool LoaderMgr::retrieve(LoadModule* loader)
|
||||||
{
|
{
|
||||||
if (!loader) return false;
|
if (!loader) return false;
|
||||||
if (loader->close()) {
|
if (loader->close()) {
|
||||||
if (loader->cached()) {
|
if (loader->cached) {
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.remove(loader);
|
_activeLoaders.remove(loader);
|
||||||
}
|
}
|
||||||
|
@ -287,8 +287,7 @@ LoadModule* LoaderMgr::loader(const char* filename, bool* invalid)
|
||||||
if (auto loader = _findByPath(filename)) {
|
if (auto loader = _findByPath(filename)) {
|
||||||
if (loader->open(filename)) {
|
if (loader->open(filename)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->hashpath = duplicate(filename);
|
loader->cache(duplicate(filename));
|
||||||
loader->pathcache = true;
|
|
||||||
{
|
{
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
|
@ -303,8 +302,7 @@ LoadModule* LoaderMgr::loader(const char* filename, bool* invalid)
|
||||||
if (auto loader = _find(static_cast<FileType>(i))) {
|
if (auto loader = _find(static_cast<FileType>(i))) {
|
||||||
if (loader->open(filename)) {
|
if (loader->open(filename)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->hashpath = duplicate(filename);
|
loader->cache(duplicate(filename));
|
||||||
loader->pathcache = true;
|
|
||||||
{
|
{
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
|
@ -327,30 +325,6 @@ bool LoaderMgr::retrieve(const char* filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LoadModule* LoaderMgr::loader(const char* key)
|
|
||||||
{
|
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
|
||||||
if (loader->pathcache && strstr(loader->hashpath, key)) {
|
|
||||||
++loader->sharing;
|
|
||||||
return loader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LoadModule* LoaderMgr::anyfont()
|
|
||||||
{
|
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
|
||||||
if ((loader->type == FileType::Ttf) && loader->pathcache) {
|
|
||||||
++loader->sharing;
|
|
||||||
return loader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy)
|
LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy)
|
||||||
{
|
{
|
||||||
//Note that users could use the same data pointer with the different content.
|
//Note that users could use the same data pointer with the different content.
|
||||||
|
@ -372,7 +346,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeT
|
||||||
if (auto loader = _findByType(mimeType)) {
|
if (auto loader = _findByType(mimeType)) {
|
||||||
if (loader->open(data, size, rpath, copy)) {
|
if (loader->open(data, size, rpath, copy)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->hashkey = HASH_KEY(data);
|
loader->cache(HASH_KEY(data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +363,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeT
|
||||||
if (loader) {
|
if (loader) {
|
||||||
if (loader->open(data, size, rpath, copy)) {
|
if (loader->open(data, size, rpath, copy)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->hashkey = HASH_KEY(data);
|
loader->cache(HASH_KEY(data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
|
@ -415,7 +389,7 @@ LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, Colo
|
||||||
auto loader = new RawLoader;
|
auto loader = new RawLoader;
|
||||||
if (loader->open(data, w, h, cs, copy)) {
|
if (loader->open(data, w, h, cs, copy)) {
|
||||||
if (!copy) {
|
if (!copy) {
|
||||||
loader->hashkey = HASH_KEY((const char*)data);
|
loader->cache(HASH_KEY((const char*)data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
|
@ -431,13 +405,13 @@ LoadModule* LoaderMgr::loader(const char* name, const char* data, uint32_t size,
|
||||||
{
|
{
|
||||||
#ifdef THORVG_TTF_LOADER_SUPPORT
|
#ifdef THORVG_TTF_LOADER_SUPPORT
|
||||||
//TODO: add check for mimetype ?
|
//TODO: add check for mimetype ?
|
||||||
if (auto loader = _findFromCache(name)) return loader;
|
if (auto loader = font(name)) return loader;
|
||||||
|
|
||||||
//function is dedicated for ttf loader (the only supported font loader)
|
//function is dedicated for ttf loader (the only supported font loader)
|
||||||
auto loader = new TtfLoader;
|
auto loader = new TtfLoader;
|
||||||
if (loader->open(data, size, "", copy)) {
|
if (loader->open(data, size, "", copy)) {
|
||||||
loader->hashpath = duplicate(name);
|
loader->name = duplicate(name);
|
||||||
loader->pathcache = true;
|
loader->cached = true; //force it.
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -448,3 +422,28 @@ LoadModule* LoaderMgr::loader(const char* name, const char* data, uint32_t size,
|
||||||
#endif
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LoadModule* LoaderMgr::font(const char* name)
|
||||||
|
{
|
||||||
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
|
if (loader->type != FileType::Ttf) continue;
|
||||||
|
if (loader->cached && tvg::equal(name, static_cast<FontLoader*>(loader)->name)) {
|
||||||
|
++loader->sharing;
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LoadModule* LoaderMgr::anyfont()
|
||||||
|
{
|
||||||
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
|
if (loader->cached && loader->type == FileType::Ttf) {
|
||||||
|
++loader->sharing;
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct LoaderMgr
|
||||||
static LoadModule* loader(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy);
|
static LoadModule* loader(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy);
|
||||||
static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, ColorSpace cs, bool copy);
|
static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, ColorSpace cs, bool copy);
|
||||||
static LoadModule* loader(const char* name, const char* data, uint32_t size, const char* mimeType, bool copy);
|
static LoadModule* loader(const char* name, const char* data, uint32_t size, const char* mimeType, bool copy);
|
||||||
static LoadModule* loader(const char* key);
|
static LoadModule* font(const char* name);
|
||||||
static LoadModule* anyfont();
|
static LoadModule* anyfont();
|
||||||
static bool retrieve(const char* filename);
|
static bool retrieve(const char* filename);
|
||||||
static bool retrieve(LoadModule* loader);
|
static bool retrieve(LoadModule* loader);
|
||||||
|
|
|
@ -67,7 +67,7 @@ Result Text::load(const char* name, const char* data, uint32_t size, const char*
|
||||||
|
|
||||||
//unload font
|
//unload font
|
||||||
if (!data) {
|
if (!data) {
|
||||||
if (LoaderMgr::retrieve(name)) return Result::Success;
|
if (LoaderMgr::retrieve(LoaderMgr::font(name))) return Result::Success;
|
||||||
return Result::InsufficientCondition;
|
return Result::InsufficientCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct Text::Impl : Paint::Impl
|
||||||
|
|
||||||
Result font(const char* name, float size, const char* style)
|
Result font(const char* name, float size, const char* style)
|
||||||
{
|
{
|
||||||
auto loader = name ? LoaderMgr::loader(name) : LoaderMgr::anyfont();
|
auto loader = name ? LoaderMgr::font(name) : LoaderMgr::anyfont();
|
||||||
if (!loader) return Result::InsufficientCondition;
|
if (!loader) return Result::InsufficientCondition;
|
||||||
|
|
||||||
if (style && strstr(style, "italic")) italic = true;
|
if (style && strstr(style, "italic")) italic = true;
|
||||||
|
|
Loading…
Add table
Reference in a new issue