SvgLoader: Implement SvgSceneBuilder using SvgNode 47/237047/13
authorJunsuChoi <jsuya.choi@samsung.com>
Wed, 24 Jun 2020 10:35:40 +0000 (19:35 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Mon, 29 Jun 2020 07:16:08 +0000 (16:16 +0900)
SvgSceneBuilder builds Scene using SvgNode tree.
build(root node) function return the root scene.
Following SVG tags are supported.
Polygon, Polyline, Circle, Rect, Line

Change-Id: I8c9b8c28d9a4799af6ddc45c35f77a75f696b2a5

src/loaders/svg_loader/meson.build
src/loaders/svg_loader/tvgSvgLoader.cpp
src/loaders/svg_loader/tvgSvgLoader.h
src/loaders/svg_loader/tvgSvgSceneBuilder.cpp [new file with mode: 0644]
src/loaders/svg_loader/tvgSvgSceneBuilder.h [new file with mode: 0644]

index 88fd37a..21967af 100644 (file)
@@ -2,8 +2,10 @@ source_file = [
    'tvgSimpleXmlParser.h',
    'tvgSvgLoader.h',
    'tvgSvgLoaderCommon.h',
+   'tvgSvgSceneBuilder.h',
    'tvgSimpleXmlParser.cpp',
    'tvgSvgLoader.cpp',
+   'tvgSvgSceneBuilder.cpp',
 ]
 
 svgloader_dep = declare_dependency(
index 4db8200..4dd5fd4 100644 (file)
@@ -2289,6 +2289,8 @@ bool SvgLoader::read()
         }
     }
 
+    root = builder.build(loaderData.doc);
+
     if (!res) return false;
     return true;
 }
@@ -2304,7 +2306,7 @@ bool SvgLoader::close()
 
 unique_ptr<Scene> SvgLoader::data()
 {
-    return nullptr;
+    return move(root);
 }
 
 #endif //_TVG_SVG_LOADER_CPP_
index 13441f3..eba74c3 100644 (file)
 #define _TVG_SVG_LOADER_H_
 
 #include "tvgSvgLoaderCommon.h"
+#include "tvgSvgSceneBuilder.h"
+
 
 class SvgLoader : public Loader
 {
 private:
     string content;
     SvgLoaderData loaderData;
+    SvgSceneBuilder builder;
+    unique_ptr<Scene> root;
 
 public:
     SvgLoader();
diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp
new file mode 100644 (file)
index 0000000..601ed0c
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *               http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+#ifndef _TVG_SVG_SCENE_BUILDER_CPP_
+#define _TVG_SVG_SCENE_BUILDER_CPP_
+
+
+#include "tvgSvgSceneBuilder.h"
+
+
+unique_ptr<tvg::Shape> _applyProperty(SvgNode* node, unique_ptr<tvg::Shape> vg)
+{
+    SvgStyleProperty* style = node->style;
+
+    //Apply the transformation
+    if (node->transform) vg->transform(*node->transform);
+
+    if (node->type == SvgNodeType::Doc) return vg;
+
+    //If fill property is nullptr then do nothing
+    if (style->fill.paint.none) {
+        //Do nothing
+    } else if (style->fill.paint.gradient) {
+        //TODO: Support gradient style
+    } else if (style->fill.paint.curColor) {
+        //Apply the current style color
+        float fa = ((float)style->fill.opacity / 255.0);
+        vg->fill(((float)style->r) * fa, ((float)style->g) * fa, ((float)style->b) * fa, style->fill.opacity);
+    } else {
+        //Apply the fill color
+        float fa = ((float)style->fill.opacity / 255.0);
+        vg->fill(((float)style->fill.paint.r) * fa, ((float)style->fill.paint.g) * fa, ((float)style->fill.paint.b) * fa, style->fill.opacity);
+    }
+
+    //Apply node opacity
+    if (style->opacity < 255) {
+        uint8_t r, g, b, a;
+        vg->fill(&r, &g, &b, &a);
+        float fa = ((float)style->opacity / 255.0);
+        vg->fill(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa);
+    }
+
+    if (node->type == SvgNodeType::G) return vg;
+
+    //Apply the stroke style property
+    vg->stroke(style->stroke.width);
+    vg->stroke(style->stroke.cap);
+    vg->stroke(style->stroke.join);
+
+
+    //If stroke property is nullptr then do nothing
+    if (style->stroke.paint.none) {
+        //Do nothing
+    } else if (style->stroke.paint.gradient) {
+        //TODO: Support gradient style
+    } else if (style->stroke.paint.url) {
+        //TODO: Apply the color pointed by url
+    } else if (style->stroke.paint.curColor) {
+        //Apply the current style color
+        vg->stroke(style->r, style->g, style->b, style->stroke.opacity);
+
+    } else {
+        //Apply the stroke color
+        vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity);
+    }
+
+    //Apply node opacity to stroke color
+    if (style->opacity < 255) {
+        uint8_t r, g, b, a;
+        vg->strokeColor(&r, &g, &b, &a);
+        float fa = ((float)style->opacity / 255.0);
+        vg->stroke(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa);
+    }
+    return vg;
+}
+
+
+unique_ptr<tvg::Shape> _shapeBuildHelper(SvgNode* node)
+{
+    auto shape = tvg::Shape::gen();
+    switch (node->type) {
+        case SvgNodeType::Path: {
+            //TODO: Support path
+            break;
+        }
+        case SvgNodeType::Ellipse: {
+            //TODO: Support ellipse
+            break;
+        }
+        case SvgNodeType::Polygon: {
+            if (node->node.polygon.pointsCount < 2) break;
+            shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]);
+            for (int i = 2; i < node->node.polygon.pointsCount; i += 2) {
+                shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]);
+            }
+            shape->close();
+            break;
+        }
+        case SvgNodeType::Polyline: {
+            if (node->node.polygon.pointsCount < 2) break;
+            shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]);
+            for (int i = 2; i < node->node.polygon.pointsCount; i += 2) {
+                shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]);
+            }
+            break;
+        }
+        case SvgNodeType::Circle: {
+            shape->appendCircle(node->node.circle.cx, node->node.circle.cy, node->node.circle.r, node->node.circle.r);
+            break;
+        }
+        case SvgNodeType::Rect: {
+            if (node->node.rect.rx == node->node.rect.ry) {
+                 shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx);
+            }
+            else {
+                //TODO: Support rounded rectangle
+            }
+            break;
+        }
+        case SvgNodeType::Line: {
+            shape->moveTo(node->node.line.x1, node->node.line.y1);
+            shape->lineTo(node->node.line.x2, node->node.line.y2);
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+    shape = move(_applyProperty(node, move(shape)));
+    return shape;
+}
+
+
+unique_ptr<tvg::Scene> _sceneBuildHelper(SvgNode* node)
+{
+    if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) {
+        auto scene = tvg::Scene::gen();
+        if (node->transform) scene->transform(*node->transform);
+
+        for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) {
+            SvgNode* child = *itrChild;
+            if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild));
+            else scene->push(_shapeBuildHelper(*itrChild));
+        }
+        return move(scene);
+    }
+    return nullptr;
+}
+
+
+SvgSceneBuilder::SvgSceneBuilder()
+{
+}
+
+
+SvgSceneBuilder::~SvgSceneBuilder()
+{
+}
+
+
+unique_ptr<Scene> SvgSceneBuilder::build(SvgNode* node)
+{
+    if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
+
+    viewBox.x = node->node.doc.vx;
+    viewBox.y = node->node.doc.vy;
+    viewBox.w = node->node.doc.vw;
+    viewBox.h = node->node.doc.vh;
+    preserveAspect = node->node.doc.preserveAspect;
+    staticViewBox = true;
+    return _sceneBuildHelper(node);
+}
+
+
+#endif //_TVG_SVG_SCENE_BUILDER_CPP_
diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg_loader/tvgSvgSceneBuilder.h
new file mode 100644 (file)
index 0000000..20a41a7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *               http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+#ifndef _TVG_SVG_SCENE_BUILDER_H_
+#define _TVG_SVG_SCENE_BUILDER_H_
+
+#include "tvgSvgLoaderCommon.h"
+
+class SvgSceneBuilder
+{
+private:
+    struct {
+        int x, y;
+        uint32_t w, h;
+    } viewBox;
+    int      ref;
+    uint32_t w, h;                 //Default size
+    bool     staticViewBox;
+    bool     preserveAspect;       //Used in SVG
+    bool     shareable;
+
+public:
+    SvgSceneBuilder();
+    ~SvgSceneBuilder();
+
+    unique_ptr<Scene> build(SvgNode* node);
+};
+
+#endif //_TVG_SVG_SCENE_BUILDER_H_