svg_loader: proper svg resizing

Solves the problem of 'vx' and 'vy' < 0 and cases with 'width'
and 'height' values different than widht and height from the 'viewBox'
attribute.
This commit is contained in:
Mira Grudzinska 2021-09-15 01:43:45 +02:00 committed by Hermet Park
parent 1d8625d40d
commit c9c3776207
3 changed files with 52 additions and 20 deletions

View file

@ -2770,7 +2770,7 @@ void SvgLoader::run(unsigned tid)
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes);
}
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh);
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect);
};
@ -2855,31 +2855,31 @@ bool SvgLoader::resize(Paint* paint, float w, float h)
{
if (!paint) return false;
auto sx = w / vw;
auto sy = h / vh;
auto sx = w / this->w;
auto sy = h / this->h;
if (preserveAspect) {
//Scale
auto scale = sx < sy ? sx : sy;
paint->scale(scale);
//Align
auto vx = this->vx * scale;
auto vy = this->vy * scale;
auto vw = this->vw * scale;
auto vh = this->vh * scale;
if (vw > vh) vy -= (h - vh) * 0.5f;
else vx -= (w - vw) * 0.5f;
paint->translate(-vx, -vy);
auto tx = 0.0f;
auto ty = 0.0f;
auto tw = this->w * scale;
auto th = this->h * scale;
if (tw > th) ty -= (h - th) * 0.5f;
else tx -= (w - tw) * 0.5f;
paint->translate(-tx, -ty);
} else {
//Align
auto vx = this->vx * sx;
auto vy = this->vy * sy;
auto vw = this->vw * sx;
auto vh = this->vh * sy;
if (vw > vh) vy -= (h - vh) * 0.5f;
else vx -= (w - vw) * 0.5f;
auto tx = 0.0f;
auto ty = 0.0f;
auto tw = this->w * sx;
auto th = this->h * sy;
if (tw > th) ty -= (h - th) * 0.5f;
else tx -= (w - tw) * 0.5f;
Matrix m = {sx, 0, -vx, 0, sy, -vy, 0, 0, 1};
Matrix m = {sx, 0, -tx, 0, sy, -ty, 0, 0, 1};
paint->transform(m);
}
return true;

View file

@ -25,6 +25,7 @@
#include "tvgSvgSceneBuilder.h"
#include "tvgSvgPath.h"
#include "tvgSvgUtil.h"
#include <float.h>
static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh);
@ -516,14 +517,45 @@ static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, float vx, float
/* External Class Implementation */
/************************************************************************/
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh)
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect)
{
if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
auto docNode = _sceneBuildHelper(node, vx, vy, vw, vh);
if (fabsf(w - vw) > FLT_EPSILON || fabsf(h - vh) > FLT_EPSILON) {
auto sx = w / vw;
auto sy = h / vh;
if (preserveAspect) {
//Scale
auto scale = sx < sy ? sx : sy;
docNode->scale(scale);
//Align
auto tvx = vx * scale;
auto tvy = vy * scale;
auto tvw = vw * scale;
auto tvh = vh * scale;
if (vw > vh) tvy -= (h - tvh) * 0.5f;
else tvx -= (w - tvw) * 0.5f;
docNode->translate(-tvx, -tvy);
} else {
//Align
auto tvx = vx * sx;
auto tvy = vy * sy;
auto tvw = vw * sx;
auto tvh = vh * sy;
if (tvw > tvh) tvy -= (h - tvh) * 0.5f;
else tvx -= (w - tvw) * 0.5f;
Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
docNode->transform(m);
}
} else if (vx < 0 || vy < 0) {
docNode->translate(-vx, -vy);
}
auto viewBoxClip = Shape::gen();
viewBoxClip->appendRect(vx, vy, vw, vh, 0, 0);
viewBoxClip->appendRect(0, 0, w, h, 0, 0);
viewBoxClip->fill(0, 0, 0, 255);
auto compositeLayer = Scene::gen();

View file

@ -25,6 +25,6 @@
#include "tvgCommon.h"
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh);
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect);
#endif //_TVG_SVG_SCENE_BUILDER_H_