From 2bad9f1cd8da0cd3d8ff33e875eaf10c1fd9d0bf Mon Sep 17 00:00:00 2001 From: Takeshi Abe Date: Sun, 27 Nov 2016 02:55:15 +0900 Subject: tdf#103430 Apply mathvariant attribute to and by emulating it with SmFontNode. In case of , current implementation supports only the one named with an alphabet. Change-Id: I827a7e80f5aa94e243098a6e50eb758cf915c282 Reviewed-on: https://gerrit.libreoffice.org/31240 Tested-by: Jenkins Reviewed-by: Takeshi Abe --- starmath/qa/extras/data/tdf103430.mml | 15 +++ starmath/qa/extras/mmlimport-test.cxx | 11 +- starmath/source/mathmlattr.cxx | 35 ++++++ starmath/source/mathmlattr.hxx | 27 +++++ starmath/source/mathmlimport.cxx | 201 +++++++++++++++++++++++++++++----- starmath/source/mathmlimport.hxx | 3 +- starmath/source/node.cxx | 5 + 7 files changed, 267 insertions(+), 30 deletions(-) create mode 100644 starmath/qa/extras/data/tdf103430.mml diff --git a/starmath/qa/extras/data/tdf103430.mml b/starmath/qa/extras/data/tdf103430.mml new file mode 100644 index 000000000000..92fba05dc295 --- /dev/null +++ b/starmath/qa/extras/data/tdf103430.mml @@ -0,0 +1,15 @@ + + + + + d + 2 + + y + + + d + x + + + diff --git a/starmath/qa/extras/mmlimport-test.cxx b/starmath/qa/extras/mmlimport-test.cxx index 3db697f1f849..01ae2ffaaec7 100644 --- a/starmath/qa/extras/mmlimport-test.cxx +++ b/starmath/qa/extras/mmlimport-test.cxx @@ -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()); } diff --git a/starmath/source/mathmlattr.cxx b/starmath/source/mathmlattr.cxx index 262609f1875d..0c39c3e2862e 100644 --- a/starmath/source/mathmlattr.cxx +++ b/starmath/source/mathmlattr.cxx @@ -10,6 +10,7 @@ #include "mathmlattr.hxx" #include +#include 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 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: */ diff --git a/starmath/source/mathmlattr.hxx b/starmath/source/mathmlattr.hxx index 75dddb06d402..f5402546e68e 100644 --- a/starmath/source/mathmlattr.hxx +++ b/starmath/source/mathmlattr.hxx @@ -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 +// + +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: */ diff --git a/starmath/source/mathmlimport.cxx b/starmath/source/mathmlimport.cxx index dc0d03212fa0..476150850a98 100644 --- a/starmath/source/mathmlimport.cxx +++ b/starmath/source/mathmlimport.cxx @@ -43,6 +43,7 @@ one go*/ #include #include #include +#include #include #include #include @@ -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;igetNameByIndex(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 + // . + 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& xAttrList); + void ApplyAttrs(MathMLMathvariantValue eDefaultMv); +}; + +void SmXMLTokenAttrHelper::RetrieveAttrs(const uno::Reference& xAttrList) +{ + if (!xAttrList.is()) + return; + sal_Int16 nAttrCount = xAttrList->getLength(); + for (sal_Int16 i=0;igetNameByIndex(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 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 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 1) GetSubNode(1)->CreateTextFromNode(rText); + + rText = comphelper::string::stripEnd(rText, ' '); + rText += "} "; } void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell) -- cgit