Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / starmath / source / mathml / mathmlattr.cxx
blob5e54f0d92e3eddd66b52cc918f6f8a7458515ec4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <mathmlattr.hxx>
12 #include <o3tl/safeint.hxx>
13 #include <o3tl/string_view.hxx>
14 #include <rtl/math.h>
16 #include <cstddef>
17 #include <string_view>
18 #include <unordered_map>
20 static std::size_t ParseMathMLUnsignedNumber(std::u16string_view rStr, Fraction& rUN)
22 auto nLen = rStr.length();
23 std::size_t nDecimalPoint = std::u16string_view::npos;
24 std::size_t nIdx;
25 sal_Int64 nom = 0;
26 sal_Int64 den = 1;
27 bool validNomDen = true;
28 for (nIdx = 0; nIdx < nLen; nIdx++)
30 auto cD = rStr[nIdx];
31 if (cD == u'.')
33 if (nDecimalPoint != std::u16string_view::npos)
34 return std::u16string_view::npos;
35 nDecimalPoint = nIdx;
36 continue;
38 if (cD < u'0' || u'9' < cD)
39 break;
40 if (validNomDen
41 && (o3tl::checked_multiply(nom, sal_Int64(10), nom)
42 || o3tl::checked_add(nom, sal_Int64(cD - u'0'), nom)
43 || nom >= std::numeric_limits<sal_Int32>::max()
44 || (nDecimalPoint != std::u16string_view::npos
45 && o3tl::checked_multiply(den, sal_Int64(10), den))))
47 validNomDen = false;
50 if (nIdx == 0 || (nIdx == 1 && nDecimalPoint == 0))
51 return std::u16string_view::npos;
53 // If the input "xx.yyy" can be represented with nom = xx*10^n + yyy and den = 10^n in sal_Int64
54 // (where n is the length of "yyy"), then use that to create an accurate Fraction (and TODO: we
55 // could even ignore trailing "0" characters in "yyy", for a smaller n and thus a greater chance
56 // of validNomDen); if not, use the less accurate approach of creating a Fraction from double:
57 if (validNomDen)
59 rUN = Fraction(nom, den);
61 else
63 rUN = Fraction(
64 rtl_math_uStringToDouble(rStr.data(), rStr.data() + nIdx, '.', 0, nullptr, nullptr));
67 return nIdx;
70 static std::size_t ParseMathMLNumber(std::u16string_view rStr, Fraction& rN)
72 if (rStr.empty())
73 return std::u16string_view::npos;
74 bool bNegative = (rStr[0] == '-');
75 std::size_t nOffset = bNegative ? 1 : 0;
76 auto nIdx = ParseMathMLUnsignedNumber(rStr.substr(nOffset), rN);
77 if (nIdx == std::u16string_view::npos || !rN.IsValid())
78 return std::u16string_view::npos;
79 if (bNegative)
80 rN *= -1;
81 return nOffset + nIdx;
84 bool ParseMathMLAttributeLengthValue(std::u16string_view rStr, MathMLAttributeLengthValue& rV)
86 auto nIdx = ParseMathMLNumber(rStr, rV.aNumber);
87 if (nIdx == std::u16string_view::npos)
88 return false;
89 std::u16string_view sRest = rStr.substr(nIdx);
90 if (sRest.empty())
92 rV.eUnit = MathMLLengthUnit::None;
94 if (o3tl::starts_with(sRest, u"em"))
96 rV.eUnit = MathMLLengthUnit::Em;
98 if (o3tl::starts_with(sRest, u"ex"))
100 rV.eUnit = MathMLLengthUnit::Ex;
102 if (o3tl::starts_with(sRest, u"px"))
104 rV.eUnit = MathMLLengthUnit::Px;
106 if (o3tl::starts_with(sRest, u"in"))
108 rV.eUnit = MathMLLengthUnit::In;
110 if (o3tl::starts_with(sRest, u"cm"))
112 rV.eUnit = MathMLLengthUnit::Cm;
114 if (o3tl::starts_with(sRest, u"mm"))
116 rV.eUnit = MathMLLengthUnit::Mm;
118 if (o3tl::starts_with(sRest, u"pt"))
120 rV.eUnit = MathMLLengthUnit::Pt;
122 if (o3tl::starts_with(sRest, u"pc"))
124 rV.eUnit = MathMLLengthUnit::Pc;
126 if (sRest[0] == u'%')
128 rV.eUnit = MathMLLengthUnit::Percent;
130 return true;
133 bool GetMathMLMathvariantValue(const OUString& rStr, MathMLMathvariantValue& rV)
135 static const std::unordered_map<OUString, MathMLMathvariantValue> aMap{
136 { "normal", MathMLMathvariantValue::Normal },
137 { "bold", MathMLMathvariantValue::Bold },
138 { "italic", MathMLMathvariantValue::Italic },
139 { "bold-italic", MathMLMathvariantValue::BoldItalic },
140 { "double-struck", MathMLMathvariantValue::DoubleStruck },
141 { "bold-fraktur", MathMLMathvariantValue::BoldFraktur },
142 { "script", MathMLMathvariantValue::Script },
143 { "bold-script", MathMLMathvariantValue::BoldScript },
144 { "fraktur", MathMLMathvariantValue::Fraktur },
145 { "sans-serif", MathMLMathvariantValue::SansSerif },
146 { "bold-sans-serif", MathMLMathvariantValue::BoldSansSerif },
147 { "sans-serif-italic", MathMLMathvariantValue::SansSerifItalic },
148 { "sans-serif-bold-italic", MathMLMathvariantValue::SansSerifBoldItalic },
149 { "monospace", MathMLMathvariantValue::Monospace },
150 { "initial", MathMLMathvariantValue::Initial },
151 { "tailed", MathMLMathvariantValue::Tailed },
152 { "looped", MathMLMathvariantValue::Looped },
153 { "stretched", MathMLMathvariantValue::Stretched }
156 auto it = aMap.find(rStr);
157 if (it != aMap.end())
159 rV = it->second;
160 return true;
162 return false;
165 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */