diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index c1b3b337..b5957126 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -139,23 +139,17 @@ static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengt } -static float _gradientToFloat(const SvgParser* svgParse, const char* str, SvgParserLengthType type) +static float _gradientToFloat(const SvgParser* svgParse, const char* str, SvgParserLengthType type, uint8_t& pct) { char* end = nullptr; float parsedValue = svgUtilStrtof(str, &end); - float max = 1; + pct = 0; - /** - * That is according to Units in here - * - * https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html - */ - if (type == SvgParserLengthType::Vertical) max = (float)svgParse->global.h; - else if (type == SvgParserLengthType::Horizontal) max = (float)svgParse->global.w; - else if (type == SvgParserLengthType::Other) max = sqrtf(pow(svgParse->global.h, 2) + pow(svgParse->global.w, 2)) / sqrtf(2.0); - - if (strstr(str, "%")) parsedValue = parsedValue / 100.0; + if (strstr(str, "%")) { + parsedValue = parsedValue / 100.0; + pct = 1; + } else if (strstr(str, "cm")) parsedValue = parsedValue * 35.43307; else if (strstr(str, "mm")) parsedValue = parsedValue * 3.543307; else if (strstr(str, "pt")) parsedValue = parsedValue * 1.25; @@ -163,9 +157,6 @@ static float _gradientToFloat(const SvgParser* svgParse, const char* str, SvgPar else if (strstr(str, "in")) parsedValue = parsedValue * 90; //TODO: Implement 'em', 'ex' attributes - //Transform into global percentage - parsedValue = parsedValue / max; - return parsedValue; } @@ -1935,65 +1926,72 @@ FillSpread _parseSpreadValue(const char* value) static void _handleRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) { - radial->cx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); - if (!loader->svgParse->gradient.parsedFx) radial->fx = radial->cx; + radial->cx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal, radial->cxPct); + if (!loader->svgParse->gradient.parsedFx) { + radial->fx = radial->cx; + radial->fxPct = radial->cxPct; + } } static void _handleRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) { - radial->cy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); - if (!loader->svgParse->gradient.parsedFy) radial->fy = radial->cy; + radial->cy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical, radial->cyPct); + if (!loader->svgParse->gradient.parsedFy) { + radial->fy = radial->cy; + radial->fyPct = radial->cyPct; + } } static void _handleRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) { - radial->fx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + radial->fx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal, radial->fxPct); loader->svgParse->gradient.parsedFx = true; } static void _handleRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) { - radial->fy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + radial->fy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical, radial->fyPct); loader->svgParse->gradient.parsedFy = true; } static void _handleRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) { - radial->r = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Other); + radial->r = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Other, radial->rPct); } static void _recalcRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) { - if (!userSpace) radial->cx = radial->cx * loader->svgParse->global.w; + if (userSpace && radial->cxPct == 0) radial->cx = radial->cx / loader->svgParse->global.w; } static void _recalcRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) { - if (!userSpace) radial->cy = radial->cy * loader->svgParse->global.h; + if (userSpace && radial->cyPct == 0) radial->cy = radial->cy / loader->svgParse->global.h; } static void _recalcRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) { - if (!userSpace) radial->fx = radial->fx * loader->svgParse->global.w; + if (userSpace && radial->fxPct == 0) radial->fx = radial->fx / loader->svgParse->global.w; } static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) { - if (!userSpace) radial->fy = radial->fy * loader->svgParse->global.h; + if (userSpace && radial->fyPct == 0) radial->fy = radial->fy / loader->svgParse->global.h; } static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) { - if (!userSpace) radial->r = radial->r * (sqrtf(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrtf(2.0)); + // scaling factor based on the Units paragraph from : https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html + if (userSpace && radial->rPct == 0) radial->r = radial->r / (sqrtf(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrtf(2.0)); } @@ -2076,6 +2074,11 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char grad->radial->fx = 0.5f / loader->svgParse->global.w; grad->radial->fy = 0.5f / loader->svgParse->global.h; grad->radial->r = 0.5f / (sqrtf(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrtf(2.0f)); + grad->radial->cxPct = 1; + grad->radial->cyPct = 1; + grad->radial->fxPct = 1; + grad->radial->fyPct = 1; + grad->radial->rPct = 1; loader->svgParse->gradient.parsedFx = false; loader->svgParse->gradient.parsedFy = false; @@ -2136,49 +2139,49 @@ static bool _attrParseStops(void* data, const char* key, const char* value) static void _handleLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) { - linear->x1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + linear->x1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal, linear->x1Pct); } static void _handleLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) { - linear->y1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + linear->y1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical, linear->y1Pct); } static void _handleLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) { - linear->x2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + linear->x2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal, linear->x2Pct); } static void _handleLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) { - linear->y2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + linear->y2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical, linear->y2Pct); } static void _recalcLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) { - if (!userSpace) linear->x1 = linear->x1 * loader->svgParse->global.w; + if (userSpace && linear->x1Pct == 0) linear->x1 = linear->x1 / loader->svgParse->global.w; } static void _recalcLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) { - if (!userSpace) linear->y1 = linear->y1 * loader->svgParse->global.h; + if (userSpace && linear->y1Pct == 0) linear->y1 = linear->y1 / loader->svgParse->global.h; } static void _recalcLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) { - if (!userSpace) linear->x2 = linear->x2 * loader->svgParse->global.w; + if (userSpace && linear->x2Pct == 0) linear->x2 = linear->x2 / loader->svgParse->global.w; } static void _recalcLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) { - if (!userSpace) linear->y2 = linear->y2 * loader->svgParse->global.h; + if (userSpace && linear->y2Pct == 0) linear->y2 = linear->y2 / loader->svgParse->global.h; } @@ -2256,6 +2259,8 @@ static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char * Default value of x2 is 100% - transformed to the global percentage */ grad->linear->x2 = 1.0f / loader->svgParse->global.w; + grad->linear->x2Pct = 1; + simpleXmlParseAttributes(buf, bufLength, _attrParseLinearGradientNode, loader); for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) { @@ -2273,10 +2278,9 @@ static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char /** - * For all Gradients lengths would be calculated into percentages related to - * canvas width and height. - * - * if user then recalculate actual pixels into percentages + * In the case when the gradients lengths are given as numbers (not percentages) + * in the current user coordinate system, they are recalculated into percentages + * related to the canvas width and height. */ static constexpr struct { diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 37762dba..e8c1ab37 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -216,6 +216,11 @@ struct SvgLinearGradient float y1; float x2; float y2; + uint8_t x1Pct; + uint8_t y1Pct; + uint8_t x2Pct; + uint8_t y2Pct; + }; struct SvgRadialGradient @@ -225,6 +230,11 @@ struct SvgRadialGradient float fx; float fy; float r; + uint8_t cxPct; + uint8_t cyPct; + uint8_t fxPct; + uint8_t fyPct; + uint8_t rPct; }; struct SvgComposite