node->transform = _parseTransformationMatrix(value);
}
+static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
+{
+ SvgStyleProperty* style = node->style;
+ style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::ClipPath);
+
+ int len = strlen(value);
+ if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3));
+}
static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
STYLE_DEF(stroke-opacity, StrokeOpacity),
STYLE_DEF(stroke-dasharray, StrokeDashArray),
STYLE_DEF(transform, Transform),
+ STYLE_DEF(clip-path, ClipPath),
STYLE_DEF(display, Display)
};
}
+/* parse clipPath node
+ * https://www.w3.org/TR/SVG/struct.html#Groups
+ */
+static bool _attrParseClipPathNode(void* data, const char* key, const char* value)
+{
+ SvgLoaderData* loader = (SvgLoaderData*)data;
+ SvgNode* node = loader->svgParse->node;
+
+ if (!strcmp(key, "style")) {
+ return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
+ } else if (!strcmp(key, "transform")) {
+ node->transform = _parseTransformationMatrix(value);
+ } else if (!strcmp(key, "id")) {
+ node->id = _copyId(value);
+ } else {
+ return _parseStyleAttr(loader, key, value);
+ }
+ return true;
+}
+
static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
{
SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode));
static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
{
- loader->svgParse->node = _createNode(parent, SvgNodeType::Unknown);
+ loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath);
loader->svgParse->node->display = false;
+ simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader);
+
return loader->svgParse->node;
}
return nullptr;
}
+static SvgNode* _findNodeById(SvgNode *node, string* id)
+{
+ SvgNode* result = nullptr;
+ if ((node->id != nullptr) && !node->id->compare(*id)) return node;
+
+ if (node->child.cnt > 0) {
+ auto child = node->child.list;
+ for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
+ result = _findNodeById(*child, id);
+ if (result) break;
+ }
+ }
+ return result;
+}
static void _cloneGradStops(SvgVector<Fill::ColorStop*>* dst, SvgVector<Fill::ColorStop*>* src)
{
}
}
+static void _updateComposite(SvgNode* node, SvgNode* root)
+{
+ if (node->style->comp.url && !node->style->comp.node) {
+ SvgNode *findResult = _findNodeById(root, node->style->comp.url);
+ if (findResult) node->style->comp.node = findResult;
+ }
+ if (node->child.cnt > 0) {
+ auto child = node->child.list;
+ for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
+ _updateComposite(*child, root);
+ }
+ }
+}
+
static void _freeGradientStyle(SvgStyleGradient* grad)
{
if (!grad) return;
if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients);
if (loaderData.gradients.cnt > 0) _updateGradient(loaderData.doc, &loaderData.gradients);
+
+ _updateComposite(loaderData.doc, loaderData.doc);
+ if (defs) _updateComposite(loaderData.doc, defs);
}
root = builder.build(loaderData.doc);
};
#include "tvgSvgSceneBuilder.h"
#include "tvgSvgPath.h"
+void _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh);
+
+bool _isGroupType(SvgNodeType type)
+{
+ if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::ClipPath) return true;
+ return false;
+}
+
unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh)
{
Fill::ColorStop* stops;
return fillGrad;
}
+void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh)
+{
+ _appendShape(node, shape, vx, vy, vw, vh);
+ if (node->child.cnt > 0) {
+ auto child = node->child.list;
+ for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) _appendChildShape(*child, shape, vx, vy, vw, vh);
+ }
+}
void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh)
{
vg->strokeColor(&r, &g, &b, &a);
vg->stroke(r, g, b, (a * style->opacity) / 255.0f);
}
-}
+ //Apply composite node
+ if (style->comp.node) {
+ //Composite ClipPath
+ if (((int)style->comp.flags & (int)SvgCompositeFlags::ClipPath)) {
+ auto compNode = style->comp.node;
+ if (compNode->child.cnt > 0) {
+ auto comp = Shape::gen();
+ auto child = compNode->child.list;
+ for (uint32_t i = 0; i < compNode->child.cnt; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh);
+ vg->composite(move(comp), CompositeMethod::ClipPath);
+ }
+ }
+ }
+}
unique_ptr<Shape> _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh)
{
auto shape = Shape::gen();
+ _appendShape(node, shape.get(), vx, vy, vw, vh);
+ return shape;
+}
+
+void _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh)
+{
switch (node->type) {
case SvgNodeType::Path: {
if (node->node.path.path) {
break;
}
}
- _applyProperty(node, shape.get(), vx, vy, vw, vh);
- return shape;
-}
+ _applyProperty(node, shape, vx, vy, vw, vh);
+}
unique_ptr<Scene> _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh, int parentOpacity)
{
- if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) {
+ if (_isGroupType(node->type)) {
auto scene = Scene::gen();
if (node->transform) scene->transform(*node->transform);
node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f;
+
if (node->display) {
auto child = node->child.list;
for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
- if ((*child)->type == SvgNodeType::Doc || (*child)->type == SvgNodeType::G) {
+ if (_isGroupType((*child)->type)) {
scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, node->style->opacity));
} else {
(*child)->style->opacity = ((*child)->style->opacity * node->style->opacity) / 255.0f;
scene->push(_shapeBuildHelper(*child, vx, vy, vw, vh));
}
+
+ //Apply composite node
+ if (node->style->comp.node) {
+ //Composite ClipPath
+ if (((int)node->style->comp.flags & (int)SvgCompositeFlags::ClipPath)) {
+ auto compNode = node->style->comp.node;
+ if (compNode->child.cnt > 0) {
+ auto comp = Shape::gen();
+ auto child = compNode->child.list;
+ for (uint32_t i = 0; i < compNode->child.cnt; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh);
+ scene->composite(move(comp), CompositeMethod::ClipPath);
+ }
+ }
+ }
}
}
return scene;