1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 /*todo: Change characters and tcharacters to accumulate the characters together
21 into one string, xml parser hands them to us line by line rather than all in
24 #include <com/sun/star/xml/sax/InputSource.hpp>
25 #include <com/sun/star/xml/sax/FastParser.hpp>
26 #include <com/sun/star/xml/sax/Parser.hpp>
27 #include <com/sun/star/xml/sax/SAXParseException.hpp>
28 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
29 #include <com/sun/star/packages/WrongPasswordException.hpp>
30 #include <com/sun/star/packages/zip/ZipIOException.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
33 #include <com/sun/star/uno/Any.h>
34 #include <com/sun/star/task/XStatusIndicator.hpp>
36 #include <comphelper/fileformat.h>
37 #include <comphelper/genericpropertyset.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/servicehelper.hxx>
40 #include <comphelper/propertysetinfo.hxx>
41 #include <rtl/character.hxx>
42 #include <sal/log.hxx>
43 #include <sfx2/frame.hxx>
44 #include <sfx2/docfile.hxx>
45 #include <sfx2/sfxsids.hrc>
46 #include <sfx2/sfxmodelfactory.hxx>
47 #include <osl/diagnose.h>
48 #include <sot/storage.hxx>
49 #include <svtools/sfxecode.hxx>
50 #include <svl/itemset.hxx>
51 #include <svl/stritem.hxx>
52 #include <unotools/streamwrap.hxx>
53 #include <sax/tools/converter.hxx>
54 #include <xmloff/DocumentSettingsContext.hxx>
55 #include <xmloff/xmlnamespace.hxx>
56 #include <xmloff/xmltoken.hxx>
57 #include <xmloff/xmluconv.hxx>
58 #include <xmloff/xmlmetai.hxx>
59 #include <svx/dialmgr.hxx>
60 #include <svx/strings.hrc>
61 #include <comphelper/diagnose_ex.hxx>
62 #include <o3tl/string_view.hxx>
64 #include <mathmlattr.hxx>
65 #include <xparsmlbase.hxx>
66 #include <mathmlimport.hxx>
67 #include <document.hxx>
69 #include <unomodel.hxx>
70 #include <utility.hxx>
71 #include <visitors.hxx>
72 #include <starmathdatabase.hxx>
74 #include <cfgitem.hxx>
76 using namespace ::com::sun::star::beans
;
77 using namespace ::com::sun::star::document
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::uno
;
80 using namespace ::com::sun::star
;
81 using namespace ::xmloff::token
;
85 std::unique_ptr
<SmNode
> popOrZero(SmNodeStack
& rStack
)
89 auto pTmp
= std::move(rStack
.front());
95 ErrCode
SmXMLImportWrapper::Import(SfxMedium
& rMedium
)
97 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
99 const uno::Reference
<uno::XComponentContext
>& xContext(
100 comphelper::getProcessComponentContext());
102 OSL_ENSURE(m_xModel
.is(), "XMLReader::Read: got no model");
104 // try to get an XStatusIndicator from the Medium
105 uno::Reference
<task::XStatusIndicator
> xStatusIndicator
;
107 bool bEmbedded
= false;
108 SmModel
* pModel
= m_xModel
.get();
110 SmDocShell
* pDocShell
= pModel
? static_cast<SmDocShell
*>(pModel
->GetObjectShell()) : nullptr;
113 OSL_ENSURE(pDocShell
->GetMedium() == &rMedium
, "different SfxMedium found");
115 const SfxUnoAnyItem
* pItem
= rMedium
.GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL
);
117 pItem
->GetValue() >>= xStatusIndicator
;
119 if (SfxObjectCreateMode::EMBEDDED
== pDocShell
->GetCreateMode())
123 static const comphelper::PropertyMapEntry aInfoMap
[]
124 = { { u
"PrivateData"_ustr
, 0, cppu::UnoType
<XInterface
>::get(),
125 beans::PropertyAttribute::MAYBEVOID
, 0 },
126 { u
"BaseURI"_ustr
, 0, ::cppu::UnoType
<OUString
>::get(),
127 beans::PropertyAttribute::MAYBEVOID
, 0 },
128 { u
"StreamRelPath"_ustr
, 0, ::cppu::UnoType
<OUString
>::get(),
129 beans::PropertyAttribute::MAYBEVOID
, 0 },
130 { u
"StreamName"_ustr
, 0, ::cppu::UnoType
<OUString
>::get(),
131 beans::PropertyAttribute::MAYBEVOID
, 0 } };
132 uno::Reference
<beans::XPropertySet
> xInfoSet(
133 comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap
)));
136 OUString
const baseURI(rMedium
.GetBaseURL());
137 // needed for relative URLs; but it's OK to import e.g. MathML from the
138 // clipboard without one
139 SAL_INFO_IF(baseURI
.isEmpty(), "starmath", "SmXMLImportWrapper: no base URL");
140 xInfoSet
->setPropertyValue(u
"BaseURI"_ustr
, Any(baseURI
));
142 sal_Int32 nSteps
= 3;
143 if (!(rMedium
.IsStorage()))
146 sal_Int32
nProgressRange(nSteps
);
147 if (xStatusIndicator
.is())
149 xStatusIndicator
->start(SvxResId(RID_SVXSTR_DOC_LOAD
), nProgressRange
);
153 if (xStatusIndicator
.is())
154 xStatusIndicator
->setValue(nSteps
++);
156 if (rMedium
.IsStorage())
158 // TODO/LATER: handle the case of embedded links gracefully
159 if (bEmbedded
) // && !rMedium.GetStorage()->IsRoot() )
161 OUString
aName(u
"dummyObjName"_ustr
);
162 const SfxStringItem
* pDocHierarchItem
163 = rMedium
.GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME
);
164 if (pDocHierarchItem
)
165 aName
= pDocHierarchItem
->GetValue();
167 if (!aName
.isEmpty())
169 xInfoSet
->setPropertyValue(u
"StreamRelPath"_ustr
, Any(aName
));
173 bool bOASIS
= (SotStorage::GetVersion(rMedium
.GetStorage()) > SOFFICE_FILEFORMAT_60
);
174 if (xStatusIndicator
.is())
175 xStatusIndicator
->setValue(nSteps
++);
178 = ReadThroughComponent(rMedium
.GetStorage(), m_xModel
, "meta.xml", xContext
, xInfoSet
,
179 (bOASIS
? "com.sun.star.comp.Math.XMLOasisMetaImporter"
180 : "com.sun.star.comp.Math.XMLMetaImporter"),
181 m_bUseHTMLMLEntities
);
183 if (nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
185 if (xStatusIndicator
.is())
186 xStatusIndicator
->setValue(nSteps
++);
188 nWarn
= ReadThroughComponent(rMedium
.GetStorage(), m_xModel
, "settings.xml", xContext
,
190 (bOASIS
? "com.sun.star.comp.Math.XMLOasisSettingsImporter"
191 : "com.sun.star.comp.Math.XMLSettingsImporter"),
192 m_bUseHTMLMLEntities
);
194 if (nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
196 if (xStatusIndicator
.is())
197 xStatusIndicator
->setValue(nSteps
++);
199 nError
= ReadThroughComponent(
200 rMedium
.GetStorage(), m_xModel
, "content.xml", xContext
, xInfoSet
,
201 "com.sun.star.comp.Math.XMLImporter", m_bUseHTMLMLEntities
);
204 nError
= ERRCODE_IO_BROKENPACKAGE
;
207 nError
= ERRCODE_IO_BROKENPACKAGE
;
211 Reference
<io::XInputStream
> xInputStream
212 = new utl::OInputStreamWrapper(rMedium
.GetInStream());
214 if (xStatusIndicator
.is())
215 xStatusIndicator
->setValue(nSteps
++);
217 nError
= ReadThroughComponent(xInputStream
, m_xModel
, xContext
, xInfoSet
,
218 "com.sun.star.comp.Math.XMLImporter", false,
219 m_bUseHTMLMLEntities
);
222 if (xStatusIndicator
.is())
223 xStatusIndicator
->end();
227 /// read a component (file + filter version)
228 ErrCode
SmXMLImportWrapper::ReadThroughComponent(const Reference
<io::XInputStream
>& xInputStream
,
229 const Reference
<XComponent
>& xModelComponent
,
230 Reference
<uno::XComponentContext
> const& rxContext
,
231 Reference
<beans::XPropertySet
> const& rPropSet
,
232 const char* pFilterName
, bool bEncrypted
,
233 bool bUseHTMLMLEntities
)
235 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
236 OSL_ENSURE(xInputStream
.is(), "input stream missing");
237 OSL_ENSURE(xModelComponent
.is(), "document missing");
238 OSL_ENSURE(rxContext
.is(), "factory missing");
239 OSL_ENSURE(nullptr != pFilterName
, "I need a service name for the component!");
241 // prepare ParserInputSource
242 xml::sax::InputSource aParserInput
;
243 aParserInput
.aInputStream
= xInputStream
;
245 Sequence
<Any
> aArgs
{ Any(rPropSet
) };
248 Reference
<XInterface
> xFilter
249 = rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
250 OUString::createFromAscii(pFilterName
), aArgs
, rxContext
);
251 SAL_WARN_IF(!xFilter
, "starmath", "Can't instantiate filter component " << pFilterName
);
255 // connect model and filter
256 Reference
<XImporter
> xImporter(xFilter
, UNO_QUERY
);
257 xImporter
->setTargetDocument(xModelComponent
);
259 // finally, parser the stream
262 Reference
<css::xml::sax::XFastParser
> xFastParser(xFilter
, UNO_QUERY
);
263 Reference
<css::xml::sax::XFastDocumentHandler
> xFastDocHandler(xFilter
, UNO_QUERY
);
266 if (bUseHTMLMLEntities
)
267 xFastParser
->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntities
);
268 xFastParser
->parseStream(aParserInput
);
270 else if (xFastDocHandler
)
272 Reference
<css::xml::sax::XFastParser
> xParser
273 = css::xml::sax::FastParser::create(rxContext
);
274 if (bUseHTMLMLEntities
)
275 xParser
->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntities
);
276 xParser
->setFastDocumentHandler(xFastDocHandler
);
277 xParser
->parseStream(aParserInput
);
281 Reference
<css::xml::sax::XDocumentHandler
> xDocHandler(xFilter
, UNO_QUERY
);
283 Reference
<css::xml::sax::XParser
> xParser
= css::xml::sax::Parser::create(rxContext
);
284 xParser
->setDocumentHandler(xDocHandler
);
285 xParser
->parseStream(aParserInput
);
288 auto pFilter
= dynamic_cast<SmXMLImport
*>(xFilter
.get());
289 if (pFilter
&& pFilter
->GetSuccess())
290 nError
= ERRCODE_NONE
;
292 catch (const xml::sax::SAXParseException
& r
)
294 // sax parser sends wrapped exceptions,
295 // try to find the original one
296 xml::sax::SAXException aSaxEx
= *static_cast<const xml::sax::SAXException
*>(&r
);
297 bool bTryChild
= true;
301 xml::sax::SAXException aTmp
;
302 if (aSaxEx
.WrappedException
>>= aTmp
)
303 aSaxEx
= std::move(aTmp
);
308 packages::zip::ZipIOException aBrokenPackage
;
309 if (aSaxEx
.WrappedException
>>= aBrokenPackage
)
310 return ERRCODE_IO_BROKENPACKAGE
;
313 nError
= ERRCODE_SFX_WRONGPASSWORD
;
315 catch (const xml::sax::SAXException
& r
)
317 packages::zip::ZipIOException aBrokenPackage
;
318 if (r
.WrappedException
>>= aBrokenPackage
)
319 return ERRCODE_IO_BROKENPACKAGE
;
322 nError
= ERRCODE_SFX_WRONGPASSWORD
;
324 catch (const packages::zip::ZipIOException
&)
326 nError
= ERRCODE_IO_BROKENPACKAGE
;
328 catch (const io::IOException
&)
331 catch (const std::range_error
&)
338 ErrCode
SmXMLImportWrapper::ReadThroughComponent(const uno::Reference
<embed::XStorage
>& xStorage
,
339 const Reference
<XComponent
>& xModelComponent
,
340 const char* pStreamName
,
341 Reference
<uno::XComponentContext
> const& rxContext
,
342 Reference
<beans::XPropertySet
> const& rPropSet
,
343 const char* pFilterName
, bool bUseHTMLMLEntities
)
345 OSL_ENSURE(xStorage
.is(), "Need storage!");
346 OSL_ENSURE(nullptr != pStreamName
, "Please, please, give me a name!");
348 // open stream (and set parser input)
349 OUString sStreamName
= OUString::createFromAscii(pStreamName
);
354 uno::Reference
<io::XStream
> xEventsStream
355 = xStorage
->openStreamElement(sStreamName
, embed::ElementModes::READ
);
357 // determine if stream is encrypted or not
358 uno::Reference
<beans::XPropertySet
> xProps(xEventsStream
, uno::UNO_QUERY
);
359 Any aAny
= xProps
->getPropertyValue(u
"Encrypted"_ustr
);
360 bool bEncrypted
= false;
361 if (aAny
.getValueType() == cppu::UnoType
<bool>::get())
367 rPropSet
->setPropertyValue(u
"StreamName"_ustr
, Any(sStreamName
));
370 Reference
<io::XInputStream
> xStream
= xEventsStream
->getInputStream();
371 return ReadThroughComponent(xStream
, xModelComponent
, rxContext
, rPropSet
, pFilterName
,
372 bEncrypted
, bUseHTMLMLEntities
);
374 catch (packages::WrongPasswordException
&)
376 return ERRCODE_SFX_WRONGPASSWORD
;
378 catch (packages::zip::ZipIOException
&)
380 return ERRCODE_IO_BROKENPACKAGE
;
382 catch (uno::Exception
&)
386 return ERRCODE_SFX_DOLOADFAILED
;
389 SmXMLImport::SmXMLImport(const css::uno::Reference
<css::uno::XComponentContext
>& rContext
,
390 OUString
const& implementationName
, SvXMLImportFlags nImportFlags
)
391 : SvXMLImport(rContext
, implementationName
, nImportFlags
)
394 , mnSmSyntaxVersion(SmModule::get()->GetConfig()->GetDefaultSmSyntaxVersion())
398 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
399 Math_XMLImporter_get_implementation(uno::XComponentContext
* pCtx
,
400 uno::Sequence
<uno::Any
> const& /*rSeq*/)
402 return cppu::acquire(
403 new SmXMLImport(pCtx
, u
"com.sun.star.comp.Math.XMLImporter"_ustr
, SvXMLImportFlags::ALL
));
406 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
407 Math_XMLOasisMetaImporter_get_implementation(uno::XComponentContext
* pCtx
,
408 uno::Sequence
<uno::Any
> const& /*rSeq*/)
410 return cppu::acquire(new SmXMLImport(pCtx
, u
"com.sun.star.comp.Math.XMLOasisMetaImporter"_ustr
,
411 SvXMLImportFlags::META
));
414 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
415 Math_XMLOasisSettingsImporter_get_implementation(uno::XComponentContext
* pCtx
,
416 uno::Sequence
<uno::Any
> const& /*rSeq*/)
418 return cppu::acquire(new SmXMLImport(
419 pCtx
, u
"com.sun.star.comp.Math.XMLOasisSettingsImporter"_ustr
, SvXMLImportFlags::SETTINGS
));
422 void SmXMLImport::endDocument()
424 //Set the resulted tree into the SmDocShell where it belongs
425 std::unique_ptr
<SmNode
> pTree
= popOrZero(aNodeStack
);
426 if (pTree
&& pTree
->GetType() == SmNodeType::Table
)
428 uno::Reference
<frame::XModel
> xModel
= GetModel();
429 SmModel
* pModel
= dynamic_cast<SmModel
*>(xModel
.get());
433 SmDocShell
* pDocShell
= static_cast<SmDocShell
*>(pModel
->GetObjectShell());
434 auto pTreeTmp
= pTree
.get();
435 pDocShell
->SetFormulaTree(static_cast<SmTableNode
*>(pTree
.release()));
436 if (aText
.isEmpty()) //If we picked up no annotation text
438 // Get text from imported formula
439 SmNodeToTextVisitor
tmpvisitor(pTreeTmp
, aText
);
442 // Convert symbol names
443 AbstractSmParser
* rParser
= pDocShell
->GetParser();
444 bool bVal
= rParser
->IsImportSymbolNames();
445 rParser
->SetImportSymbolNames(true);
446 auto pTmpTree
= rParser
->Parse(aText
);
447 aText
= rParser
->GetText();
449 rParser
->SetImportSymbolNames(bVal
);
451 pDocShell
->SetText(aText
);
452 pDocShell
->SetSmSyntaxVersion(mnSmSyntaxVersion
);
454 OSL_ENSURE(pModel
, "So there *was* a UNO problem after all");
459 SvXMLImport::endDocument();
464 class SmXMLImportContext
: public SvXMLImportContext
467 SmXMLImportContext(SmXMLImport
& rImport
)
468 : SvXMLImportContext(rImport
)
470 GetSmImport().IncParseDepth();
473 virtual ~SmXMLImportContext() override
{ GetSmImport().DecParseDepth(); }
475 SmXMLImport
& GetSmImport() { return static_cast<SmXMLImport
&>(GetImport()); }
477 virtual void TCharacters(const OUString
& /*rChars*/);
478 virtual void SAL_CALL
characters(const OUString
& rChars
) override
;
479 virtual void SAL_CALL
startFastElement(
480 sal_Int32
/*nElement*/,
481 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& /*rAttrList*/) override
483 if (GetSmImport().TooDeep())
484 throw std::range_error("too deep");
489 void SmXMLImportContext::TCharacters(const OUString
& /*rChars*/) {}
491 void SmXMLImportContext::characters(const OUString
& rChars
)
494 Whitespace occurring within the content of token elements is "trimmed"
495 from the ends (i.e. all whitespace at the beginning and end of the
496 content is removed), and "collapsed" internally (i.e. each sequence of
497 1 or more whitespace characters is replaced with one blank character).
499 //collapsing not done yet!
500 const OUString aChars2
= rChars
.trim();
501 if (!aChars2
.isEmpty())
502 TCharacters(aChars2
/*.collapse()*/);
507 struct SmXMLContext_Helper
512 OUString sFontFamily
;
515 SmXMLImportContext
& rContext
;
517 explicit SmXMLContext_Helper(SmXMLImportContext
& rImport
)
525 bool IsFontNodeNeeded() const;
526 void RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
);
531 bool SmXMLContext_Helper::IsFontNodeNeeded() const
533 return nIsBold
!= -1 || nIsItalic
!= -1 || nFontSize
!= 0.0 || !sFontFamily
.isEmpty()
534 || !sColor
.isEmpty();
537 void SmXMLContext_Helper::RetrieveAttrs(
538 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
540 bool bMvFound
= false;
541 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
543 // sometimes they have namespace, sometimes not?
544 switch (aIter
.getToken() & TOKEN_MASK
)
547 nIsBold
= sal_Int8(IsXMLToken(aIter
, XML_BOLD
));
550 nIsItalic
= sal_Int8(IsXMLToken(aIter
, XML_ITALIC
));
555 OUString sValue
= aIter
.toString();
556 ::sax::Converter::convertDouble(nFontSize
, sValue
);
557 rContext
.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
558 util::MeasureUnit::POINT
);
559 if (-1 == sValue
.indexOf(GetXMLToken(XML_UNIT_PT
)))
561 if (-1 == sValue
.indexOf('%'))
565 rContext
.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
566 util::MeasureUnit::PERCENT
);
572 sFontFamily
= aIter
.toString();
576 sColor
= aIter
.toString();
578 case XML_MATHVARIANT
:
582 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
589 // Ignore deprecated attributes fontfamily, fontweight, and fontstyle
590 // in favor of mathvariant, as specified in
591 // <https://www.w3.org/TR/MathML3/chapter3.html#presm.deprecatt>.
598 void SmXMLContext_Helper::ApplyAttrs()
600 SmNodeStack
& rNodeStack
= rContext
.GetSmImport().GetNodeStack();
602 if (!IsFontNodeNeeded())
606 aToken
.cMathChar
= u
""_ustr
;
612 aToken
.eType
= TBOLD
;
614 aToken
.eType
= TNBOLD
;
615 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
616 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
617 rNodeStack
.push_front(std::move(pFontNode
));
622 aToken
.eType
= TITALIC
;
624 aToken
.eType
= TNITALIC
;
625 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
626 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
627 rNodeStack
.push_front(std::move(pFontNode
));
629 if (nFontSize
!= 0.0)
631 aToken
.eType
= TSIZE
;
632 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
634 if (util::MeasureUnit::PERCENT
635 == rContext
.GetSmImport().GetMM100UnitConverter().GetXMLMeasureUnit())
637 if (nFontSize
< 100.00)
638 pFontNode
->SetSizeParameter(Fraction(100.00 / nFontSize
), FontSizeType::DIVIDE
);
640 pFontNode
->SetSizeParameter(Fraction(nFontSize
/ 100.00), FontSizeType::MULTIPLY
);
643 pFontNode
->SetSizeParameter(Fraction(nFontSize
), FontSizeType::ABSOLUT
);
645 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
646 rNodeStack
.push_front(std::move(pFontNode
));
648 if (!sColor
.isEmpty())
650 SmColorTokenTableEntry aSmColorTokenTableEntry
;
651 aSmColorTokenTableEntry
= starmathdatabase::Identify_ColorName_HTML(sColor
);
652 if (aSmColorTokenTableEntry
.eType
== TRGB
)
653 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser(
654 sal_uInt32(aSmColorTokenTableEntry
.cColor
));
655 if (aSmColorTokenTableEntry
.eType
!= TERROR
)
657 aToken
= aSmColorTokenTableEntry
;
658 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
659 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
660 rNodeStack
.push_front(std::move(pFontNode
));
662 // If not known, not implemented yet. Giving up.
664 if (sFontFamily
.isEmpty())
667 if (sFontFamily
.equalsIgnoreAsciiCase(GetXMLToken(XML_FIXED
)))
668 aToken
.eType
= TFIXED
;
669 else if (sFontFamily
.equalsIgnoreAsciiCase("sans"))
670 aToken
.eType
= TSANS
;
671 else if (sFontFamily
.equalsIgnoreAsciiCase("serif"))
672 aToken
.eType
= TSERIF
;
673 else //Just give up, we need to extend our font mechanism to be
677 aToken
.aText
= sFontFamily
;
678 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
679 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
680 rNodeStack
.push_front(std::move(pFontNode
));
685 class SmXMLTokenAttrHelper
687 SmXMLImportContext
& mrContext
;
688 MathMLMathvariantValue meMv
;
692 SmXMLTokenAttrHelper(SmXMLImportContext
& rContext
)
693 : mrContext(rContext
)
694 , meMv(MathMLMathvariantValue::Normal
)
699 void RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
);
700 void ApplyAttrs(MathMLMathvariantValue eDefaultMv
);
704 void SmXMLTokenAttrHelper::RetrieveAttrs(
705 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
707 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
709 OUString sValue
= aIter
.toString();
710 switch (aIter
.getToken())
712 case XML_MATHVARIANT
:
713 if (!GetMathMLMathvariantValue(sValue
, meMv
))
714 SAL_WARN("starmath", "failed to recognize mathvariant: " << sValue
);
718 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
724 void SmXMLTokenAttrHelper::ApplyAttrs(MathMLMathvariantValue eDefaultMv
)
726 assert(eDefaultMv
== MathMLMathvariantValue::Normal
727 || eDefaultMv
== MathMLMathvariantValue::Italic
);
729 std::vector
<SmTokenType
> vVariant
;
730 MathMLMathvariantValue eMv
= mbMvFound
? meMv
: eDefaultMv
;
733 case MathMLMathvariantValue::Normal
:
734 vVariant
.push_back(TNITALIC
);
736 case MathMLMathvariantValue::Bold
:
737 case MathMLMathvariantValue::BoldFraktur
:
739 case MathMLMathvariantValue::BoldScript
:
741 vVariant
.push_back(TBOLD
);
743 case MathMLMathvariantValue::Italic
:
746 case MathMLMathvariantValue::BoldItalic
:
747 vVariant
.push_back(TITALIC
);
748 vVariant
.push_back(TBOLD
);
750 case MathMLMathvariantValue::DoubleStruck
:
753 case MathMLMathvariantValue::Script
:
756 case MathMLMathvariantValue::Fraktur
:
759 case MathMLMathvariantValue::SansSerif
:
760 vVariant
.push_back(TSANS
);
762 case MathMLMathvariantValue::BoldSansSerif
:
763 vVariant
.push_back(TSANS
);
764 vVariant
.push_back(TBOLD
);
766 case MathMLMathvariantValue::SansSerifItalic
:
767 vVariant
.push_back(TITALIC
);
768 vVariant
.push_back(TSANS
);
770 case MathMLMathvariantValue::SansSerifBoldItalic
:
771 vVariant
.push_back(TITALIC
);
772 vVariant
.push_back(TBOLD
);
773 vVariant
.push_back(TSANS
);
775 case MathMLMathvariantValue::Monospace
:
776 vVariant
.push_back(TFIXED
);
778 case MathMLMathvariantValue::Initial
:
779 case MathMLMathvariantValue::Tailed
:
780 case MathMLMathvariantValue::Looped
:
781 case MathMLMathvariantValue::Stretched
:
785 if (vVariant
.empty())
787 SmNodeStack
& rNodeStack
= mrContext
.GetSmImport().GetNodeStack();
788 for (auto eType
: vVariant
)
791 aToken
.eType
= eType
;
792 aToken
.cMathChar
= u
""_ustr
;
794 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
795 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
796 rNodeStack
.push_front(std::move(pFontNode
));
802 class SmXMLDocContext_Impl
: public SmXMLImportContext
805 SmXMLDocContext_Impl(SmXMLImport
& rImport
)
806 : SmXMLImportContext(rImport
)
810 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
811 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
813 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
816 /*avert the gaze from the originator*/
817 class SmXMLRowContext_Impl
: public SmXMLDocContext_Impl
820 size_t nElementCount
;
823 SmXMLRowContext_Impl(SmXMLImport
& rImport
)
824 : SmXMLDocContext_Impl(rImport
)
825 , nElementCount(GetSmImport().GetNodeStack().size())
829 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
830 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
832 uno::Reference
<xml::sax::XFastContextHandler
> StrictCreateChildContext(sal_Int32 nElement
);
834 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
837 class SmXMLEncloseContext_Impl
: public SmXMLRowContext_Impl
840 // TODO/LATER: convert <menclose notation="horizontalstrike"> into
841 // "overstrike{}" and extend the Math syntax to support more notations
842 SmXMLEncloseContext_Impl(SmXMLImport
& rImport
)
843 : SmXMLRowContext_Impl(rImport
)
847 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
851 void SmXMLEncloseContext_Impl::endFastElement(sal_Int32 nElement
)
854 <menclose> accepts any number of arguments; if this number is not 1, its
855 contents are treated as a single "inferred <mrow>" containing its
858 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
859 SmXMLRowContext_Impl::endFastElement(nElement
);
864 class SmXMLFracContext_Impl
: public SmXMLRowContext_Impl
867 // TODO/LATER: convert <mfrac bevelled="true"> into "wideslash{}{}"
868 SmXMLFracContext_Impl(SmXMLImport
& rImport
)
869 : SmXMLRowContext_Impl(rImport
)
873 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
876 class SmXMLSqrtContext_Impl
: public SmXMLRowContext_Impl
879 SmXMLSqrtContext_Impl(SmXMLImport
& rImport
)
880 : SmXMLRowContext_Impl(rImport
)
884 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
887 class SmXMLRootContext_Impl
: public SmXMLRowContext_Impl
890 SmXMLRootContext_Impl(SmXMLImport
& rImport
)
891 : SmXMLRowContext_Impl(rImport
)
895 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
898 class SmXMLStyleContext_Impl
: public SmXMLRowContext_Impl
901 SmXMLContext_Helper aStyleHelper
;
904 /*Right now the style tag is completely ignored*/
905 SmXMLStyleContext_Impl(SmXMLImport
& rImport
)
906 : SmXMLRowContext_Impl(rImport
)
907 , aStyleHelper(*this)
911 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
912 void SAL_CALL
startFastElement(
913 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
917 void SmXMLStyleContext_Impl::startFastElement(
918 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
920 aStyleHelper
.RetrieveAttrs(xAttrList
);
923 void SmXMLStyleContext_Impl::endFastElement(sal_Int32 nElement
)
926 <mstyle> accepts any number of arguments; if this number is not 1, its
927 contents are treated as a single "inferred <mrow>" containing its
930 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
931 if (rNodeStack
.size() - nElementCount
!= 1)
932 SmXMLRowContext_Impl::endFastElement(nElement
);
933 aStyleHelper
.ApplyAttrs();
938 class SmXMLPaddedContext_Impl
: public SmXMLRowContext_Impl
941 /*Right now the style tag is completely ignored*/
942 SmXMLPaddedContext_Impl(SmXMLImport
& rImport
)
943 : SmXMLRowContext_Impl(rImport
)
947 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
951 void SmXMLPaddedContext_Impl::endFastElement(sal_Int32 nElement
)
954 <mpadded> accepts any number of arguments; if this number is not 1, its
955 contents are treated as a single "inferred <mrow>" containing its
958 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
959 SmXMLRowContext_Impl::endFastElement(nElement
);
964 class SmXMLPhantomContext_Impl
: public SmXMLRowContext_Impl
967 /*Right now the style tag is completely ignored*/
968 SmXMLPhantomContext_Impl(SmXMLImport
& rImport
)
969 : SmXMLRowContext_Impl(rImport
)
973 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
977 void SmXMLPhantomContext_Impl::endFastElement(sal_Int32 nElement
)
980 <mphantom> accepts any number of arguments; if this number is not 1, its
981 contents are treated as a single "inferred <mrow>" containing its
984 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
985 SmXMLRowContext_Impl::endFastElement(nElement
);
988 aToken
.cMathChar
= u
""_ustr
;
990 aToken
.eType
= TPHANTOM
;
992 std::unique_ptr
<SmFontNode
> pPhantom(new SmFontNode(aToken
));
993 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
994 pPhantom
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
995 rNodeStack
.push_front(std::move(pPhantom
));
1000 class SmXMLFencedContext_Impl
: public SmXMLRowContext_Impl
1008 SmXMLFencedContext_Impl(SmXMLImport
& rImport
)
1009 : SmXMLRowContext_Impl(rImport
)
1012 , bIsStretchy(false)
1016 void SAL_CALL
startFastElement(
1017 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1018 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1022 void SmXMLFencedContext_Impl::startFastElement(
1023 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1025 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1027 switch (aIter
.getToken())
1029 //temp, starmath cannot handle multichar brackets (I think)
1031 cBegin
= aIter
.toString();
1034 cEnd
= aIter
.toString();
1037 bIsStretchy
= IsXMLToken(aIter
, XML_TRUE
);
1040 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1041 /*Go to superclass*/
1047 void SmXMLFencedContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1050 aToken
.cMathChar
= u
""_ustr
;
1054 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
1056 aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cBegin
);
1058 aToken
= starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(cBegin
);
1059 if (aToken
.eType
== TERROR
)
1060 aToken
= SmToken(TLPARENT
, MS_LPARENT
, u
"("_ustr
, TG::LBrace
, 5);
1061 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
1063 aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cEnd
);
1065 aToken
= starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(cEnd
);
1066 if (aToken
.eType
== TERROR
)
1067 aToken
= SmToken(TRPARENT
, MS_RPARENT
, u
")"_ustr
, TG::LBrace
, 5);
1068 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
1070 SmNodeArray aRelationArray
;
1071 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1072 aToken
.cMathChar
= u
""_ustr
;
1073 aToken
.eType
= TIDENT
;
1075 auto i
= rNodeStack
.size() - nElementCount
;
1076 if (rNodeStack
.size() - nElementCount
> 1)
1077 i
+= rNodeStack
.size() - 1 - nElementCount
;
1078 aRelationArray
.resize(i
);
1079 while (rNodeStack
.size() > nElementCount
)
1081 auto pNode
= std::move(rNodeStack
.front());
1082 rNodeStack
.pop_front();
1083 aRelationArray
[--i
] = pNode
.release();
1084 if (i
> 1 && rNodeStack
.size() > 1)
1085 aRelationArray
[--i
] = new SmGlyphSpecialNode(aToken
);
1089 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
1090 pBody
->SetSubNodes(std::move(aRelationArray
));
1092 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
1093 // mfenced is always scalable. Stretchy keyword is not official, but in case of been in there
1094 // can be used as a hint.
1095 pSNode
->SetScaleMode(SmScaleMode::Height
);
1096 GetSmImport().GetNodeStack().push_front(std::move(pSNode
));
1101 class SmXMLErrorContext_Impl
: public SmXMLRowContext_Impl
1104 SmXMLErrorContext_Impl(SmXMLImport
& rImport
)
1105 : SmXMLRowContext_Impl(rImport
)
1109 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1113 void SmXMLErrorContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1115 /*Right now the error tag is completely ignored, what
1116 can I do with it in starmath, ?, maybe we need a
1117 report window ourselves, do a test for validity of
1118 the xml input, use mirrors, and then generate
1119 the markup inside the merror with a big red colour
1120 of something. For now just throw them all away.
1122 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1123 while (rNodeStack
.size() > nElementCount
)
1125 rNodeStack
.pop_front();
1131 class SmXMLNumberContext_Impl
: public SmXMLImportContext
1137 SmXMLNumberContext_Impl(SmXMLImport
& rImport
)
1138 : SmXMLImportContext(rImport
)
1140 aToken
.cMathChar
= u
""_ustr
;
1142 aToken
.eType
= TNUMBER
;
1145 virtual void TCharacters(const OUString
& rChars
) override
;
1147 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1151 void SmXMLNumberContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1153 void SmXMLNumberContext_Impl::endFastElement(sal_Int32
)
1155 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_NUMBER
));
1160 class SmXMLAnnotationContext_Impl
: public SmXMLImportContext
1162 sal_uInt8 mnStarMathVersion
;
1165 SmXMLAnnotationContext_Impl(SmXMLImport
& rImport
)
1166 : SmXMLImportContext(rImport
)
1167 , mnStarMathVersion(0)
1171 void SAL_CALL
characters(const OUString
& rChars
) override
;
1173 void SAL_CALL
startFastElement(
1174 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1178 void SmXMLAnnotationContext_Impl::startFastElement(
1179 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1181 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1183 // sometimes they have namespace, sometimes not?
1184 switch (aIter
.getToken() & TOKEN_MASK
)
1188 = aIter
.toView() == "StarMath 5.0" ? 5 : aIter
.toView() == "StarMath 6" ? 6 : 0;
1191 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1197 void SmXMLAnnotationContext_Impl::characters(const OUString
& rChars
)
1199 if (mnStarMathVersion
)
1201 GetSmImport().SetText(GetSmImport().GetText() + rChars
);
1202 GetSmImport().SetSmSyntaxVersion(mnStarMathVersion
);
1208 class SmXMLTextContext_Impl
: public SmXMLImportContext
1214 SmXMLTextContext_Impl(SmXMLImport
& rImport
)
1215 : SmXMLImportContext(rImport
)
1217 aToken
.cMathChar
= u
""_ustr
;
1219 aToken
.eType
= TTEXT
;
1222 virtual void TCharacters(const OUString
& rChars
) override
;
1224 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1228 void SmXMLTextContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1230 void SmXMLTextContext_Impl::endFastElement(sal_Int32
)
1232 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_TEXT
));
1237 class SmXMLStringContext_Impl
: public SmXMLImportContext
1243 SmXMLStringContext_Impl(SmXMLImport
& rImport
)
1244 : SmXMLImportContext(rImport
)
1246 aToken
.cMathChar
= u
""_ustr
;
1248 aToken
.eType
= TTEXT
;
1251 virtual void TCharacters(const OUString
& rChars
) override
;
1253 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1257 void SmXMLStringContext_Impl::TCharacters(const OUString
& rChars
)
1260 The content of <ms> elements should be rendered with visible "escaping" of
1261 certain characters in the content, including at least "double quote"
1262 itself, and preferably whitespace other than individual blanks. The intent
1263 is for the viewer to see that the expression is a string literal, and to
1264 see exactly which characters form its content. For example, <ms>double
1265 quote is "</ms> might be rendered as "double quote is \"".
1267 Obviously this isn't fully done here.
1269 aToken
.aText
= "\"" + rChars
+ "\"";
1272 void SmXMLStringContext_Impl::endFastElement(sal_Int32
)
1274 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_FIXED
));
1279 class SmXMLIdentifierContext_Impl
: public SmXMLImportContext
1281 SmXMLTokenAttrHelper maTokenAttrHelper
;
1282 SmXMLContext_Helper aStyleHelper
;
1286 SmXMLIdentifierContext_Impl(SmXMLImport
& rImport
)
1287 : SmXMLImportContext(rImport
)
1288 , maTokenAttrHelper(*this)
1289 , aStyleHelper(*this)
1291 aToken
.cMathChar
= u
""_ustr
;
1293 aToken
.eType
= TIDENT
;
1296 void TCharacters(const OUString
& rChars
) override
;
1298 startFastElement(sal_Int32
/*nElement*/,
1299 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
1301 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1302 aStyleHelper
.RetrieveAttrs(xAttrList
);
1304 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1308 void SmXMLIdentifierContext_Impl::endFastElement(sal_Int32
)
1310 std::unique_ptr
<SmTextNode
> pNode
;
1311 //we will handle identifier italic/normal here instead of with a standalone
1313 if (((aStyleHelper
.nIsItalic
== -1) && (aToken
.aText
.getLength() > 1))
1314 || ((aStyleHelper
.nIsItalic
== 0) && (aToken
.aText
.getLength() == 1)))
1316 pNode
.reset(new SmTextNode(aToken
, FNT_FUNCTION
));
1317 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1318 aStyleHelper
.nIsItalic
= -1;
1321 pNode
.reset(new SmTextNode(aToken
, FNT_VARIABLE
));
1322 if (aStyleHelper
.nIsItalic
!= -1)
1324 if (aStyleHelper
.nIsItalic
)
1325 pNode
->GetFont().SetItalic(ITALIC_NORMAL
);
1327 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1328 aStyleHelper
.nIsItalic
= -1;
1330 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1331 aStyleHelper
.ApplyAttrs();
1333 maTokenAttrHelper
.ApplyAttrs((aToken
.aText
.getLength() == 1) ? MathMLMathvariantValue::Italic
1334 : MathMLMathvariantValue::Normal
);
1337 void SmXMLIdentifierContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1341 class SmXMLOperatorContext_Impl
: public SmXMLImportContext
1343 SmXMLTokenAttrHelper maTokenAttrHelper
;
1352 SmXMLOperatorContext_Impl(SmXMLImport
& rImport
)
1353 : SmXMLImportContext(rImport
)
1354 , maTokenAttrHelper(*this)
1355 , bIsStretchy(false)
1361 aToken
.eType
= TSPECIAL
;
1365 void TCharacters(const OUString
& rChars
) override
;
1366 void SAL_CALL
startFastElement(
1367 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1368 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1372 void SmXMLOperatorContext_Impl::TCharacters(const OUString
& rChars
)
1374 aToken
.setChar(rChars
);
1379 bToken
= starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(aToken
.cMathChar
);
1381 bToken
= SmToken(TMLINE
, MS_VERTLINE
, u
"mline"_ustr
, TG::NONE
, 0);
1383 bToken
= starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(aToken
.cMathChar
);
1385 bToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(
1390 = starmathdatabase::Identify_SmXMLOperatorContext_Impl(aToken
.cMathChar
, bIsStretchy
);
1391 if (bToken
.eType
!= TERROR
)
1392 aToken
= std::move(bToken
);
1395 void SmXMLOperatorContext_Impl::endFastElement(sal_Int32
)
1397 std::unique_ptr
<SmMathSymbolNode
> pNode(new SmMathSymbolNode(aToken
));
1398 //For stretchy scaling the scaling must be retrieved from this node
1399 //and applied to the expression itself so as to get the expression
1400 //to scale the operator to the height of the expression itself
1402 pNode
->SetScaleMode(SmScaleMode::Height
);
1403 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1405 // TODO: apply to non-alphabetic characters too
1406 if (rtl::isAsciiAlpha(aToken
.cMathChar
[0]))
1407 maTokenAttrHelper
.ApplyAttrs(MathMLMathvariantValue::Normal
);
1410 void SmXMLOperatorContext_Impl::startFastElement(
1411 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1413 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1415 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1417 switch (aIter
.getToken())
1420 bIsStretchy
= IsXMLToken(aIter
, XML_TRUE
);
1423 bIsFenced
= IsXMLToken(aIter
, XML_TRUE
);
1426 isPrefix
= IsXMLToken(aIter
, XML_PREFIX
); // <
1427 isInfix
= IsXMLToken(aIter
, XML_INFIX
); // |
1428 isPostfix
= IsXMLToken(aIter
, XML_POSTFIX
); // >
1431 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1439 class SmXMLSpaceContext_Impl
: public SmXMLImportContext
1442 SmXMLSpaceContext_Impl(SmXMLImport
& rImport
)
1443 : SmXMLImportContext(rImport
)
1447 void SAL_CALL
startFastElement(
1448 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1451 bool lcl_CountBlanks(const MathMLAttributeLengthValue
& rLV
, sal_Int32
* pWide
, sal_Int32
* pNarrow
)
1455 if (rLV
.aNumber
.GetNumerator() == 0)
1457 *pWide
= *pNarrow
= 0;
1460 // TODO: honor other units than em
1461 if (rLV
.eUnit
!= MathMLLengthUnit::Em
)
1463 if (rLV
.aNumber
.GetNumerator() < 0)
1465 const Fraction
aTwo(2, 1);
1466 auto aWide
= rLV
.aNumber
/ aTwo
;
1467 auto nWide
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aWide
));
1470 const Fraction
aPointFive(1, 2);
1471 auto aNarrow
= (rLV
.aNumber
- Fraction(nWide
, 1) * aTwo
) / aPointFive
;
1472 auto nNarrow
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aNarrow
));
1481 void SmXMLSpaceContext_Impl::startFastElement(
1482 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1484 // There is no syntax in Math to specify blank nodes of arbitrary size yet.
1485 MathMLAttributeLengthValue aLV
;
1486 sal_Int32 nWide
= 0, nNarrow
= 0;
1488 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1490 OUString sValue
= aIter
.toString();
1491 switch (aIter
.getToken())
1494 if (!ParseMathMLAttributeLengthValue(o3tl::trim(sValue
), aLV
)
1495 || !lcl_CountBlanks(aLV
, &nWide
, &nNarrow
))
1496 SAL_WARN("starmath", "ignore mspace's width: " << sValue
);
1499 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1504 aToken
.eType
= TBLANK
;
1505 aToken
.cMathChar
= u
""_ustr
;
1506 aToken
.nGroup
= TG::Blank
;
1508 std::unique_ptr
<SmBlankNode
> pBlank(new SmBlankNode(aToken
));
1510 pBlank
->IncreaseBy(aToken
, nWide
);
1513 aToken
.eType
= TSBLANK
;
1514 pBlank
->IncreaseBy(aToken
, nNarrow
);
1516 GetSmImport().GetNodeStack().push_front(std::move(pBlank
));
1521 class SmXMLSubContext_Impl
: public SmXMLRowContext_Impl
1524 void GenericEndElement(SmTokenType eType
, SmSubSup aSubSup
);
1527 SmXMLSubContext_Impl(SmXMLImport
& rImport
)
1528 : SmXMLRowContext_Impl(rImport
)
1532 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUB
, RSUB
); }
1536 void SmXMLSubContext_Impl::GenericEndElement(SmTokenType eType
, SmSubSup eSubSup
)
1538 /*The <msub> element requires exactly 2 arguments.*/
1539 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1540 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1545 aToken
.cMathChar
= u
""_ustr
;
1546 aToken
.eType
= eType
;
1547 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1548 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1550 // initialize subnodes array
1551 SmNodeArray aSubNodes
;
1552 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1553 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1554 aSubNodes
[i
] = nullptr;
1556 aSubNodes
[eSubSup
+ 1] = popOrZero(rNodeStack
).release();
1557 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1558 pNode
->SetSubNodes(std::move(aSubNodes
));
1559 rNodeStack
.push_front(std::move(pNode
));
1564 class SmXMLSupContext_Impl
: public SmXMLSubContext_Impl
1567 SmXMLSupContext_Impl(SmXMLImport
& rImport
)
1568 : SmXMLSubContext_Impl(rImport
)
1572 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUP
, RSUP
); }
1575 class SmXMLSubSupContext_Impl
: public SmXMLRowContext_Impl
1578 void GenericEndElement(SmTokenType eType
, SmSubSup aSub
, SmSubSup aSup
);
1581 SmXMLSubSupContext_Impl(SmXMLImport
& rImport
)
1582 : SmXMLRowContext_Impl(rImport
)
1586 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUB
, RSUB
, RSUP
); }
1590 void SmXMLSubSupContext_Impl::GenericEndElement(SmTokenType eType
, SmSubSup aSub
, SmSubSup aSup
)
1592 /*The <msub> element requires exactly 3 arguments.*/
1593 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 3;
1594 OSL_ENSURE(bNodeCheck
, "SubSup has not three arguments");
1599 aToken
.cMathChar
= u
""_ustr
;
1600 aToken
.eType
= eType
;
1601 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1602 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1604 // initialize subnodes array
1605 SmNodeArray aSubNodes
;
1606 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1607 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1608 aSubNodes
[i
] = nullptr;
1610 aSubNodes
[aSup
+ 1] = popOrZero(rNodeStack
).release();
1611 aSubNodes
[aSub
+ 1] = popOrZero(rNodeStack
).release();
1612 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1613 pNode
->SetSubNodes(std::move(aSubNodes
));
1614 rNodeStack
.push_front(std::move(pNode
));
1619 class SmXMLUnderContext_Impl
: public SmXMLSubContext_Impl
1622 sal_Int16 nAttrCount
;
1625 SmXMLUnderContext_Impl(SmXMLImport
& rImport
)
1626 : SmXMLSubContext_Impl(rImport
)
1631 void SAL_CALL
startFastElement(
1632 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1633 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1634 void HandleAccent();
1638 void SmXMLUnderContext_Impl::startFastElement(
1639 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1641 sax_fastparser::FastAttributeList
& rAttribList
1642 = sax_fastparser::castToFastAttributeList(xAttrList
);
1643 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1646 void SmXMLUnderContext_Impl::HandleAccent()
1648 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1649 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1653 /*Just one special case for the underline thing*/
1654 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1655 std::unique_ptr
<SmNode
> pTest
= popOrZero(rNodeStack
);
1657 aToken
.cMathChar
= u
""_ustr
;
1658 aToken
.eType
= TUNDERLINE
;
1660 std::unique_ptr
<SmNode
> pFirst
;
1661 std::unique_ptr
<SmStructureNode
> pNode(new SmAttributeNode(aToken
));
1662 if ((pTest
->GetToken().cMathChar
[0] & 0x0FFF) == 0x0332)
1664 pFirst
.reset(new SmRectangleNode(aToken
));
1667 pFirst
= std::move(pTest
);
1669 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1670 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1671 pNode
->SetScaleMode(SmScaleMode::Width
);
1672 rNodeStack
.push_front(std::move(pNode
));
1675 void SmXMLUnderContext_Impl::endFastElement(sal_Int32
)
1678 GenericEndElement(TCSUB
, CSUB
);
1685 class SmXMLOverContext_Impl
: public SmXMLSubContext_Impl
1688 sal_Int16 nAttrCount
;
1691 SmXMLOverContext_Impl(SmXMLImport
& rImport
)
1692 : SmXMLSubContext_Impl(rImport
)
1697 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1698 void SAL_CALL
startFastElement(
1699 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1700 void HandleAccent();
1704 void SmXMLOverContext_Impl::startFastElement(
1705 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1707 sax_fastparser::FastAttributeList
& rAttribList
1708 = sax_fastparser::castToFastAttributeList(xAttrList
);
1709 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1712 void SmXMLOverContext_Impl::endFastElement(sal_Int32
)
1715 GenericEndElement(TCSUP
, CSUP
);
1720 void SmXMLOverContext_Impl::HandleAccent()
1722 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1723 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1728 aToken
.cMathChar
= u
""_ustr
;
1729 aToken
.eType
= TACUTE
;
1731 std::unique_ptr
<SmAttributeNode
> pNode(new SmAttributeNode(aToken
));
1732 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1734 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
1735 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1736 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1737 pNode
->SetScaleMode(SmScaleMode::Width
);
1738 rNodeStack
.push_front(std::move(pNode
));
1743 class SmXMLUnderOverContext_Impl
: public SmXMLSubSupContext_Impl
1746 SmXMLUnderOverContext_Impl(SmXMLImport
& rImport
)
1747 : SmXMLSubSupContext_Impl(rImport
)
1751 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TCSUB
, CSUB
, CSUP
); }
1754 class SmXMLMultiScriptsContext_Impl
: public SmXMLSubSupContext_Impl
1756 bool bHasPrescripts
;
1758 void ProcessSubSupPairs(bool bIsPrescript
);
1761 SmXMLMultiScriptsContext_Impl(SmXMLImport
& rImport
)
1762 : SmXMLSubSupContext_Impl(rImport
)
1763 , bHasPrescripts(false)
1767 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1768 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1769 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1772 class SmXMLNoneContext_Impl
: public SmXMLImportContext
1775 SmXMLNoneContext_Impl(SmXMLImport
& rImport
)
1776 : SmXMLImportContext(rImport
)
1780 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1784 void SmXMLNoneContext_Impl::endFastElement(sal_Int32
)
1787 aToken
.cMathChar
= u
""_ustr
;
1788 aToken
.aText
.clear();
1790 aToken
.eType
= TIDENT
;
1791 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_VARIABLE
));
1796 class SmXMLPrescriptsContext_Impl
: public SmXMLImportContext
1799 SmXMLPrescriptsContext_Impl(SmXMLImport
& rImport
)
1800 : SmXMLImportContext(rImport
)
1805 class SmXMLTableRowContext_Impl
: public SmXMLRowContext_Impl
1808 SmXMLTableRowContext_Impl(SmXMLImport
& rImport
)
1809 : SmXMLRowContext_Impl(rImport
)
1813 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1814 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1817 class SmXMLTableContext_Impl
: public SmXMLTableRowContext_Impl
1820 SmXMLTableContext_Impl(SmXMLImport
& rImport
)
1821 : SmXMLTableRowContext_Impl(rImport
)
1825 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1826 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1827 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1830 class SmXMLTableCellContext_Impl
: public SmXMLRowContext_Impl
1833 SmXMLTableCellContext_Impl(SmXMLImport
& rImport
)
1834 : SmXMLRowContext_Impl(rImport
)
1839 class SmXMLAlignGroupContext_Impl
: public SmXMLRowContext_Impl
1842 SmXMLAlignGroupContext_Impl(SmXMLImport
& rImport
)
1843 : SmXMLRowContext_Impl(rImport
)
1847 /*Don't do anything with alignment for now*/
1850 class SmXMLActionContext_Impl
: public SmXMLRowContext_Impl
1852 size_t mnSelection
; // 1-based
1855 SmXMLActionContext_Impl(SmXMLImport
& rImport
)
1856 : SmXMLRowContext_Impl(rImport
)
1861 void SAL_CALL
startFastElement(
1862 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1863 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1866 // NB: virtually inherit so we can multiply inherit properly
1867 // in SmXMLFlatDocContext_Impl
1868 class SmXMLOfficeContext_Impl
: public virtual SvXMLImportContext
1871 SmXMLOfficeContext_Impl(SmXMLImport
& rImport
)
1872 : SvXMLImportContext(rImport
)
1876 virtual css::uno::Reference
<css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1878 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1882 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLOfficeContext_Impl::createFastChildContext(
1883 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
1885 if (nElement
== XML_ELEMENT(OFFICE
, XML_META
))
1887 SAL_WARN("starmath",
1888 "XML_TOK_DOC_META: should not have come here, maybe document is invalid?");
1890 else if (nElement
== XML_ELEMENT(OFFICE
, XML_SETTINGS
))
1892 return new XMLDocumentSettingsContext(GetImport());
1899 // context for flat file xml format
1900 class SmXMLFlatDocContext_Impl
: public SmXMLOfficeContext_Impl
, public SvXMLMetaDocumentContext
1903 SmXMLFlatDocContext_Impl(SmXMLImport
& i_rImport
,
1904 const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
);
1906 virtual css::uno::Reference
<css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1908 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1912 SmXMLFlatDocContext_Impl::SmXMLFlatDocContext_Impl(
1913 SmXMLImport
& i_rImport
, const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
)
1914 : SvXMLImportContext(i_rImport
)
1915 , SmXMLOfficeContext_Impl(i_rImport
)
1916 , SvXMLMetaDocumentContext(i_rImport
, i_xDocProps
)
1920 uno::Reference
<xml::sax::XFastContextHandler
>
1921 SAL_CALL
SmXMLFlatDocContext_Impl::createFastChildContext(
1922 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1924 // behave like meta base class iff we encounter office:meta
1925 if (nElement
== XML_ELEMENT(OFFICE
, XML_META
))
1927 return SvXMLMetaDocumentContext::createFastChildContext(nElement
, xAttrList
);
1931 return SmXMLOfficeContext_Impl::createFastChildContext(nElement
, xAttrList
);
1935 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLDocContext_Impl::createFastChildContext(
1936 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
1938 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
1942 //Consider semantics a dummy except for any starmath annotations
1943 case XML_ELEMENT(MATH
, XML_SEMANTICS
):
1944 /*General Layout Schemata*/
1945 case XML_ELEMENT(MATH
, XML_MROW
):
1946 xContext
= new SmXMLRowContext_Impl(GetSmImport());
1948 case XML_ELEMENT(MATH
, XML_MENCLOSE
):
1949 xContext
= new SmXMLEncloseContext_Impl(GetSmImport());
1951 case XML_ELEMENT(MATH
, XML_MFRAC
):
1952 xContext
= new SmXMLFracContext_Impl(GetSmImport());
1954 case XML_ELEMENT(MATH
, XML_MSQRT
):
1955 xContext
= new SmXMLSqrtContext_Impl(GetSmImport());
1957 case XML_ELEMENT(MATH
, XML_MROOT
):
1958 xContext
= new SmXMLRootContext_Impl(GetSmImport());
1960 case XML_ELEMENT(MATH
, XML_MSTYLE
):
1961 xContext
= new SmXMLStyleContext_Impl(GetSmImport());
1963 case XML_ELEMENT(MATH
, XML_MERROR
):
1964 xContext
= new SmXMLErrorContext_Impl(GetSmImport());
1966 case XML_ELEMENT(MATH
, XML_MPADDED
):
1967 xContext
= new SmXMLPaddedContext_Impl(GetSmImport());
1969 case XML_ELEMENT(MATH
, XML_MPHANTOM
):
1970 xContext
= new SmXMLPhantomContext_Impl(GetSmImport());
1972 case XML_ELEMENT(MATH
, XML_MFENCED
):
1973 xContext
= new SmXMLFencedContext_Impl(GetSmImport());
1975 /*Script and Limit Schemata*/
1976 case XML_ELEMENT(MATH
, XML_MSUB
):
1977 xContext
= new SmXMLSubContext_Impl(GetSmImport());
1979 case XML_ELEMENT(MATH
, XML_MSUP
):
1980 xContext
= new SmXMLSupContext_Impl(GetSmImport());
1982 case XML_ELEMENT(MATH
, XML_MSUBSUP
):
1983 xContext
= new SmXMLSubSupContext_Impl(GetSmImport());
1985 case XML_ELEMENT(MATH
, XML_MUNDER
):
1986 xContext
= new SmXMLUnderContext_Impl(GetSmImport());
1988 case XML_ELEMENT(MATH
, XML_MOVER
):
1989 xContext
= new SmXMLOverContext_Impl(GetSmImport());
1991 case XML_ELEMENT(MATH
, XML_MUNDEROVER
):
1992 xContext
= new SmXMLUnderOverContext_Impl(GetSmImport());
1994 case XML_ELEMENT(MATH
, XML_MMULTISCRIPTS
):
1995 xContext
= new SmXMLMultiScriptsContext_Impl(GetSmImport());
1997 case XML_ELEMENT(MATH
, XML_MTABLE
):
1998 xContext
= new SmXMLTableContext_Impl(GetSmImport());
2000 case XML_ELEMENT(MATH
, XML_MACTION
):
2001 xContext
= new SmXMLActionContext_Impl(GetSmImport());
2004 /*Basically there's an implicit mrow around certain bare
2005 *elements, use a RowContext to see if this is one of
2007 rtl::Reference
<SmXMLRowContext_Impl
> aTempContext(
2008 new SmXMLRowContext_Impl(GetSmImport()));
2010 xContext
= aTempContext
->StrictCreateChildContext(nElement
);
2016 void SmXMLDocContext_Impl::endFastElement(sal_Int32
)
2018 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2020 std::unique_ptr
<SmNode
> pContextNode
= popOrZero(rNodeStack
);
2023 std::unique_ptr
<SmStructureNode
> pSNode(new SmLineNode(aDummy
));
2024 pSNode
->SetSubNodes(std::move(pContextNode
), nullptr);
2025 rNodeStack
.push_front(std::move(pSNode
));
2027 SmNodeArray LineArray
;
2028 auto n
= rNodeStack
.size();
2029 LineArray
.resize(n
);
2030 for (size_t j
= 0; j
< n
; j
++)
2032 auto pNode
= std::move(rNodeStack
.front());
2033 rNodeStack
.pop_front();
2034 LineArray
[n
- (j
+ 1)] = pNode
.release();
2036 std::unique_ptr
<SmStructureNode
> pSNode2(new SmTableNode(aDummy
));
2037 pSNode2
->SetSubNodes(std::move(LineArray
));
2038 rNodeStack
.push_front(std::move(pSNode2
));
2041 void SmXMLFracContext_Impl::endFastElement(sal_Int32
)
2043 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2044 const bool bNodeCheck
= rNodeStack
.size() - nElementCount
== 2;
2045 OSL_ENSURE(bNodeCheck
, "Fraction (mfrac) tag is missing component");
2050 aToken
.cMathChar
= u
""_ustr
;
2051 aToken
.eType
= TFRAC
;
2052 std::unique_ptr
<SmStructureNode
> pSNode(new SmBinVerNode(aToken
));
2053 std::unique_ptr
<SmNode
> pOper(new SmRectangleNode(aToken
));
2054 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
2055 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
2056 pSNode
->SetSubNodes(std::move(pFirst
), std::move(pOper
), std::move(pSecond
));
2057 rNodeStack
.push_front(std::move(pSNode
));
2060 void SmXMLRootContext_Impl::endFastElement(sal_Int32
)
2062 /*The <mroot> element requires exactly 2 arguments.*/
2063 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
2064 OSL_ENSURE(bNodeCheck
, "Root tag is missing component");
2069 aToken
.setChar(MS_SQRT
); //Temporary: alert, based on StarSymbol font
2070 aToken
.eType
= TNROOT
;
2071 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2072 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2073 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2074 std::unique_ptr
<SmNode
> pIndex
= popOrZero(rNodeStack
);
2075 std::unique_ptr
<SmNode
> pBase
= popOrZero(rNodeStack
);
2076 pSNode
->SetSubNodes(std::move(pIndex
), std::move(pOper
), std::move(pBase
));
2077 rNodeStack
.push_front(std::move(pSNode
));
2080 void SmXMLSqrtContext_Impl::endFastElement(sal_Int32 nElement
)
2083 <msqrt> accepts any number of arguments; if this number is not 1, its
2084 contents are treated as a single "inferred <mrow>" containing its
2087 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
2088 SmXMLRowContext_Impl::endFastElement(nElement
);
2091 aToken
.setChar(MS_SQRT
); //Temporary: alert, based on StarSymbol font
2092 aToken
.eType
= TSQRT
;
2093 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2094 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2095 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2096 pSNode
->SetSubNodes(nullptr, std::move(pOper
), popOrZero(rNodeStack
));
2097 rNodeStack
.push_front(std::move(pSNode
));
2100 void SmXMLRowContext_Impl::endFastElement(sal_Int32
)
2102 SmNodeArray aRelationArray
;
2103 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2105 if (rNodeStack
.size() > nElementCount
)
2107 auto nSize
= rNodeStack
.size() - nElementCount
;
2109 aRelationArray
.resize(nSize
);
2110 for (auto j
= nSize
; j
> 0; j
--)
2112 auto pNode
= std::move(rNodeStack
.front());
2113 rNodeStack
.pop_front();
2114 aRelationArray
[j
- 1] = pNode
.release();
2117 //If the first or last element is an operator with stretchyness
2118 //set then we must create a brace node here from those elements,
2119 //removing the stretchness from the operators and applying it to
2120 //ourselves, and creating the appropriate dummy StarMath none bracket
2121 //to balance the arrangement
2122 if (((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2123 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2124 || ((aRelationArray
[nSize
- 1]->GetScaleMode() == SmScaleMode::Height
)
2125 && (aRelationArray
[nSize
- 1]->GetType() == SmNodeType::Math
)))
2128 aToken
.cMathChar
= u
""_ustr
;
2131 int nLeft
= 0, nRight
= 0;
2132 if ((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2133 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2135 aToken
= aRelationArray
[0]->GetToken();
2139 aToken
.cMathChar
= u
""_ustr
;
2141 aToken
.eType
= TLPARENT
;
2142 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
2144 if ((aRelationArray
[nSize
- 1]->GetScaleMode() == SmScaleMode::Height
)
2145 && (aRelationArray
[nSize
- 1]->GetType() == SmNodeType::Math
))
2147 aToken
= aRelationArray
[nSize
- 1]->GetToken();
2151 aToken
.cMathChar
= u
""_ustr
;
2153 aToken
.eType
= TRPARENT
;
2154 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
2156 SmNodeArray aRelationArray2
;
2158 //!! nSize-nLeft-nRight may be < 0 !!
2159 int nRelArrSize
= nSize
- nLeft
- nRight
;
2160 if (nRelArrSize
> 0)
2162 aRelationArray2
.resize(nRelArrSize
);
2163 for (int i
= 0; i
< nRelArrSize
; i
++)
2165 aRelationArray2
[i
] = aRelationArray
[i
+ nLeft
];
2166 aRelationArray
[i
+ nLeft
] = nullptr;
2171 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
2172 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
2173 pBody
->SetSubNodes(std::move(aRelationArray2
));
2175 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
2176 pSNode
->SetScaleMode(SmScaleMode::Height
);
2177 rNodeStack
.push_front(std::move(pSNode
));
2179 for (auto a
: aRelationArray
)
2187 // The elements msqrt, mstyle, merror, menclose, mpadded, mphantom, mtd, and math
2188 // treat their content as a single inferred mrow in case their content is empty.
2189 // Here an empty group {} is used to catch those cases and transform them without error
2191 aRelationArray
.resize(2);
2193 aToken
.setChar(MS_LBRACE
);
2195 aToken
.eType
= TLGROUP
;
2196 aToken
.nGroup
= TG::NONE
;
2198 aRelationArray
[0] = new SmLineNode(aToken
);
2200 aToken
.setChar(MS_RBRACE
);
2202 aToken
.eType
= TRGROUP
;
2203 aToken
.nGroup
= TG::NONE
;
2205 aRelationArray
[1] = new SmLineNode(aToken
);
2209 std::unique_ptr
<SmStructureNode
> pSNode(new SmExpressionNode(aDummy
));
2210 pSNode
->SetSubNodes(std::move(aRelationArray
));
2211 rNodeStack
.push_front(std::move(pSNode
));
2214 uno::Reference
<xml::sax::XFastContextHandler
>
2215 SmXMLRowContext_Impl::StrictCreateChildContext(sal_Int32 nElement
)
2217 uno::Reference
<xml::sax::XFastContextHandler
> pContext
;
2221 /*Note that these should accept malignmark subelements, but do not*/
2222 case XML_ELEMENT(MATH
, XML_MN
):
2223 pContext
= new SmXMLNumberContext_Impl(GetSmImport());
2225 case XML_ELEMENT(MATH
, XML_MI
):
2226 pContext
= new SmXMLIdentifierContext_Impl(GetSmImport());
2228 case XML_ELEMENT(MATH
, XML_MO
):
2229 pContext
= new SmXMLOperatorContext_Impl(GetSmImport());
2231 case XML_ELEMENT(MATH
, XML_MTEXT
):
2232 pContext
= new SmXMLTextContext_Impl(GetSmImport());
2234 case XML_ELEMENT(MATH
, XML_MSPACE
):
2235 pContext
= new SmXMLSpaceContext_Impl(GetSmImport());
2237 case XML_ELEMENT(MATH
, XML_MS
):
2238 pContext
= new SmXMLStringContext_Impl(GetSmImport());
2241 /*Note: The maligngroup should only be seen when the row
2242 * (or descendants) are in a table*/
2243 case XML_ELEMENT(MATH
, XML_MALIGNGROUP
):
2244 pContext
= new SmXMLAlignGroupContext_Impl(GetSmImport());
2247 case XML_ELEMENT(MATH
, XML_ANNOTATION
):
2248 pContext
= new SmXMLAnnotationContext_Impl(GetSmImport());
2257 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLRowContext_Impl::createFastChildContext(
2258 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2260 uno::Reference
<xml::sax::XFastContextHandler
> xContext
= StrictCreateChildContext(nElement
);
2264 //Hmm, unrecognized for this level, check to see if it's
2265 //an element that can have an implicit schema around it
2266 xContext
= SmXMLDocContext_Impl::createFastChildContext(nElement
, xAttrList
);
2271 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLMultiScriptsContext_Impl::createFastChildContext(
2272 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2274 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
2278 case XML_ELEMENT(MATH
, XML_MPRESCRIPTS
):
2279 bHasPrescripts
= true;
2280 ProcessSubSupPairs(false);
2281 xContext
= new SmXMLPrescriptsContext_Impl(GetSmImport());
2283 case XML_ELEMENT(MATH
, XML_NONE
):
2284 xContext
= new SmXMLNoneContext_Impl(GetSmImport());
2287 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2293 void SmXMLMultiScriptsContext_Impl::ProcessSubSupPairs(bool bIsPrescript
)
2295 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2297 if (rNodeStack
.size() <= nElementCount
)
2300 auto nCount
= rNodeStack
.size() - nElementCount
- 1;
2304 if (nCount
% 2 == 0)
2307 aToken
.cMathChar
= u
""_ustr
;
2308 aToken
.eType
= bIsPrescript
? TLSUB
: TRSUB
;
2310 SmNodeStack aReverseStack
;
2311 for (size_t i
= 0; i
< nCount
+ 1; i
++)
2313 auto pNode
= std::move(rNodeStack
.front());
2314 rNodeStack
.pop_front();
2315 aReverseStack
.push_front(std::move(pNode
));
2318 SmSubSup eSub
= bIsPrescript
? LSUB
: RSUB
;
2319 SmSubSup eSup
= bIsPrescript
? LSUP
: RSUP
;
2321 for (size_t i
= 0; i
< nCount
; i
+= 2)
2323 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
2325 // initialize subnodes array
2326 SmNodeArray
aSubNodes(1 + SUBSUP_NUM_ENTRIES
);
2328 /*On each loop the base and its sub sup pair becomes the
2329 base for the next loop to which the next sub sup pair is
2330 attached, i.e. wheels within wheels*/
2331 aSubNodes
[0] = popOrZero(aReverseStack
).release();
2333 std::unique_ptr
<SmNode
> pScriptNode
= popOrZero(aReverseStack
);
2336 && ((pScriptNode
->GetToken().eType
!= TIDENT
)
2337 || (!pScriptNode
->GetToken().aText
.isEmpty())))
2338 aSubNodes
[eSub
+ 1] = pScriptNode
.release();
2339 pScriptNode
= popOrZero(aReverseStack
);
2341 && ((pScriptNode
->GetToken().eType
!= TIDENT
)
2342 || (!pScriptNode
->GetToken().aText
.isEmpty())))
2343 aSubNodes
[eSup
+ 1] = pScriptNode
.release();
2345 pNode
->SetSubNodes(std::move(aSubNodes
));
2346 aReverseStack
.push_front(std::move(pNode
));
2348 assert(!aReverseStack
.empty());
2349 auto pNode
= std::move(aReverseStack
.front());
2350 aReverseStack
.pop_front();
2351 rNodeStack
.push_front(std::move(pNode
));
2355 // Ignore odd number of elements.
2356 for (size_t i
= 0; i
< nCount
; i
++)
2358 rNodeStack
.pop_front();
2363 void SmXMLTableContext_Impl::endFastElement(sal_Int32
)
2365 SmNodeArray aExpressionArray
;
2366 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2367 SmNodeStack aReverseStack
;
2368 aExpressionArray
.resize(rNodeStack
.size() - nElementCount
);
2370 size_t nRows
= rNodeStack
.size() - nElementCount
;
2373 for (size_t i
= nRows
; i
> 0; --i
)
2375 SmNode
* pArray
= rNodeStack
.front().release();
2376 rNodeStack
.pop_front();
2377 if (pArray
->GetNumSubNodes() == 0)
2379 //This is a little tricky, it is possible that there was
2380 //be elements that were not inside a <mtd> pair, in which
2381 //case they will not be in a row, i.e. they will not have
2382 //SubNodes, so we have to wait until here before we can
2383 //resolve the situation. Implicit surrounding tags are
2384 //surprisingly difficult to get right within this
2387 SmNodeArray aRelationArray
;
2388 aRelationArray
.resize(1);
2389 aRelationArray
[0] = pArray
;
2391 SmExpressionNode
* pExprNode
= new SmExpressionNode(aDummy
);
2392 pExprNode
->SetSubNodes(std::move(aRelationArray
));
2396 nCols
= std::max(nCols
, pArray
->GetNumSubNodes());
2397 aReverseStack
.push_front(std::unique_ptr
<SmNode
>(pArray
));
2399 if (nCols
> SAL_MAX_UINT16
)
2400 throw std::range_error("column limit");
2401 if (nRows
> SAL_MAX_UINT16
)
2402 throw std::range_error("row limit");
2403 aExpressionArray
.resize(nCols
* nRows
);
2405 for (auto& elem
: aReverseStack
)
2407 std::unique_ptr
<SmStructureNode
> xArray(static_cast<SmStructureNode
*>(elem
.release()));
2408 for (size_t i
= 0; i
< xArray
->GetNumSubNodes(); ++i
)
2409 aExpressionArray
[j
++] = xArray
->GetSubNode(i
);
2410 xArray
->ClearSubNodes();
2412 aReverseStack
.clear();
2415 aToken
.cMathChar
= u
""_ustr
;
2416 aToken
.eType
= TMATRIX
;
2417 std::unique_ptr
<SmMatrixNode
> pSNode(new SmMatrixNode(aToken
));
2418 pSNode
->SetSubNodes(std::move(aExpressionArray
));
2419 pSNode
->SetRowCol(nRows
, nCols
);
2420 rNodeStack
.push_front(std::move(pSNode
));
2423 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLTableRowContext_Impl::createFastChildContext(
2424 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2426 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
2430 case XML_ELEMENT(MATH
, XML_MTD
):
2431 xContext
= new SmXMLTableCellContext_Impl(GetSmImport());
2434 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2440 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLTableContext_Impl::createFastChildContext(
2441 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2443 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
2447 case XML_ELEMENT(MATH
, XML_MTR
):
2448 xContext
= new SmXMLTableRowContext_Impl(GetSmImport());
2451 xContext
= SmXMLTableRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2457 void SmXMLMultiScriptsContext_Impl::endFastElement(sal_Int32
)
2459 ProcessSubSupPairs(bHasPrescripts
);
2462 void SmXMLActionContext_Impl::startFastElement(
2463 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2465 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
2467 switch (aIter
.getToken())
2471 sal_Int32 n
= aIter
.toInt32();
2473 mnSelection
= static_cast<size_t>(n
);
2477 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
2483 void SmXMLActionContext_Impl::endFastElement(sal_Int32
)
2485 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2486 auto nSize
= rNodeStack
.size();
2487 if (nSize
<= nElementCount
)
2489 // not compliant to maction's specification, e.g., no subexpressions
2492 assert(mnSelection
> 0);
2493 if (nSize
< nElementCount
+ mnSelection
)
2495 // No selected subexpression exists, which is a MathML error;
2496 // fallback to selecting the first
2499 assert(nSize
>= nElementCount
+ mnSelection
);
2500 for (auto i
= nSize
- (nElementCount
+ mnSelection
); i
> 0; i
--)
2502 rNodeStack
.pop_front();
2504 auto pSelected
= std::move(rNodeStack
.front());
2505 rNodeStack
.pop_front();
2506 for (auto i
= rNodeStack
.size() - nElementCount
; i
> 0; i
--)
2508 rNodeStack
.pop_front();
2510 rNodeStack
.push_front(std::move(pSelected
));
2514 SmXMLImport::CreateFastContext(sal_Int32 nElement
,
2515 const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
2517 SvXMLImportContext
* pContext
= nullptr;
2521 case XML_ELEMENT(OFFICE
, XML_DOCUMENT
):
2522 case XML_ELEMENT(OFFICE
, XML_DOCUMENT_META
):
2524 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(GetModel(),
2525 uno::UNO_QUERY_THROW
);
2526 pContext
= ((nElement
& TOKEN_MASK
) == XML_DOCUMENT_META
)
2527 ? new SvXMLMetaDocumentContext(*this, xDPS
->getDocumentProperties())
2528 // flat OpenDocument file format -- this has not been tested...
2529 : new SmXMLFlatDocContext_Impl(*this, xDPS
->getDocumentProperties());
2533 if (IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE
))
2534 pContext
= new SmXMLOfficeContext_Impl(*this);
2536 pContext
= new SmXMLDocContext_Impl(*this);
2541 SmXMLImport::~SmXMLImport() noexcept
{ cleanup(); }
2543 void SmXMLImport::SetViewSettings(const Sequence
<PropertyValue
>& aViewProps
)
2545 uno::Reference
<frame::XModel
> xModel
= GetModel();
2549 SmModel
* pModel
= dynamic_cast<SmModel
*>(xModel
.get());
2554 SmDocShell
* pDocShell
= static_cast<SmDocShell
*>(pModel
->GetObjectShell());
2558 tools::Rectangle
aRect(pDocShell
->GetVisArea());
2560 tools::Long nTmp
= 0;
2562 for (const PropertyValue
& rValue
: aViewProps
)
2564 if (rValue
.Name
== "ViewAreaTop")
2566 rValue
.Value
>>= nTmp
;
2567 aRect
.SaturatingSetPosY(nTmp
);
2569 else if (rValue
.Name
== "ViewAreaLeft")
2571 rValue
.Value
>>= nTmp
;
2572 aRect
.SaturatingSetPosX(nTmp
);
2574 else if (rValue
.Name
== "ViewAreaWidth")
2576 rValue
.Value
>>= nTmp
;
2577 Size
aSize(aRect
.GetSize());
2578 aSize
.setWidth(nTmp
);
2579 aRect
.SaturatingSetSize(aSize
);
2581 else if (rValue
.Name
== "ViewAreaHeight")
2583 rValue
.Value
>>= nTmp
;
2584 Size
aSize(aRect
.GetSize());
2585 aSize
.setHeight(nTmp
);
2586 aRect
.SaturatingSetSize(aSize
);
2590 pDocShell
->SetVisArea(aRect
);
2593 void SmXMLImport::SetConfigurationSettings(const Sequence
<PropertyValue
>& aConfProps
)
2595 uno::Reference
<XPropertySet
> xProps(GetModel(), UNO_QUERY
);
2599 Reference
<XPropertySetInfo
> xInfo(xProps
->getPropertySetInfo());
2603 static constexpr OUStringLiteral
sFormula(u
"Formula");
2604 static constexpr OUStringLiteral
sBasicLibraries(u
"BasicLibraries");
2605 static constexpr OUStringLiteral
sDialogLibraries(u
"DialogLibraries");
2606 for (const PropertyValue
& rValue
: aConfProps
)
2608 if (rValue
.Name
!= sFormula
&& rValue
.Name
!= sBasicLibraries
2609 && rValue
.Name
!= sDialogLibraries
)
2613 if (xInfo
->hasPropertyByName(rValue
.Name
))
2614 xProps
->setPropertyValue(rValue
.Name
, rValue
.Value
);
2616 catch (const beans::PropertyVetoException
&)
2618 // dealing with read-only properties here. Nothing to do...
2620 catch (const Exception
&)
2622 DBG_UNHANDLED_EXCEPTION("starmath");
2628 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportMML(SvStream
& rStream
)
2630 SmGlobals::ensure();
2632 SfxObjectShellLock
xDocSh(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT
));
2633 xDocSh
->DoInitNew();
2634 uno::Reference
<frame::XModel
> xModel(xDocSh
->GetModel());
2636 uno::Reference
<beans::XPropertySet
> xInfoSet
;
2637 const uno::Reference
<uno::XComponentContext
>& xContext(
2638 comphelper::getProcessComponentContext());
2639 uno::Reference
<io::XInputStream
> xStream(new utl::OSeekableInputStreamWrapper(rStream
));
2641 //SetLoading hack because the document properties will be re-initted
2642 //by the xml filter and during the init, while it's considered uninitialized,
2643 //setting a property will inform the document it's modified, which attempts
2644 //to update the properties, which throws cause the properties are uninitialized
2645 xDocSh
->SetLoading(SfxLoadedFlags::NONE
);
2647 ErrCode nRet
= ERRCODE_SFX_DOLOADFAILED
;
2651 nRet
= SmXMLImportWrapper::ReadThroughComponent(xStream
, xModel
, xContext
, xInfoSet
,
2652 "com.sun.star.comp.Math.XMLImporter", false,
2659 xDocSh
->SetLoading(SfxLoadedFlags::ALL
);
2663 return nRet
!= ERRCODE_NONE
;
2666 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */