diff --git a/.gitignore b/.gitignore index 7f4d09bf..53a53b5b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ testLinearGradient testRadialGradient testGradientTransform testSvg +testSvg2 testAsync testCapi testArc diff --git a/inc/thorvg.h b/inc/thorvg.h index 452234d8..3f43a2fc 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -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 gen() noexcept; diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index c714f92c..9c7279eb 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -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 data() = 0; diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index a35dcd5d..5e59a447 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -50,12 +50,11 @@ bool LoaderMgr::term() return true; } -unique_ptr LoaderMgr::loader(const char* path) +unique_ptr LoaderMgr::loader() { #ifdef THORVG_SVG_LOADER_SUPPORT return unique_ptr(new SvgLoader); #endif - cout << "Non supported format: " << path << endl; return nullptr; } diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h index 7c9d52e1..95a06767 100644 --- a/src/lib/tvgLoaderMgr.h +++ b/src/lib/tvgLoaderMgr.h @@ -26,7 +26,7 @@ struct LoaderMgr { static bool init(); static bool term(); - static unique_ptr loader(const char* path); + static unique_ptr loader(); }; #endif //_TVG_LOADER_MGR_H_ \ No newline at end of file diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 7595afab..70836924 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -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; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 45e2e9d8..5ab9618f 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -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; } diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 442d3b78..1579390c 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -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 tag is parsed first. + //If the 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 " <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 tag is parsed first. - //If the 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 " <(), 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); diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 3ef981df..e85582bf 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -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 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 data() override; diff --git a/test/makefile b/test/makefile index 29e6e779..f48278d4 100644 --- a/test/makefile +++ b/test/makefile @@ -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` diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp new file mode 100644 index 00000000..171db919 --- /dev/null +++ b/test/testSvg2.cpp @@ -0,0 +1,148 @@ +#include "testCommon.h" + +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ + +static const char* 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 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 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; +}