picture svg: introduce load() with memory data input source.

picture now affords the memory data as input source so that
user can pass svg data memory directly.

Change-Id: I246c09b682a2d60e53ad556ce0c90337142ee4f1
This commit is contained in:
Hermet Park 2020-08-14 19:35:39 +09:00
parent 1eb11f249e
commit 7ab71c52d0
11 changed files with 228 additions and 31 deletions

1
.gitignore vendored
View file

@ -19,6 +19,7 @@ testLinearGradient
testRadialGradient
testGradientTransform
testSvg
testSvg2
testAsync
testCapi
testArc

View file

@ -267,6 +267,7 @@ public:
~Picture();
Result load(const std::string& path) noexcept;
Result load(const char* data, uint32_t size) noexcept;
Result viewbox(float* x, float* y, float* w, float* h) const noexcept;
static std::unique_ptr<Picture> gen() noexcept;

View file

@ -37,6 +37,7 @@ public:
virtual ~Loader() {}
virtual bool open(const char* path) = 0;
virtual bool open(const char* data, uint32_t size) = 0;
virtual bool read() = 0;
virtual bool close() = 0;
virtual unique_ptr<Scene> data() = 0;

View file

@ -50,12 +50,11 @@ bool LoaderMgr::term()
return true;
}
unique_ptr<Loader> LoaderMgr::loader(const char* path)
unique_ptr<Loader> LoaderMgr::loader()
{
#ifdef THORVG_SVG_LOADER_SUPPORT
return unique_ptr<SvgLoader>(new SvgLoader);
#endif
cout << "Non supported format: " << path << endl;
return nullptr;
}

View file

@ -26,7 +26,7 @@ struct LoaderMgr
{
static bool init();
static bool term();
static unique_ptr<Loader> loader(const char* path);
static unique_ptr<Loader> loader();
};
#endif //_TVG_LOADER_MGR_H_

View file

@ -53,6 +53,14 @@ Result Picture::load(const std::string& path) noexcept
}
Result Picture::load(const char* data, uint32_t size) noexcept
{
if (!data || size <= 0) return Result::InvalidArguments;
return IMPL->load(data, size);
}
Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept
{
if (IMPL->viewbox(x, y, w, h)) return Result::Success;

View file

@ -84,8 +84,23 @@ struct Picture::Impl
Result load(const string& path)
{
if (loader) loader->close();
loader = LoaderMgr::loader(path.c_str());
if (!loader || !loader->open(path.c_str())) return Result::NonSupport;
loader = LoaderMgr::loader();
if (!loader || !loader->open(path.c_str())) {
cout << "Non supported format: " << path.c_str() << endl;
return Result::NonSupport;
}
if (!loader->read()) return Result::Unknown;
return Result::Success;
}
Result load(const char* data, uint32_t size)
{
if (loader) loader->close();
loader = LoaderMgr::loader();
if (!loader || !loader->open(data, size)) {
cout << "Non supported load data" << endl;
return Result::NonSupport;
}
if (!loader->read()) return Result::Unknown;
return Result::Success;
}

View file

@ -35,6 +35,7 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const
typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength);
static void _freeNode(SvgNode* node);
static char* _skipSpace(const char* str, const char* end)
{
while (((end != nullptr && str < end) || (end == nullptr && *str != '\0')) && isspace(*str))
@ -2280,6 +2281,40 @@ SvgLoader::~SvgLoader()
}
bool SvgLoader::header()
{
//For valid check, only <svg> tag is parsed first.
//If the <svg> tag is found, the loaded file is valid and stores viewbox information.
//After that, the remaining content data is parsed in order with async.
loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
if (!loaderData.svgParse) return false;
simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData));
if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) {
//Return the brief resource info such as viewbox:
this->vx = loaderData.doc->node.doc.vx;
this->vy = loaderData.doc->node.doc.vy;
this->vw = loaderData.doc->node.doc.vw;
this->vh = loaderData.doc->node.doc.vh;
} else {
cout << "ERROR : No SVG File. There is no <svg/>" <<endl;
return false;
}
return true;
}
bool SvgLoader::open(const char* data, uint32_t size)
{
this->content = data;
this->size = size;
return header();
}
bool SvgLoader::open(const char* path)
{
ifstream f;
@ -2290,39 +2325,22 @@ bool SvgLoader::open(const char* path)
cout << "ERROR: Failed to open file = " << path;
return false;
} else {
getline(f, content, '\0');
getline(f, filePath, '\0');
f.close();
if (content.empty()) return false;
if (filePath.empty()) return false;
this->content = filePath.c_str();
this->size = filePath.size();
}
//For valid check, only <svg> tag is parsed first.
//If the <svg> tag is found, the loaded file is valid and stores viewbox information.
//After that, the remaining content data is parsed in order with async.
loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
if (!loaderData.svgParse) return false;
simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParserForValidCheck, &(loaderData));
if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) {
//Return the brief resource info such as viewbox:
this->vx = loaderData.doc->node.doc.vx;
this->vy = loaderData.doc->node.doc.vy;
this->vw = loaderData.doc->node.doc.vw;
this->vh = loaderData.doc->node.doc.vh;
} else {
cout << "ERROR : No SVG File. There is no <svg/>" <<endl;
return false;
}
return true;
return header();
}
bool SvgLoader::read()
{
if (content.empty()) return false;
if (!content || size == 0) return false;
loaderData = {vector<SvgNode*>(),
nullptr,
@ -2335,7 +2353,7 @@ bool SvgLoader::read()
loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
if (!simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData)) return false;
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &loaderData)) return false;
if (loaderData.doc) {
_updateStyle(loaderData.doc, nullptr);

View file

@ -29,7 +29,10 @@
class SvgLoader : public Loader
{
private:
string content;
string filePath;
const char* content = nullptr;
uint32_t size = 0;
SvgLoaderData loaderData;
SvgSceneBuilder builder;
unique_ptr<Scene> root;
@ -39,6 +42,8 @@ public:
~SvgLoader();
bool open(const char* path) override;
bool open(const char* data, uint32_t size) override;
bool header();
bool read() override;
bool close() override;
unique_ptr<Scene> data() override;

View file

@ -17,6 +17,7 @@ all:
gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testArc testArc.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg`

148
test/testSvg2.cpp Normal file
View file

@ -0,0 +1,148 @@
#include "testCommon.h"
/************************************************************************/
/* Drawing Commands */
/************************************************************************/
static const char* svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" stroke-linejoin=\"round\" viewBox=\"50 -100 500 500\"><path fill=\"none\" stroke=\"black\" stroke-width=\"10\" d=\"M 212,220 C 197,171 156,153 123,221 109,157 120,109 159,63.6 190,114 234,115 254,89.8 260,82.3 268,69.6 270,60.3 273,66.5 275,71.6 280,75.6 286,79.5 294,79.8 300,79.8 306,79.8 314,79.5 320,75.6 325,71.6 327,66.5 330,60.3 332,69.6 340,82.3 346,89.8 366,115 410,114 441,63.6 480,109 491,157 477,221 444,153 403,171 388,220 366,188 316,200 300,248 284,200 234,188 212,220 Z\"/></svg>";
void tvgDrawCmds(tvg::Canvas* canvas)
{
if (!canvas) return;
//Background
auto shape = tvg::Shape::gen();
shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry
shape->fill(255, 255, 255, 255); //r, g, b, a
if (canvas->push(move(shape)) != tvg::Result::Success) return;
auto picture = tvg::Picture::gen();
if (picture->load(svg, strlen(svg)) != tvg::Result::Success) return;
float x, y, w, h;
picture->viewbox(&x, &y, &w, &h);
float rate = (WIDTH/(w > h ? w : h));
picture->scale(rate);
x *= rate;
y *= rate;
w *= rate;
h *= rate;
//Center Align ?
if (w > h) {
y -= (WIDTH - h) * 0.5f;
} else {
x -= (WIDTH - w) * 0.5f;
}
picture->translate(-x, -y);
canvas->push(move(picture));
}
/************************************************************************/
/* Sw Engine Test Code */
/************************************************************************/
static unique_ptr<tvg::SwCanvas> swCanvas;
void tvgSwTest(uint32_t* buffer)
{
//Create a Canvas
swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT);
/* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare
internal data asynchronously for coming rendering.
Canvas keeps this shape node unless user call canvas->clear() */
tvgDrawCmds(swCanvas.get());
}
void drawSwView(void* data, Eo* obj)
{
if (swCanvas->draw() == tvg::Result::Success) {
swCanvas->sync();
}
}
/************************************************************************/
/* GL Engine Test Code */
/************************************************************************/
static unique_ptr<tvg::GlCanvas> glCanvas;
void initGLview(Evas_Object *obj)
{
static constexpr auto BPP = 4;
//Create a Canvas
glCanvas = tvg::GlCanvas::gen();
glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
/* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare
internal data asynchronously for coming rendering.
Canvas keeps this shape node unless user call canvas->clear() */
tvgDrawCmds(glCanvas.get());
}
void drawGLview(Evas_Object *obj)
{
auto gl = elm_glview_gl_api_get(obj);
gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl->glClear(GL_COLOR_BUFFER_BIT);
if (glCanvas->draw() == tvg::Result::Success) {
glCanvas->sync();
}
}
/************************************************************************/
/* Main Code */
/************************************************************************/
int main(int argc, char **argv)
{
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
if (argc > 1) {
if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl;
}
//Initialize ThorVG Engine
if (tvgEngine == tvg::CanvasEngine::Sw) {
cout << "tvg engine: software" << endl;
} else {
cout << "tvg engine: opengl" << endl;
}
//Initialize ThorVG Engine
if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) {
elm_init(argc, argv);
if (tvgEngine == tvg::CanvasEngine::Sw) {
createSwView();
} else {
createGlView();
}
elm_run();
elm_shutdown();
//Terminate ThorVG Engine
tvg::Initializer::term(tvg::CanvasEngine::Sw);
} else {
cout << "engine is not supported" << endl;
}
return 0;
}