svg_loader: allow both clipPath and mask together (#622)

* svg_loader: allow both clipPath and mask together

* svg_loader: allow both clipPath and mask together fix #1

Changed seperate functions _applyClipPathComposition and _applyMaskComposition into single function _applyComposition
This commit is contained in:
Michal Maciola 2021-07-21 05:12:09 +02:00 committed by GitHub
parent 02b3d7dd20
commit c2ec997db5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 42 deletions

View file

@ -873,15 +873,10 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node
static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
SvgStyleProperty* style = node->style;
#ifdef THORVG_LOG_ENABLED
if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n");
#endif
style->comp.method = CompositeMethod::ClipPath;
int len = strlen(value);
if (len >= 3 && !strncmp(value, "url", 3)) {
//FIXME: Support multiple composition.
if (style->comp.url) delete(style->comp.url);
style->comp.url = _idFromUrl((const char*)(value + 3));
if (style->clipPath.url) delete(style->clipPath.url);
style->clipPath.url = _idFromUrl((const char*)(value + 3));
}
}
@ -889,15 +884,10 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
SvgStyleProperty* style = node->style;
#ifdef THORVG_LOG_ENABLED
if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n");
#endif
style->comp.method = CompositeMethod::AlphaMask;
int len = strlen(value);
if (len >= 3 && !strncmp(value, "url", 3)) {
//FIXME: Support multiple composition.
if (style->comp.url) delete(style->comp.url);
style->comp.url = _idFromUrl((const char*)(value + 3));
if (style->mask.url) delete(style->mask.url);
style->mask.url = _idFromUrl((const char*)(value + 3));
}
}
@ -1707,7 +1697,8 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
*to->style = *from->style;
if (from->style->fill.paint.url) to->style->fill.paint.url = new string(from->style->fill.paint.url->c_str());
if (from->style->stroke.paint.url) to->style->stroke.paint.url = new string(from->style->stroke.paint.url->c_str());
if (from->style->comp.url) to->style->comp.url = new string(from->style->comp.url->c_str());
if (from->style->clipPath.url) to->style->clipPath.url = new string(from->style->clipPath.url->c_str());
if (from->style->mask.url) to->style->mask.url = new string(from->style->mask.url->c_str());
//Copy node attribute
switch (from->type) {
@ -2598,9 +2589,13 @@ static void _updateGradient(SvgNode* node, Array<SvgStyleGradient*>* gradients)
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->style->clipPath.url && !node->style->clipPath.node) {
SvgNode *findResult = _findNodeById(root, node->style->clipPath.url);
if (findResult) node->style->clipPath.node = findResult;
}
if (node->style->mask.url && !node->style->mask.node) {
SvgNode *findResult = _findNodeById(root, node->style->mask.url);
if (findResult) node->style->mask.node = findResult;
}
if (node->child.count > 0) {
auto child = node->child.data;
@ -2615,8 +2610,9 @@ static void _freeNodeStyle(SvgStyleProperty* style)
{
if (!style) return;
//style->comp.node has only the addresses of node. Therefore, style->comp.node is released from _freeNode.
delete(style->comp.url);
//style->clipPath.node and style->mask.node has only the addresses of node. Therefore, node is released from _freeNode.
delete(style->clipPath.url);
delete(style->mask.url);
if (style->fill.paint.gradient) delete(style->fill.paint.gradient);
if (style->stroke.paint.gradient) delete(style->stroke.paint.gradient);

View file

@ -225,10 +225,9 @@ struct SvgRadialGradient
struct SvgComposite
{
CompositeMethod method; //TODO: Currently support either one method
string *url;
SvgNode* node;
bool applying; //flag for checking circualr dependency.
bool applying; //flag for checking circular dependency.
};
struct SvgColor
@ -302,7 +301,8 @@ struct SvgStyleProperty
{
SvgStyleFill fill;
SvgStyleStroke stroke;
SvgComposite comp;
SvgComposite clipPath;
SvgComposite mask;
int opacity;
SvgColor color;
bool curColorSet;

View file

@ -178,36 +178,63 @@ static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, f
static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float vy, float vw, float vh)
{
if (node->style->comp.method == CompositeMethod::None) return;
/* Do not drop in Circular Dependency.
/* ClipPath */
/* Do not drop in Circular Dependency for ClipPath.
Composition can be applied recursively if its children nodes have composition target to this one. */
if (node->style->comp.applying) {
if (node->style->clipPath.applying) {
#ifdef THORVG_LOG_ENABLED
printf("SVG: Multiple Composition Tried! Check out Circular dependency?\n");
#endif
return;
} else {
auto compNode = node->style->clipPath.node;
if (compNode && compNode->child.count > 0) {
node->style->clipPath.applying = true;
auto comp = Shape::gen();
comp->fill(255, 255, 255, 255);
if (node->transform) comp->transform(*node->transform);
auto child = compNode->child.data;
auto valid = false; //Composite only when valid shapes are existed
for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) {
if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true;
}
if (valid) paint->composite(move(comp), CompositeMethod::ClipPath);
node->style->clipPath.applying = false;
}
}
auto compNode = node->style->comp.node;
if (!compNode || compNode->child.count == 0) return;
/* Mask */
/* Do not drop in Circular Dependency for Mask.
Composition can be applied recursively if its children nodes have composition target to this one. */
if (node->style->mask.applying) {
#ifdef THORVG_LOG_ENABLED
printf("SVG: Multiple Composition Tried! Check out Circular dependency?\n");
#endif
} else {
auto compNode = node->style->mask.node;
if (compNode && compNode->child.count > 0) {
node->style->mask.applying = true;
node->style->comp.applying = true;
auto comp = Shape::gen();
comp->fill(255, 255, 255, 255);
if (node->transform) comp->transform(*node->transform);
auto comp = Shape::gen();
comp->fill(255, 255, 255, 255);
if (node->transform) comp->transform(*node->transform);
auto child = compNode->child.data;
auto valid = false; //Composite only when valid shapes are existed
auto child = compNode->child.data;
auto valid = false; //Composite only when valid shapes are existed
for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) {
if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true;
}
for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) {
if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true;
if (valid) paint->composite(move(comp), CompositeMethod::AlphaMask);
node->style->mask.applying = false;
}
}
if (valid) paint->composite(move(comp), node->style->comp.method);
node->style->comp.applying = false;
}