Loaders: Introduced a loader cache.

The loader cache is applied to conserve memory.

If the input data is already present in loaders,
the loader cache will promptly return the active loader.

This results in a lot of memory savings for the duplicated resources.

binary diff: -400 bytes
This commit is contained in:
Hermet Park 2023-11-23 12:04:20 +09:00 committed by Hermet Park
parent bd3d01d222
commit ff6ea4b6c4
25 changed files with 293 additions and 241 deletions

View file

@ -33,8 +33,8 @@ namespace tvg {
template<typename T> template<typename T>
struct Inlist struct Inlist
{ {
T *head = nullptr; T* head = nullptr;
T *tail = nullptr; T* tail = nullptr;
void free() void free()
{ {
@ -52,6 +52,7 @@ struct Inlist
tail->next = element; tail->next = element;
element->prev = tail; element->prev = tail;
element->next = nullptr; element->next = nullptr;
tail = element;
} else { } else {
head = tail = element; head = tail = element;
element->prev = nullptr; element->prev = nullptr;
@ -62,9 +63,10 @@ struct Inlist
void front(T* element) void front(T* element)
{ {
if (head) { if (head) {
head->prev = element;
element->prev = nullptr; element->prev = nullptr;
element->next = head; element->next = head;
head->prev = element; head = element;
} else { } else {
head = tail = element; head = tail = element;
element->prev = nullptr; element->prev = nullptr;
@ -90,6 +92,14 @@ struct Inlist
return t; return t;
} }
void remove(T* element)
{
if (element->prev) element->prev->next = element->next;
if (element->next) element->next->prev = element->prev;
if (element == head) head = element->next;
if (element == tail) tail = element->prev;
}
bool empty() bool empty()
{ {
return head ? false : true; return head ? false : true;

View file

@ -41,7 +41,7 @@ void JpgLoader::clear()
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
JpgLoader::JpgLoader() JpgLoader::JpgLoader() : LoadModule(FileType::Jpg)
{ {
jpegDecompressor = tjInitDecompress(); jpegDecompressor = tjInitDecompress();
} }
@ -49,7 +49,7 @@ JpgLoader::JpgLoader()
JpgLoader::~JpgLoader() JpgLoader::~JpgLoader()
{ {
if (freeData) free(data); clear();
tjDestroy(jpegDecompressor); tjDestroy(jpegDecompressor);
//This image is shared with raster engine. //This image is shared with raster engine.
@ -59,8 +59,6 @@ JpgLoader::~JpgLoader()
bool JpgLoader::open(const string& path) bool JpgLoader::open(const string& path)
{ {
clear();
auto jpegFile = fopen(path.c_str(), "rb"); auto jpegFile = fopen(path.c_str(), "rb");
if (!jpegFile) return false; if (!jpegFile) return false;
@ -102,8 +100,6 @@ finalize:
bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy)
{ {
clear();
int width, height, subSample, colorSpace; int width, height, subSample, colorSpace;
if (tjDecompressHeader3(jpegDecompressor, (unsigned char *) data, size, &width, &height, &subSample, &colorSpace) < 0) return false; if (tjDecompressHeader3(jpegDecompressor, (unsigned char *) data, size, &width, &height, &subSample, &colorSpace) < 0) return false;
@ -128,6 +124,10 @@ bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r
bool JpgLoader::read() bool JpgLoader::read()
{ {
if (!LoadModule::read()) return true;
if (w == 0 || h == 0) return false;
/* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB /* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB
How could we notice the renderer colorspace at this time? */ How could we notice the renderer colorspace at this time? */
if (image) tjFree(image); if (image) tjFree(image);
@ -142,12 +142,6 @@ bool JpgLoader::read()
return false; return false;
} }
return true;
}
bool JpgLoader::close()
{
clear(); clear();
return true; return true;
} }

View file

@ -38,7 +38,6 @@ public:
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 open(const char* data, uint32_t size, const string& rpath, bool copy) override;
bool read() override; bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override; unique_ptr<Surface> bitmap() override;

View file

@ -26,12 +26,19 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
void PngLoader::clear()
{
png_image_free(image);
free(image);
image = nullptr;
}
/************************************************************************/ /************************************************************************/
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
PngLoader::PngLoader() PngLoader::PngLoader() : LoadModule(FileType::Png)
{ {
image = static_cast<png_imagep>(calloc(1, sizeof(png_image))); image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
image->version = PNG_IMAGE_VERSION; image->version = PNG_IMAGE_VERSION;
@ -40,13 +47,11 @@ PngLoader::PngLoader()
PngLoader::~PngLoader() PngLoader::~PngLoader()
{ {
if (content) { clear();
free((void*)content); free((void*)content);
content = nullptr;
}
free(image);
} }
bool PngLoader::open(const string& path) bool PngLoader::open(const string& path)
{ {
image->opaque = NULL; image->opaque = NULL;
@ -60,6 +65,7 @@ bool PngLoader::open(const string& path)
return true; return true;
} }
bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy)
{ {
image->opaque = NULL; image->opaque = NULL;
@ -76,6 +82,10 @@ bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r
bool PngLoader::read() bool PngLoader::read()
{ {
if (!LoadModule::read()) return true;
if (w == 0 || h == 0) return false;
png_bytep buffer; png_bytep buffer;
image->format = PNG_FORMAT_BGRA; image->format = PNG_FORMAT_BGRA;
buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image)))); buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
@ -90,14 +100,11 @@ bool PngLoader::read()
} }
content = reinterpret_cast<uint32_t*>(buffer); content = reinterpret_cast<uint32_t*>(buffer);
clear();
return true; return true;
} }
bool PngLoader::close()
{
png_image_free(image);
return true;
}
unique_ptr<Surface> PngLoader::bitmap() unique_ptr<Surface> PngLoader::bitmap()
{ {
@ -115,5 +122,4 @@ unique_ptr<Surface> PngLoader::bitmap()
surface->premultiplied = false; surface->premultiplied = false;
return unique_ptr<Surface>(surface); return unique_ptr<Surface>(surface);
} }

View file

@ -36,11 +36,12 @@ public:
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 open(const char* data, uint32_t size, const string& rpath, bool copy) override;
bool read() override; bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override; unique_ptr<Surface> bitmap() override;
private: private:
void clear();
png_imagep image = nullptr; png_imagep image = nullptr;
uint32_t* content = nullptr; uint32_t* content = nullptr;
}; };

View file

@ -30,22 +30,9 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
void WebpLoader::clear()
{
if (freeData) free(data);
data = nullptr;
size = 0;
freeData = false;
}
void WebpLoader::run(unsigned tid) void WebpLoader::run(unsigned tid)
{ {
if (image) {
WebPFree(image);
image = nullptr;
}
image = WebPDecodeBGRA(data, size, nullptr, nullptr); image = WebPDecodeBGRA(data, size, nullptr, nullptr);
} }
@ -54,22 +41,25 @@ void WebpLoader::run(unsigned tid)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
WebpLoader::WebpLoader() WebpLoader::WebpLoader() : LoadModule(FileType::Webp)
{ {
} }
WebpLoader::~WebpLoader() WebpLoader::~WebpLoader()
{ {
this->done();
if (freeData) free(data); if (freeData) free(data);
data = nullptr;
size = 0;
freeData = false;
WebPFree(image); WebPFree(image);
} }
bool WebpLoader::open(const string& path) bool WebpLoader::open(const string& path)
{ {
clear();
auto webpFile = fopen(path.c_str(), "rb"); auto webpFile = fopen(path.c_str(), "rb");
if (!webpFile) return false; if (!webpFile) return false;
@ -85,10 +75,10 @@ bool WebpLoader::open(const string& path)
freeData = true; freeData = true;
if (fread(data, size, 1, webpFile) < 1) goto failure; if (fread(data, size, 1, webpFile) < 1) goto finalize;
int width, height; int width, height;
if (!WebPGetInfo(data, size, &width, &height)) goto failure; if (!WebPGetInfo(data, size, &width, &height)) goto finalize;
w = static_cast<float>(width); w = static_cast<float>(width);
h = static_cast<float>(height); h = static_cast<float>(height);
@ -96,11 +86,6 @@ bool WebpLoader::open(const string& path)
ret = true; ret = true;
goto finalize;
failure:
clear();
finalize: finalize:
fclose(webpFile); fclose(webpFile);
return ret; return ret;
@ -109,8 +94,6 @@ finalize:
bool WebpLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) bool WebpLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy)
{ {
clear();
if (copy) { if (copy) {
this->data = (unsigned char *) malloc(size); this->data = (unsigned char *) malloc(size);
if (!this->data) return false; if (!this->data) return false;
@ -134,21 +117,15 @@ bool WebpLoader::open(const char* data, uint32_t size, TVG_UNUSED const string&
bool WebpLoader::read() bool WebpLoader::read()
{ {
if (!data || w <= 0 || h <= 0) return false; if (!LoadModule::read()) return true;
if (!data || w == 0 || h == 0) return false;
TaskScheduler::request(this); TaskScheduler::request(this);
return true; return true;
} }
bool WebpLoader::close()
{
this->done();
clear();
return true;
}
unique_ptr<Surface> WebpLoader::bitmap() unique_ptr<Surface> WebpLoader::bitmap()
{ {
this->done(); this->done();

View file

@ -36,12 +36,10 @@ public:
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 open(const char* data, uint32_t size, const string& rpath, bool copy) override;
bool read() override; bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override; unique_ptr<Surface> bitmap() override;
private: private:
void clear();
void run(unsigned tid) override; void run(unsigned tid) override;
unsigned char* data = nullptr; unsigned char* data = nullptr;

View file

@ -44,6 +44,8 @@ void JpgLoader::run(unsigned tid)
image = nullptr; image = nullptr;
} }
image = jpgdDecompress(decoder); image = jpgdDecompress(decoder);
clear();
} }
@ -51,19 +53,21 @@ void JpgLoader::run(unsigned tid)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
JpgLoader::JpgLoader() : LoadModule(FileType::Jpg)
{
}
JpgLoader::~JpgLoader() JpgLoader::~JpgLoader()
{ {
jpgdDelete(decoder); clear();
if (freeData) free(data);
free(image); free(image);
} }
bool JpgLoader::open(const string& path) bool JpgLoader::open(const string& path)
{ {
clear();
int width, height; int width, height;
decoder = jpgdHeader(path.c_str(), &width, &height); decoder = jpgdHeader(path.c_str(), &width, &height);
if (!decoder) return false; if (!decoder) return false;
@ -78,8 +82,6 @@ bool JpgLoader::open(const string& path)
bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy)
{ {
clear();
if (copy) { if (copy) {
this->data = (char *) malloc(size); this->data = (char *) malloc(size);
if (!this->data) return false; if (!this->data) return false;
@ -105,7 +107,9 @@ bool JpgLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r
bool JpgLoader::read() bool JpgLoader::read()
{ {
if (!decoder || w <= 0 || h <= 0) return false; if (!LoadModule::read()) return true;
if (!decoder || w == 0 || h == 0) return false;
TaskScheduler::request(this); TaskScheduler::request(this);
@ -115,8 +119,8 @@ bool JpgLoader::read()
bool JpgLoader::close() bool JpgLoader::close()
{ {
if (!LoadModule::close()) return false;
this->done(); this->done();
clear();
return true; return true;
} }

View file

@ -39,6 +39,7 @@ private:
void run(unsigned tid) override; void run(unsigned tid) override;
public: public:
JpgLoader();
~JpgLoader(); ~JpgLoader();
using LoadModule::open; using LoadModule::open;

View file

@ -20,7 +20,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "tvgLoader.h"
#include "tvgLottieLoader.h" #include "tvgLottieLoader.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
#include "tvgLottieParser.h" #include "tvgLottieParser.h"
@ -48,17 +47,6 @@ static float _str2float(const char* str, int len)
} }
void LottieLoader::clear()
{
if (copy) free((char*)content);
free(dirName);
dirName = nullptr;
size = 0;
content = nullptr;
copy = false;
}
void LottieLoader::run(unsigned tid) void LottieLoader::run(unsigned tid)
{ {
//update frame //update frame
@ -84,21 +72,21 @@ void LottieLoader::run(unsigned tid)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
LottieLoader::LottieLoader() : builder(new LottieBuilder) LottieLoader::LottieLoader() : FrameModule(FileType::Lottie), builder(new LottieBuilder)
{ {
} }
LottieLoader::~LottieLoader() LottieLoader::~LottieLoader()
{ {
close(); this->done();
if (copy) free((char*)content);
free(dirName);
//TODO: correct position? //TODO: correct position?
if (comp) { delete(comp);
delete(comp);
comp = nullptr;
}
delete(builder); delete(builder);
} }
@ -208,8 +196,6 @@ bool LottieLoader::header()
bool LottieLoader::open(const char* data, uint32_t size, const std::string& rpath, bool copy) bool LottieLoader::open(const char* data, uint32_t size, const std::string& rpath, bool copy)
{ {
clear();
//If the format is dotLottie //If the format is dotLottie
auto dotLottie = _checkDotLottie(data); auto dotLottie = _checkDotLottie(data);
if (dotLottie) { if (dotLottie) {
@ -236,8 +222,6 @@ bool LottieLoader::open(const char* data, uint32_t size, const std::string& rpat
bool LottieLoader::open(const string& path) bool LottieLoader::open(const string& path)
{ {
clear();
auto f = fopen(path.c_str(), "r"); auto f = fopen(path.c_str(), "r");
if (!f) return false; if (!f) return false;
@ -297,6 +281,8 @@ bool LottieLoader::read()
{ {
if (!content || size == 0) return false; if (!content || size == 0) return false;
if (!LoadModule::read()) return true;
//the loading has been already completed in header() //the loading has been already completed in header()
if (comp) return true; if (comp) return true;
@ -306,16 +292,6 @@ bool LottieLoader::read()
} }
bool LottieLoader::close()
{
this->done();
clear();
return true;
}
unique_ptr<Paint> LottieLoader::paint() unique_ptr<Paint> LottieLoader::paint()
{ {
this->done(); this->done();

View file

@ -39,7 +39,7 @@ public:
float frameCnt = 0.0f; float frameCnt = 0.0f;
float frameDuration = 0.0f; float frameDuration = 0.0f;
LottieBuilder* builder = nullptr; LottieBuilder* builder;
LottieComposition* comp = nullptr; LottieComposition* comp = nullptr;
char* dirName = nullptr; //base resource directory char* dirName = nullptr; //base resource directory
@ -54,7 +54,6 @@ public:
bool open(const char* data, uint32_t size, const std::string& rpath, bool copy) override; bool open(const char* data, uint32_t size, const std::string& rpath, bool copy) override;
bool resize(Paint* paint, float w, float h) override; bool resize(Paint* paint, float w, float h) override;
bool read() override; bool read() override;
bool close() override;
unique_ptr<Paint> paint() override; unique_ptr<Paint> paint() override;
//Frame Controls //Frame Controls

View file

@ -29,16 +29,6 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
void PngLoader::clear()
{
lodepng_state_cleanup(&state);
if (freeData) free(data);
data = nullptr;
size = 0;
freeData = false;
}
void PngLoader::run(unsigned tid) void PngLoader::run(unsigned tid)
{ {
@ -59,7 +49,7 @@ void PngLoader::run(unsigned tid)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
PngLoader::PngLoader() PngLoader::PngLoader() : LoadModule(FileType::Png)
{ {
lodepng_state_init(&state); lodepng_state_init(&state);
} }
@ -69,13 +59,12 @@ PngLoader::~PngLoader()
{ {
if (freeData) free(data); if (freeData) free(data);
free(image); free(image);
lodepng_state_cleanup(&state);
} }
bool PngLoader::open(const string& path) bool PngLoader::open(const string& path)
{ {
clear();
auto pngFile = fopen(path.c_str(), "rb"); auto pngFile = fopen(path.c_str(), "rb");
if (!pngFile) return false; if (!pngFile) return false;
@ -91,12 +80,12 @@ bool PngLoader::open(const string& path)
freeData = true; freeData = true;
if (fread(data, size, 1, pngFile) < 1) goto failure; if (fread(data, size, 1, pngFile) < 1) goto finalize;
lodepng_state_init(&state); lodepng_state_init(&state);
unsigned int width, height; unsigned int width, height;
if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto failure; if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto finalize;
w = static_cast<float>(width); w = static_cast<float>(width);
h = static_cast<float>(height); h = static_cast<float>(height);
@ -108,9 +97,6 @@ bool PngLoader::open(const string& path)
goto finalize; goto finalize;
failure:
clear();
finalize: finalize:
fclose(pngFile); fclose(pngFile);
return ret; return ret;
@ -119,10 +105,6 @@ finalize:
bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy) bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& rpath, bool copy)
{ {
clear();
lodepng_state_init(&state);
unsigned int width, height; unsigned int width, height;
if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false; if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false;
@ -148,7 +130,9 @@ bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r
bool PngLoader::read() bool PngLoader::read()
{ {
if (!data || w <= 0 || h <= 0) return false; if (!data || w == 0 || h == 0) return false;
if (!LoadModule::read()) return true;
TaskScheduler::request(this); TaskScheduler::request(this);
@ -156,14 +140,6 @@ bool PngLoader::read()
} }
bool PngLoader::close()
{
this->done();
clear();
return true;
}
unique_ptr<Surface> PngLoader::bitmap() unique_ptr<Surface> PngLoader::bitmap()
{ {
this->done(); this->done();

View file

@ -36,7 +36,6 @@ private:
unsigned long size = 0; unsigned long size = 0;
bool freeData = false; bool freeData = false;
void clear();
void run(unsigned tid) override; void run(unsigned tid) override;
public: public:
@ -47,7 +46,6 @@ public:
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 open(const char* data, uint32_t size, const string& rpath, bool copy) override;
bool read() override; bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override; unique_ptr<Surface> bitmap() override;
}; };

View file

@ -34,6 +34,11 @@
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
RawLoader::RawLoader() : LoadModule(FileType::Raw)
{
}
RawLoader::~RawLoader() RawLoader::~RawLoader()
{ {
if (copy && content) { if (copy && content) {
@ -45,6 +50,8 @@ RawLoader::~RawLoader()
bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy) bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy)
{ {
if (!LoadModule::read()) return true;
if (!data || w == 0 || h == 0) return false; if (!data || w == 0 || h == 0) return false;
this->w = (float)w; this->w = (float)w;
@ -67,12 +74,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool premulti
bool RawLoader::read() bool RawLoader::read()
{ {
return true; LoadModule::read();
}
bool RawLoader::close()
{
return true; return true;
} }

View file

@ -30,12 +30,12 @@ public:
bool copy = false; bool copy = false;
bool premultiplied = false; bool premultiplied = false;
RawLoader();
~RawLoader(); ~RawLoader();
using LoadModule::open; using LoadModule::open;
bool open(const uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy); bool open(const uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy);
bool read() override; bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override; unique_ptr<Surface> bitmap() override;
}; };

View file

@ -3538,14 +3538,15 @@ void SvgLoader::clear(bool all)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
SvgLoader::SvgLoader() SvgLoader::SvgLoader() : LoadModule(FileType::Svg)
{ {
} }
SvgLoader::~SvgLoader() SvgLoader::~SvgLoader()
{ {
close(); this->done();
clear();
} }
@ -3727,6 +3728,8 @@ bool SvgLoader::read()
{ {
if (!content || size == 0) return false; if (!content || size == 0) return false;
if (!LoadModule::read()) return true;
//the loading has been already completed in header() //the loading has been already completed in header()
if (root) return true; if (root) return true;
@ -3738,10 +3741,9 @@ bool SvgLoader::read()
bool SvgLoader::close() bool SvgLoader::close()
{ {
if (!LoadModule::close()) return false;
this->done(); this->done();
clear(); clear();
return true; return true;
} }

View file

@ -39,10 +39,8 @@ void TvgLoader::clear()
size = 0; size = 0;
copy = false; copy = false;
if (interpreter) { delete(interpreter);
delete(interpreter); interpreter = nullptr;
interpreter = nullptr;
}
} }
@ -103,13 +101,37 @@ bool TvgLoader::readHeader()
} }
void TvgLoader::run(unsigned tid)
{
if (root) root.reset();
auto data = const_cast<char*>(ptr);
if (compressed) {
data = (char*) lzwDecode((uint8_t*) data, compressedSize, compressedSizeBits, uncompressedSize);
root = interpreter->run(data, data + uncompressedSize);
free(data);
} else {
root = interpreter->run(data, this->data + size);
}
clear();
}
/************************************************************************/ /************************************************************************/
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
TvgLoader::TvgLoader() : LoadModule(FileType::Tvg)
{
}
TvgLoader::~TvgLoader() TvgLoader::~TvgLoader()
{ {
close(); this->done();
clear();
} }
@ -193,38 +215,14 @@ bool TvgLoader::read()
{ {
if (!ptr || size == 0) return false; if (!ptr || size == 0) return false;
if (!LoadModule::read()) return true;
TaskScheduler::request(this); TaskScheduler::request(this);
return true; return true;
} }
bool TvgLoader::close()
{
this->done();
clear();
return true;
}
void TvgLoader::run(unsigned tid)
{
if (root) root.reset();
auto data = const_cast<char*>(ptr);
if (compressed) {
data = (char*) lzwDecode((uint8_t*) data, compressedSize, compressedSizeBits, uncompressedSize);
root = interpreter->run(data, data + uncompressedSize);
free(data);
} else {
root = interpreter->run(data, this->data + size);
}
if (!root) clear();
}
unique_ptr<Paint> TvgLoader::paint() unique_ptr<Paint> TvgLoader::paint()
{ {
this->done(); this->done();

View file

@ -42,13 +42,13 @@ public:
bool copy = false; bool copy = false;
bool compressed = false; bool compressed = false;
TvgLoader();
~TvgLoader(); ~TvgLoader();
using LoadModule::open; using LoadModule::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 open(const char *data, uint32_t size, const string& rpath, bool copy) override;
bool read() override; bool read() override;
bool close() override;
bool resize(Paint* paint, float w, float h) override; bool resize(Paint* paint, float w, float h) override;
unique_ptr<Paint> paint() override; unique_ptr<Paint> paint() override;

View file

@ -64,7 +64,7 @@ Animation::Animation() : pImpl(new Impl)
Result Animation::frame(float no) noexcept Result Animation::frame(float no) noexcept
{ {
auto loader = pImpl->picture->pImpl->loader.get(); auto loader = pImpl->picture->pImpl->loader;
if (!loader) return Result::InsufficientCondition; if (!loader) return Result::InsufficientCondition;
if (!loader->animatable()) return Result::NonSupport; if (!loader->animatable()) return Result::NonSupport;
@ -82,7 +82,7 @@ Picture* Animation::picture() const noexcept
float Animation::curFrame() const noexcept float Animation::curFrame() const noexcept
{ {
auto loader = pImpl->picture->pImpl->loader.get(); auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0; if (!loader) return 0;
if (!loader->animatable()) return 0; if (!loader->animatable()) return 0;
@ -93,7 +93,7 @@ float Animation::curFrame() const noexcept
float Animation::totalFrame() const noexcept float Animation::totalFrame() const noexcept
{ {
auto loader = pImpl->picture->pImpl->loader.get(); auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0; if (!loader) return 0;
if (!loader->animatable()) return 0; if (!loader->animatable()) return 0;
@ -104,7 +104,7 @@ float Animation::totalFrame() const noexcept
float Animation::duration() const noexcept float Animation::duration() const noexcept
{ {
auto loader = pImpl->picture->pImpl->loader.get(); auto loader = pImpl->picture->pImpl->loader;
if (!loader) return 0; if (!loader) return 0;
if (!loader->animatable()) return 0; if (!loader->animatable()) return 0;

View file

@ -31,6 +31,7 @@ namespace tvg
class FrameModule: public LoadModule class FrameModule: public LoadModule
{ {
public: public:
FrameModule(FileType type) : LoadModule(type) {}
virtual ~FrameModule() {} virtual ~FrameModule() {}
virtual bool frame(float no) = 0; //set the current frame number virtual bool frame(float no) = 0; //set the current frame number

View file

@ -24,16 +24,26 @@
#define _TVG_LOAD_MODULE_H_ #define _TVG_LOAD_MODULE_H_
#include "tvgRender.h" #include "tvgRender.h"
#include "tvgInlist.h"
namespace tvg namespace tvg
{ {
class LoadModule struct LoadModule
{ {
public: INLIST_ITEM(LoadModule);
//Use either hashkey(data) or hashpath(path)
uint64_t hashkey;
string hashpath;
float w = 0, h = 0; //default image size float w = 0, h = 0; //default image size
ColorSpace cs = ColorSpace::Unsupported; //must be clarified at open() ColorSpace cs = ColorSpace::Unsupported; //must be clarified at open()
FileType type; //current loader file type
uint16_t sharing = 0; //reference count
bool readied = false; //read done already.
LoadModule(FileType type) : type(type) {}
virtual ~LoadModule() {} virtual ~LoadModule() {}
virtual bool open(const string& path) { return false; } virtual bool open(const string& path) { return false; }
@ -45,8 +55,19 @@ public:
virtual bool animatable() { return false; } //true if this loader supports animation. virtual bool animatable() { return false; } //true if this loader supports animation.
virtual void sync() {}; //finish immediately if any async update jobs. virtual void sync() {}; //finish immediately if any async update jobs.
virtual bool read() = 0; virtual bool read()
virtual bool close() = 0; {
if (readied) return false;
readied = true;
return true;
}
virtual bool close()
{
if (sharing == 0) return true;
--sharing;
return false;
}
virtual unique_ptr<Surface> bitmap() { return nullptr; } virtual unique_ptr<Surface> bitmap() { return nullptr; }
virtual unique_ptr<Paint> paint() { return nullptr; } virtual unique_ptr<Paint> paint() { return nullptr; }

View file

@ -20,6 +20,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "tvgInlist.h"
#include "tvgLoader.h" #include "tvgLoader.h"
#ifdef THORVG_SVG_LOADER_SUPPORT #ifdef THORVG_SVG_LOADER_SUPPORT
@ -48,10 +49,19 @@
#include "tvgRawLoader.h" #include "tvgRawLoader.h"
uint64_t HASH_KEY(const char* data, uint64_t size)
{
return (((uint64_t) data) << 32) | size;
}
/************************************************************************/ /************************************************************************/
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
static Inlist<LoadModule> _activeLoaders;
static LoadModule* _find(FileType type) static LoadModule* _find(FileType type)
{ {
switch(type) { switch(type) {
@ -156,10 +166,8 @@ static LoadModule* _findByPath(const string& path)
} }
static LoadModule* _findByType(const string& mimeType) static FileType _convert(const string& mimeType)
{ {
if (mimeType.empty()) return nullptr;
auto type = FileType::Unknown; auto type = FileType::Unknown;
if (mimeType == "tvg") type = FileType::Tvg; if (mimeType == "tvg") type = FileType::Tvg;
@ -169,12 +177,50 @@ static LoadModule* _findByType(const string& mimeType)
else if (mimeType == "png") type = FileType::Png; else if (mimeType == "png") type = FileType::Png;
else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg; else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg;
else if (mimeType == "webp") type = FileType::Webp; else if (mimeType == "webp") type = FileType::Webp;
else { else TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
return nullptr;
}
return _find(type); return type;
}
static LoadModule* _findByType(const string& mimeType)
{
return _find(_convert(mimeType));
}
static LoadModule* _findFromCache(const string& path)
{
auto loader = _activeLoaders.head;
while (loader) {
if (loader->hashpath == path) {
++loader->sharing;
return loader;
}
loader = loader->next;
}
return nullptr;
}
static LoadModule* _findFromCache(const char* data, uint32_t size, const string& mimeType)
{
auto type = _convert(mimeType);
if (type == FileType::Unknown) return nullptr;
auto loader = _activeLoaders.head;
auto key = HASH_KEY(data, size);
while (loader) {
if (loader->type == type && loader->hashkey == key) {
++loader->sharing;
return loader;
}
loader = loader->next;
}
return nullptr;
} }
@ -185,40 +231,57 @@ static LoadModule* _findByType(const string& mimeType)
bool LoaderMgr::init() bool LoaderMgr::init()
{ {
//TODO:
return true; return true;
} }
bool LoaderMgr::term() bool LoaderMgr::term()
{ {
//TODO:
return true; return true;
} }
shared_ptr<LoadModule> LoaderMgr::loader(const string& path, bool* invalid) void LoaderMgr::retrieve(LoadModule* loader)
{
if (!loader) return;
if (loader->close()) {
_activeLoaders.remove(loader);
delete(loader);
}
}
LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
{ {
*invalid = false; *invalid = false;
if (auto loader = _findFromCache(path)) return loader;
if (auto loader = _findByPath(path)) { if (auto loader = _findByPath(path)) {
if (loader->open(path)) return shared_ptr<LoadModule>(loader); if (loader->open(path)) {
else delete(loader); loader->hashpath = path;
_activeLoaders.back(loader);
return loader;
}
delete(loader);
*invalid = true; *invalid = true;
} }
return nullptr; return nullptr;
} }
shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, const string& rpath, bool copy) LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, const string& rpath, bool copy)
{ {
if (auto loader = _findFromCache(data, size, mimeType)) return loader;
//Try with the given MimeType //Try with the given MimeType
if (!mimeType.empty()) { if (!mimeType.empty()) {
if (auto loader = _findByType(mimeType)) { if (auto loader = _findByType(mimeType)) {
if (loader->open(data, size, rpath, copy)) { if (loader->open(data, size, rpath, copy)) {
return shared_ptr<LoadModule>(loader); loader->hashkey = HASH_KEY(data, size);
_activeLoaders.back(loader);
return loader;
} else { } else {
TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str()); TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str());
delete(loader); delete(loader);
@ -229,8 +292,12 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const
for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) { for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) {
auto loader = _find(static_cast<FileType>(i)); auto loader = _find(static_cast<FileType>(i));
if (loader) { if (loader) {
if (loader->open(data, size, rpath, copy)) return shared_ptr<LoadModule>(loader); if (loader->open(data, size, rpath, copy)) {
else delete(loader); loader->hashkey = HASH_KEY(data, size);
_activeLoaders.back(loader);
return loader;
}
delete(loader);
} }
} }
} }
@ -238,12 +305,18 @@ shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const
} }
shared_ptr<LoadModule> LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool premultiplied, bool copy) LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool premultiplied, bool copy)
{ {
//TODO: should we check premultiplied??
if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader;
//function is dedicated for raw images only //function is dedicated for raw images only
auto loader = new RawLoader; auto loader = new RawLoader;
if (loader->open(data, w, h, premultiplied, copy)) return shared_ptr<LoadModule>(loader); if (loader->open(data, w, h, premultiplied, copy)) {
else delete(loader); loader->hashkey = HASH_KEY((const char*)data, w * h);
_activeLoaders.back(loader);
return loader;
}
delete(loader);
return nullptr; return nullptr;
} }

View file

@ -29,9 +29,10 @@ struct LoaderMgr
{ {
static bool init(); static bool init();
static bool term(); static bool term();
static shared_ptr<LoadModule> loader(const string& path, bool* invalid); static LoadModule* loader(const string& path, bool* invalid);
static shared_ptr<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 shared_ptr<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 void retrieve(LoadModule* loader);
}; };
#endif //_TVG_LOADER_H_ #endif //_TVG_LOADER_H_

View file

@ -32,7 +32,6 @@ RenderUpdateFlag Picture::Impl::load()
if (!paint) { if (!paint) {
if (auto p = loader->paint()) { if (auto p = loader->paint()) {
paint = p.release(); paint = p.release();
loader->close();
if (w != loader->w || h != loader->h) { if (w != loader->w || h != loader->h) {
if (!resizing) { if (!resizing) {
w = loader->w; w = loader->w;
@ -47,7 +46,6 @@ RenderUpdateFlag Picture::Impl::load()
if (!surface) { if (!surface) {
if ((surface = loader->bitmap().release())) { if ((surface = loader->bitmap().release())) {
loader->close();
return RenderUpdateFlag::Image; return RenderUpdateFlag::Image;
} }
} }
@ -120,6 +118,28 @@ RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform
} }
Result Picture::Impl::load(LoadModule* loader)
{
//Same resource has been loaded.
if (this->loader == loader) {
this->loader->sharing--; //make it sure the reference counting.
return Result::Success;
} else if (this->loader) {
LoaderMgr::retrieve(this->loader);
}
this->loader = loader;
if (!loader->read()) return Result::Unknown;
this->w = loader->w;
this->h = loader->h;
return Result::Success;
}
/************************************************************************/ /************************************************************************/
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/

View file

@ -57,7 +57,7 @@ struct PictureIterator : Iterator
struct Picture::Impl struct Picture::Impl
{ {
shared_ptr<LoadModule> loader = nullptr; LoadModule* loader = nullptr;
Paint* paint = nullptr; //vector picture uses Paint* paint = nullptr; //vector picture uses
Surface* surface = nullptr; //bitmap picture uses Surface* surface = nullptr; //bitmap picture uses
@ -73,6 +73,7 @@ struct Picture::Impl
bool render(RenderMethod &renderer); bool render(RenderMethod &renderer);
bool size(float w, float h); bool size(float w, float h);
RenderRegion bounds(RenderMethod& renderer); RenderRegion bounds(RenderMethod& renderer);
Result load(LoadModule* ploader);
Impl(Picture* p) : picture(p) Impl(Picture* p) : picture(p)
{ {
@ -80,6 +81,7 @@ struct Picture::Impl
~Impl() ~Impl()
{ {
LoaderMgr::retrieve(loader);
delete(paint); delete(paint);
delete(surface); delete(surface);
} }
@ -149,40 +151,32 @@ struct Picture::Impl
Result load(const string& path) Result load(const string& path)
{ {
if (paint || surface) return Result::InsufficientCondition; if (paint || surface) return Result::InsufficientCondition;
if (loader) loader->close();
bool invalid; //Invalid Path bool invalid; //Invalid Path
loader = LoaderMgr::loader(path, &invalid); auto loader = LoaderMgr::loader(path, &invalid);
if (!loader) { if (!loader) {
if (invalid) return Result::InvalidArguments; if (invalid) return Result::InvalidArguments;
return Result::NonSupport; return Result::NonSupport;
} }
if (!loader->read()) return Result::Unknown; return load(loader);
w = loader->w;
h = loader->h;
return Result::Success;
} }
Result load(const char* data, uint32_t size, const string& mimeType, const string& rpath, bool copy) Result load(const char* data, uint32_t size, const string& mimeType, const string& rpath, bool copy)
{ {
if (paint || surface) return Result::InsufficientCondition; if (paint || surface) return Result::InsufficientCondition;
if (loader) loader->close(); auto loader = LoaderMgr::loader(data, size, mimeType, rpath, copy);
loader = LoaderMgr::loader(data, size, mimeType, rpath, copy);
if (!loader) return Result::NonSupport; if (!loader) return Result::NonSupport;
if (!loader->read()) return Result::Unknown; return load(loader);
w = loader->w;
h = loader->h;
return Result::Success;
} }
Result load(uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy) Result load(uint32_t* data, uint32_t w, uint32_t h, bool premultiplied, bool copy)
{ {
if (paint || surface) return Result::InsufficientCondition; if (paint || surface) return Result::InsufficientCondition;
if (loader) loader->close();
loader = LoaderMgr::loader(data, w, h, premultiplied, copy); auto loader = LoaderMgr::loader(data, w, h, premultiplied, copy);
if (!loader) return Result::FailedAllocation; if (!loader) return Result::FailedAllocation;
this->w = loader->w;
this->h = loader->h; return load(loader);
return Result::Success;
} }
void mesh(const Polygon* triangles, const uint32_t triangleCnt) void mesh(const Polygon* triangles, const uint32_t triangleCnt)
@ -208,10 +202,11 @@ struct Picture::Impl
if (paint) dup->paint = paint->duplicate(); if (paint) dup->paint = paint->duplicate();
dup->loader = loader; dup->loader = loader;
++dup->loader->sharing;
if (surface) { if (surface) {
dup->surface = new Surface; dup->surface = new Surface;
*dup->surface = *surface; *dup->surface = *surface;
//TODO: A dupilcation is not a proxy... it needs copy of the pixel data?
dup->surface->owner = false; dup->surface->owner = false;
} }
dup->w = w; dup->w = w;