tdf#103430 Apply mathvariant attribute to <mi> and <mo>

by emulating it with SmFontNode.
In case of <mo>, current implementation supports only the one named
with an alphabet.

Change-Id: I827a7e80f5aa94e243098a6e50eb758cf915c282
Reviewed-on: https://gerrit.libreoffice.org/31240
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Takeshi Abe <tabe@fixedpoint.jp>
This commit is contained in:
Takeshi Abe
2016-11-27 02:55:15 +09:00
parent 9abc547ef2
commit 2bad9f1cd8
7 changed files with 267 additions and 30 deletions

View File

@@ -0,0 +1,15 @@
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mfrac>
<mrow>
<msup>
<mo form="prefix" rspace="0">d</mo>
<mn>2</mn>
</msup>
<mi mathvariant="normal" mathcolor="blue">y</mi>
</mrow>
<mrow>
<mo fontstyle="italic" fontweight="bold" mathvariant="normal" form="prefix" rspace="0">d</mo>
<mi fontfamily="serif" mathvariant="sans-serif-bold-italic" mathcolor="red">x</mi>
</mrow>
</mfrac>
</math>

View File

@@ -34,6 +34,7 @@ public:
void testMaction();
void testMspace();
void testtdf99556();
void testTdf103430();
void testTdf103500();
CPPUNIT_TEST_SUITE(Test);
@@ -42,6 +43,7 @@ public:
CPPUNIT_TEST(testMaction);
CPPUNIT_TEST(testMspace);
CPPUNIT_TEST(testtdf99556);
CPPUNIT_TEST(testTdf103430);
CPPUNIT_TEST(testTdf103500);
CPPUNIT_TEST_SUITE_END();
@@ -122,10 +124,17 @@ void Test::testtdf99556()
CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", sExpected, mxDocShell->GetText());
}
void Test::testTdf103430()
{
loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/tdf103430.mml"));
CPPUNIT_ASSERT_EQUAL(OUString("{{nitalic d}^2 {nitalic {color blue y}}} over {{nitalic d} {font sans {bold {italic {color red x}}}}}"),
mxDocShell->GetText());
}
void Test::testTdf103500()
{
loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/tdf103500.mml"));
CPPUNIT_ASSERT_EQUAL(OUString("{{ int csub a csup b {1 over x ` d x}} = {intd csub a csup b {1 over y ` d y}}}"),
CPPUNIT_ASSERT_EQUAL(OUString("{{ int csub a csup b {1 over x ` {nitalic d} x}} = {intd csub a csup b {1 over y ` {nitalic d} y}}}"),
mxDocShell->GetText());
}

View File

@@ -10,6 +10,7 @@
#include "mathmlattr.hxx"
#include <cassert>
#include <unordered_map>
namespace {
@@ -144,4 +145,38 @@ sal_Int32 ParseMathMLAttributeLengthValue(const OUString &rStr, MathMLAttributeL
return nIdx;
}
bool GetMathMLMathvariantValue(const OUString &rStr, MathMLMathvariantValue *pV)
{
static const std::unordered_map<OUString, MathMLMathvariantValue, OUStringHash> 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}
};
assert(pV);
auto it = aMap.find(rStr);
if (it != aMap.end())
{
*pV = it->second;
return true;
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View File

@@ -47,6 +47,33 @@ struct MathMLAttributeLengthValue
sal_Int32 ParseMathMLAttributeLengthValue(const OUString &rStr, MathMLAttributeLengthValue *pV);
// MathML 3: 3.2.2 Mathematics style attributes common to token elements
// <https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt>
enum class MathMLMathvariantValue {
Normal,
Bold,
Italic,
BoldItalic,
DoubleStruck,
BoldFraktur,
Script,
BoldScript,
Fraktur,
SansSerif,
BoldSansSerif,
SansSerifItalic,
SansSerifBoldItalic,
Monospace,
Initial,
Tailed,
Looped,
Stretched
};
bool GetMathMLMathvariantValue(const OUString &rStr, MathMLMathvariantValue *pV);
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View File

@@ -43,6 +43,7 @@ one go*/
#include <comphelper/servicehelper.hxx>
#include <comphelper/string.hxx>
#include <o3tl/make_unique.hxx>
#include <rtl/character.hxx>
#include <rtl/math.hxx>
#include <sfx2/frame.hxx>
#include <sfx2/docfile.hxx>
@@ -573,7 +574,6 @@ struct SmXMLContext_Helper
sal_Int8 nIsBold;
sal_Int8 nIsItalic;
double nFontSize;
bool bFontNodeNeeded;
OUString sFontFamily;
OUString sColor;
@@ -583,22 +583,28 @@ struct SmXMLContext_Helper
: nIsBold( -1 )
, nIsItalic( -1 )
, nFontSize( 0.0 )
, bFontNodeNeeded( false )
, rContext( rImport )
{}
bool IsFontNodeNeeded() const;
void RetrieveAttrs(const uno::Reference< xml::sax::XAttributeList > &xAttrList );
void ApplyAttrs();
};
bool SmXMLContext_Helper::IsFontNodeNeeded() const
{
return nIsBold != -1 ||
nIsItalic != -1 ||
nFontSize != 0.0 ||
!sFontFamily.isEmpty() ||
!sColor.isEmpty();
}
void SmXMLContext_Helper::RetrieveAttrs(const uno::Reference<
xml::sax::XAttributeList > & xAttrList )
{
sal_Int8 nOldIsBold=nIsBold;
sal_Int8 nOldIsItalic=nIsItalic;
double nOldFontSize=nFontSize;
bool bMvFound = false;
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
OUString sOldFontFamily = sFontFamily;
for (sal_Int16 i=0;i<nAttrCount;i++)
{
OUString sAttrName = xAttrList->getNameByIndex(i);
@@ -640,24 +646,30 @@ void SmXMLContext_Helper::RetrieveAttrs(const uno::Reference<
case XML_TOK_MATHCOLOR:
sColor = sValue;
break;
case XML_TOK_MATHVARIANT:
bMvFound = true;
break;
default:
break;
}
}
if ((nOldIsBold!=nIsBold) || (nOldIsItalic!=nIsItalic) ||
(nOldFontSize!=nFontSize) || (sOldFontFamily!=sFontFamily)
|| !sColor.isEmpty())
bFontNodeNeeded=true;
else
bFontNodeNeeded=false;
if (bMvFound)
{
// Ignore deprecated attributes fontfamily, fontweight, and fontstyle
// in favor of mathvariant, as specified in
// <https://www.w3.org/TR/MathML3/chapter3.html#presm.deprecatt>.
sFontFamily.clear();
nIsBold = -1;
nIsItalic = -1;
}
}
void SmXMLContext_Helper::ApplyAttrs()
{
SmNodeStack &rNodeStack = rContext.GetSmImport().GetNodeStack();
if (bFontNodeNeeded)
if (IsFontNodeNeeded())
{
SmToken aToken;
aToken.cMathChar = '\0';
@@ -741,6 +753,131 @@ void SmXMLContext_Helper::ApplyAttrs()
}
class SmXMLTokenAttrHelper
{
SmXMLImportContext& mrContext;
MathMLMathvariantValue meMv;
bool mbMvFound;
public:
SmXMLTokenAttrHelper(SmXMLImportContext& rContext)
: mrContext(rContext)
, meMv(MathMLMathvariantValue::Normal)
, mbMvFound(false)
{}
void RetrieveAttrs(const uno::Reference<xml::sax::XAttributeList>& xAttrList);
void ApplyAttrs(MathMLMathvariantValue eDefaultMv);
};
void SmXMLTokenAttrHelper::RetrieveAttrs(const uno::Reference<xml::sax::XAttributeList>& xAttrList)
{
if (!xAttrList.is())
return;
sal_Int16 nAttrCount = xAttrList->getLength();
for (sal_Int16 i=0;i<nAttrCount;i++)
{
OUString sAttrName = xAttrList->getNameByIndex(i);
OUString aLocalName;
sal_uInt16 nPrefix = mrContext.GetSmImport().GetNamespaceMap().
GetKeyByAttrName(sAttrName, &aLocalName);
OUString sValue = xAttrList->getValueByIndex(i);
const SvXMLTokenMap &rAttrTokenMap =
mrContext.GetSmImport().GetPresLayoutAttrTokenMap();
switch(rAttrTokenMap.Get(nPrefix, aLocalName))
{
case XML_TOK_MATHVARIANT:
if (!GetMathMLMathvariantValue(sValue, &meMv))
SAL_WARN("starmath", "failed to recognize mathvariant: " << sValue);
mbMvFound = true;
break;
default:
break;
}
}
}
void SmXMLTokenAttrHelper::ApplyAttrs(MathMLMathvariantValue eDefaultMv)
{
assert( eDefaultMv == MathMLMathvariantValue::Normal ||
eDefaultMv == MathMLMathvariantValue::Italic );
std::vector<SmTokenType> vVariant;
MathMLMathvariantValue eMv = mbMvFound ? meMv : eDefaultMv;
switch(eMv)
{
case MathMLMathvariantValue::Normal:
vVariant.push_back(TNITALIC);
break;
case MathMLMathvariantValue::Bold:
vVariant.push_back(TBOLD);
break;
case MathMLMathvariantValue::Italic:
// nothing to do
break;
case MathMLMathvariantValue::BoldItalic:
vVariant.push_back(TITALIC);
vVariant.push_back(TBOLD);
break;
case MathMLMathvariantValue::DoubleStruck:
// TODO
break;
case MathMLMathvariantValue::BoldFraktur:
// TODO: Fraktur
vVariant.push_back(TBOLD);
break;
case MathMLMathvariantValue::Script:
// TODO
break;
case MathMLMathvariantValue::BoldScript:
// TODO: Script
vVariant.push_back(TBOLD);
break;
case MathMLMathvariantValue::Fraktur:
// TODO
break;
case MathMLMathvariantValue::SansSerif:
vVariant.push_back(TSANS);
break;
case MathMLMathvariantValue::BoldSansSerif:
vVariant.push_back(TSANS);
vVariant.push_back(TBOLD);
break;
case MathMLMathvariantValue::SansSerifItalic:
vVariant.push_back(TITALIC);
vVariant.push_back(TSANS);
break;
case MathMLMathvariantValue::SansSerifBoldItalic:
vVariant.push_back(TITALIC);
vVariant.push_back(TBOLD);
vVariant.push_back(TSANS);
break;
case MathMLMathvariantValue::Monospace:
vVariant.push_back(TFIXED);
break;
case MathMLMathvariantValue::Initial:
case MathMLMathvariantValue::Tailed:
case MathMLMathvariantValue::Looped:
case MathMLMathvariantValue::Stretched:
// TODO
break;
}
if (vVariant.empty())
return;
SmNodeStack &rNodeStack = mrContext.GetSmImport().GetNodeStack();
for (auto eType : vVariant)
{
SmToken aToken;
aToken.eType = eType;
aToken.cMathChar = '\0';
aToken.nLevel = 5;
std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(aToken));
pFontNode->SetSubNodes(nullptr, popOrZero(rNodeStack));
rNodeStack.push_front(std::move(pFontNode));
}
}
class SmXMLDocContext_Impl : public SmXMLImportContext
{
public:
@@ -1198,14 +1335,16 @@ void SmXMLStringContext_Impl::EndElement()
class SmXMLIdentifierContext_Impl : public SmXMLImportContext
{
protected:
SmXMLTokenAttrHelper maTokenAttrHelper;
SmXMLContext_Helper aStyleHelper;
SmToken aToken;
public:
SmXMLIdentifierContext_Impl(SmXMLImport &rImport,sal_uInt16 nPrefix,
const OUString& rLName)
: SmXMLImportContext(rImport,nPrefix,rLName),aStyleHelper(*this)
: SmXMLImportContext(rImport,nPrefix,rLName)
, maTokenAttrHelper(*this)
, aStyleHelper(*this)
{
aToken.cMathChar = '\0';
aToken.nLevel = 5;
@@ -1215,6 +1354,7 @@ public:
void TCharacters(const OUString &rChars) override;
void StartElement(const uno::Reference< xml::sax::XAttributeList > & xAttrList ) override
{
maTokenAttrHelper.RetrieveAttrs(xAttrList);
aStyleHelper.RetrieveAttrs(xAttrList);
};
void EndElement() override;
@@ -1234,23 +1374,20 @@ void SmXMLIdentifierContext_Impl::EndElement()
}
else
pNode.reset(new SmTextNode(aToken,FNT_VARIABLE));
if (aStyleHelper.bFontNodeNeeded && aStyleHelper.nIsItalic != -1)
if (aStyleHelper.nIsItalic != -1)
{
if (aStyleHelper.nIsItalic)
pNode->GetFont().SetItalic(ITALIC_NORMAL);
else
pNode->GetFont().SetItalic(ITALIC_NONE);
aStyleHelper.nIsItalic = -1;
}
if ((-1!=aStyleHelper.nIsBold) || (0.0!=aStyleHelper.nFontSize) ||
(!aStyleHelper.sFontFamily.isEmpty()) ||
!aStyleHelper.sColor.isEmpty())
aStyleHelper.bFontNodeNeeded=true;
else
aStyleHelper.bFontNodeNeeded=false;
if (aStyleHelper.bFontNodeNeeded)
aStyleHelper.ApplyAttrs();
GetSmImport().GetNodeStack().push_front(std::move(pNode));
aStyleHelper.ApplyAttrs();
maTokenAttrHelper.ApplyAttrs( (aToken.aText.getLength() == 1)
? MathMLMathvariantValue::Italic
: MathMLMathvariantValue::Normal );
}
void SmXMLIdentifierContext_Impl::TCharacters(const OUString &rChars)
@@ -1261,15 +1398,16 @@ void SmXMLIdentifierContext_Impl::TCharacters(const OUString &rChars)
class SmXMLOperatorContext_Impl : public SmXMLImportContext
{
SmXMLTokenAttrHelper maTokenAttrHelper;
bool bIsStretchy;
protected:
SmToken aToken;
public:
SmXMLOperatorContext_Impl(SmXMLImport &rImport,sal_uInt16 nPrefix,
const OUString& rLName)
: SmXMLImportContext(rImport,nPrefix,rLName), bIsStretchy(false)
: SmXMLImportContext(rImport,nPrefix,rLName)
, maTokenAttrHelper(*this)
, bIsStretchy(false)
{
aToken.eType = TSPECIAL;
aToken.nLevel = 5;
@@ -1294,12 +1432,18 @@ void SmXMLOperatorContext_Impl::EndElement()
if (bIsStretchy)
pNode->SetScaleMode(SCALE_HEIGHT);
GetSmImport().GetNodeStack().push_front(std::move(pNode));
// TODO: apply to non-alphabetic characters too
if (rtl::isAsciiAlpha(aToken.cMathChar))
maTokenAttrHelper.ApplyAttrs(MathMLMathvariantValue::Normal);
}
void SmXMLOperatorContext_Impl::StartElement(const uno::Reference<
xml::sax::XAttributeList > & xAttrList )
{
maTokenAttrHelper.RetrieveAttrs(xAttrList);
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for (sal_Int16 i=0;i<nAttrCount;i++)
{
@@ -1885,6 +2029,7 @@ static const SvXMLTokenMapEntry aPresLayoutAttrTokenMap[] =
{ XML_NAMESPACE_MATH, XML_FONTFAMILY, XML_TOK_FONTFAMILY },
{ XML_NAMESPACE_MATH, XML_COLOR, XML_TOK_COLOR },
{ XML_NAMESPACE_MATH, XML_MATHCOLOR, XML_TOK_MATHCOLOR },
{ XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_TOK_MATHVARIANT },
XML_TOKEN_MAP_END
};

View File

@@ -286,7 +286,8 @@ enum SmXMLPresLayoutAttrTokenMap
XML_TOK_FONTSIZE,
XML_TOK_FONTFAMILY,
XML_TOK_COLOR,
XML_TOK_MATHCOLOR
XML_TOK_MATHCOLOR,
XML_TOK_MATHVARIANT
};

View File

@@ -1710,6 +1710,8 @@ void SmAttributNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
void SmFontNode::CreateTextFromNode(OUString &rText)
{
rText += "{";
switch (GetToken().eType)
{
case TBOLD:
@@ -1823,6 +1825,9 @@ void SmFontNode::CreateTextFromNode(OUString &rText)
}
if(GetNumSubNodes() > 1)
GetSubNode(1)->CreateTextFromNode(rText);
rText = comphelper::string::stripEnd(rText, ' ');
rText += "} ";
}
void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)