picture svg: introduce load() with memory data input source. 86/241086/2 accepted/tizen/unified/20200820.034622 submit/tizen/20200817.223215
authorHermet Park <chuneon.park@samsung.com>
Fri, 14 Aug 2020 10:35:39 +0000 (19:35 +0900)
committerHermet Park <chuneon.park@samsung.com>
Fri, 14 Aug 2020 10:41:04 +0000 (19:41 +0900)
picture now affords the memory data as input source so that
user can pass svg data memory directly.

Change-Id: I246c09b682a2d60e53ad556ce0c90337142ee4f1

.gitignore
inc/thorvg.h
src/lib/tvgLoader.h
src/lib/tvgLoaderMgr.cpp
src/lib/tvgLoaderMgr.h
src/lib/tvgPicture.cpp
src/lib/tvgPictureImpl.h
src/loaders/svg/tvgSvgLoader.cpp
src/loaders/svg/tvgSvgLoader.h
test/makefile
test/testSvg2.cpp [new file with mode: 0644]

index 7f4d09bf777063f425123f99cecfc1bc00135fb4..53a53b5b7d9c2c212172bee4a1ae08975d71f858 100644 (file)
@@ -19,6 +19,7 @@ testLinearGradient
 testRadialGradient
 testGradientTransform
 testSvg
+testSvg2
 testAsync
 testCapi
 testArc
index 452234d86673a8523ceb448897f21bc7d817a5c7..3f43a2fc751f4f21a89d8d5c59ec65d3a374daf6 100644 (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;
index c714f92c625292a2fd050d41c50c7964cee930eb..9c7279ebd9f0cadb30c04909adfbde84b5f898e0 100644 (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;
index a35dcd5d9ed9cc25c4c7e004e0e155f4273f7dd5..5e59a44755926e62a647b7639002d69d428c76eb 100644 (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;
 }
 
index 7c9d52e1d50859a34727f88b5d90517ad083ba82..95a06767701d6f182d0c4a72267bf6fbf86fb865 100644 (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_
\ No newline at end of file
index 7595afabb6d46e6ea1abaf0bbcd6cdc509e90fd2..708369248edd964f7df402b825cb420ff3d17f31 100644 (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;
index 45e2e9d859d865f69f726fc50f2a8b6d08f3ed49..5ab9618f2befa736837186db48d5e8238503ba50 100644 (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;
     }
index 442d3b7845506abface278eb39892ba0f1b7b40b..1579390cbd81bee7f6c339f5ead3561ca027600d 100644 (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,29 +2281,15 @@ SvgLoader::~SvgLoader()
 }
 
 
-bool SvgLoader::open(const char* path)
+bool SvgLoader::header()
 {
-    ifstream f;
-    f.open(path);
-
-    if (!f.is_open())
-    {
-        cout << "ERROR: Failed to open file = " << path;
-        return false;
-    } else {
-        getline(f, content, '\0');
-        f.close();
-
-        if (content.empty()) return false;
-    }
-
     //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));
+    simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData));
 
     if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) {
         //Return the brief resource info such as viewbox:
@@ -2310,7 +2297,6 @@ bool SvgLoader::open(const char* path)
         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;
@@ -2320,9 +2306,41 @@ bool SvgLoader::open(const char* path)
 }
 
 
+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;
+    f.open(path);
+
+    if (!f.is_open())
+    {
+        cout << "ERROR: Failed to open file = " << path;
+        return false;
+    } else {
+        getline(f, filePath, '\0');
+        f.close();
+
+        if (filePath.empty()) return false;
+
+        this->content = filePath.c_str();
+        this->size = filePath.size();
+    }
+
+    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);
index 3ef981df360cfb1ed49d8953554e2c63437acb9b..e85582bf7f37fdbf26dffa03df2c746ca1e5ff5b 100644 (file)
 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;
index 29e6e779dc71d60821315bc92f46878f160a3ec1..f48278d4978c0b644112b8ab3cf21afb9eba8ba1 100644 (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`
diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp
new file mode 100644 (file)
index 0000000..171db91
--- /dev/null
@@ -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;
+}