mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-10 14:41:50 +00:00
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:
parent
70e1e7f1c6
commit
795121fa67
3 changed files with 57 additions and 4 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ enum class SvgLengthType
|
|||
enum class SvgCompositeFlags
|
||||
{
|
||||
ClipPath = 0x01,
|
||||
AlphaMask = 0x02,
|
||||
};
|
||||
|
||||
enum class SvgFillFlags
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue