mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +00:00
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:
parent
14e90e9b31
commit
f64ee28079
25 changed files with 293 additions and 241 deletions
|
@ -33,8 +33,8 @@ namespace tvg {
|
|||
template<typename T>
|
||||
struct Inlist
|
||||
{
|
||||
T *head = nullptr;
|
||||
T *tail = nullptr;
|
||||
T* head = nullptr;
|
||||
T* tail = nullptr;
|
||||
|
||||
void free()
|
||||
{
|
||||
|
@ -52,6 +52,7 @@ struct Inlist
|
|||
tail->next = element;
|
||||
element->prev = tail;
|
||||
element->next = nullptr;
|
||||
tail = element;
|
||||
} else {
|
||||
head = tail = element;
|
||||
element->prev = nullptr;
|
||||
|
@ -62,9 +63,10 @@ struct Inlist
|
|||
void front(T* element)
|
||||
{
|
||||
if (head) {
|
||||
head->prev = element;
|
||||
element->prev = nullptr;
|
||||
element->next = head;
|
||||
head->prev = element;
|
||||
head = element;
|
||||
} else {
|
||||
head = tail = element;
|
||||
element->prev = nullptr;
|
||||
|
@ -90,6 +92,14 @@ struct Inlist
|
|||
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()
|
||||
{
|
||||
return head ? false : true;
|
||||
|
|
|
@ -41,7 +41,7 @@ void JpgLoader::clear()
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
JpgLoader::JpgLoader()
|
||||
JpgLoader::JpgLoader() : LoadModule(FileType::Jpg)
|
||||
{
|
||||
jpegDecompressor = tjInitDecompress();
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ JpgLoader::JpgLoader()
|
|||
|
||||
JpgLoader::~JpgLoader()
|
||||
{
|
||||
if (freeData) free(data);
|
||||
clear();
|
||||
tjDestroy(jpegDecompressor);
|
||||
|
||||
//This image is shared with raster engine.
|
||||
|
@ -59,8 +59,6 @@ JpgLoader::~JpgLoader()
|
|||
|
||||
bool JpgLoader::open(const string& path)
|
||||
{
|
||||
clear();
|
||||
|
||||
auto jpegFile = fopen(path.c_str(), "rb");
|
||||
if (!jpegFile) return false;
|
||||
|
||||
|
@ -102,8 +100,6 @@ finalize:
|
|||
|
||||
bool JpgLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
clear();
|
||||
|
||||
int width, height, subSample, colorSpace;
|
||||
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, bool copy)
|
|||
|
||||
bool JpgLoader::read()
|
||||
{
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
if (w == 0 || h == 0) return false;
|
||||
|
||||
/* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB
|
||||
How could we notice the renderer colorspace at this time? */
|
||||
if (image) tjFree(image);
|
||||
|
@ -142,12 +142,6 @@ bool JpgLoader::read()
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JpgLoader::close()
|
||||
{
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ public:
|
|||
bool open(const string& path) override;
|
||||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
|
||||
unique_ptr<Surface> bitmap() override;
|
||||
|
||||
|
|
|
@ -26,12 +26,19 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
void PngLoader::clear()
|
||||
{
|
||||
png_image_free(image);
|
||||
free(image);
|
||||
image = nullptr;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
PngLoader::PngLoader()
|
||||
PngLoader::PngLoader() : LoadModule(FileType::Png)
|
||||
{
|
||||
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
|
||||
image->version = PNG_IMAGE_VERSION;
|
||||
|
@ -40,13 +47,11 @@ PngLoader::PngLoader()
|
|||
|
||||
PngLoader::~PngLoader()
|
||||
{
|
||||
if (content) {
|
||||
clear();
|
||||
free((void*)content);
|
||||
content = nullptr;
|
||||
}
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::open(const string& path)
|
||||
{
|
||||
image->opaque = NULL;
|
||||
|
@ -60,6 +65,7 @@ bool PngLoader::open(const string& path)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
image->opaque = NULL;
|
||||
|
@ -76,6 +82,10 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
|||
|
||||
bool PngLoader::read()
|
||||
{
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
if (w == 0 || h == 0) return false;
|
||||
|
||||
png_bytep buffer;
|
||||
image->format = PNG_FORMAT_BGRA;
|
||||
buffer = static_cast<png_bytep>(malloc(PNG_IMAGE_SIZE((*image))));
|
||||
|
@ -90,14 +100,11 @@ bool PngLoader::read()
|
|||
}
|
||||
content = reinterpret_cast<uint32_t*>(buffer);
|
||||
|
||||
clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PngLoader::close()
|
||||
{
|
||||
png_image_free(image);
|
||||
return true;
|
||||
}
|
||||
|
||||
unique_ptr<Surface> PngLoader::bitmap()
|
||||
{
|
||||
|
@ -116,4 +123,3 @@ unique_ptr<Surface> PngLoader::bitmap()
|
|||
|
||||
return unique_ptr<Surface>(surface);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,11 +36,12 @@ public:
|
|||
bool open(const string& path) override;
|
||||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
|
||||
unique_ptr<Surface> bitmap() override;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
|
||||
png_imagep image = nullptr;
|
||||
uint32_t* content = nullptr;
|
||||
};
|
||||
|
|
|
@ -30,22 +30,9 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
void WebpLoader::clear()
|
||||
{
|
||||
if (freeData) free(data);
|
||||
data = nullptr;
|
||||
size = 0;
|
||||
freeData = false;
|
||||
}
|
||||
|
||||
|
||||
void WebpLoader::run(unsigned tid)
|
||||
{
|
||||
if (image) {
|
||||
WebPFree(image);
|
||||
image = nullptr;
|
||||
}
|
||||
|
||||
image = WebPDecodeBGRA(data, size, nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
@ -54,22 +41,25 @@ void WebpLoader::run(unsigned tid)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
WebpLoader::WebpLoader()
|
||||
WebpLoader::WebpLoader() : LoadModule(FileType::Webp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
WebpLoader::~WebpLoader()
|
||||
{
|
||||
this->done();
|
||||
|
||||
if (freeData) free(data);
|
||||
data = nullptr;
|
||||
size = 0;
|
||||
freeData = false;
|
||||
WebPFree(image);
|
||||
}
|
||||
|
||||
|
||||
bool WebpLoader::open(const string& path)
|
||||
{
|
||||
clear();
|
||||
|
||||
auto webpFile = fopen(path.c_str(), "rb");
|
||||
if (!webpFile) return false;
|
||||
|
||||
|
@ -85,10 +75,10 @@ bool WebpLoader::open(const string& path)
|
|||
|
||||
freeData = true;
|
||||
|
||||
if (fread(data, size, 1, webpFile) < 1) goto failure;
|
||||
if (fread(data, size, 1, webpFile) < 1) goto finalize;
|
||||
|
||||
int width, height;
|
||||
if (!WebPGetInfo(data, size, &width, &height)) goto failure;
|
||||
if (!WebPGetInfo(data, size, &width, &height)) goto finalize;
|
||||
|
||||
w = static_cast<float>(width);
|
||||
h = static_cast<float>(height);
|
||||
|
@ -96,11 +86,6 @@ bool WebpLoader::open(const string& path)
|
|||
|
||||
ret = true;
|
||||
|
||||
goto finalize;
|
||||
|
||||
failure:
|
||||
clear();
|
||||
|
||||
finalize:
|
||||
fclose(webpFile);
|
||||
return ret;
|
||||
|
@ -109,8 +94,6 @@ finalize:
|
|||
|
||||
bool WebpLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (copy) {
|
||||
this->data = (unsigned char *) malloc(size);
|
||||
if (!this->data) return false;
|
||||
|
@ -134,21 +117,15 @@ bool WebpLoader::open(const char* data, uint32_t size, bool copy)
|
|||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WebpLoader::close()
|
||||
{
|
||||
this->done();
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<Surface> WebpLoader::bitmap()
|
||||
{
|
||||
this->done();
|
||||
|
|
|
@ -36,12 +36,10 @@ public:
|
|||
bool open(const string& path) override;
|
||||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
|
||||
unique_ptr<Surface> bitmap() override;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void run(unsigned tid) override;
|
||||
|
||||
unsigned char* data = nullptr;
|
||||
|
|
|
@ -44,6 +44,8 @@ void JpgLoader::run(unsigned tid)
|
|||
image = nullptr;
|
||||
}
|
||||
image = jpgdDecompress(decoder);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,19 +53,21 @@ void JpgLoader::run(unsigned tid)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
JpgLoader::JpgLoader() : LoadModule(FileType::Jpg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
JpgLoader::~JpgLoader()
|
||||
{
|
||||
jpgdDelete(decoder);
|
||||
if (freeData) free(data);
|
||||
clear();
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
||||
bool JpgLoader::open(const string& path)
|
||||
{
|
||||
clear();
|
||||
|
||||
int width, height;
|
||||
decoder = jpgdHeader(path.c_str(), &width, &height);
|
||||
if (!decoder) return false;
|
||||
|
@ -78,8 +82,6 @@ bool JpgLoader::open(const string& path)
|
|||
|
||||
bool JpgLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (copy) {
|
||||
this->data = (char *) malloc(size);
|
||||
if (!this->data) return false;
|
||||
|
@ -105,7 +107,9 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy)
|
|||
|
||||
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);
|
||||
|
||||
|
@ -115,8 +119,8 @@ bool JpgLoader::read()
|
|||
|
||||
bool JpgLoader::close()
|
||||
{
|
||||
if (!LoadModule::close()) return false;
|
||||
this->done();
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
void run(unsigned tid) override;
|
||||
|
||||
public:
|
||||
JpgLoader();
|
||||
~JpgLoader();
|
||||
|
||||
using LoadModule::open;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "tvgLoader.h"
|
||||
#include "tvgLottieLoader.h"
|
||||
#include "tvgLottieModel.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)
|
||||
{
|
||||
//update frame
|
||||
|
@ -84,21 +72,21 @@ void LottieLoader::run(unsigned tid)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
LottieLoader::LottieLoader() : builder(new LottieBuilder)
|
||||
LottieLoader::LottieLoader() : FrameModule(FileType::Lottie), builder(new LottieBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
LottieLoader::~LottieLoader()
|
||||
{
|
||||
close();
|
||||
this->done();
|
||||
|
||||
if (copy) free((char*)content);
|
||||
free(dirName);
|
||||
|
||||
//TODO: correct position?
|
||||
if (comp) {
|
||||
delete(comp);
|
||||
comp = nullptr;
|
||||
}
|
||||
|
||||
delete(builder);
|
||||
}
|
||||
|
||||
|
@ -208,8 +196,6 @@ bool LottieLoader::header()
|
|||
|
||||
bool LottieLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
clear();
|
||||
|
||||
//If the format is dotLottie
|
||||
auto dotLottie = _checkDotLottie(data);
|
||||
if (dotLottie) {
|
||||
|
@ -232,8 +218,6 @@ bool LottieLoader::open(const char* data, uint32_t size, bool copy)
|
|||
|
||||
bool LottieLoader::open(const string& path)
|
||||
{
|
||||
clear();
|
||||
|
||||
auto f = fopen(path.c_str(), "r");
|
||||
if (!f) return false;
|
||||
|
||||
|
@ -293,6 +277,8 @@ bool LottieLoader::read()
|
|||
{
|
||||
if (!content || size == 0) return false;
|
||||
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
//the loading has been already completed in header()
|
||||
if (comp) return true;
|
||||
|
||||
|
@ -302,16 +288,6 @@ bool LottieLoader::read()
|
|||
}
|
||||
|
||||
|
||||
bool LottieLoader::close()
|
||||
{
|
||||
this->done();
|
||||
|
||||
clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<Paint> LottieLoader::paint()
|
||||
{
|
||||
this->done();
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
float frameCnt = 0.0f;
|
||||
float frameDuration = 0.0f;
|
||||
|
||||
LottieBuilder* builder = nullptr;
|
||||
LottieBuilder* builder;
|
||||
LottieComposition* comp = nullptr;
|
||||
|
||||
char* dirName = nullptr; //base resource directory
|
||||
|
@ -54,7 +54,6 @@ public:
|
|||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool resize(Paint* paint, float w, float h) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
unique_ptr<Paint> paint() override;
|
||||
|
||||
//Frame Controls
|
||||
|
|
|
@ -29,16 +29,6 @@
|
|||
/* 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)
|
||||
{
|
||||
|
@ -59,7 +49,7 @@ void PngLoader::run(unsigned tid)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
PngLoader::PngLoader()
|
||||
PngLoader::PngLoader() : LoadModule(FileType::Png)
|
||||
{
|
||||
lodepng_state_init(&state);
|
||||
}
|
||||
|
@ -69,13 +59,12 @@ PngLoader::~PngLoader()
|
|||
{
|
||||
if (freeData) free(data);
|
||||
free(image);
|
||||
lodepng_state_cleanup(&state);
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::open(const string& path)
|
||||
{
|
||||
clear();
|
||||
|
||||
auto pngFile = fopen(path.c_str(), "rb");
|
||||
if (!pngFile) return false;
|
||||
|
||||
|
@ -91,12 +80,12 @@ bool PngLoader::open(const string& path)
|
|||
|
||||
freeData = true;
|
||||
|
||||
if (fread(data, size, 1, pngFile) < 1) goto failure;
|
||||
if (fread(data, size, 1, pngFile) < 1) goto finalize;
|
||||
|
||||
lodepng_state_init(&state);
|
||||
|
||||
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);
|
||||
h = static_cast<float>(height);
|
||||
|
@ -108,9 +97,6 @@ bool PngLoader::open(const string& path)
|
|||
|
||||
goto finalize;
|
||||
|
||||
failure:
|
||||
clear();
|
||||
|
||||
finalize:
|
||||
fclose(pngFile);
|
||||
return ret;
|
||||
|
@ -119,10 +105,6 @@ finalize:
|
|||
|
||||
bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
clear();
|
||||
|
||||
lodepng_state_init(&state);
|
||||
|
||||
unsigned int width, height;
|
||||
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, bool copy)
|
|||
|
||||
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);
|
||||
|
||||
|
@ -156,14 +140,6 @@ bool PngLoader::read()
|
|||
}
|
||||
|
||||
|
||||
bool PngLoader::close()
|
||||
{
|
||||
this->done();
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<Surface> PngLoader::bitmap()
|
||||
{
|
||||
this->done();
|
||||
|
|
|
@ -36,7 +36,6 @@ private:
|
|||
unsigned long size = 0;
|
||||
bool freeData = false;
|
||||
|
||||
void clear();
|
||||
void run(unsigned tid) override;
|
||||
|
||||
public:
|
||||
|
@ -47,7 +46,6 @@ public:
|
|||
bool open(const string& path) override;
|
||||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
|
||||
unique_ptr<Surface> bitmap() override;
|
||||
};
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
RawLoader::RawLoader() : LoadModule(FileType::Raw)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RawLoader::~RawLoader()
|
||||
{
|
||||
if (copy && content) {
|
||||
|
@ -45,6 +50,8 @@ RawLoader::~RawLoader()
|
|||
|
||||
bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
|
||||
{
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
if (!data || w == 0 || h == 0) return false;
|
||||
|
||||
this->w = (float)w;
|
||||
|
@ -66,12 +73,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
|
|||
|
||||
bool RawLoader::read()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RawLoader::close()
|
||||
{
|
||||
LoadModule::read();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,12 @@ public:
|
|||
uint32_t* content = nullptr;
|
||||
bool copy = false;
|
||||
|
||||
RawLoader();
|
||||
~RawLoader();
|
||||
|
||||
using LoadModule::open;
|
||||
bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
|
||||
unique_ptr<Surface> bitmap() override;
|
||||
};
|
||||
|
|
|
@ -3538,14 +3538,15 @@ void SvgLoader::clear(bool all)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
SvgLoader::SvgLoader()
|
||||
SvgLoader::SvgLoader() : LoadModule(FileType::Svg)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SvgLoader::~SvgLoader()
|
||||
{
|
||||
close();
|
||||
this->done();
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -3727,6 +3728,8 @@ bool SvgLoader::read()
|
|||
{
|
||||
if (!content || size == 0) return false;
|
||||
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
//the loading has been already completed in header()
|
||||
if (root) return true;
|
||||
|
||||
|
@ -3738,10 +3741,9 @@ bool SvgLoader::read()
|
|||
|
||||
bool SvgLoader::close()
|
||||
{
|
||||
if (!LoadModule::close()) return false;
|
||||
this->done();
|
||||
|
||||
clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,10 +39,8 @@ void TvgLoader::clear()
|
|||
size = 0;
|
||||
copy = false;
|
||||
|
||||
if (interpreter) {
|
||||
delete(interpreter);
|
||||
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 */
|
||||
/************************************************************************/
|
||||
|
||||
TvgLoader::TvgLoader() : LoadModule(FileType::Tvg)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TvgLoader::~TvgLoader()
|
||||
{
|
||||
close();
|
||||
this->done();
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -193,38 +215,14 @@ bool TvgLoader::read()
|
|||
{
|
||||
if (!ptr || size == 0) return false;
|
||||
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
TaskScheduler::request(this);
|
||||
|
||||
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()
|
||||
{
|
||||
this->done();
|
||||
|
|
|
@ -42,13 +42,13 @@ public:
|
|||
bool copy = false;
|
||||
bool compressed = false;
|
||||
|
||||
TvgLoader();
|
||||
~TvgLoader();
|
||||
|
||||
using LoadModule::open;
|
||||
bool open(const string &path) override;
|
||||
bool open(const char *data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
bool resize(Paint* paint, float w, float h) override;
|
||||
|
||||
unique_ptr<Paint> paint() override;
|
||||
|
|
|
@ -64,7 +64,7 @@ Animation::Animation() : pImpl(new Impl)
|
|||
|
||||
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->animatable()) return Result::NonSupport;
|
||||
|
@ -82,7 +82,7 @@ Picture* Animation::picture() 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->animatable()) return 0;
|
||||
|
@ -93,7 +93,7 @@ float Animation::curFrame() 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->animatable()) return 0;
|
||||
|
@ -104,7 +104,7 @@ float Animation::totalFrame() 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->animatable()) return 0;
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace tvg
|
|||
class FrameModule: public LoadModule
|
||||
{
|
||||
public:
|
||||
FrameModule(FileType type) : LoadModule(type) {}
|
||||
virtual ~FrameModule() {}
|
||||
|
||||
virtual bool frame(float no) = 0; //set the current frame number
|
||||
|
|
|
@ -24,16 +24,26 @@
|
|||
#define _TVG_LOAD_MODULE_H_
|
||||
|
||||
#include "tvgRender.h"
|
||||
#include "tvgInlist.h"
|
||||
|
||||
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
|
||||
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 bool open(const string& path) { return false; }
|
||||
|
@ -45,8 +55,19 @@ public:
|
|||
virtual bool animatable() { return false; } //true if this loader supports animation.
|
||||
virtual void sync() {}; //finish immediately if any async update jobs.
|
||||
|
||||
virtual bool read() = 0;
|
||||
virtual bool close() = 0;
|
||||
virtual bool read()
|
||||
{
|
||||
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<Paint> paint() { return nullptr; }
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "tvgInlist.h"
|
||||
#include "tvgLoader.h"
|
||||
|
||||
#ifdef THORVG_SVG_LOADER_SUPPORT
|
||||
|
@ -48,10 +49,19 @@
|
|||
|
||||
#include "tvgRawLoader.h"
|
||||
|
||||
|
||||
uint64_t HASH_KEY(const char* data, uint64_t size)
|
||||
{
|
||||
return (((uint64_t) data) << 32) | size;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
static Inlist<LoadModule> _activeLoaders;
|
||||
|
||||
|
||||
static LoadModule* _find(FileType 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;
|
||||
|
||||
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 == "jpg" || mimeType == "jpeg") type = FileType::Jpg;
|
||||
else if (mimeType == "webp") type = FileType::Webp;
|
||||
else {
|
||||
TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
else TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
|
||||
|
||||
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()
|
||||
{
|
||||
//TODO:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LoaderMgr::term()
|
||||
{
|
||||
//TODO:
|
||||
|
||||
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;
|
||||
|
||||
if (auto loader = _findFromCache(path)) return loader;
|
||||
|
||||
if (auto loader = _findByPath(path)) {
|
||||
if (loader->open(path)) return shared_ptr<LoadModule>(loader);
|
||||
else delete(loader);
|
||||
if (loader->open(path)) {
|
||||
loader->hashpath = path;
|
||||
_activeLoaders.back(loader);
|
||||
return loader;
|
||||
}
|
||||
delete(loader);
|
||||
*invalid = true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
|
||||
LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
|
||||
{
|
||||
if (auto loader = _findFromCache(data, size, mimeType)) return loader;
|
||||
|
||||
//Try with the given MimeType
|
||||
if (!mimeType.empty()) {
|
||||
if (auto loader = _findByType(mimeType)) {
|
||||
if (loader->open(data, size, copy)) {
|
||||
return shared_ptr<LoadModule>(loader);
|
||||
loader->hashkey = HASH_KEY(data, size);
|
||||
_activeLoaders.back(loader);
|
||||
return loader;
|
||||
} else {
|
||||
TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str());
|
||||
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++) {
|
||||
auto loader = _find(static_cast<FileType>(i));
|
||||
if (loader) {
|
||||
if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader);
|
||||
else delete(loader);
|
||||
if (loader->open(data, size, copy)) {
|
||||
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 copy)
|
||||
LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, 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
|
||||
auto loader = new RawLoader;
|
||||
if (loader->open(data, w, h, copy)) return shared_ptr<LoadModule>(loader);
|
||||
else delete(loader);
|
||||
|
||||
if (loader->open(data, w, h, copy)) {
|
||||
loader->hashkey = HASH_KEY((const char*)data, w * h);
|
||||
_activeLoaders.back(loader);
|
||||
return loader;
|
||||
}
|
||||
delete(loader);
|
||||
return nullptr;
|
||||
}
|
|
@ -29,9 +29,10 @@ struct LoaderMgr
|
|||
{
|
||||
static bool init();
|
||||
static bool term();
|
||||
static shared_ptr<LoadModule> loader(const string& path, bool* invalid);
|
||||
static shared_ptr<LoadModule> loader(const char* data, uint32_t size, const string& mimeType, bool copy);
|
||||
static shared_ptr<LoadModule> loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
|
||||
static LoadModule* loader(const string& path, bool* invalid);
|
||||
static LoadModule* loader(const char* data, uint32_t size, const string& mimeType, bool copy);
|
||||
static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
|
||||
static void retrieve(LoadModule* loader);
|
||||
};
|
||||
|
||||
#endif //_TVG_LOADER_H_
|
||||
|
|
|
@ -32,7 +32,6 @@ RenderUpdateFlag Picture::Impl::load()
|
|||
if (!paint) {
|
||||
if (auto p = loader->paint()) {
|
||||
paint = p.release();
|
||||
loader->close();
|
||||
if (w != loader->w || h != loader->h) {
|
||||
if (!resizing) {
|
||||
w = loader->w;
|
||||
|
@ -47,7 +46,6 @@ RenderUpdateFlag Picture::Impl::load()
|
|||
|
||||
if (!surface) {
|
||||
if ((surface = loader->bitmap().release())) {
|
||||
loader->close();
|
||||
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 */
|
||||
/************************************************************************/
|
||||
|
|
|
@ -57,7 +57,7 @@ struct PictureIterator : Iterator
|
|||
|
||||
struct Picture::Impl
|
||||
{
|
||||
shared_ptr<LoadModule> loader = nullptr;
|
||||
LoadModule* loader = nullptr;
|
||||
|
||||
Paint* paint = nullptr; //vector picture uses
|
||||
Surface* surface = nullptr; //bitmap picture uses
|
||||
|
@ -73,6 +73,7 @@ struct Picture::Impl
|
|||
bool render(RenderMethod &renderer);
|
||||
bool size(float w, float h);
|
||||
RenderRegion bounds(RenderMethod& renderer);
|
||||
Result load(LoadModule* ploader);
|
||||
|
||||
Impl(Picture* p) : picture(p)
|
||||
{
|
||||
|
@ -80,6 +81,7 @@ struct Picture::Impl
|
|||
|
||||
~Impl()
|
||||
{
|
||||
LoaderMgr::retrieve(loader);
|
||||
delete(paint);
|
||||
delete(surface);
|
||||
}
|
||||
|
@ -149,40 +151,32 @@ struct Picture::Impl
|
|||
Result load(const string& path)
|
||||
{
|
||||
if (paint || surface) return Result::InsufficientCondition;
|
||||
if (loader) loader->close();
|
||||
|
||||
bool invalid; //Invalid Path
|
||||
loader = LoaderMgr::loader(path, &invalid);
|
||||
auto loader = LoaderMgr::loader(path, &invalid);
|
||||
if (!loader) {
|
||||
if (invalid) return Result::InvalidArguments;
|
||||
return Result::NonSupport;
|
||||
}
|
||||
if (!loader->read()) return Result::Unknown;
|
||||
w = loader->w;
|
||||
h = loader->h;
|
||||
return Result::Success;
|
||||
return load(loader);
|
||||
}
|
||||
|
||||
Result load(const char* data, uint32_t size, const string& mimeType, bool copy)
|
||||
{
|
||||
if (paint || surface) return Result::InsufficientCondition;
|
||||
if (loader) loader->close();
|
||||
loader = LoaderMgr::loader(data, size, mimeType, copy);
|
||||
auto loader = LoaderMgr::loader(data, size, mimeType, copy);
|
||||
if (!loader) return Result::NonSupport;
|
||||
if (!loader->read()) return Result::Unknown;
|
||||
w = loader->w;
|
||||
h = loader->h;
|
||||
return Result::Success;
|
||||
return load(loader);
|
||||
}
|
||||
|
||||
Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy)
|
||||
{
|
||||
if (paint || surface) return Result::InsufficientCondition;
|
||||
if (loader) loader->close();
|
||||
loader = LoaderMgr::loader(data, w, h, copy);
|
||||
|
||||
auto loader = LoaderMgr::loader(data, w, h, copy);
|
||||
if (!loader) return Result::FailedAllocation;
|
||||
this->w = loader->w;
|
||||
this->h = loader->h;
|
||||
return Result::Success;
|
||||
|
||||
return load(loader);
|
||||
}
|
||||
|
||||
void mesh(const Polygon* triangles, const uint32_t triangleCnt)
|
||||
|
@ -208,10 +202,11 @@ struct Picture::Impl
|
|||
if (paint) dup->paint = paint->duplicate();
|
||||
|
||||
dup->loader = loader;
|
||||
++dup->loader->sharing;
|
||||
|
||||
if (surface) {
|
||||
dup->surface = new Surface;
|
||||
*dup->surface = *surface;
|
||||
//TODO: A dupilcation is not a proxy... it needs copy of the pixel data?
|
||||
dup->surface->owner = false;
|
||||
}
|
||||
dup->w = w;
|
||||
|
|
Loading…
Add table
Reference in a new issue