svg_loader: support other units for mask and clip

Added support for the objectBoundingBox value of
the clipPathUnits and for the userSpaceOnUse value
of the maskContentUnits.

@Issue: https://github.com/thorvg/thorvg/issues/429
This commit is contained in:
Mira Grudzinska 2023-08-05 01:25:58 +02:00 committed by Hermet Park
parent f573e1390f
commit 70fff186b2

View file

@ -24,6 +24,7 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
#include "tvgCompressor.h" #include "tvgCompressor.h"
#include "tvgPaint.h"
#include "tvgSvgLoaderCommon.h" #include "tvgSvgLoaderCommon.h"
#include "tvgSvgSceneBuilder.h" #include "tvgSvgSceneBuilder.h"
#include "tvgSvgPath.h" #include "tvgSvgPath.h"
@ -220,6 +221,26 @@ static bool _appendClipChild(SvgNode* node, Shape* shape, const Box& vBox, const
} }
static Matrix _compositionTransform(Paint* paint, const SvgNode* node, const SvgNode* compNode, SvgNodeType type)
{
Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
//The initial mask transformation ignored according to the SVG standard.
if (node->transform && type != SvgNodeType::Mask) {
m = *node->transform;
}
if (compNode->transform) {
m = mathMultiply(&m, compNode->transform);
}
if (!compNode->node.clip.userSpace) {
float x, y, w, h;
P(paint)->bounds(&x, &y, &w, &h, false, false);
Matrix mBBox = {w, 0, x, 0, h, y, 0, 0, 1};
m = mathMultiply(&m, &mBBox);
}
return m;
}
static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox, const string& svgPath) static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox, const string& svgPath)
{ {
/* ClipPath */ /* ClipPath */
@ -241,13 +262,12 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
if (_appendClipChild(*child, comp.get(), vBox, svgPath, compNode->child.count > 1)) valid = true; if (_appendClipChild(*child, comp.get(), vBox, svgPath, compNode->child.count > 1)) valid = true;
} }
if (node->transform) { if (valid) {
auto m = comp->transform(); Matrix finalTransform = _compositionTransform(paint, node, compNode, SvgNodeType::ClipPath);
m = mathMultiply(node->transform, &m); comp->transform(finalTransform);
comp->transform(m);
}
if (valid) paint->composite(std::move(comp), CompositeMethod::ClipPath); paint->composite(std::move(comp), CompositeMethod::ClipPath);
}
node->style->clipPath.applying = false; node->style->clipPath.applying = false;
} }
@ -264,9 +284,9 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
node->style->mask.applying = true; node->style->mask.applying = true;
bool isMaskWhite = true; bool isMaskWhite = true;
auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, 0, &isMaskWhite); if (auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, 0, &isMaskWhite)) {
if (comp) { Matrix finalTransform = _compositionTransform(paint, node, compNode, SvgNodeType::Mask);
if (node->transform) comp->transform(*node->transform); comp->transform(finalTransform);
if (compNode->node.mask.type == SvgMaskType::Luminance && !isMaskWhite) { if (compNode->node.mask.type == SvgMaskType::Luminance && !isMaskWhite) {
paint->composite(std::move(comp), CompositeMethod::LumaMask); paint->composite(std::move(comp), CompositeMethod::LumaMask);