/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include <svgtools.hxx>
#include <sal/log.hxx>
#include <tools/color.hxx>
#include <rtl/math.hxx>
#include <o3tl/string_view.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <svgtoken.hxx>
#include <frozen/bits/defines.h>
#include <frozen/bits/elsa_std.h>
#include <frozen/unordered_map.h>
 
namespace svgio::svgreader
{
        constexpr auto aColorTokenMapperList = frozen::make_unordered_map<std::u16string_view, Color>(
        {
            { u"aliceblue", Color(240, 248, 255) },
            { u"antiquewhite", Color(250, 235, 215) },
            { u"aqua", Color( 0, 255, 255) },
            { u"aquamarine", Color(127, 255, 212) },
            { u"azure", Color(240, 255, 255) },
            { u"beige", Color(245, 245, 220) },
            { u"bisque", Color(255, 228, 196) },
            { u"black", Color( 0, 0, 0) },
            { u"blanchedalmond", Color(255, 235, 205) },
            { u"blue", Color( 0, 0, 255) },
            { u"blueviolet", Color(138, 43, 226) },
            { u"brown", Color(165, 42, 42) },
            { u"burlywood", Color(222, 184, 135) },
            { u"cadetblue", Color( 95, 158, 160) },
            { u"chartreuse", Color(127, 255, 0) },
            { u"chocolate", Color(210, 105, 30) },
            { u"coral", Color(255, 127, 80) },
            { u"cornflowerblue", Color(100, 149, 237) },
            { u"cornsilk", Color(255, 248, 220) },
            { u"crimson", Color(220, 20, 60) },
            { u"cyan", Color( 0, 255, 255) },
            { u"darkblue", Color( 0, 0, 139) },
            { u"darkcyan", Color( 0, 139, 139) },
            { u"darkgoldenrod", Color(184, 134, 11) },
            { u"darkgray", Color(169, 169, 169) },
            { u"darkgreen", Color( 0, 100, 0) },
            { u"darkgrey", Color(169, 169, 169) },
            { u"darkkhaki", Color(189, 183, 107) },
            { u"darkmagenta", Color(139, 0, 139) },
            { u"darkolivegreen", Color( 85, 107, 47) },
            { u"darkorange", Color(255, 140, 0) },
            { u"darkorchid", Color(153, 50, 204) },
            { u"darkred", Color(139, 0, 0) },
            { u"darksalmon", Color(233, 150, 122) },
            { u"darkseagreen", Color(143, 188, 143) },
            { u"darkslateblue", Color( 72, 61, 139) },
            { u"darkslategray", Color( 47, 79, 79) },
            { u"darkslategrey", Color( 47, 79, 79) },
            { u"darkturquoise", Color( 0, 206, 209) },
            { u"darkviolet", Color(148, 0, 211) },
            { u"deeppink", Color(255, 20, 147) },
            { u"deepskyblue", Color( 0, 191, 255) },
            { u"dimgray", Color(105, 105, 105) },
            { u"dimgrey", Color(105, 105, 105) },
            { u"dodgerblue", Color( 30, 144, 255) },
            { u"firebrick", Color(178, 34, 34) },
            { u"floralwhite", Color(255, 250, 240) },
            { u"forestgreen", Color( 34, 139, 34) },
            { u"fuchsia", Color(255, 0, 255) },
            { u"gainsboro", Color(220, 220, 220) },
            { u"ghostwhite", Color(248, 248, 255) },
            { u"gold", Color(255, 215, 0) },
            { u"goldenrod", Color(218, 165, 32) },
            { u"gray", Color(128, 128, 128) },
            { u"grey", Color(128, 128, 128) },
            { u"green", Color(0, 128, 0) },
            { u"greenyellow", Color(173, 255, 47) },
            { u"honeydew", Color(240, 255, 240) },
            { u"hotpink", Color(255, 105, 180) },
            { u"indianred", Color(205, 92, 92) },
            { u"indigo", Color( 75, 0, 130) },
            { u"ivory", Color(255, 255, 240) },
            { u"khaki", Color(240, 230, 140) },
            { u"lavender", Color(230, 230, 250) },
            { u"lavenderblush", Color(255, 240, 245) },
            { u"lawngreen", Color(124, 252, 0) },
            { u"lemonchiffon", Color(255, 250, 205) },
            { u"lightblue", Color(173, 216, 230) },
            { u"lightcoral", Color(240, 128, 128) },
            { u"lightcyan", Color(224, 255, 255) },
            { u"lightgoldenrodyellow", Color(250, 250, 210) },
            { u"lightgray", Color(211, 211, 211) },
            { u"lightgreen", Color(144, 238, 144) },
            { u"lightgrey", Color(211, 211, 211) },
            { u"lightpink", Color(255, 182, 193) },
            { u"lightsalmon", Color(255, 160, 122) },
            { u"lightseagreen", Color( 32, 178, 170) },
            { u"lightskyblue", Color(135, 206, 250) },
            { u"lightslategray", Color(119, 136, 153) },
            { u"lightslategrey", Color(119, 136, 153) },
            { u"lightsteelblue", Color(176, 196, 222) },
            { u"lightyellow", Color(255, 255, 224) },
            { u"lime", Color( 0, 255, 0) },
            { u"limegreen", Color( 50, 205, 50) },
            { u"linen", Color(250, 240, 230) },
            { u"magenta", Color(255, 0, 255) },
            { u"maroon", Color(128, 0, 0) },
            { u"mediumaquamarine", Color(102, 205, 170) },
            { u"mediumblue", Color( 0, 0, 205) },
            { u"mediumorchid", Color(186, 85, 211) },
            { u"mediumpurple", Color(147, 112, 219) },
            { u"mediumseagreen", Color( 60, 179, 113) },
            { u"mediumslateblue", Color(123, 104, 238) },
            { u"mediumspringgreen", Color( 0, 250, 154) },
            { u"mediumturquoise", Color( 72, 209, 204) },
            { u"mediumvioletred", Color(199, 21, 133) },
            { u"midnightblue", Color( 25, 25, 112) },
            { u"mintcream", Color(245, 255, 250) },
            { u"mistyrose", Color(255, 228, 225) },
            { u"moccasin", Color(255, 228, 181) },
            { u"navajowhite", Color(255, 222, 173) },
            { u"navy", Color( 0, 0, 128) },
            { u"oldlace", Color(253, 245, 230) },
            { u"olive", Color(128, 128, 0) },
            { u"olivedrab", Color(107, 142, 35) },
            { u"orange", Color(255, 165, 0) },
            { u"orangered", Color(255, 69, 0) },
            { u"orchid", Color(218, 112, 214) },
            { u"palegoldenrod", Color(238, 232, 170) },
            { u"palegreen", Color(152, 251, 152) },
            { u"paleturquoise", Color(175, 238, 238) },
            { u"palevioletred", Color(219, 112, 147) },
            { u"papayawhip", Color(255, 239, 213) },
            { u"peachpuff", Color(255, 218, 185) },
            { u"peru", Color(205, 133, 63) },
            { u"pink", Color(255, 192, 203) },
            { u"plum", Color(221, 160, 221) },
            { u"powderblue", Color(176, 224, 230) },
            { u"purple", Color(128, 0, 128) },
            { u"rebeccapurple", Color(102, 51, 153) },
            { u"red", Color(255, 0, 0) },
            { u"rosybrown", Color(188, 143, 143) },
            { u"royalblue", Color( 65, 105, 225) },
            { u"saddlebrown", Color(139, 69, 19) },
            { u"salmon", Color(250, 128, 114) },
            { u"sandybrown", Color(244, 164, 96) },
            { u"seagreen", Color( 46, 139, 87) },
            { u"seashell", Color(255, 245, 238) },
            { u"sienna", Color(160, 82, 45) },
            { u"silver", Color(192, 192, 192) },
            { u"skyblue", Color(135, 206, 235) },
            { u"slateblue", Color(106, 90, 205) },
            { u"slategray", Color(112, 128, 144) },
            { u"slategrey", Color(112, 128, 144) },
            { u"snow", Color(255, 250, 250) },
            { u"springgreen", Color( 0, 255, 127) },
            { u"steelblue", Color( 70, 130, 180) },
            { u"tan", Color(210, 180, 140) },
            { u"teal", Color( 0, 128, 128) },
            { u"thistle", Color(216, 191, 216) },
            { u"tomato", Color(255, 99, 71) },
            { u"turquoise", Color( 64, 224, 208) },
            { u"violet", Color(238, 130, 238) },
            { u"wheat", Color(245, 222, 179) },
            { u"white", Color(255, 255, 255) },
            { u"whitesmoke", Color(245, 245, 245) },
            { u"yellow", Color(255, 255, 0) },
            { u"yellowgreen", Color(154, 205, 50) }
        });
 
        basegfx::B2DHomMatrix SvgAspectRatio::createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource)
        {
            basegfx::B2DHomMatrix aRetval;
            const double fSWidth(rSource.getWidth());
            const double fSHeight(rSource.getHeight());
            const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
            const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
 
            // transform from source state to unit range
            aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
            aRetval.scale(
                (bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth(),
                (bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
 
            // transform from unit rage to target range
            aRetval.translate(rTarget.getMinX(), rTarget.getMinY());
 
            return aRetval;
        }
 
        basegfx::B2DHomMatrix SvgAspectRatio::createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const
        {
            // removed !isSet() from below. Due to correct defaults in the constructor an instance
            // of this class is perfectly useful without being set by any importer
            if(SvgAlign::none == getSvgAlign())
            {
                // create linear mapping (default)
                return createLinearMapping(rTarget, rSource);
            }
 
            basegfx::B2DHomMatrix aRetval;
 
            const double fSWidth(rSource.getWidth());
            const double fSHeight(rSource.getHeight());
            const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
            const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
            const double fScaleX((bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth());
            const double fScaleY((bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
            const double fScale(isMeetOrSlice() ? std::min(fScaleX, fScaleY) : std::max(fScaleX, fScaleY));
 
            // remove source translation, apply scale
            aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
            aRetval.scale(fScale, fScale);
 
            // evaluate horizontal alignment
            const double fNewWidth(fSWidth * fScale);
            double fTransX(0.0);
 
            switch(getSvgAlign())
            {
                case SvgAlign::xMidYMin:
                case SvgAlign::xMidYMid:
                case SvgAlign::xMidYMax:
                {
                    // centerX
                    const double fFreeSpace(rTarget.getWidth() - fNewWidth);
                    fTransX = fFreeSpace * 0.5;
                    break;
                }
                case SvgAlign::xMaxYMin:
                case SvgAlign::xMaxYMid:
                case SvgAlign::xMaxYMax:
                {
                    // Right align
                    const double fFreeSpace(rTarget.getWidth() - fNewWidth);
                    fTransX = fFreeSpace;
                    break;
                }
                default: break;
            }
 
            // evaluate vertical alignment
            const double fNewHeight(fSHeight * fScale);
            double fTransY(0.0);
 
            switch(getSvgAlign())
            {
                case SvgAlign::xMinYMid:
                case SvgAlign::xMidYMid:
                case SvgAlign::xMaxYMid:
                {
                    // centerY
                    const double fFreeSpace(rTarget.getHeight() - fNewHeight);
                    fTransY = fFreeSpace * 0.5;
                    break;
                }
                case SvgAlign::xMinYMax:
                case SvgAlign::xMidYMax:
                case SvgAlign::xMaxYMax:
                {
                    // Bottom align
                    const double fFreeSpace(rTarget.getHeight() - fNewHeight);
                    fTransY = fFreeSpace;
                    break;
                }
                default: break;
            }
 
            // add target translation
            aRetval.translate(
                rTarget.getMinX() + fTransX,
                rTarget.getMinY() + fTransY);
 
            return aRetval;
        }
 
        void skip_char(std::u16string_view rCandidate, sal_Unicode nChar, sal_Int32& nPos, const sal_Int32 nLen)
        {
            while(nPos < nLen && nChar == rCandidate[nPos])
            {
                nPos++;
            }
        }
 
        void skip_char(std::u16string_view rCandidate, sal_Unicode nCharA, sal_Unicode nCharB, sal_Int32& nPos, const sal_Int32 nLen)
        {
            while(nPos < nLen && (nCharA == rCandidate[nPos] || nCharB == rCandidate[nPos]))
            {
                nPos++;
            }
        }
 
        void copySign(std::u16string_view rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
        {
            if(nPos < nLen)
            {
                const sal_Unicode aChar(rCandidate[nPos]);
 
                if('+' == aChar || '-' == aChar)
                {
                    rTarget.append(aChar);
                    nPos++;
                }
            }
        }
 
        void copyNumber(std::u16string_view rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
        {
            bool bOnNumber(true);
 
            while(bOnNumber && nPos < nLen)
            {
                const sal_Unicode aChar(rCandidate[nPos]);
 
                bOnNumber = ('0' <= aChar && '9' >= aChar) || '.' == aChar;
 
                if(bOnNumber)
                {
                    rTarget.append(aChar);
                    nPos++;
                }
            }
        }
 
        void copyHex(std::u16string_view rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
        {
            bool bOnHex(true);
 
            while(bOnHex && nPos < nLen)
            {
                const sal_Unicode aChar(rCandidate[nPos]);
 
                bOnHex = ('0' <= aChar && '9' >= aChar)
                    || ('A' <= aChar && 'F' >= aChar)
                    || ('a' <= aChar && 'f' >= aChar);
 
                if(bOnHex)
                {
                    rTarget.append(aChar);
                    nPos++;
                }
            }
        }
 
        void copyString(std::u16string_view rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
        {
            bool bOnChar(true);
 
            while(bOnChar && nPos < nLen)
            {
                const sal_Unicode aChar(rCandidate[nPos]);
 
                bOnChar = ('a' <= aChar && 'z' >= aChar)
                    || ('A' <= aChar && 'Z' >= aChar)
                    || '-' == aChar;
 
                if(bOnChar)
                {
                    rTarget.append(aChar);
                    nPos++;
                }
            }
        }
 
        void copyToLimiter(std::u16string_view rCandidate, sal_Unicode nLimiter, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
        {
            while(nPos < nLen && nLimiter != rCandidate[nPos])
            {
                rTarget.append(rCandidate[nPos]);
                nPos++;
            }
        }
 
        bool readNumber(std::u16string_view rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen)
        {
            if(nPos < nLen)
            {
                OUStringBuffer aNum;
 
                copySign(rCandidate, nPos, aNum, nLen);
                copyNumber(rCandidate, nPos, aNum, nLen);
 
                if(nPos < nLen)
                {
                    const sal_Unicode aChar(rCandidate[nPos]);
 
                    if('e' == aChar || 'E' == aChar)
                    {
                        // try to read exponential number, but be careful. I had
                        // a case where dx="2em" was used, thus the 'e' was consumed
                        // by error. First try if there are numbers after the 'e',
                        // safe current state
                        nPos++;
                        const OUStringBuffer aNum2(aNum);
                        const sal_Int32 nPosAfterE(nPos);
 
                        aNum.append(aChar);
                        copySign(rCandidate, nPos, aNum, nLen);
                        copyNumber(rCandidate, nPos, aNum, nLen);
 
                        if(nPosAfterE == nPos)
                        {
                            // no number after 'e', go back. Do not
                            // return false, it's still a valid integer number
                            aNum = aNum2;
                            nPos--;
                        }
                    }
                }
 
                if(!aNum.isEmpty())
                {
                    rtl_math_ConversionStatus eStatus;
 
                    fNum = rtl::math::stringToDouble(
                        aNum, '.', ',',
                        &eStatus);
 
                    return eStatus == rtl_math_ConversionStatus_Ok;
                }
            }
 
            return false;
        }
 
        SvgUnit readUnit(std::u16string_view rCandidate, sal_Int32& nPos, const sal_Int32 nLen)
        {
            SvgUnit aRetval(SvgUnit::px);
 
            if(nPos < nLen)
            {
                const sal_Unicode aCharA(rCandidate[nPos]);
 
                if('%' == aCharA)
                {
                    // percent used, relative to current
                    nPos++;
                    aRetval = SvgUnit::percent;
                }
                else if(nPos + 1 < nLen)
                {
                    const sal_Unicode aCharB(rCandidate[nPos + 1]);
                    bool bTwoCharValid(false);
 
                    switch(aCharA)
                    {
                        case u'e' :
                        {
                            if('m' == aCharB)
                            {
                                // 'em' Relative to current font size
                                aRetval = SvgUnit::em;
                                bTwoCharValid = true;
                            }
                            else if('x' == aCharB)
                            {
                                // 'ex' Relative to current font x-height
                                aRetval = SvgUnit::ex;
                                bTwoCharValid = true;
                            }
                            break;
                        }
                        case u'p' :
                        {
                            if('x' == aCharB)
                            {
                                // 'px' UserUnit (default)
                                bTwoCharValid = true;
                            }
                            else if('t' == aCharB)
                            {
                                // 'pt' == 4/3 px
                                aRetval = SvgUnit::pt;
                                bTwoCharValid = true;
                            }
                            else if('c' == aCharB)
                            {
                                // 'pc' == 16 px
                                aRetval = SvgUnit::pc;
                                bTwoCharValid = true;
                            }
                            break;
                        }
                        case u'i' :
                        {
                            if('n' == aCharB)
                            {
                                // 'in' == 96 px, since CSS 2.1
                                aRetval = SvgUnit::in;
                                bTwoCharValid = true;
                            }
                            break;
                        }
                        case u'c' :
                        {
                            if('m' == aCharB)
                            {
                                // 'cm' == 37.79527559 px
                                aRetval = SvgUnit::cm;
                                bTwoCharValid = true;
                            }
                            break;
                        }
                        case u'm' :
                        {
                            if('m' == aCharB)
                            {
                                // 'mm' == 3.779528 px
                                aRetval = SvgUnit::mm;
                                bTwoCharValid = true;
                            }
                            break;
                        }
                    }
 
                    if(bTwoCharValid)
                    {
                        nPos += 2;
                    }
                }
            }
 
            return aRetval;
        }
 
        bool readNumberAndUnit(std::u16string_view rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen)
        {
            double fNum(0.0);
 
            if(readNumber(rCandidate, nPos, fNum, nLen))
            {
                skip_char(rCandidate, ' ', nPos, nLen);
                aNum = SvgNumber(fNum, readUnit(rCandidate, nPos, nLen));
 
                return true;
            }
 
            return false;
        }
 
        bool readAngle(std::u16string_view rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen)
        {
            if(readNumber(rCandidate, nPos, fAngle, nLen))
            {
                skip_char(rCandidate, ' ', nPos, nLen);
 
                enum class DegreeType
                {
                    deg,
                    grad,
                    rad
                } aType(DegreeType::deg); // degrees is default
 
                if(nPos < nLen)
                {
                    const sal_Unicode aChar(rCandidate[nPos]);
                    static constexpr std::u16string_view aStrGrad = u"grad";
                    static constexpr std::u16string_view aStrRad = u"rad";
 
                    switch(aChar)
                    {
                        case u'g' :
                        case u'G' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrGrad, nPos))
                            {
                                // angle in grad
                                nPos += aStrGrad.size();
                                aType = DegreeType::grad;
                            }
                            break;
                        }
                        case u'r' :
                        case u'R' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrRad, nPos))
                            {
                                // angle in radians
                                nPos += aStrRad.size();
                                aType = DegreeType::rad;
                            }
                            break;
                        }
                    }
                }
 
                // convert to radians
                if (DegreeType::deg == aType)
                {
                    fAngle = basegfx::deg2rad(fAngle);
                }
                else if (DegreeType::grad == aType)
                {
                    // looks like 100 grad is 90 degrees
                    fAngle *= M_PI / 200.0;
                }
 
                return true;
            }
 
            return false;
        }
 
        sal_Int32 read_hex(sal_Unicode nChar)
        {
            if(nChar >= '0' && nChar <= '9')
            {
                return nChar - u'0';
            }
            else if(nChar >= 'A' && nChar <= 'F')
            {
                return 10 + sal_Int32(nChar - u'A');
            }
            else if(nChar >= 'a' && nChar <= 'f')
            {
                return 10 + sal_Int32(nChar - u'a');
            }
            else
            {
                // error
                return 0;
            }
        }
 
        bool match_colorKeyword(basegfx::BColor& rColor, const OUString& rName)
        {
            auto const aResult = aColorTokenMapperList.find(rName.toAsciiLowerCase().trim());
 
            if(aResult == aColorTokenMapperList.end())
            {
                return false;
            }
            else
            {
                rColor = aResult->second.getBColor();
                return true;
            }
        }
 
        bool read_color(const OUString& rCandidate, basegfx::BColor& rColor, SvgNumber& rOpacity)
        {
            const sal_Int32 nLen(rCandidate.getLength());
 
            if(nLen)
            {
                const sal_Unicode aChar(rCandidate[0]);
                const double fFactor(1.0 / 255.0);
 
                if(aChar == '#')
                {
                    // hex definition
                    OUStringBuffer aNum;
                    sal_Int32 nPos(1);
 
                    copyHex(rCandidate, nPos, aNum, nLen);
                    const sal_Int32 nLength(aNum.getLength());
 
                    if(3 == nLength)
                    {
                        const sal_Int32 nR(read_hex(aNum[0]));
                        const sal_Int32 nG(read_hex(aNum[1]));
                        const sal_Int32 nB(read_hex(aNum[2]));
 
                        rColor.setRed((nR | (nR << 4)) * fFactor);
                        rColor.setGreen((nG | (nG << 4)) * fFactor);
                        rColor.setBlue((nB | (nB << 4)) * fFactor);
 
                        return true;
                    }
                    else if(6 == nLength)
                    {
                        const sal_Int32 nR1(read_hex(aNum[0]));
                        const sal_Int32 nR2(read_hex(aNum[1]));
                        const sal_Int32 nG1(read_hex(aNum[2]));
                        const sal_Int32 nG2(read_hex(aNum[3]));
                        const sal_Int32 nB1(read_hex(aNum[4]));
                        const sal_Int32 nB2(read_hex(aNum[5]));
 
                        rColor.setRed((nR2 | (nR1 << 4)) * fFactor);
                        rColor.setGreen((nG2 | (nG1 << 4)) * fFactor);
                        rColor.setBlue((nB2 | (nB1 << 4)) * fFactor);
 
                        return true;
                    }
                }
                else
                {
                    static const char aStrRgb[] = "rgb";
 
                    if(rCandidate.matchIgnoreAsciiCase(aStrRgb, 0))
                    {
                        // rgb/rgba definition
                        sal_Int32 nPos(strlen(aStrRgb));
                        bool bIsRGBA = false;
 
                        if('a' == rCandidate[nPos])
                        {
                            //Delete the 'a' from 'rbga'
                            skip_char(rCandidate, 'a', nPos, nPos + 1);
                            bIsRGBA = true;
                        }
 
                        skip_char(rCandidate, ' ', '(', nPos, nLen);
                        double fR(0.0);
 
                        if(readNumber(rCandidate, nPos, fR, nLen))
                        {
                            skip_char(rCandidate, ' ', nPos, nLen);
 
                            if(nPos < nLen)
                            {
                                const sal_Unicode aPercentChar(rCandidate[nPos]);
                                const bool bIsPercent('%' == aPercentChar);
                                double fG(0.0);
 
                                if(bIsPercent)
                                {
                                    skip_char(rCandidate, '%', nPos, nLen);
                                }
 
                                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                if(readNumber(rCandidate, nPos, fG, nLen))
                                {
                                    double fB(0.0);
 
                                    if(bIsPercent)
                                    {
                                        skip_char(rCandidate, '%', nPos, nLen);
                                    }
 
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    if(readNumber(rCandidate, nPos, fB, nLen))
                                    {
                                        double fA(1.0);
 
                                        if(bIsPercent)
                                        {
                                            skip_char(rCandidate, '%', nPos, nLen);
                                        }
 
                                        skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                        if(readNumber(rCandidate, nPos, fA, nLen))
                                        {
                                            if(bIsRGBA)
                                            {
                                                const double fFac(bIsPercent ? 0.01 : 1);
                                                rOpacity = SvgNumber(fA * fFac);
 
                                                if(bIsPercent)
                                                {
                                                    skip_char(rCandidate, '%', nPos, nLen);
                                                }
                                            }
                                            else
                                            {
                                                return false;
                                            }
                                        }
 
                                        const double fFac(bIsPercent ? 0.01 : fFactor);
 
                                        rColor.setRed(fR * fFac);
                                        rColor.setGreen(fG * fFac);
                                        rColor.setBlue(fB * fFac);
 
                                        skip_char(rCandidate, ' ', ')', nPos, nLen);
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        // color keyword
                        if(match_colorKeyword(rColor, rCandidate))
                        {
                            return true;
                        }
                    }
                }
            }
 
            return false;
        }
 
        basegfx::B2DRange readViewBox(std::u16string_view rCandidate, InfoProvider const & rInfoProvider)
        {
            const sal_Int32 nLen(rCandidate.size());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                SvgNumber aMinX;
                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                if(readNumberAndUnit(rCandidate, nPos, aMinX, nLen))
                {
                    SvgNumber aMinY;
                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                    if(readNumberAndUnit(rCandidate, nPos, aMinY, nLen))
                    {
                        SvgNumber aWidth;
                        skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                        if(readNumberAndUnit(rCandidate, nPos, aWidth, nLen))
                        {
                            SvgNumber aHeight;
                            skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                            if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen))
                            {
                                double fX(aMinX.solve(rInfoProvider, NumberType::xcoordinate));
                                double fY(aMinY.solve(rInfoProvider, NumberType::ycoordinate));
                                double fW(aWidth.solve(rInfoProvider, NumberType::xcoordinate));
                                double fH(aHeight.solve(rInfoProvider, NumberType::ycoordinate));
                                return basegfx::B2DRange(fX,fY,fX+fW,fY+fH);
                            }
                        }
                    }
                }
            }
 
            return basegfx::B2DRange();
        }
 
        std::vector<double> readFilterMatrix(std::u16string_view rCandidate, InfoProvider const & rInfoProvider)
        {
            std::vector<double> aVector;
            const sal_Int32 nLen(rCandidate.size());
 
            sal_Int32 nPos(0);
            skip_char(rCandidate, ' ', ',', nPos, nLen);
 
            SvgNumber aVal;
 
            while (nPos < nLen)
            {
                if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                {
                    aVector.push_back(aVal.solve(rInfoProvider));
                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                }
            }
 
            return aVector;
        }
 
        basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, InfoProvider const & rInfoProvider)
        {
            basegfx::B2DHomMatrix aMatrix;
            const sal_Int32 nLen(rCandidate.size());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                while(nPos < nLen)
                {
                    const sal_Unicode aChar(rCandidate[nPos]);
                    const sal_Int32 nInitPos(nPos);
                    static constexpr std::u16string_view aStrMatrix = u"matrix";
                    static constexpr std::u16string_view aStrTranslate = u"translate";
                    static constexpr std::u16string_view aStrScale = u"scale";
                    static constexpr std::u16string_view aStrRotate = u"rotate";
                    static constexpr std::u16string_view aStrSkewX = u"skewX";
                    static constexpr std::u16string_view aStrSkewY = u"skewY";
 
                    switch(aChar)
                    {
                        case u'm' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrMatrix, nPos))
                            {
                                // matrix element
                                nPos += aStrMatrix.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                SvgNumber aVal;
                                basegfx::B2DHomMatrix aNew;
 
                                if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                {
                                    aNew.set(0, 0, aVal.solve(rInfoProvider)); // Element A
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                    {
                                        aNew.set(1, 0, aVal.solve(rInfoProvider)); // Element B
                                        skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                        if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                        {
                                            aNew.set(0, 1, aVal.solve(rInfoProvider)); // Element C
                                            skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                            if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                            {
                                                aNew.set(1, 1, aVal.solve(rInfoProvider)); // Element D
                                                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                                if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                                {
                                                    aNew.set(0, 2, aVal.solve(rInfoProvider, NumberType::xcoordinate)); // Element E
                                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                                    if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
                                                    {
                                                        aNew.set(1, 2, aVal.solve(rInfoProvider, NumberType::ycoordinate)); // Element F
                                                        skip_char(rCandidate, ' ', ')', nPos, nLen);
                                                        skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                                        // caution: String is evaluated from left to right, but matrix multiplication
                                                        // in SVG is right to left, so put the new transformation before the current
                                                        // one by multiplicating from the right side
                                                        aMatrix = aMatrix * aNew;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            break;
                        }
                        case u't' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrTranslate, nPos))
                            {
                                // translate element
                                nPos += aStrTranslate.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                SvgNumber aTransX;
 
                                if(readNumberAndUnit(rCandidate, nPos, aTransX, nLen))
                                {
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                                    SvgNumber aTransY;
                                    readNumberAndUnit(rCandidate, nPos, aTransY, nLen);
                                    skip_char(rCandidate, ' ', ')', nPos, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    aMatrix = aMatrix * basegfx::utils::createTranslateB2DHomMatrix(
                                        aTransX.solve(rInfoProvider, NumberType::xcoordinate),
                                        aTransY.solve(rInfoProvider, NumberType::ycoordinate));
                                }
                            }
                            break;
                        }
                        case u's' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrScale, nPos))
                            {
                                // scale element
                                nPos += aStrScale.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                SvgNumber aScaleX;
 
                                if(readNumberAndUnit(rCandidate, nPos, aScaleX, nLen))
                                {
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                                    SvgNumber aScaleY(aScaleX);
                                    readNumberAndUnit(rCandidate, nPos, aScaleY, nLen);
                                    skip_char(rCandidate, ' ', ')', nPos, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    aMatrix = aMatrix * basegfx::utils::createScaleB2DHomMatrix(
                                        aScaleX.solve(rInfoProvider),
                                        aScaleY.solve(rInfoProvider));
                                }
                            }
                            else if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrSkewX, nPos))
                            {
                                // skewx element
                                nPos += aStrSkewX.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                double fSkewX(0.0);
 
                                if(readAngle(rCandidate, nPos, fSkewX, nLen))
                                {
                                    skip_char(rCandidate, ' ', ')', nPos, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    aMatrix = aMatrix * basegfx::utils::createShearXB2DHomMatrix(tan(fSkewX));
                                }
                            }
                            else if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrSkewY, nPos))
                            {
                                // skewy element
                                nPos += aStrSkewY.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                double fSkewY(0.0);
 
                                if(readAngle(rCandidate, nPos, fSkewY, nLen))
                                {
                                    skip_char(rCandidate, ' ', ')', nPos, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    aMatrix = aMatrix * basegfx::utils::createShearYB2DHomMatrix(tan(fSkewY));
                                }
                            }
                            break;
                        }
                        case u'r' :
                        {
                            if(o3tl::matchIgnoreAsciiCase(rCandidate, aStrRotate, nPos))
                            {
                                // rotate element
                                nPos += aStrRotate.size();
                                skip_char(rCandidate, ' ', '(', nPos, nLen);
                                double fAngle(0.0);
 
                                if(readAngle(rCandidate, nPos, fAngle, nLen))
                                {
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                                    SvgNumber aX;
                                    readNumberAndUnit(rCandidate, nPos, aX, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                                    SvgNumber aY;
                                    readNumberAndUnit(rCandidate, nPos, aY, nLen);
                                    skip_char(rCandidate, ' ', ')', nPos, nLen);
                                    skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                                    const double fX(aX.isSet() ? aX.solve(rInfoProvider, NumberType::xcoordinate) : 0.0);
                                    const double fY(aY.isSet() ? aY.solve(rInfoProvider, NumberType::ycoordinate) : 0.0);
 
                                    if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
                                    {
                                        // rotate around point
                                        aMatrix = aMatrix * basegfx::utils::createRotateAroundPoint(fX, fY, fAngle);
                                    }
                                    else
                                    {
                                        // rotate
                                        aMatrix = aMatrix * basegfx::utils::createRotateB2DHomMatrix(fAngle);
                                    }
                                }
                            }
                            break;
                        }
                    }
 
                    if(nInitPos == nPos)
                    {
                        SAL_WARN("svgio", "Could not interpret on current position (!)");
                        nPos++;
                    }
                }
            }
 
            return aMatrix;
        }
 
        bool readSingleNumber(std::u16string_view rCandidate, SvgNumber& aNum)
        {
            const sal_Int32 nLen(rCandidate.size());
            sal_Int32 nPos(0);
 
            return readNumberAndUnit(rCandidate, nPos, aNum, nLen);
        }
 
        bool readLocalLink(std::u16string_view rCandidate, OUString& rURL)
        {
            sal_Int32 nPos(0);
            const sal_Int32 nLen(rCandidate.size());
 
            skip_char(rCandidate, ' ', nPos, nLen);
 
            if (nLen && nPos < nLen && '#' == rCandidate[nPos])
            {
                ++nPos;
                rURL = rCandidate.substr(nPos);
 
                return true;
            }
 
            return false;
        }
 
        bool readLocalUrl(const OUString& rCandidate, OUString& rURL)
        {
            static const char aStrUrl[] = "url(";
 
            if(rCandidate.startsWithIgnoreAsciiCase(aStrUrl))
            {
                const sal_Int32 nLen(rCandidate.getLength());
                sal_Int32 nPos(strlen(aStrUrl));
                sal_Unicode aLimiter(')');
 
                skip_char(rCandidate, ' ', nPos, nLen);
 
                if('"' == rCandidate[nPos])
                {
                    aLimiter = '"';
                    ++nPos;
                }
                else if('\'' == rCandidate[nPos])
                {
                    aLimiter = '\'';
                    ++nPos;
                }
 
                skip_char(rCandidate, ' ', nPos, nLen);
                skip_char(rCandidate, '#', nPos, nPos + 1);
                OUStringBuffer aTokenValue;
 
                copyToLimiter(rCandidate, aLimiter, nPos, aTokenValue, nLen);
 
                rURL = aTokenValue.makeStringAndClear();
 
                return true;
            }
 
            return false;
        }
 
        bool readSvgPaint(const OUString& rCandidate, SvgPaint& rSvgPaint,
            OUString& rURL, SvgNumber& rOpacity)
        {
            if( !rCandidate.isEmpty() )
            {
                basegfx::BColor aColor;
 
                if(read_color(rCandidate, aColor, rOpacity))
                {
                    rSvgPaint = SvgPaint(aColor, true, true);
                    return true;
                }
                else
                {
                    if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(rCandidate), u"none"))
                    {
                        rSvgPaint = SvgPaint(aColor, true, false, false);
                        return true;
                    }
                    else if(readLocalUrl(rCandidate, rURL))
                    {
                        /// Url is copied to rURL, but needs to be solved outside this helper
                        return false;
                    }
                    else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(rCandidate), u"currentColor"))
                    {
                        rSvgPaint = SvgPaint(aColor, true, true, true);
                        return true;
                    }
                }
            }
 
            return false;
        }
 
        bool readSvgNumberVector(std::u16string_view rCandidate, SvgNumberVector& rSvgNumberVector)
        {
            const sal_Int32 nLen(rCandidate.size());
            rSvgNumberVector.clear();
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                SvgNumber aNum;
                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                while(readNumberAndUnit(rCandidate, nPos, aNum, nLen))
                {
                    rSvgNumberVector.push_back(aNum);
                    skip_char(rCandidate, ' ', ',', nPos, nLen);
                }
 
                return !rSvgNumberVector.empty();
            }
 
            return false;
        }
 
        SvgAspectRatio readSvgAspectRatio(std::u16string_view rCandidate)
        {
            const sal_Int32 nLen(rCandidate.size());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                SvgAlign aSvgAlign(SvgAlign::xMidYMid);
                bool bMeetOrSlice(true);
                bool bChanged(false);
 
                while(nPos < nLen)
                {
                    const sal_Int32 nInitPos(nPos);
                    skip_char(rCandidate, ' ', nPos, nLen);
                    OUStringBuffer aTokenName;
                    copyString(rCandidate, nPos, aTokenName, nLen);
 
                    if(!aTokenName.isEmpty())
                    {
                        switch(StrToSVGToken(aTokenName.makeStringAndClear(), false))
                        {
                            case SVGToken::Defer:
                            {
                                bChanged = true;
                                break;
                            }
                            case SVGToken::None:
                            {
                                aSvgAlign = SvgAlign::none;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMinYMin:
                            {
                                aSvgAlign = SvgAlign::xMinYMin;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMidYMin:
                            {
                                aSvgAlign = SvgAlign::xMidYMin;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMaxYMin:
                            {
                                aSvgAlign = SvgAlign::xMaxYMin;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMinYMid:
                            {
                                aSvgAlign = SvgAlign::xMinYMid;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMidYMid:
                            {
                                aSvgAlign = SvgAlign::xMidYMid;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMaxYMid:
                            {
                                aSvgAlign = SvgAlign::xMaxYMid;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMinYMax:
                            {
                                aSvgAlign = SvgAlign::xMinYMax;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMidYMax:
                            {
                                aSvgAlign = SvgAlign::xMidYMax;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::XMaxYMax:
                            {
                                aSvgAlign = SvgAlign::xMaxYMax;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::Meet:
                            {
                                bMeetOrSlice = true;
                                bChanged = true;
                                break;
                            }
                            case SVGToken::Slice:
                            {
                                bMeetOrSlice = false;
                                bChanged = true;
                                break;
                            }
                            default:
                            {
                                break;
                            }
                        }
                    }
 
                    if(nInitPos == nPos)
                    {
                        SAL_WARN("svgio", "Could not interpret on current position (!)");
                        nPos++;
                    }
                }
 
                if(bChanged)
                {
                    return SvgAspectRatio(aSvgAlign, bMeetOrSlice);
                }
            }
 
            return SvgAspectRatio();
        }
 
        bool readSvgStringVector(std::u16string_view rCandidate, SvgStringVector& rSvgStringVector, sal_Unicode nSeparator)
        {
            rSvgStringVector.clear();
            const sal_Int32 nLen(rCandidate.size());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                OUStringBuffer aTokenValue;
                skip_char(rCandidate, ' ', ',', nPos, nLen);
 
                while(nPos < nLen)
                {
                    copyToLimiter(rCandidate, nSeparator, nPos, aTokenValue, nLen);
                    skip_char(rCandidate, nSeparator, nPos, nLen);
                    const OUString aString = aTokenValue.makeStringAndClear();
 
                    if(!aString.isEmpty())
                    {
                        rSvgStringVector.push_back(aString);
                    }
                }
            }
 
            return !rSvgStringVector.empty();
        }
 
        void readImageLink(const OUString& rCandidate, OUString& rXLink, OUString& rUrl, OUString& rData)
        {
            rXLink.clear();
            rUrl.clear();
            rData.clear();
 
            if(!readLocalLink(rCandidate, rXLink))
            {
                static const char aStrData[] = "data:";
 
                if(rCandidate.matchIgnoreAsciiCase(aStrData, 0))
                {
                    // embedded data
                    sal_Int32 nPos(strlen(aStrData));
                    sal_Int32 nLen(rCandidate.getLength());
                    OUStringBuffer aBuffer;
 
                    // read mime type
                    skip_char(rCandidate, ' ', nPos, nLen);
                    copyToLimiter(rCandidate, ';', nPos, aBuffer, nLen);
                    skip_char(rCandidate, ' ', ';', nPos, nLen);
                    const OUString aMimeType = aBuffer.makeStringAndClear();
 
                    if(!aMimeType.isEmpty() && nPos < nLen)
                    {
                        if(aMimeType.startsWith("image"))
                        {
                            // image data
                            std::u16string_view aData(rCandidate.subView(nPos));
                            static constexpr std::u16string_view aStrBase64 = u"base64";
 
                            if(o3tl::starts_with(aData, aStrBase64))
                            {
                                // base64 encoded
                                nPos = aStrBase64.size();
                                nLen = aData.size();
 
                                skip_char(aData, ' ', ',', nPos, nLen);
 
                                if(nPos < nLen)
                                {
                                    rData = aData.substr(nPos);
                                }
                            }
                        }
                    }
                }
                else
                {
                    // Url (path and filename)
                    rUrl = rCandidate;
                }
            }
        }
 
        // #i125325#
        OUString removeBlockComments(const OUString& rCandidate)
        {
            const sal_Int32 nLen(rCandidate.getLength());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                OUStringBuffer aBuffer;
                bool bChanged(false);
                sal_Int32 nInsideComment(0);
                const sal_Unicode aCommentSlash('/');
                const sal_Unicode aCommentStar('*');
 
                while(nPos < nLen)
                {
                    const sal_Unicode aChar(rCandidate[nPos]);
                    const bool bStart(aCommentSlash == aChar && nPos + 1 < nLen && aCommentStar == rCandidate[nPos + 1]);
                    const bool bEnd(aCommentStar == aChar && nPos + 1 < nLen && aCommentSlash == rCandidate[nPos + 1]);
 
                    if(bStart)
                    {
                        nPos += 2;
                        nInsideComment++;
                        bChanged = true;
                    }
                    else if(bEnd)
                    {
                        nPos += 2;
                        nInsideComment--;
                    }
                    else
                    {
                        if(!nInsideComment)
                        {
                            aBuffer.append(aChar);
                        }
 
                        nPos++;
                    }
                }
 
                if(bChanged)
                {
                    return aBuffer.makeStringAndClear();
                }
            }
 
            return rCandidate;
        }
 
        OUString consolidateContiguousSpace(const OUString& rCandidate)
        {
            const sal_Int32 nLen(rCandidate.getLength());
 
            if(nLen)
            {
                sal_Int32 nPos(0);
                OUStringBuffer aBuffer;
                bool bInsideSpace(false);
                const sal_Unicode aSpace(' ');
 
                while(nPos < nLen)
                {
                    const sal_Unicode aChar(rCandidate[nPos]);
 
                    if(aSpace == aChar)
                    {
                        bInsideSpace = true;
                    }
                    else
                    {
                        if(bInsideSpace)
                        {
                            bInsideSpace = false;
                            aBuffer.append(aSpace);
                        }
 
                        aBuffer.append(aChar);
                    }
 
                    nPos++;
                }
 
                if(bInsideSpace)
                {
                    aBuffer.append(aSpace);
                }
 
                if(aBuffer.getLength() != nLen)
                {
                    return aBuffer.makeStringAndClear();
                }
            }
 
            return rCandidate;
        }
 
        ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider)
        {
            ::std::vector< double > aRetval;
 
            if(!rInput.empty())
            {
                const double nCount(rInput.size());
                aRetval.reserve(nCount);
 
                for(sal_uInt32 a(0); a < nCount; a++)
                {
                    aRetval.push_back(rInput[a].solve(rInfoProvider));
                }
            }
 
            return aRetval;
        }
 
} // end of namespace svgio::svgreader
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.