SvgLoader: Mask style implementation

Supprot case when style is defined as <mask> attribute.

[Example SVG file]
```html
<svg version="1.1" id="Layer_1" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve"
  xmlns="http://www.w3.org/2000/svg">
  <defs>
    <mask id="myMask">
      <circle id="maskID" cx="40" cy="40" r="10" fill="white" fill-opacity="1" />
    </mask>
  </defs>
  <rect x="0" y="0" width="64" height="64" style="fill: skyblue; mask=url(#myMask);"/>
</svg>
```

Change-Id: I3b856db85204bf7c503a20e4023417ca79aa930c
This commit is contained in:
Patryk Kaczmarek 2021-02-09 21:03:10 +01:00 committed by JunsuChoi
parent 70e1e7f1c6
commit 795121fa67
3 changed files with 57 additions and 4 deletions

View file

@ -864,6 +864,15 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3));
}
static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
SvgStyleProperty* style = node->style;
style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::AlphaMask);
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)
{
//TODO : The display attribute can have various values as well as "none".
@ -903,6 +912,7 @@ static constexpr struct
STYLE_DEF(stroke-dasharray, StrokeDashArray),
STYLE_DEF(transform, Transform),
STYLE_DEF(clip-path, ClipPath),
STYLE_DEF(mask, Mask),
STYLE_DEF(display, Display)
};
@ -946,6 +956,8 @@ static bool _attrParseGNode(void* data, const char* key, const char* value)
node->id = _copyId(value);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value);
}
@ -973,6 +985,25 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu
return true;
}
static bool _attrParseMaskNode(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));
@ -1057,10 +1088,7 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUS
loader->svgParse->node = _createNode(parent, SvgNodeType::Unknown);
if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false;
#ifdef THORVG_LOG_ENABLED
printf("SVG: Unsupported elements used [Elements: mask]\n");
#endif
simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader);
return loader->svgParse->node;
}
@ -1092,6 +1120,8 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else if (!strcmp(key, "id")) {
node->id = _copyId(value);
} else {
@ -1149,6 +1179,8 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value)
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else if (!strcmp(key, "id")) {
node->id = _copyId(value);
} else {
@ -1208,6 +1240,8 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value);
}
@ -1281,6 +1315,8 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else if (!strcmp(key, "id")) {
node->id = _copyId(value);
} else {
@ -1360,6 +1396,8 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value)
ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else {
ret = _parseStyleAttr(loader, key, value);
}
@ -1420,6 +1458,8 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value)
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value);
}
@ -1634,6 +1674,8 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
delete id;
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else {
return _attrParseGNode(data, key, value);
}

View file

@ -65,6 +65,7 @@ enum class SvgLengthType
enum class SvgCompositeFlags
{
ClipPath = 0x01,
AlphaMask = 0x02,
};
enum class SvgFillFlags

View file

@ -273,6 +273,16 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa
vg->composite(move(comp), CompositeMethod::ClipPath);
}
}
//Composite Alpha Mask
if (((int)style->comp.flags & (int)SvgCompositeFlags::AlphaMask)) {
auto compNode = style->comp.node;
if (compNode->child.count > 0) {
auto comp = Shape::gen();
auto child = compNode->child.data;
for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh);
vg->composite(move(comp), CompositeMethod::AlphaMask);
}
}
}
}