From 92346c4119f72eea7c7c0d36ab396d7d4af6e94f Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 30 Apr 2023 10:41:29 +0200 Subject: [PATCH] svg_loader: handling svg width/height in percentages The percentages should refer to the size of the viewbox. This was not the case for not knowing the viewbox before reading the width/height. @Issue: https://github.com/thorvg/thorvg/issues/1409 --- src/loaders/svg/tvgSvgLoader.cpp | 26 ++++++++++++++++++++++---- src/loaders/svg/tvgSvgLoaderCommon.h | 2 ++ src/loaders/svg/tvgSvgSceneBuilder.cpp | 3 +++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index cea78ed1..19e52c93 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -861,10 +861,18 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) if (!strcmp(key, "width")) { doc->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); - doc->viewFlag = (doc->viewFlag | SvgViewFlag::Width); + if (strstr(value, "%")) { + doc->sw = svgUtilStrtof(value, nullptr) / 100.0f; + } else { + doc->viewFlag = (doc->viewFlag | SvgViewFlag::Width); + } } else if (!strcmp(key, "height")) { doc->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical); - doc->viewFlag = (doc->viewFlag | SvgViewFlag::Height); + if (strstr(value, "%")) { + doc->sh = svgUtilStrtof(value, nullptr) / 100.0f; + } else { + doc->viewFlag = (doc->viewFlag | SvgViewFlag::Height); + } } else if (!strcmp(key, "viewBox")) { if (_parseNumber(&value, &doc->vx)) { if (_parseNumber(&value, &doc->vy)) { @@ -1347,6 +1355,8 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha doc->align = AspectRatioAlign::XMidYMid; doc->meetOrSlice = AspectRatioMeetOrSlice::Meet; doc->viewFlag = SvgViewFlag::None; + doc->sw = 1.0f; + doc->sh = 1.0f; func(buf, bufLength, _attrParseSvgNode, loader); if (!(doc->viewFlag & SvgViewFlag::Viewbox)) { @@ -3530,8 +3540,16 @@ bool SvgLoader::header() vw = loaderData.doc->node.doc.vw; vh = loaderData.doc->node.doc.vh; - if (!(viewFlag & SvgViewFlag::Width)) w = vw; - if (!(viewFlag & SvgViewFlag::Height)) h = vh; + if (!(viewFlag & SvgViewFlag::Width)) { + w = vw * loaderData.doc->node.doc.sw; + loaderData.doc->node.doc.sw = 1.0f; + viewFlag = (viewFlag | SvgViewFlag::Width); + } + if (!(viewFlag & SvgViewFlag::Height)) { + h = vh * loaderData.doc->node.doc.sh; + loaderData.doc->node.doc.sh = 1.0f; + viewFlag = (viewFlag | SvgViewFlag::Height); + } } else { vw = w; vh = h; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index e66000f6..3e4ff033 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -260,6 +260,8 @@ struct SvgDocNode float vy; float vw; float vh; + float sw; + float sh; SvgViewFlag viewFlag; SvgNode* defs; SvgNode* style; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 2a33e382..e57c9f4f 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -796,7 +796,10 @@ unique_ptr svgSceneBuild(SvgNode* node, float& vx, float& vy, float& vw, Box vBox = {vx, vy, vw, vh}; auto docNode = _sceneBuildHelper(node, vBox, svgPath, false, 0); + _applySvgViewFlag(docNode.get(), vx, vy, vw, vh, w, h, viewFlag); + w *= node->node.doc.sw; + h *= node->node.doc.sh; if (!mathEqual(w, vw) || !mathEqual(h, vh)) { Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, {vx, vy, vw, vh});