return true;
}
-
-static constexpr struct
-{
- AspectRatioAlign align;
- const char* tag;
-} alignTags[] = {
- { AspectRatioAlign::XMinYMin, "xMinYMin" },
- { AspectRatioAlign::XMidYMin, "xMidYMin" },
- { AspectRatioAlign::XMaxYMin, "xMaxYMin" },
- { AspectRatioAlign::XMinYMid, "xMinYMid" },
- { AspectRatioAlign::XMidYMid, "xMidYMid" },
- { AspectRatioAlign::XMaxYMid, "xMaxYMid" },
- { AspectRatioAlign::XMinYMax, "xMinYMax" },
- { AspectRatioAlign::XMidYMax, "xMidYMax" },
- { AspectRatioAlign::XMaxYMax, "xMaxYMax" },
-};
-
-
-static void _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice)
-{
- if (!strcmp(*content, "none")) {
- *align = AspectRatioAlign::None;
- return;
- }
-
- for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) {
- if (!strncmp(*content, alignTags[i].tag, 8)) {
- *align = alignTags[i].align;
- *content += 8;
- *content = _skipSpace(*content, nullptr);
- break;
- }
- }
-
- if (!strcmp(*content, "meet"))
- *meetOrSlice = AspectRatioMeetOrSlice::Meet;
- else if (!strcmp(*content, "slice"))
- *meetOrSlice = AspectRatioMeetOrSlice::Slice;
-
- return;
-}
-
-
/**
* According to https://www.w3.org/TR/SVG/coords.html#Units
*/
}
loader->svgParse->global.x = (int)doc->vx;
} else if (!strcmp(key, "preserveAspectRatio")) {
- _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
+ if (!strcmp(value, "none")) doc->preserveAspect = false;
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
}
loader->svgParse->global.w = 0;
loader->svgParse->global.h = 0;
- doc->align = AspectRatioAlign::XMidYMid;
- doc->meetOrSlice = AspectRatioMeetOrSlice::Meet;
-
+ doc->preserveAspect = true;
simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader);
if (loader->svgParse->global.w == 0) {
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes);
}
- root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath);
+ root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath);
}
if (vh < FLT_EPSILON) vh = h;
}
- align = loaderData.doc->node.doc.align;
- meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
+ preserveAspect = loaderData.doc->node.doc.preserveAspect;
} else {
TVGLOG("SVG", "No SVG File. There is no <svg/>");
return false;
auto sx = w / this->w;
auto sy = h / this->h;
- Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1};
- paint->transform(m);
+ if (preserveAspect) {
+ //Scale
+ auto scale = sx < sy ? sx : sy;
+ paint->scale(scale);
+ //Align
+ 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 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, -tx, 0, sy, -ty, 0, 0, 1};
+ paint->transform(m);
+ }
return true;
}
}
-static Matrix _calculateAspectRatioMatrix(AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, float width, float height, const Box& box)
-{
- auto sx = width / box.w;
- auto sy = height / box.h;
- auto tvx = box.x * sx;
- auto tvy = box.y * sy;
-
- if (align == AspectRatioAlign::None)
- return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
-
- //Scale
- if (meetOrSlice == AspectRatioMeetOrSlice::Meet) {
- if (sx < sy) sy = sx;
- else sx = sy;
- } else {
- if (sx < sy) sx = sy;
- else sy = sx;
- }
-
- //Align
- tvx = box.x * sx;
- tvy = box.y * sy;
- auto tvw = box.w * sx;
- auto tvh = box.h * sy;
-
- switch (align) {
- case AspectRatioAlign::XMinYMin: {
- break;
- }
- case AspectRatioAlign::XMidYMin: {
- tvx -= (width - tvw) * 0.5f;
- break;
- }
- case AspectRatioAlign::XMaxYMin: {
- tvx -= width - tvw;
- break;
- }
- case AspectRatioAlign::XMinYMid: {
- tvy -= (height - tvh) * 0.5f;
- break;
- }
- case AspectRatioAlign::XMidYMid: {
- tvx -= (width - tvw) * 0.5f;
- tvy -= (height - tvh) * 0.5f;
- break;
- }
- case AspectRatioAlign::XMaxYMid: {
- tvx -= width - tvw;
- tvy -= (height - tvh) * 0.5f;
- break;
- }
- case AspectRatioAlign::XMinYMax: {
- tvy -= height - tvh;
- break;
- }
- case AspectRatioAlign::XMidYMax: {
- tvx -= (width - tvw) * 0.5f;
- tvy -= height - tvh;
- break;
- }
- case AspectRatioAlign::XMaxYMax: {
- tvx -= width - tvw;
- tvy -= height - tvh;
- break;
- }
- default: {
- break;
- }
- }
-
- return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
-}
-
-
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath)
+unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath)
{
if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
auto docNode = _sceneBuildHelper(node, vBox, svgPath, false);
if (!mathEqual(w, vw) || !mathEqual(h, vh)) {
- Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox);
- docNode->transform(m);
+ 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 (!mathZero(vx) || !mathZero(vy)) {
docNode->translate(-vx, -vy);
}