From: JunsuChoi Date: Thu, 24 Sep 2020 02:52:26 +0000 (+0900) Subject: SvgLoader: Implement ClipPath style X-Git-Tag: submit/tizen/20201018.221456~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=64a3623c9d11dc694925737cd053ce5380e93129;p=platform%2Fcore%2Fgraphics%2Ftizenvg.git SvgLoader: Implement ClipPath style Supports case of using style attribute for defined . In SVG, can be used as a "clipPath" attribute or a style "clip-path". This patch only supports "clip-path" of style is declared. The remaining features will be added later. [Example SVG case] Change-Id: Ie9b1000a52070ca86f67ce794413c3640784a079 --- diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 3495fca..0624a1b 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -850,6 +850,14 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node 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) { @@ -889,6 +897,7 @@ static constexpr struct STYLE_DEF(stroke-opacity, StrokeOpacity), STYLE_DEF(stroke-dasharray, StrokeDashArray), STYLE_DEF(transform, Transform), + STYLE_DEF(clip-path, ClipPath), STYLE_DEF(display, Display) }; @@ -938,6 +947,26 @@ static bool _attrParseGNode(void* data, const char* key, const char* value) } +/* 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)); @@ -1019,10 +1048,12 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, const ch 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; } @@ -1397,6 +1428,20 @@ static SvgNode* _findChildById(SvgNode* node, const char* id) 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* dst, SvgVector* src) { @@ -2200,6 +2245,20 @@ static void _updateGradient(SvgNode* node, SvgVector* gradide } } +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; @@ -2362,6 +2421,9 @@ void SvgLoader::run() 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); }; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 3cbe22d..b91bd08 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -45,6 +45,7 @@ enum class SvgNodeType Tspan, Use, Video, + ClipPath, //Custome_command, //Not support Unknown }; @@ -60,12 +61,18 @@ enum class SvgLengthType In, }; +enum class SvgCompositeFlags +{ + ClipPath = 0x01, +}; + enum class SvgFillFlags { - Paint = 0x1, - Opacity = 0x2, - Gradient = 0x4, - FillRule = 0x8 + Paint = 0x01, + Opacity = 0x02, + Gradient = 0x04, + FillRule = 0x08, + ClipPath = 0x16 }; enum class SvgStrokeFlags @@ -244,6 +251,13 @@ struct SvgGradientStop uint8_t a; }; +struct SvgComposite +{ + SvgCompositeFlags flags; + string *url; + SvgNode* node; +}; + struct SvgPaint { SvgStyleGradient* gradient; @@ -300,6 +314,7 @@ struct SvgStyleProperty { SvgStyleFill fill; SvgStyleStroke stroke; + SvgComposite comp; int opacity; uint8_t r; uint8_t g; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index f3922cb..6c20164 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -23,6 +23,14 @@ #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 _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop* stops; @@ -185,6 +193,14 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha 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) { @@ -252,12 +268,31 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa 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 _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) { @@ -304,26 +339,40 @@ unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, break; } } - _applyProperty(node, shape.get(), vx, vy, vw, vh); - return shape; -} + _applyProperty(node, shape, vx, vy, vw, vh); +} unique_ptr _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;