1
0
Fork 0
libreoffice/starmath/source/mathml/mathmlattr.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

165 lines
5.3 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* 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/.
*/
#include <mathmlattr.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <rtl/math.h>
#include <cstddef>
#include <string_view>
#include <unordered_map>
static std::size_t ParseMathMLUnsignedNumber(std::u16string_view rStr, Fraction& rUN)
{
auto nLen = rStr.length();
std::size_t nDecimalPoint = std::u16string_view::npos;
std::size_t nIdx;
sal_Int64 nom = 0;
sal_Int64 den = 1;
bool validNomDen = true;
for (nIdx = 0; nIdx < nLen; nIdx++)
{
auto cD = rStr[nIdx];
if (cD == u'.')
{
if (nDecimalPoint != std::u16string_view::npos)
return std::u16string_view::npos;
nDecimalPoint = nIdx;
continue;
}
if (cD < u'0' || u'9' < cD)
break;
if (validNomDen
&& (o3tl::checked_multiply(nom, sal_Int64(10), nom)
|| o3tl::checked_add(nom, sal_Int64(cD - u'0'), nom)
|| nom >= std::numeric_limits<sal_Int32>::max()
|| (nDecimalPoint != std::u16string_view::npos
&& o3tl::checked_multiply(den, sal_Int64(10), den))))
{
validNomDen = false;
}
}
if (nIdx == 0 || (nIdx == 1 && nDecimalPoint == 0))
return std::u16string_view::npos;
// If the input "xx.yyy" can be represented with nom = xx*10^n + yyy and den = 10^n in sal_Int64
// (where n is the length of "yyy"), then use that to create an accurate Fraction (and TODO: we
// could even ignore trailing "0" characters in "yyy", for a smaller n and thus a greater chance
// of validNomDen); if not, use the less accurate approach of creating a Fraction from double:
if (validNomDen)
{
rUN = Fraction(nom, den);
}
else
{
rUN = Fraction(
rtl_math_uStringToDouble(rStr.data(), rStr.data() + nIdx, '.', 0, nullptr, nullptr));
}
return nIdx;
}
static std::size_t ParseMathMLNumber(std::u16string_view rStr, Fraction& rN)
{
if (rStr.empty())
return std::u16string_view::npos;
bool bNegative = (rStr[0] == '-');
std::size_t nOffset = bNegative ? 1 : 0;
auto nIdx = ParseMathMLUnsignedNumber(rStr.substr(nOffset), rN);
if (nIdx == std::u16string_view::npos || !rN.IsValid())
return std::u16string_view::npos;
if (bNegative)
rN *= -1;
return nOffset + nIdx;
}
bool ParseMathMLAttributeLengthValue(std::u16string_view rStr, MathMLAttributeLengthValue& rV)
{
auto nIdx = ParseMathMLNumber(rStr, rV.aNumber);
if (nIdx == std::u16string_view::npos)
return false;
std::u16string_view sRest = rStr.substr(nIdx);
if (sRest.empty())
{
rV.eUnit = MathMLLengthUnit::None;
}
if (o3tl::starts_with(sRest, u"em"))
{
rV.eUnit = MathMLLengthUnit::Em;
}
if (o3tl::starts_with(sRest, u"ex"))
{
rV.eUnit = MathMLLengthUnit::Ex;
}
if (o3tl::starts_with(sRest, u"px"))
{
rV.eUnit = MathMLLengthUnit::Px;
}
if (o3tl::starts_with(sRest, u"in"))
{
rV.eUnit = MathMLLengthUnit::In;
}
if (o3tl::starts_with(sRest, u"cm"))
{
rV.eUnit = MathMLLengthUnit::Cm;
}
if (o3tl::starts_with(sRest, u"mm"))
{
rV.eUnit = MathMLLengthUnit::Mm;
}
if (o3tl::starts_with(sRest, u"pt"))
{
rV.eUnit = MathMLLengthUnit::Pt;
}
if (o3tl::starts_with(sRest, u"pc"))
{
rV.eUnit = MathMLLengthUnit::Pc;
}
if (sRest[0] == u'%')
{
rV.eUnit = MathMLLengthUnit::Percent;
}
return true;
}
bool GetMathMLMathvariantValue(const OUString& rStr, MathMLMathvariantValue& rV)
{
static const std::unordered_map<OUString, MathMLMathvariantValue> aMap{
{ "normal", MathMLMathvariantValue::Normal },
{ "bold", MathMLMathvariantValue::Bold },
{ "italic", MathMLMathvariantValue::Italic },
{ "bold-italic", MathMLMathvariantValue::BoldItalic },
{ "double-struck", MathMLMathvariantValue::DoubleStruck },
{ "bold-fraktur", MathMLMathvariantValue::BoldFraktur },
{ "script", MathMLMathvariantValue::Script },
{ "bold-script", MathMLMathvariantValue::BoldScript },
{ "fraktur", MathMLMathvariantValue::Fraktur },
{ "sans-serif", MathMLMathvariantValue::SansSerif },
{ "bold-sans-serif", MathMLMathvariantValue::BoldSansSerif },
{ "sans-serif-italic", MathMLMathvariantValue::SansSerifItalic },
{ "sans-serif-bold-italic", MathMLMathvariantValue::SansSerifBoldItalic },
{ "monospace", MathMLMathvariantValue::Monospace },
{ "initial", MathMLMathvariantValue::Initial },
{ "tailed", MathMLMathvariantValue::Tailed },
{ "looped", MathMLMathvariantValue::Looped },
{ "stretched", MathMLMathvariantValue::Stretched }
};
auto it = aMap.find(rStr);
if (it != aMap.end())
{
rV = it->second;
return true;
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */