/* -*- 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 .
*/
/*todo: Change characters and tcharacters to accumulate the characters together into one string, xml parser hands them to us line by line rather than all in
one go*/
// Set base URI
OUString const baseURI(rMedium.GetBaseURL()); // needed for relative URLs; but it's OK to import e.g. MathML from the // clipboard without one
SAL_INFO_IF(baseURI.isEmpty(), "starmath", "SmXMLImportWrapper: no base URL");
xInfoSet->setPropertyValue(u"BaseURI"_ustr, Any(baseURI));
sal_Int32 nSteps = 3; if (!(rMedium.IsStorage()))
nSteps = 1;
sal_Int32 nProgressRange(nSteps); if (xStatusIndicator.is())
{
xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
}
nSteps = 0; if (xStatusIndicator.is())
xStatusIndicator->setValue(nSteps++);
if (rMedium.IsStorage())
{ // TODO/LATER: handle the case of embedded links gracefully if (bEmbedded) // && !rMedium.GetStorage()->IsRoot() )
{
OUString aName(u"dummyObjName"_ustr); const SfxStringItem* pDocHierarchItem
= rMedium.GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME); if (pDocHierarchItem)
aName = pDocHierarchItem->GetValue();
if (!aName.isEmpty())
{
xInfoSet->setPropertyValue(u"StreamRelPath"_ustr, Any(aName));
}
}
bool bOASIS = (SotStorage::GetVersion(rMedium.GetStorage()) > SOFFICE_FILEFORMAT_60); if (xStatusIndicator.is())
xStatusIndicator->setValue(nSteps++);
// determine if stream is encrypted or not
uno::Reference<beans::XPropertySet> xProps(xEventsStream, uno::UNO_QUERY);
Any aAny = xProps->getPropertyValue(u"Encrypted"_ustr); bool bEncrypted = false; if (aAny.getValueType() == cppu::UnoType<bool>::get())
aAny >>= bEncrypted;
// set Base URL if (rPropSet.is())
{
rPropSet->setPropertyValue(u"StreamName"_ustr, Any(sStreamName));
}
void SmXMLImport::endDocument()
{ //Set the resulted tree into the SmDocShell where it belongs
std::unique_ptr<SmNode> pTree = popOrZero(aNodeStack); if (pTree && pTree->GetType() == SmNodeType::Table)
{
uno::Reference<frame::XModel> xModel = GetModel();
SmModel* pModel = dynamic_cast<SmModel*>(xModel.get());
if (pModel)
{
SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell()); auto pTreeTmp = pTree.get();
pDocShell->SetFormulaTree(static_cast<SmTableNode*>(pTree.release())); if (aText.isEmpty()) //If we picked up no annotation text
{ // Get text from imported formula
SmNodeToTextVisitor tmpvisitor(pTreeTmp, aText);
}
void SmXMLImportContext::characters(const OUString& rChars)
{ /* Whitespace occurring within the content of token elements is "trimmed" from the ends (i.e. all whitespace at the beginning and end of the content is removed), and "collapsed" internally (i.e. each sequence of 1 or more whitespace characters is replaced with one blank character).
*/ //collapsing not done yet! const OUString aChars2 = rChars.trim(); if (!aChars2.isEmpty())
TCharacters(aChars2 /*.collapse()*/);
}
void SmXMLContext_Helper::RetrieveAttrs( const uno::Reference<xml::sax::XFastAttributeList>& xAttrList)
{ bool bMvFound = false; for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList))
{ // sometimes they have namespace, sometimes not? switch (aIter.getToken() & TOKEN_MASK)
{ case XML_FONTWEIGHT:
nIsBold = sal_Int8(IsXMLToken(aIter, XML_BOLD)); break; case XML_FONTSTYLE:
nIsItalic = sal_Int8(IsXMLToken(aIter, XML_ITALIC)); break; case XML_FONTSIZE: case XML_MATHSIZE:
{
OUString sValue = aIter.toString();
::sax::Converter::convertDouble(nFontSize, sValue);
rContext.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
util::MeasureUnit::POINT); if (-1 == sValue.indexOf(GetXMLToken(XML_UNIT_PT)))
{ if (-1 == sValue.indexOf('%'))
nFontSize = 0.0; else
{
rContext.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
util::MeasureUnit::PERCENT);
}
} break;
} case XML_FONTFAMILY:
sFontFamily = aIter.toString(); break; case XML_COLOR: case XML_MATHCOLOR:
sColor = aIter.toString(); break; case XML_MATHVARIANT:
bMvFound = true; break; default:
XMLOFF_WARN_UNKNOWN("starmath", aIter); break;
}
}
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;
}
}
pFontNode->SetSubNodes(nullptr, popOrZero(rNodeStack));
rNodeStack.push_front(std::move(pFontNode));
} if (!sColor.isEmpty())
{
SmColorTokenTableEntry aSmColorTokenTableEntry;
aSmColorTokenTableEntry = starmathdatabase::Identify_ColorName_HTML(sColor); if (aSmColorTokenTableEntry.eType == TRGB)
aSmColorTokenTableEntry = starmathdatabase::Identify_Color_Parser(
sal_uInt32(aSmColorTokenTableEntry.cColor)); if (aSmColorTokenTableEntry.eType != TERROR)
{
aToken = aSmColorTokenTableEntry;
std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(aToken));
pFontNode->SetSubNodes(nullptr, popOrZero(rNodeStack));
rNodeStack.push_front(std::move(pFontNode));
} // If not known, not implemented yet. Giving up.
} if (sFontFamily.isEmpty()) return;
if (sFontFamily.equalsIgnoreAsciiCase(GetXMLToken(XML_FIXED)))
aToken.eType = TFIXED; elseif (sFontFamily.equalsIgnoreAsciiCase("sans"))
aToken.eType = TSANS; elseif (sFontFamily.equalsIgnoreAsciiCase("serif"))
aToken.eType = TSERIF; else//Just give up, we need to extend our font mechanism to be //more general return;
std::vector<SmTokenType> vVariant;
MathMLMathvariantValue eMv = mbMvFound ? meMv : eDefaultMv; switch (eMv)
{ case MathMLMathvariantValue::Normal:
vVariant.push_back(TNITALIC); break; case MathMLMathvariantValue::Bold: case MathMLMathvariantValue::BoldFraktur: // TODO: Fraktur case MathMLMathvariantValue::BoldScript: // TODO: Script
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::Script: // TODO 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 = u""_ustr;
aToken.nLevel = 5;
std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(aToken));
pFontNode->SetSubNodes(nullptr, popOrZero(rNodeStack));
rNodeStack.push_front(std::move(pFontNode));
}
}
namespace
{ class SmXMLDocContext_Impl : public SmXMLImportContext
{ public:
SmXMLDocContext_Impl(SmXMLImport& rImport)
: SmXMLImportContext(rImport)
{
}
class SmXMLEncloseContext_Impl : public SmXMLRowContext_Impl
{ public: // TODO/LATER: convert <menclose notation="horizontalstrike"> into // "overstrike{}" and extend the Math syntax to support more notations
SmXMLEncloseContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
{
}
void SmXMLEncloseContext_Impl::endFastElement(sal_Int32 nElement)
{ /* <menclose> accepts any number of arguments; if this number is not 1, its contents are treated as a single "inferred <mrow>" containing its arguments
*/ if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
SmXMLRowContext_Impl::endFastElement(nElement);
}
namespace
{ class SmXMLFracContext_Impl : public SmXMLRowContext_Impl
{ public: // TODO/LATER: convert <mfrac bevelled="true"> into "wideslash{}{}"
SmXMLFracContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
{
}
class SmXMLStyleContext_Impl : public SmXMLRowContext_Impl
{ protected:
SmXMLContext_Helper aStyleHelper;
public: /*Right now the style tag is completely ignored*/
SmXMLStyleContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
, aStyleHelper(*this)
{
}
void SmXMLStyleContext_Impl::endFastElement(sal_Int32 nElement)
{ /* <mstyle> accepts any number of arguments; if this number is not 1, its contents are treated as a single "inferred <mrow>" containing its arguments
*/
SmNodeStack& rNodeStack = GetSmImport().GetNodeStack(); if (rNodeStack.size() - nElementCount != 1)
SmXMLRowContext_Impl::endFastElement(nElement);
aStyleHelper.ApplyAttrs();
}
namespace
{ class SmXMLPaddedContext_Impl : public SmXMLRowContext_Impl
{ public: /*Right now the style tag is completely ignored*/
SmXMLPaddedContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
{
}
void SmXMLPaddedContext_Impl::endFastElement(sal_Int32 nElement)
{ /* <mpadded> accepts any number of arguments; if this number is not 1, its contents are treated as a single "inferred <mrow>" containing its arguments
*/ if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
SmXMLRowContext_Impl::endFastElement(nElement);
}
namespace
{ class SmXMLPhantomContext_Impl : public SmXMLRowContext_Impl
{ public: /*Right now the style tag is completely ignored*/
SmXMLPhantomContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
{
}
void SmXMLPhantomContext_Impl::endFastElement(sal_Int32 nElement)
{ /* <mphantom> accepts any number of arguments; if this number is not 1, its contents are treated as a single "inferred <mrow>" containing its arguments
*/ if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
SmXMLRowContext_Impl::endFastElement(nElement);
pSNode->SetSubNodes(std::move(pLeft), std::move(pBody), std::move(pRight)); // mfenced is always scalable. Stretchy keyword is not official, but in case of been in there // can be used as a hint.
pSNode->SetScaleMode(SmScaleMode::Height);
GetSmImport().GetNodeStack().push_front(std::move(pSNode));
}
namespace
{ class SmXMLErrorContext_Impl : public SmXMLRowContext_Impl
{ public:
SmXMLErrorContext_Impl(SmXMLImport& rImport)
: SmXMLRowContext_Impl(rImport)
{
}
void SmXMLErrorContext_Impl::endFastElement(sal_Int32 /*nElement*/)
{ /*Right now the error tag is completely ignored, what can I do with it in starmath, ?, maybe we need a report window ourselves, do a test for validity of the xml input, use mirrors, and then generate the markup inside the merror with a big red colour of something. For now just throw them all away.
*/
SmNodeStack& rNodeStack = GetSmImport().GetNodeStack(); while (rNodeStack.size() > nElementCount)
{
rNodeStack.pop_front();
}
}
namespace
{ class SmXMLNumberContext_Impl : public SmXMLImportContext
{ protected:
SmToken aToken;
void SmXMLStringContext_Impl::TCharacters(const OUString& rChars)
{ /* The content of <ms> elements should be rendered with visible "escaping" of certain characters in the content, including at least "double quote" itself, and preferably whitespace other than individual blanks. The intent is for the viewer to see that the expression is a string literal, and to see exactly which characters form its content. For example, <ms>double quote is "</ms> might be rendered as "double quote is \"".
void SmXMLOperatorContext_Impl::endFastElement(sal_Int32)
{
std::unique_ptr<SmMathSymbolNode> pNode(new SmMathSymbolNode(aToken)); //For stretchy scaling the scaling must be retrieved from this node //and applied to the expression itself so as to get the expression //to scale the operator to the height of the expression itself if (bIsStretchy)
pNode->SetScaleMode(SmScaleMode::Height);
GetSmImport().GetNodeStack().push_front(std::move(pNode));
// TODO: apply to non-alphabetic characters too if (rtl::isAsciiAlpha(aToken.cMathChar[0]))
maTokenAttrHelper.ApplyAttrs(MathMLMathvariantValue::Normal);
}
bool lcl_CountBlanks(const MathMLAttributeLengthValue& rLV, sal_Int32* pWide, sal_Int32* pNarrow)
{
assert(pWide);
assert(pNarrow); if (rLV.aNumber.GetNumerator() == 0)
{
*pWide = *pNarrow = 0; returntrue;
} // TODO: honor other units than em if (rLV.eUnit != MathMLLengthUnit::Em) returnfalse; if (rLV.aNumber.GetNumerator() < 0) returnfalse; const Fraction aTwo(2, 1); auto aWide = rLV.aNumber / aTwo; auto nWide = static_cast<sal_Int32>(static_cast<tools::Long>(aWide)); if (nWide < 0) returnfalse; const Fraction aPointFive(1, 2); auto aNarrow = (rLV.aNumber - Fraction(nWide, 1) * aTwo) / aPointFive; auto nNarrow = static_cast<sal_Int32>(static_cast<tools::Long>(aNarrow)); if (nNarrow < 0) returnfalse;
*pWide = nWide;
*pNarrow = nNarrow; returntrue;
}
}
void SmXMLSpaceContext_Impl::startFastElement(
sal_Int32 /*nElement*/, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList)
{ // There is no syntax in Math to specify blank nodes of arbitrary size yet.
MathMLAttributeLengthValue aLV;
sal_Int32 nWide = 0, nNarrow = 0;
void SmXMLUnderContext_Impl::HandleAccent()
{ constbool bNodeCheck = GetSmImport().GetNodeStack().size() - nElementCount == 2;
OSL_ENSURE(bNodeCheck, "Sub has not two arguments"); if (!bNodeCheck) return;
/*Just one special case for the underline thing*/
SmNodeStack& rNodeStack = GetSmImport().GetNodeStack();
std::unique_ptr<SmNode> pTest = popOrZero(rNodeStack);
SmToken aToken;
aToken.cMathChar = u""_ustr;
aToken.eType = TUNDERLINE;
void SmXMLOverContext_Impl::endFastElement(sal_Int32)
{ if (!nAttrCount)
GenericEndElement(TCSUP, CSUP); else
HandleAccent();
}
void SmXMLOverContext_Impl::HandleAccent()
{ constbool bNodeCheck = GetSmImport().GetNodeStack().size() - nElementCount == 2;
OSL_ENSURE(bNodeCheck, "Sub has not two arguments"); if (!bNodeCheck) return;
uno::Reference<xml::sax::XFastContextHandler> SmXMLOfficeContext_Impl::createFastChildContext(
sal_Int32 nElement, const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/)
{ if (nElement == XML_ELEMENT(OFFICE, XML_META))
{
SAL_WARN("starmath", "XML_TOK_DOC_META: should not have come here, maybe document is invalid?");
} elseif (nElement == XML_ELEMENT(OFFICE, XML_SETTINGS))
{ returnnew XMLDocumentSettingsContext(GetImport());
} return nullptr;
}
namespace
{ // context for flat file xml format class SmXMLFlatDocContext_Impl : public SmXMLOfficeContext_Impl, public SvXMLMetaDocumentContext
{ public:
SmXMLFlatDocContext_Impl(SmXMLImport& i_rImport, const uno::Reference<document::XDocumentProperties>& i_xDocProps);
switch (nElement)
{ //Consider semantics a dummy except for any starmath annotations case XML_ELEMENT(MATH, XML_SEMANTICS): /*General Layout Schemata*/ case XML_ELEMENT(MATH, XML_MROW):
xContext = new SmXMLRowContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MENCLOSE):
xContext = new SmXMLEncloseContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MFRAC):
xContext = new SmXMLFracContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MSQRT):
xContext = new SmXMLSqrtContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MROOT):
xContext = new SmXMLRootContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MSTYLE):
xContext = new SmXMLStyleContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MERROR):
xContext = new SmXMLErrorContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MPADDED):
xContext = new SmXMLPaddedContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MPHANTOM):
xContext = new SmXMLPhantomContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MFENCED):
xContext = new SmXMLFencedContext_Impl(GetSmImport()); break; /*Script and Limit Schemata*/ case XML_ELEMENT(MATH, XML_MSUB):
xContext = new SmXMLSubContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MSUP):
xContext = new SmXMLSupContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MSUBSUP):
xContext = new SmXMLSubSupContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MUNDER):
xContext = new SmXMLUnderContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MOVER):
xContext = new SmXMLOverContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MUNDEROVER):
xContext = new SmXMLUnderOverContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MMULTISCRIPTS):
xContext = new SmXMLMultiScriptsContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MTABLE):
xContext = new SmXMLTableContext_Impl(GetSmImport()); break; case XML_ELEMENT(MATH, XML_MACTION):
xContext = new SmXMLActionContext_Impl(GetSmImport()); break; default: /*Basically there's an implicit mrow around certain bare *elements, use a RowContext to see if this is one of
*those ones*/
rtl::Reference<SmXMLRowContext_Impl> aTempContext( new SmXMLRowContext_Impl(GetSmImport()));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.