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::container
;
78 using namespace ::com::sun::star::document
;
79 using namespace ::com::sun::star::lang
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star
;
82 using namespace ::xmloff::token
;
86 std::unique_ptr
<SmNode
> popOrZero(SmNodeStack
& rStack
)
90 auto pTmp
= std::move(rStack
.front());
96 ErrCode
SmXMLImportWrapper::Import(SfxMedium
& rMedium
)
98 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
100 uno::Reference
<uno::XComponentContext
> xContext(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 SfxItemSet
* pSet
= rMedium
.GetItemSet();
118 const SfxUnoAnyItem
* pItem
= pSet
->GetItem(SID_PROGRESS_STATUSBAR_CONTROL
);
120 pItem
->GetValue() >>= xStatusIndicator
;
123 if (SfxObjectCreateMode::EMBEDDED
== pDocShell
->GetCreateMode())
127 static const comphelper::PropertyMapEntry aInfoMap
[]
128 = { { OUString("PrivateData"), 0, cppu::UnoType
<XInterface
>::get(),
129 beans::PropertyAttribute::MAYBEVOID
, 0 },
130 { OUString("BaseURI"), 0, ::cppu::UnoType
<OUString
>::get(),
131 beans::PropertyAttribute::MAYBEVOID
, 0 },
132 { OUString("StreamRelPath"), 0, ::cppu::UnoType
<OUString
>::get(),
133 beans::PropertyAttribute::MAYBEVOID
, 0 },
134 { OUString("StreamName"), 0, ::cppu::UnoType
<OUString
>::get(),
135 beans::PropertyAttribute::MAYBEVOID
, 0 } };
136 uno::Reference
<beans::XPropertySet
> xInfoSet(
137 comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap
)));
140 OUString
const baseURI(rMedium
.GetBaseURL());
141 // needed for relative URLs; but it's OK to import e.g. MathML from the
142 // clipboard without one
143 SAL_INFO_IF(baseURI
.isEmpty(), "starmath", "SmXMLImportWrapper: no base URL");
144 xInfoSet
->setPropertyValue("BaseURI", Any(baseURI
));
146 sal_Int32 nSteps
= 3;
147 if (!(rMedium
.IsStorage()))
150 sal_Int32
nProgressRange(nSteps
);
151 if (xStatusIndicator
.is())
153 xStatusIndicator
->start(SvxResId(RID_SVXSTR_DOC_LOAD
), nProgressRange
);
157 if (xStatusIndicator
.is())
158 xStatusIndicator
->setValue(nSteps
++);
160 if (rMedium
.IsStorage())
162 // TODO/LATER: handle the case of embedded links gracefully
163 if (bEmbedded
) // && !rMedium.GetStorage()->IsRoot() )
165 OUString
aName("dummyObjName");
166 if (rMedium
.GetItemSet())
168 const SfxStringItem
* pDocHierarchItem
169 = rMedium
.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME
);
170 if (pDocHierarchItem
)
171 aName
= pDocHierarchItem
->GetValue();
174 if (!aName
.isEmpty())
176 xInfoSet
->setPropertyValue("StreamRelPath", Any(aName
));
180 bool bOASIS
= (SotStorage::GetVersion(rMedium
.GetStorage()) > SOFFICE_FILEFORMAT_60
);
181 if (xStatusIndicator
.is())
182 xStatusIndicator
->setValue(nSteps
++);
185 = ReadThroughComponent(rMedium
.GetStorage(), m_xModel
, "meta.xml", xContext
, xInfoSet
,
186 (bOASIS
? "com.sun.star.comp.Math.XMLOasisMetaImporter"
187 : "com.sun.star.comp.Math.XMLMetaImporter"),
188 m_bUseHTMLMLEntities
);
190 if (nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
192 if (xStatusIndicator
.is())
193 xStatusIndicator
->setValue(nSteps
++);
195 nWarn
= ReadThroughComponent(rMedium
.GetStorage(), m_xModel
, "settings.xml", xContext
,
197 (bOASIS
? "com.sun.star.comp.Math.XMLOasisSettingsImporter"
198 : "com.sun.star.comp.Math.XMLSettingsImporter"),
199 m_bUseHTMLMLEntities
);
201 if (nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
203 if (xStatusIndicator
.is())
204 xStatusIndicator
->setValue(nSteps
++);
206 nError
= ReadThroughComponent(
207 rMedium
.GetStorage(), m_xModel
, "content.xml", xContext
, xInfoSet
,
208 "com.sun.star.comp.Math.XMLImporter", m_bUseHTMLMLEntities
);
211 nError
= ERRCODE_IO_BROKENPACKAGE
;
214 nError
= ERRCODE_IO_BROKENPACKAGE
;
218 Reference
<io::XInputStream
> xInputStream
219 = new utl::OInputStreamWrapper(rMedium
.GetInStream());
221 if (xStatusIndicator
.is())
222 xStatusIndicator
->setValue(nSteps
++);
224 nError
= ReadThroughComponent(xInputStream
, m_xModel
, xContext
, xInfoSet
,
225 "com.sun.star.comp.Math.XMLImporter", false,
226 m_bUseHTMLMLEntities
);
229 if (xStatusIndicator
.is())
230 xStatusIndicator
->end();
234 /// read a component (file + filter version)
235 ErrCode
SmXMLImportWrapper::ReadThroughComponent(const Reference
<io::XInputStream
>& xInputStream
,
236 const Reference
<XComponent
>& xModelComponent
,
237 Reference
<uno::XComponentContext
> const& rxContext
,
238 Reference
<beans::XPropertySet
> const& rPropSet
,
239 const char* pFilterName
, bool bEncrypted
,
240 bool bUseHTMLMLEntities
)
242 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
243 OSL_ENSURE(xInputStream
.is(), "input stream missing");
244 OSL_ENSURE(xModelComponent
.is(), "document missing");
245 OSL_ENSURE(rxContext
.is(), "factory missing");
246 OSL_ENSURE(nullptr != pFilterName
, "I need a service name for the component!");
248 // prepare ParserInputSource
249 xml::sax::InputSource aParserInput
;
250 aParserInput
.aInputStream
= xInputStream
;
252 Sequence
<Any
> aArgs
{ Any(rPropSet
) };
255 Reference
<XInterface
> xFilter
256 = rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
257 OUString::createFromAscii(pFilterName
), aArgs
, rxContext
);
258 SAL_WARN_IF(!xFilter
, "starmath", "Can't instantiate filter component " << pFilterName
);
262 // connect model and filter
263 Reference
<XImporter
> xImporter(xFilter
, UNO_QUERY
);
264 xImporter
->setTargetDocument(xModelComponent
);
266 // finally, parser the stream
269 Reference
<css::xml::sax::XFastParser
> xFastParser(xFilter
, UNO_QUERY
);
270 Reference
<css::xml::sax::XFastDocumentHandler
> xFastDocHandler(xFilter
, UNO_QUERY
);
273 if (bUseHTMLMLEntities
)
274 xFastParser
->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntities
);
275 xFastParser
->parseStream(aParserInput
);
277 else if (xFastDocHandler
)
279 Reference
<css::xml::sax::XFastParser
> xParser
280 = css::xml::sax::FastParser::create(rxContext
);
281 if (bUseHTMLMLEntities
)
282 xParser
->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntities
);
283 xParser
->setFastDocumentHandler(xFastDocHandler
);
284 xParser
->parseStream(aParserInput
);
288 Reference
<css::xml::sax::XDocumentHandler
> xDocHandler(xFilter
, UNO_QUERY
);
290 Reference
<css::xml::sax::XParser
> xParser
= css::xml::sax::Parser::create(rxContext
);
291 xParser
->setDocumentHandler(xDocHandler
);
292 xParser
->parseStream(aParserInput
);
295 auto pFilter
= dynamic_cast<SmXMLImport
*>(xFilter
.get());
296 if (pFilter
&& pFilter
->GetSuccess())
297 nError
= ERRCODE_NONE
;
299 catch (const xml::sax::SAXParseException
& r
)
301 // sax parser sends wrapped exceptions,
302 // try to find the original one
303 xml::sax::SAXException aSaxEx
= *static_cast<const xml::sax::SAXException
*>(&r
);
304 bool bTryChild
= true;
308 xml::sax::SAXException aTmp
;
309 if (aSaxEx
.WrappedException
>>= aTmp
)
315 packages::zip::ZipIOException aBrokenPackage
;
316 if (aSaxEx
.WrappedException
>>= aBrokenPackage
)
317 return ERRCODE_IO_BROKENPACKAGE
;
320 nError
= ERRCODE_SFX_WRONGPASSWORD
;
322 catch (const xml::sax::SAXException
& r
)
324 packages::zip::ZipIOException aBrokenPackage
;
325 if (r
.WrappedException
>>= aBrokenPackage
)
326 return ERRCODE_IO_BROKENPACKAGE
;
329 nError
= ERRCODE_SFX_WRONGPASSWORD
;
331 catch (const packages::zip::ZipIOException
&)
333 nError
= ERRCODE_IO_BROKENPACKAGE
;
335 catch (const io::IOException
&)
338 catch (const std::range_error
&)
345 ErrCode
SmXMLImportWrapper::ReadThroughComponent(const uno::Reference
<embed::XStorage
>& xStorage
,
346 const Reference
<XComponent
>& xModelComponent
,
347 const char* pStreamName
,
348 Reference
<uno::XComponentContext
> const& rxContext
,
349 Reference
<beans::XPropertySet
> const& rPropSet
,
350 const char* pFilterName
, bool bUseHTMLMLEntities
)
352 OSL_ENSURE(xStorage
.is(), "Need storage!");
353 OSL_ENSURE(nullptr != pStreamName
, "Please, please, give me a name!");
355 // open stream (and set parser input)
356 OUString sStreamName
= OUString::createFromAscii(pStreamName
);
361 uno::Reference
<io::XStream
> xEventsStream
362 = xStorage
->openStreamElement(sStreamName
, embed::ElementModes::READ
);
364 // determine if stream is encrypted or not
365 uno::Reference
<beans::XPropertySet
> xProps(xEventsStream
, uno::UNO_QUERY
);
366 Any aAny
= xProps
->getPropertyValue("Encrypted");
367 bool bEncrypted
= false;
368 if (aAny
.getValueType() == cppu::UnoType
<bool>::get())
374 rPropSet
->setPropertyValue("StreamName", Any(sStreamName
));
377 Reference
<io::XInputStream
> xStream
= xEventsStream
->getInputStream();
378 return ReadThroughComponent(xStream
, xModelComponent
, rxContext
, rPropSet
, pFilterName
,
379 bEncrypted
, bUseHTMLMLEntities
);
381 catch (packages::WrongPasswordException
&)
383 return ERRCODE_SFX_WRONGPASSWORD
;
385 catch (packages::zip::ZipIOException
&)
387 return ERRCODE_IO_BROKENPACKAGE
;
389 catch (uno::Exception
&)
393 return ERRCODE_SFX_DOLOADFAILED
;
396 SmXMLImport::SmXMLImport(const css::uno::Reference
<css::uno::XComponentContext
>& rContext
,
397 OUString
const& implementationName
, SvXMLImportFlags nImportFlags
)
398 : SvXMLImport(rContext
, implementationName
, nImportFlags
)
401 , mnSmSyntaxVersion(SM_MOD()->GetConfig()->GetDefaultSmSyntaxVersion())
405 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
406 Math_XMLImporter_get_implementation(uno::XComponentContext
* pCtx
,
407 uno::Sequence
<uno::Any
> const& /*rSeq*/)
409 return cppu::acquire(
410 new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLImporter", SvXMLImportFlags::ALL
));
413 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
414 Math_XMLOasisMetaImporter_get_implementation(uno::XComponentContext
* pCtx
,
415 uno::Sequence
<uno::Any
> const& /*rSeq*/)
417 return cppu::acquire(new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLOasisMetaImporter",
418 SvXMLImportFlags::META
));
421 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
422 Math_XMLOasisSettingsImporter_get_implementation(uno::XComponentContext
* pCtx
,
423 uno::Sequence
<uno::Any
> const& /*rSeq*/)
425 return cppu::acquire(new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLOasisSettingsImporter",
426 SvXMLImportFlags::SETTINGS
));
429 void SmXMLImport::endDocument()
431 //Set the resulted tree into the SmDocShell where it belongs
432 std::unique_ptr
<SmNode
> pTree
= popOrZero(aNodeStack
);
433 if (pTree
&& pTree
->GetType() == SmNodeType::Table
)
435 uno::Reference
<frame::XModel
> xModel
= GetModel();
436 SmModel
* pModel
= dynamic_cast<SmModel
*>(xModel
.get());
440 SmDocShell
* pDocShell
= static_cast<SmDocShell
*>(pModel
->GetObjectShell());
441 auto pTreeTmp
= pTree
.get();
442 pDocShell
->SetFormulaTree(static_cast<SmTableNode
*>(pTree
.release()));
443 if (aText
.isEmpty()) //If we picked up no annotation text
445 // Get text from imported formula
446 SmNodeToTextVisitor
tmpvisitor(pTreeTmp
, aText
);
449 // Convert symbol names
450 AbstractSmParser
* rParser
= pDocShell
->GetParser();
451 bool bVal
= rParser
->IsImportSymbolNames();
452 rParser
->SetImportSymbolNames(true);
453 auto pTmpTree
= rParser
->Parse(aText
);
454 aText
= rParser
->GetText();
456 rParser
->SetImportSymbolNames(bVal
);
458 pDocShell
->SetText(aText
);
459 pDocShell
->SetSmSyntaxVersion(mnSmSyntaxVersion
);
461 OSL_ENSURE(pModel
, "So there *was* a UNO problem after all");
466 SvXMLImport::endDocument();
471 class SmXMLImportContext
: public SvXMLImportContext
474 SmXMLImportContext(SmXMLImport
& rImport
)
475 : SvXMLImportContext(rImport
)
477 GetSmImport().IncParseDepth();
480 virtual ~SmXMLImportContext() override
{ GetSmImport().DecParseDepth(); }
482 SmXMLImport
& GetSmImport() { return static_cast<SmXMLImport
&>(GetImport()); }
484 virtual void TCharacters(const OUString
& /*rChars*/);
485 virtual void SAL_CALL
characters(const OUString
& rChars
) override
;
486 virtual void SAL_CALL
startFastElement(
487 sal_Int32
/*nElement*/,
488 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& /*rAttrList*/) override
490 if (GetSmImport().TooDeep())
491 throw std::range_error("too deep");
496 void SmXMLImportContext::TCharacters(const OUString
& /*rChars*/) {}
498 void SmXMLImportContext::characters(const OUString
& rChars
)
501 Whitespace occurring within the content of token elements is "trimmed"
502 from the ends (i.e. all whitespace at the beginning and end of the
503 content is removed), and "collapsed" internally (i.e. each sequence of
504 1 or more whitespace characters is replaced with one blank character).
506 //collapsing not done yet!
507 const OUString
& rChars2
= rChars
.trim();
508 if (!rChars2
.isEmpty())
509 TCharacters(rChars2
/*.collapse()*/);
514 struct SmXMLContext_Helper
519 OUString sFontFamily
;
522 SmXMLImportContext
& rContext
;
524 explicit SmXMLContext_Helper(SmXMLImportContext
& rImport
)
532 bool IsFontNodeNeeded() const;
533 void RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
);
538 bool SmXMLContext_Helper::IsFontNodeNeeded() const
540 return nIsBold
!= -1 || nIsItalic
!= -1 || nFontSize
!= 0.0 || !sFontFamily
.isEmpty()
541 || !sColor
.isEmpty();
544 void SmXMLContext_Helper::RetrieveAttrs(
545 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
547 bool bMvFound
= false;
548 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
550 // sometimes they have namespace, sometimes not?
551 switch (aIter
.getToken() & TOKEN_MASK
)
554 nIsBold
= sal_Int8(IsXMLToken(aIter
, XML_BOLD
));
557 nIsItalic
= sal_Int8(IsXMLToken(aIter
, XML_ITALIC
));
562 OUString sValue
= aIter
.toString();
563 ::sax::Converter::convertDouble(nFontSize
, sValue
);
564 rContext
.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
565 util::MeasureUnit::POINT
);
566 if (-1 == sValue
.indexOf(GetXMLToken(XML_UNIT_PT
)))
568 if (-1 == sValue
.indexOf('%'))
572 rContext
.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
573 util::MeasureUnit::PERCENT
);
579 sFontFamily
= aIter
.toString();
582 sColor
= aIter
.toString();
585 sColor
= aIter
.toString();
587 case XML_MATHVARIANT
:
591 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
598 // Ignore deprecated attributes fontfamily, fontweight, and fontstyle
599 // in favor of mathvariant, as specified in
600 // <https://www.w3.org/TR/MathML3/chapter3.html#presm.deprecatt>.
607 void SmXMLContext_Helper::ApplyAttrs()
609 SmNodeStack
& rNodeStack
= rContext
.GetSmImport().GetNodeStack();
611 if (!IsFontNodeNeeded())
615 aToken
.cMathChar
= u
"";
621 aToken
.eType
= TBOLD
;
623 aToken
.eType
= TNBOLD
;
624 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
625 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
626 rNodeStack
.push_front(std::move(pFontNode
));
631 aToken
.eType
= TITALIC
;
633 aToken
.eType
= TNITALIC
;
634 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
635 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
636 rNodeStack
.push_front(std::move(pFontNode
));
638 if (nFontSize
!= 0.0)
640 aToken
.eType
= TSIZE
;
641 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
643 if (util::MeasureUnit::PERCENT
644 == rContext
.GetSmImport().GetMM100UnitConverter().GetXMLMeasureUnit())
646 if (nFontSize
< 100.00)
647 pFontNode
->SetSizeParameter(Fraction(100.00 / nFontSize
), FontSizeType::DIVIDE
);
649 pFontNode
->SetSizeParameter(Fraction(nFontSize
/ 100.00), FontSizeType::MULTIPLY
);
652 pFontNode
->SetSizeParameter(Fraction(nFontSize
), FontSizeType::ABSOLUT
);
654 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
655 rNodeStack
.push_front(std::move(pFontNode
));
657 if (!sColor
.isEmpty())
659 SmColorTokenTableEntry aSmColorTokenTableEntry
;
660 aSmColorTokenTableEntry
= starmathdatabase::Identify_ColorName_HTML(sColor
);
661 if (aSmColorTokenTableEntry
.eType
== TRGB
)
662 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser(
663 sal_uInt32(aSmColorTokenTableEntry
.cColor
));
664 if (aSmColorTokenTableEntry
.eType
!= TERROR
)
666 aToken
= aSmColorTokenTableEntry
;
667 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
668 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
669 rNodeStack
.push_front(std::move(pFontNode
));
671 // If not known, not implemented yet. Giving up.
673 if (sFontFamily
.isEmpty())
676 if (sFontFamily
.equalsIgnoreAsciiCase(GetXMLToken(XML_FIXED
)))
677 aToken
.eType
= TFIXED
;
678 else if (sFontFamily
.equalsIgnoreAsciiCase("sans"))
679 aToken
.eType
= TSANS
;
680 else if (sFontFamily
.equalsIgnoreAsciiCase("serif"))
681 aToken
.eType
= TSERIF
;
682 else //Just give up, we need to extend our font mechanism to be
686 aToken
.aText
= sFontFamily
;
687 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
688 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
689 rNodeStack
.push_front(std::move(pFontNode
));
694 class SmXMLTokenAttrHelper
696 SmXMLImportContext
& mrContext
;
697 MathMLMathvariantValue meMv
;
701 SmXMLTokenAttrHelper(SmXMLImportContext
& rContext
)
702 : mrContext(rContext
)
703 , meMv(MathMLMathvariantValue::Normal
)
708 void RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
);
709 void ApplyAttrs(MathMLMathvariantValue eDefaultMv
);
713 void SmXMLTokenAttrHelper::RetrieveAttrs(
714 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
716 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
718 OUString sValue
= aIter
.toString();
719 switch (aIter
.getToken())
721 case XML_MATHVARIANT
:
722 if (!GetMathMLMathvariantValue(sValue
, meMv
))
723 SAL_WARN("starmath", "failed to recognize mathvariant: " << sValue
);
727 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
733 void SmXMLTokenAttrHelper::ApplyAttrs(MathMLMathvariantValue eDefaultMv
)
735 assert(eDefaultMv
== MathMLMathvariantValue::Normal
736 || eDefaultMv
== MathMLMathvariantValue::Italic
);
738 std::vector
<SmTokenType
> vVariant
;
739 MathMLMathvariantValue eMv
= mbMvFound
? meMv
: eDefaultMv
;
742 case MathMLMathvariantValue::Normal
:
743 vVariant
.push_back(TNITALIC
);
745 case MathMLMathvariantValue::Bold
:
746 vVariant
.push_back(TBOLD
);
748 case MathMLMathvariantValue::Italic
:
751 case MathMLMathvariantValue::BoldItalic
:
752 vVariant
.push_back(TITALIC
);
753 vVariant
.push_back(TBOLD
);
755 case MathMLMathvariantValue::DoubleStruck
:
758 case MathMLMathvariantValue::BoldFraktur
:
760 vVariant
.push_back(TBOLD
);
762 case MathMLMathvariantValue::Script
:
765 case MathMLMathvariantValue::BoldScript
:
767 vVariant
.push_back(TBOLD
);
769 case MathMLMathvariantValue::Fraktur
:
772 case MathMLMathvariantValue::SansSerif
:
773 vVariant
.push_back(TSANS
);
775 case MathMLMathvariantValue::BoldSansSerif
:
776 vVariant
.push_back(TSANS
);
777 vVariant
.push_back(TBOLD
);
779 case MathMLMathvariantValue::SansSerifItalic
:
780 vVariant
.push_back(TITALIC
);
781 vVariant
.push_back(TSANS
);
783 case MathMLMathvariantValue::SansSerifBoldItalic
:
784 vVariant
.push_back(TITALIC
);
785 vVariant
.push_back(TBOLD
);
786 vVariant
.push_back(TSANS
);
788 case MathMLMathvariantValue::Monospace
:
789 vVariant
.push_back(TFIXED
);
791 case MathMLMathvariantValue::Initial
:
792 case MathMLMathvariantValue::Tailed
:
793 case MathMLMathvariantValue::Looped
:
794 case MathMLMathvariantValue::Stretched
:
798 if (vVariant
.empty())
800 SmNodeStack
& rNodeStack
= mrContext
.GetSmImport().GetNodeStack();
801 for (auto eType
: vVariant
)
804 aToken
.eType
= eType
;
805 aToken
.cMathChar
= u
"";
807 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
808 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
809 rNodeStack
.push_front(std::move(pFontNode
));
815 class SmXMLDocContext_Impl
: public SmXMLImportContext
818 SmXMLDocContext_Impl(SmXMLImport
& rImport
)
819 : SmXMLImportContext(rImport
)
823 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
824 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
826 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
829 /*avert the gaze from the originator*/
830 class SmXMLRowContext_Impl
: public SmXMLDocContext_Impl
833 size_t nElementCount
;
836 SmXMLRowContext_Impl(SmXMLImport
& rImport
)
837 : SmXMLDocContext_Impl(rImport
)
838 , nElementCount(GetSmImport().GetNodeStack().size())
842 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
843 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
845 uno::Reference
<xml::sax::XFastContextHandler
> StrictCreateChildContext(sal_Int32 nElement
);
847 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
850 class SmXMLEncloseContext_Impl
: public SmXMLRowContext_Impl
853 // TODO/LATER: convert <menclose notation="horizontalstrike"> into
854 // "overstrike{}" and extend the Math syntax to support more notations
855 SmXMLEncloseContext_Impl(SmXMLImport
& rImport
)
856 : SmXMLRowContext_Impl(rImport
)
860 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
864 void SmXMLEncloseContext_Impl::endFastElement(sal_Int32 nElement
)
867 <menclose> accepts any number of arguments; if this number is not 1, its
868 contents are treated as a single "inferred <mrow>" containing its
871 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
872 SmXMLRowContext_Impl::endFastElement(nElement
);
877 class SmXMLFracContext_Impl
: public SmXMLRowContext_Impl
880 // TODO/LATER: convert <mfrac bevelled="true"> into "wideslash{}{}"
881 SmXMLFracContext_Impl(SmXMLImport
& rImport
)
882 : SmXMLRowContext_Impl(rImport
)
886 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
889 class SmXMLSqrtContext_Impl
: public SmXMLRowContext_Impl
892 SmXMLSqrtContext_Impl(SmXMLImport
& rImport
)
893 : SmXMLRowContext_Impl(rImport
)
897 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
900 class SmXMLRootContext_Impl
: public SmXMLRowContext_Impl
903 SmXMLRootContext_Impl(SmXMLImport
& rImport
)
904 : SmXMLRowContext_Impl(rImport
)
908 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
911 class SmXMLStyleContext_Impl
: public SmXMLRowContext_Impl
914 SmXMLContext_Helper aStyleHelper
;
917 /*Right now the style tag is completely ignored*/
918 SmXMLStyleContext_Impl(SmXMLImport
& rImport
)
919 : SmXMLRowContext_Impl(rImport
)
920 , aStyleHelper(*this)
924 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
925 void SAL_CALL
startFastElement(
926 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
930 void SmXMLStyleContext_Impl::startFastElement(
931 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
933 aStyleHelper
.RetrieveAttrs(xAttrList
);
936 void SmXMLStyleContext_Impl::endFastElement(sal_Int32 nElement
)
939 <mstyle> accepts any number of arguments; if this number is not 1, its
940 contents are treated as a single "inferred <mrow>" containing its
943 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
944 if (rNodeStack
.size() - nElementCount
!= 1)
945 SmXMLRowContext_Impl::endFastElement(nElement
);
946 aStyleHelper
.ApplyAttrs();
951 class SmXMLPaddedContext_Impl
: public SmXMLRowContext_Impl
954 /*Right now the style tag is completely ignored*/
955 SmXMLPaddedContext_Impl(SmXMLImport
& rImport
)
956 : SmXMLRowContext_Impl(rImport
)
960 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
964 void SmXMLPaddedContext_Impl::endFastElement(sal_Int32 nElement
)
967 <mpadded> accepts any number of arguments; if this number is not 1, its
968 contents are treated as a single "inferred <mrow>" containing its
971 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
972 SmXMLRowContext_Impl::endFastElement(nElement
);
977 class SmXMLPhantomContext_Impl
: public SmXMLRowContext_Impl
980 /*Right now the style tag is completely ignored*/
981 SmXMLPhantomContext_Impl(SmXMLImport
& rImport
)
982 : SmXMLRowContext_Impl(rImport
)
986 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
990 void SmXMLPhantomContext_Impl::endFastElement(sal_Int32 nElement
)
993 <mphantom> accepts any number of arguments; if this number is not 1, its
994 contents are treated as a single "inferred <mrow>" containing its
997 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
998 SmXMLRowContext_Impl::endFastElement(nElement
);
1001 aToken
.cMathChar
= u
"";
1003 aToken
.eType
= TPHANTOM
;
1005 std::unique_ptr
<SmFontNode
> pPhantom(new SmFontNode(aToken
));
1006 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1007 pPhantom
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
1008 rNodeStack
.push_front(std::move(pPhantom
));
1013 class SmXMLFencedContext_Impl
: public SmXMLRowContext_Impl
1021 SmXMLFencedContext_Impl(SmXMLImport
& rImport
)
1022 : SmXMLRowContext_Impl(rImport
)
1025 , bIsStretchy(false)
1029 void SAL_CALL
startFastElement(
1030 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1031 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1035 void SmXMLFencedContext_Impl::startFastElement(
1036 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1038 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1040 switch (aIter
.getToken())
1042 //temp, starmath cannot handle multichar brackets (I think)
1044 cBegin
= aIter
.toString()[0];
1047 cEnd
= aIter
.toString()[0];
1050 bIsStretchy
= IsXMLToken(aIter
, XML_TRUE
);
1053 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1054 /*Go to superclass*/
1060 void SmXMLFencedContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1063 aToken
.cMathChar
= u
"";
1067 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
1069 aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cBegin
);
1071 aToken
= starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(cBegin
);
1072 if (aToken
.eType
== TERROR
)
1073 aToken
= SmToken(TLPARENT
, MS_LPARENT
, "(", TG::LBrace
, 5);
1074 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
1076 aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cEnd
);
1078 aToken
= starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(cEnd
);
1079 if (aToken
.eType
== TERROR
)
1080 aToken
= SmToken(TRPARENT
, MS_RPARENT
, ")", TG::LBrace
, 5);
1081 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
1083 SmNodeArray aRelationArray
;
1084 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1085 aToken
.cMathChar
= u
"";
1086 aToken
.eType
= TIDENT
;
1088 auto i
= rNodeStack
.size() - nElementCount
;
1089 if (rNodeStack
.size() - nElementCount
> 1)
1090 i
+= rNodeStack
.size() - 1 - nElementCount
;
1091 aRelationArray
.resize(i
);
1092 while (rNodeStack
.size() > nElementCount
)
1094 auto pNode
= std::move(rNodeStack
.front());
1095 rNodeStack
.pop_front();
1096 aRelationArray
[--i
] = pNode
.release();
1097 if (i
> 1 && rNodeStack
.size() > 1)
1098 aRelationArray
[--i
] = new SmGlyphSpecialNode(aToken
);
1102 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
1103 pBody
->SetSubNodes(std::move(aRelationArray
));
1105 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
1106 // mfenced is always scalable. Stretchy keyword is not official, but in case of been in there
1107 // can be used as a hint.
1108 pSNode
->SetScaleMode(SmScaleMode::Height
);
1109 GetSmImport().GetNodeStack().push_front(std::move(pSNode
));
1114 class SmXMLErrorContext_Impl
: public SmXMLRowContext_Impl
1117 SmXMLErrorContext_Impl(SmXMLImport
& rImport
)
1118 : SmXMLRowContext_Impl(rImport
)
1122 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1126 void SmXMLErrorContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1128 /*Right now the error tag is completely ignored, what
1129 can I do with it in starmath, ?, maybe we need a
1130 report window ourselves, do a test for validity of
1131 the xml input, use mirrors, and then generate
1132 the markup inside the merror with a big red colour
1133 of something. For now just throw them all away.
1135 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1136 while (rNodeStack
.size() > nElementCount
)
1138 rNodeStack
.pop_front();
1144 class SmXMLNumberContext_Impl
: public SmXMLImportContext
1150 SmXMLNumberContext_Impl(SmXMLImport
& rImport
)
1151 : SmXMLImportContext(rImport
)
1153 aToken
.cMathChar
= u
"";
1155 aToken
.eType
= TNUMBER
;
1158 virtual void TCharacters(const OUString
& rChars
) override
;
1160 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1164 void SmXMLNumberContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1166 void SmXMLNumberContext_Impl::endFastElement(sal_Int32
)
1168 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_NUMBER
));
1173 class SmXMLAnnotationContext_Impl
: public SmXMLImportContext
1175 sal_uInt8 mnStarMathVersion
;
1178 SmXMLAnnotationContext_Impl(SmXMLImport
& rImport
)
1179 : SmXMLImportContext(rImport
)
1180 , mnStarMathVersion(0)
1184 void SAL_CALL
characters(const OUString
& rChars
) override
;
1186 void SAL_CALL
startFastElement(
1187 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1191 void SmXMLAnnotationContext_Impl::startFastElement(
1192 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1194 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1196 // sometimes they have namespace, sometimes not?
1197 switch (aIter
.getToken() & TOKEN_MASK
)
1201 = aIter
.toView() == "StarMath 5.0" ? 5 : aIter
.toView() == "StarMath 6" ? 6 : 0;
1204 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1210 void SmXMLAnnotationContext_Impl::characters(const OUString
& rChars
)
1212 if (mnStarMathVersion
)
1214 GetSmImport().SetText(GetSmImport().GetText() + rChars
);
1215 GetSmImport().SetSmSyntaxVersion(mnStarMathVersion
);
1221 class SmXMLTextContext_Impl
: public SmXMLImportContext
1227 SmXMLTextContext_Impl(SmXMLImport
& rImport
)
1228 : SmXMLImportContext(rImport
)
1230 aToken
.cMathChar
= u
"";
1232 aToken
.eType
= TTEXT
;
1235 virtual void TCharacters(const OUString
& rChars
) override
;
1237 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1241 void SmXMLTextContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1243 void SmXMLTextContext_Impl::endFastElement(sal_Int32
)
1245 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_TEXT
));
1250 class SmXMLStringContext_Impl
: public SmXMLImportContext
1256 SmXMLStringContext_Impl(SmXMLImport
& rImport
)
1257 : SmXMLImportContext(rImport
)
1259 aToken
.cMathChar
= u
"";
1261 aToken
.eType
= TTEXT
;
1264 virtual void TCharacters(const OUString
& rChars
) override
;
1266 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1270 void SmXMLStringContext_Impl::TCharacters(const OUString
& rChars
)
1273 The content of <ms> elements should be rendered with visible "escaping" of
1274 certain characters in the content, including at least "double quote"
1275 itself, and preferably whitespace other than individual blanks. The intent
1276 is for the viewer to see that the expression is a string literal, and to
1277 see exactly which characters form its content. For example, <ms>double
1278 quote is "</ms> might be rendered as "double quote is \"".
1280 Obviously this isn't fully done here.
1282 aToken
.aText
= "\"" + rChars
+ "\"";
1285 void SmXMLStringContext_Impl::endFastElement(sal_Int32
)
1287 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_FIXED
));
1292 class SmXMLIdentifierContext_Impl
: public SmXMLImportContext
1294 SmXMLTokenAttrHelper maTokenAttrHelper
;
1295 SmXMLContext_Helper aStyleHelper
;
1299 SmXMLIdentifierContext_Impl(SmXMLImport
& rImport
)
1300 : SmXMLImportContext(rImport
)
1301 , maTokenAttrHelper(*this)
1302 , aStyleHelper(*this)
1304 aToken
.cMathChar
= u
"";
1306 aToken
.eType
= TIDENT
;
1309 void TCharacters(const OUString
& rChars
) override
;
1311 startFastElement(sal_Int32
/*nElement*/,
1312 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
1314 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1315 aStyleHelper
.RetrieveAttrs(xAttrList
);
1317 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1321 void SmXMLIdentifierContext_Impl::endFastElement(sal_Int32
)
1323 std::unique_ptr
<SmTextNode
> pNode
;
1324 //we will handle identifier italic/normal here instead of with a standalone
1326 if (((aStyleHelper
.nIsItalic
== -1) && (aToken
.aText
.getLength() > 1))
1327 || ((aStyleHelper
.nIsItalic
== 0) && (aToken
.aText
.getLength() == 1)))
1329 pNode
.reset(new SmTextNode(aToken
, FNT_FUNCTION
));
1330 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1331 aStyleHelper
.nIsItalic
= -1;
1334 pNode
.reset(new SmTextNode(aToken
, FNT_VARIABLE
));
1335 if (aStyleHelper
.nIsItalic
!= -1)
1337 if (aStyleHelper
.nIsItalic
)
1338 pNode
->GetFont().SetItalic(ITALIC_NORMAL
);
1340 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1341 aStyleHelper
.nIsItalic
= -1;
1343 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1344 aStyleHelper
.ApplyAttrs();
1346 maTokenAttrHelper
.ApplyAttrs((aToken
.aText
.getLength() == 1) ? MathMLMathvariantValue::Italic
1347 : MathMLMathvariantValue::Normal
);
1350 void SmXMLIdentifierContext_Impl::TCharacters(const OUString
& rChars
) { aToken
.aText
= rChars
; }
1354 class SmXMLOperatorContext_Impl
: public SmXMLImportContext
1356 SmXMLTokenAttrHelper maTokenAttrHelper
;
1365 SmXMLOperatorContext_Impl(SmXMLImport
& rImport
)
1366 : SmXMLImportContext(rImport
)
1367 , maTokenAttrHelper(*this)
1368 , bIsStretchy(false)
1374 aToken
.eType
= TSPECIAL
;
1378 void TCharacters(const OUString
& rChars
) override
;
1379 void SAL_CALL
startFastElement(
1380 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1381 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1385 void SmXMLOperatorContext_Impl::TCharacters(const OUString
& rChars
)
1387 aToken
.setChar(rChars
[0]);
1393 = starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(aToken
.cMathChar
[0]);
1395 bToken
= SmToken(TMLINE
, MS_VERTLINE
, "mline", TG::NONE
, 0);
1398 = starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(aToken
.cMathChar
[0]);
1400 bToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(
1401 aToken
.cMathChar
[0]);
1404 bToken
= starmathdatabase::Identify_SmXMLOperatorContext_Impl(aToken
.cMathChar
[0],
1406 if (bToken
.eType
!= TERROR
)
1410 void SmXMLOperatorContext_Impl::endFastElement(sal_Int32
)
1412 std::unique_ptr
<SmMathSymbolNode
> pNode(new SmMathSymbolNode(aToken
));
1413 //For stretchy scaling the scaling must be retrieved from this node
1414 //and applied to the expression itself so as to get the expression
1415 //to scale the operator to the height of the expression itself
1417 pNode
->SetScaleMode(SmScaleMode::Height
);
1418 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1420 // TODO: apply to non-alphabetic characters too
1421 if (rtl::isAsciiAlpha(aToken
.cMathChar
[0]))
1422 maTokenAttrHelper
.ApplyAttrs(MathMLMathvariantValue::Normal
);
1425 void SmXMLOperatorContext_Impl::startFastElement(
1426 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1428 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1430 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1432 switch (aIter
.getToken())
1435 bIsStretchy
= IsXMLToken(aIter
, XML_TRUE
);
1438 bIsFenced
= IsXMLToken(aIter
, XML_TRUE
);
1441 isPrefix
= IsXMLToken(aIter
, XML_PREFIX
); // <
1442 isInfix
= IsXMLToken(aIter
, XML_INFIX
); // |
1443 isPostfix
= IsXMLToken(aIter
, XML_POSTFIX
); // >
1446 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1454 class SmXMLSpaceContext_Impl
: public SmXMLImportContext
1457 SmXMLSpaceContext_Impl(SmXMLImport
& rImport
)
1458 : SmXMLImportContext(rImport
)
1462 void SAL_CALL
startFastElement(
1463 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1466 bool lcl_CountBlanks(const MathMLAttributeLengthValue
& rLV
, sal_Int32
* pWide
, sal_Int32
* pNarrow
)
1470 if (rLV
.aNumber
.GetNumerator() == 0)
1472 *pWide
= *pNarrow
= 0;
1475 // TODO: honor other units than em
1476 if (rLV
.eUnit
!= MathMLLengthUnit::Em
)
1478 if (rLV
.aNumber
.GetNumerator() < 0)
1480 const Fraction
aTwo(2, 1);
1481 auto aWide
= rLV
.aNumber
/ aTwo
;
1482 auto nWide
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aWide
));
1485 const Fraction
aPointFive(1, 2);
1486 auto aNarrow
= (rLV
.aNumber
- Fraction(nWide
, 1) * aTwo
) / aPointFive
;
1487 auto nNarrow
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aNarrow
));
1496 void SmXMLSpaceContext_Impl::startFastElement(
1497 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1499 // There is no syntax in Math to specify blank nodes of arbitrary size yet.
1500 MathMLAttributeLengthValue aLV
;
1501 sal_Int32 nWide
= 0, nNarrow
= 0;
1503 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
1505 OUString sValue
= aIter
.toString();
1506 switch (aIter
.getToken())
1509 if (!ParseMathMLAttributeLengthValue(o3tl::trim(sValue
), aLV
)
1510 || !lcl_CountBlanks(aLV
, &nWide
, &nNarrow
))
1511 SAL_WARN("starmath", "ignore mspace's width: " << sValue
);
1514 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1519 aToken
.eType
= TBLANK
;
1520 aToken
.cMathChar
= u
"";
1521 aToken
.nGroup
= TG::Blank
;
1523 std::unique_ptr
<SmBlankNode
> pBlank(new SmBlankNode(aToken
));
1525 pBlank
->IncreaseBy(aToken
, nWide
);
1528 aToken
.eType
= TSBLANK
;
1529 pBlank
->IncreaseBy(aToken
, nNarrow
);
1531 GetSmImport().GetNodeStack().push_front(std::move(pBlank
));
1536 class SmXMLSubContext_Impl
: public SmXMLRowContext_Impl
1539 void GenericEndElement(SmTokenType eType
, SmSubSup aSubSup
);
1542 SmXMLSubContext_Impl(SmXMLImport
& rImport
)
1543 : SmXMLRowContext_Impl(rImport
)
1547 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUB
, RSUB
); }
1551 void SmXMLSubContext_Impl::GenericEndElement(SmTokenType eType
, SmSubSup eSubSup
)
1553 /*The <msub> element requires exactly 2 arguments.*/
1554 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1555 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1560 aToken
.cMathChar
= u
"";
1561 aToken
.eType
= eType
;
1562 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1563 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1565 // initialize subnodes array
1566 SmNodeArray aSubNodes
;
1567 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1568 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1569 aSubNodes
[i
] = nullptr;
1571 aSubNodes
[eSubSup
+ 1] = popOrZero(rNodeStack
).release();
1572 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1573 pNode
->SetSubNodes(std::move(aSubNodes
));
1574 rNodeStack
.push_front(std::move(pNode
));
1579 class SmXMLSupContext_Impl
: public SmXMLSubContext_Impl
1582 SmXMLSupContext_Impl(SmXMLImport
& rImport
)
1583 : SmXMLSubContext_Impl(rImport
)
1587 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUP
, RSUP
); }
1590 class SmXMLSubSupContext_Impl
: public SmXMLRowContext_Impl
1593 void GenericEndElement(SmTokenType eType
, SmSubSup aSub
, SmSubSup aSup
);
1596 SmXMLSubSupContext_Impl(SmXMLImport
& rImport
)
1597 : SmXMLRowContext_Impl(rImport
)
1601 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TRSUB
, RSUB
, RSUP
); }
1605 void SmXMLSubSupContext_Impl::GenericEndElement(SmTokenType eType
, SmSubSup aSub
, SmSubSup aSup
)
1607 /*The <msub> element requires exactly 3 arguments.*/
1608 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 3;
1609 OSL_ENSURE(bNodeCheck
, "SubSup has not three arguments");
1614 aToken
.cMathChar
= u
"";
1615 aToken
.eType
= eType
;
1616 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1617 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1619 // initialize subnodes array
1620 SmNodeArray aSubNodes
;
1621 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1622 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1623 aSubNodes
[i
] = nullptr;
1625 aSubNodes
[aSup
+ 1] = popOrZero(rNodeStack
).release();
1626 aSubNodes
[aSub
+ 1] = popOrZero(rNodeStack
).release();
1627 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1628 pNode
->SetSubNodes(std::move(aSubNodes
));
1629 rNodeStack
.push_front(std::move(pNode
));
1634 class SmXMLUnderContext_Impl
: public SmXMLSubContext_Impl
1637 sal_Int16 nAttrCount
;
1640 SmXMLUnderContext_Impl(SmXMLImport
& rImport
)
1641 : SmXMLSubContext_Impl(rImport
)
1646 void SAL_CALL
startFastElement(
1647 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1648 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1649 void HandleAccent();
1653 void SmXMLUnderContext_Impl::startFastElement(
1654 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1656 sax_fastparser::FastAttributeList
& rAttribList
1657 = sax_fastparser::castToFastAttributeList(xAttrList
);
1658 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1661 void SmXMLUnderContext_Impl::HandleAccent()
1663 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1664 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1668 /*Just one special case for the underline thing*/
1669 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1670 std::unique_ptr
<SmNode
> pTest
= popOrZero(rNodeStack
);
1672 aToken
.cMathChar
= u
"";
1673 aToken
.eType
= TUNDERLINE
;
1675 std::unique_ptr
<SmNode
> pFirst
;
1676 std::unique_ptr
<SmStructureNode
> pNode(new SmAttributeNode(aToken
));
1677 if ((pTest
->GetToken().cMathChar
[0] & 0x0FFF) == 0x0332)
1679 pFirst
.reset(new SmRectangleNode(aToken
));
1682 pFirst
= std::move(pTest
);
1684 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1685 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1686 pNode
->SetScaleMode(SmScaleMode::Width
);
1687 rNodeStack
.push_front(std::move(pNode
));
1690 void SmXMLUnderContext_Impl::endFastElement(sal_Int32
)
1693 GenericEndElement(TCSUB
, CSUB
);
1700 class SmXMLOverContext_Impl
: public SmXMLSubContext_Impl
1703 sal_Int16 nAttrCount
;
1706 SmXMLOverContext_Impl(SmXMLImport
& rImport
)
1707 : SmXMLSubContext_Impl(rImport
)
1712 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1713 void SAL_CALL
startFastElement(
1714 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1715 void HandleAccent();
1719 void SmXMLOverContext_Impl::startFastElement(
1720 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1722 sax_fastparser::FastAttributeList
& rAttribList
1723 = sax_fastparser::castToFastAttributeList(xAttrList
);
1724 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1727 void SmXMLOverContext_Impl::endFastElement(sal_Int32
)
1730 GenericEndElement(TCSUP
, CSUP
);
1735 void SmXMLOverContext_Impl::HandleAccent()
1737 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1738 OSL_ENSURE(bNodeCheck
, "Sub has not two arguments");
1743 aToken
.cMathChar
= u
"";
1744 aToken
.eType
= TACUTE
;
1746 std::unique_ptr
<SmAttributeNode
> pNode(new SmAttributeNode(aToken
));
1747 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
1749 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
1750 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1751 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1752 pNode
->SetScaleMode(SmScaleMode::Width
);
1753 rNodeStack
.push_front(std::move(pNode
));
1758 class SmXMLUnderOverContext_Impl
: public SmXMLSubSupContext_Impl
1761 SmXMLUnderOverContext_Impl(SmXMLImport
& rImport
)
1762 : SmXMLSubSupContext_Impl(rImport
)
1766 void SAL_CALL
endFastElement(sal_Int32
) override
{ GenericEndElement(TCSUB
, CSUB
, CSUP
); }
1769 class SmXMLMultiScriptsContext_Impl
: public SmXMLSubSupContext_Impl
1771 bool bHasPrescripts
;
1773 void ProcessSubSupPairs(bool bIsPrescript
);
1776 SmXMLMultiScriptsContext_Impl(SmXMLImport
& rImport
)
1777 : SmXMLSubSupContext_Impl(rImport
)
1778 , bHasPrescripts(false)
1782 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1783 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1784 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1787 class SmXMLNoneContext_Impl
: public SmXMLImportContext
1790 SmXMLNoneContext_Impl(SmXMLImport
& rImport
)
1791 : SmXMLImportContext(rImport
)
1795 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1799 void SmXMLNoneContext_Impl::endFastElement(sal_Int32
)
1802 aToken
.cMathChar
= u
"";
1803 aToken
.aText
.clear();
1805 aToken
.eType
= TIDENT
;
1806 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
, FNT_VARIABLE
));
1811 class SmXMLPrescriptsContext_Impl
: public SmXMLImportContext
1814 SmXMLPrescriptsContext_Impl(SmXMLImport
& rImport
)
1815 : SmXMLImportContext(rImport
)
1820 class SmXMLTableRowContext_Impl
: public SmXMLRowContext_Impl
1823 SmXMLTableRowContext_Impl(SmXMLImport
& rImport
)
1824 : SmXMLRowContext_Impl(rImport
)
1828 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1829 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1832 class SmXMLTableContext_Impl
: public SmXMLTableRowContext_Impl
1835 SmXMLTableContext_Impl(SmXMLImport
& rImport
)
1836 : SmXMLTableRowContext_Impl(rImport
)
1840 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1841 virtual uno::Reference
<xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1842 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1845 class SmXMLTableCellContext_Impl
: public SmXMLRowContext_Impl
1848 SmXMLTableCellContext_Impl(SmXMLImport
& rImport
)
1849 : SmXMLRowContext_Impl(rImport
)
1854 class SmXMLAlignGroupContext_Impl
: public SmXMLRowContext_Impl
1857 SmXMLAlignGroupContext_Impl(SmXMLImport
& rImport
)
1858 : SmXMLRowContext_Impl(rImport
)
1862 /*Don't do anything with alignment for now*/
1865 class SmXMLActionContext_Impl
: public SmXMLRowContext_Impl
1867 size_t mnSelection
; // 1-based
1870 SmXMLActionContext_Impl(SmXMLImport
& rImport
)
1871 : SmXMLRowContext_Impl(rImport
)
1876 void SAL_CALL
startFastElement(
1877 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) override
;
1878 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1881 // NB: virtually inherit so we can multiply inherit properly
1882 // in SmXMLFlatDocContext_Impl
1883 class SmXMLOfficeContext_Impl
: public virtual SvXMLImportContext
1886 SmXMLOfficeContext_Impl(SmXMLImport
& rImport
)
1887 : SvXMLImportContext(rImport
)
1891 virtual css::uno::Reference
<css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1893 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1897 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLOfficeContext_Impl::createFastChildContext(
1898 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
1900 if (nElement
== XML_ELEMENT(OFFICE
, XML_META
))
1902 SAL_WARN("starmath",
1903 "XML_TOK_DOC_META: should not have come here, maybe document is invalid?");
1905 else if (nElement
== XML_ELEMENT(OFFICE
, XML_SETTINGS
))
1907 return new XMLDocumentSettingsContext(GetImport());
1914 // context for flat file xml format
1915 class SmXMLFlatDocContext_Impl
: public SmXMLOfficeContext_Impl
, public SvXMLMetaDocumentContext
1918 SmXMLFlatDocContext_Impl(SmXMLImport
& i_rImport
,
1919 const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
);
1921 virtual css::uno::Reference
<css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1923 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1927 SmXMLFlatDocContext_Impl::SmXMLFlatDocContext_Impl(
1928 SmXMLImport
& i_rImport
, const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
)
1929 : SvXMLImportContext(i_rImport
)
1930 , SmXMLOfficeContext_Impl(i_rImport
)
1931 , SvXMLMetaDocumentContext(i_rImport
, i_xDocProps
)
1935 uno::Reference
<xml::sax::XFastContextHandler
>
1936 SAL_CALL
SmXMLFlatDocContext_Impl::createFastChildContext(
1937 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
1939 // behave like meta base class iff we encounter office:meta
1940 if (nElement
== XML_ELEMENT(OFFICE
, XML_META
))
1942 return SvXMLMetaDocumentContext::createFastChildContext(nElement
, xAttrList
);
1946 return SmXMLOfficeContext_Impl::createFastChildContext(nElement
, xAttrList
);
1950 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLDocContext_Impl::createFastChildContext(
1951 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
1953 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
1957 //Consider semantics a dummy except for any starmath annotations
1958 case XML_ELEMENT(MATH
, XML_SEMANTICS
):
1959 xContext
= new SmXMLRowContext_Impl(GetSmImport());
1961 /*General Layout Schemata*/
1962 case XML_ELEMENT(MATH
, XML_MROW
):
1963 xContext
= new SmXMLRowContext_Impl(GetSmImport());
1965 case XML_ELEMENT(MATH
, XML_MENCLOSE
):
1966 xContext
= new SmXMLEncloseContext_Impl(GetSmImport());
1968 case XML_ELEMENT(MATH
, XML_MFRAC
):
1969 xContext
= new SmXMLFracContext_Impl(GetSmImport());
1971 case XML_ELEMENT(MATH
, XML_MSQRT
):
1972 xContext
= new SmXMLSqrtContext_Impl(GetSmImport());
1974 case XML_ELEMENT(MATH
, XML_MROOT
):
1975 xContext
= new SmXMLRootContext_Impl(GetSmImport());
1977 case XML_ELEMENT(MATH
, XML_MSTYLE
):
1978 xContext
= new SmXMLStyleContext_Impl(GetSmImport());
1980 case XML_ELEMENT(MATH
, XML_MERROR
):
1981 xContext
= new SmXMLErrorContext_Impl(GetSmImport());
1983 case XML_ELEMENT(MATH
, XML_MPADDED
):
1984 xContext
= new SmXMLPaddedContext_Impl(GetSmImport());
1986 case XML_ELEMENT(MATH
, XML_MPHANTOM
):
1987 xContext
= new SmXMLPhantomContext_Impl(GetSmImport());
1989 case XML_ELEMENT(MATH
, XML_MFENCED
):
1990 xContext
= new SmXMLFencedContext_Impl(GetSmImport());
1992 /*Script and Limit Schemata*/
1993 case XML_ELEMENT(MATH
, XML_MSUB
):
1994 xContext
= new SmXMLSubContext_Impl(GetSmImport());
1996 case XML_ELEMENT(MATH
, XML_MSUP
):
1997 xContext
= new SmXMLSupContext_Impl(GetSmImport());
1999 case XML_ELEMENT(MATH
, XML_MSUBSUP
):
2000 xContext
= new SmXMLSubSupContext_Impl(GetSmImport());
2002 case XML_ELEMENT(MATH
, XML_MUNDER
):
2003 xContext
= new SmXMLUnderContext_Impl(GetSmImport());
2005 case XML_ELEMENT(MATH
, XML_MOVER
):
2006 xContext
= new SmXMLOverContext_Impl(GetSmImport());
2008 case XML_ELEMENT(MATH
, XML_MUNDEROVER
):
2009 xContext
= new SmXMLUnderOverContext_Impl(GetSmImport());
2011 case XML_ELEMENT(MATH
, XML_MMULTISCRIPTS
):
2012 xContext
= new SmXMLMultiScriptsContext_Impl(GetSmImport());
2014 case XML_ELEMENT(MATH
, XML_MTABLE
):
2015 xContext
= new SmXMLTableContext_Impl(GetSmImport());
2017 case XML_ELEMENT(MATH
, XML_MACTION
):
2018 xContext
= new SmXMLActionContext_Impl(GetSmImport());
2021 /*Basically there's an implicit mrow around certain bare
2022 *elements, use a RowContext to see if this is one of
2024 rtl::Reference
<SmXMLRowContext_Impl
> aTempContext(
2025 new SmXMLRowContext_Impl(GetSmImport()));
2027 xContext
= aTempContext
->StrictCreateChildContext(nElement
);
2033 void SmXMLDocContext_Impl::endFastElement(sal_Int32
)
2035 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2037 std::unique_ptr
<SmNode
> pContextNode
= popOrZero(rNodeStack
);
2040 std::unique_ptr
<SmStructureNode
> pSNode(new SmLineNode(aDummy
));
2041 pSNode
->SetSubNodes(std::move(pContextNode
), nullptr);
2042 rNodeStack
.push_front(std::move(pSNode
));
2044 SmNodeArray LineArray
;
2045 auto n
= rNodeStack
.size();
2046 LineArray
.resize(n
);
2047 for (size_t j
= 0; j
< n
; j
++)
2049 auto pNode
= std::move(rNodeStack
.front());
2050 rNodeStack
.pop_front();
2051 LineArray
[n
- (j
+ 1)] = pNode
.release();
2053 std::unique_ptr
<SmStructureNode
> pSNode2(new SmTableNode(aDummy
));
2054 pSNode2
->SetSubNodes(std::move(LineArray
));
2055 rNodeStack
.push_front(std::move(pSNode2
));
2058 void SmXMLFracContext_Impl::endFastElement(sal_Int32
)
2060 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2061 const bool bNodeCheck
= rNodeStack
.size() - nElementCount
== 2;
2062 OSL_ENSURE(bNodeCheck
, "Fraction (mfrac) tag is missing component");
2067 aToken
.cMathChar
= u
"";
2068 aToken
.eType
= TFRAC
;
2069 std::unique_ptr
<SmStructureNode
> pSNode(new SmBinVerNode(aToken
));
2070 std::unique_ptr
<SmNode
> pOper(new SmRectangleNode(aToken
));
2071 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
2072 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
2073 pSNode
->SetSubNodes(std::move(pFirst
), std::move(pOper
), std::move(pSecond
));
2074 rNodeStack
.push_front(std::move(pSNode
));
2077 void SmXMLRootContext_Impl::endFastElement(sal_Int32
)
2079 /*The <mroot> element requires exactly 2 arguments.*/
2080 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
2081 OSL_ENSURE(bNodeCheck
, "Root tag is missing component");
2086 aToken
.setChar(MS_SQRT
); //Temporary: alert, based on StarSymbol font
2087 aToken
.eType
= TNROOT
;
2088 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2089 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2090 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2091 std::unique_ptr
<SmNode
> pIndex
= popOrZero(rNodeStack
);
2092 std::unique_ptr
<SmNode
> pBase
= popOrZero(rNodeStack
);
2093 pSNode
->SetSubNodes(std::move(pIndex
), std::move(pOper
), std::move(pBase
));
2094 rNodeStack
.push_front(std::move(pSNode
));
2097 void SmXMLSqrtContext_Impl::endFastElement(sal_Int32 nElement
)
2100 <msqrt> accepts any number of arguments; if this number is not 1, its
2101 contents are treated as a single "inferred <mrow>" containing its
2104 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
2105 SmXMLRowContext_Impl::endFastElement(nElement
);
2108 aToken
.setChar(MS_SQRT
); //Temporary: alert, based on StarSymbol font
2109 aToken
.eType
= TSQRT
;
2110 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2111 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2112 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2113 pSNode
->SetSubNodes(nullptr, std::move(pOper
), popOrZero(rNodeStack
));
2114 rNodeStack
.push_front(std::move(pSNode
));
2117 void SmXMLRowContext_Impl::endFastElement(sal_Int32
)
2119 SmNodeArray aRelationArray
;
2120 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2122 if (rNodeStack
.size() > nElementCount
)
2124 auto nSize
= rNodeStack
.size() - nElementCount
;
2126 aRelationArray
.resize(nSize
);
2127 for (auto j
= nSize
; j
> 0; j
--)
2129 auto pNode
= std::move(rNodeStack
.front());
2130 rNodeStack
.pop_front();
2131 aRelationArray
[j
- 1] = pNode
.release();
2134 //If the first or last element is an operator with stretchyness
2135 //set then we must create a brace node here from those elements,
2136 //removing the stretchness from the operators and applying it to
2137 //ourselves, and creating the appropriate dummy StarMath none bracket
2138 //to balance the arrangement
2139 if (((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2140 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2141 || ((aRelationArray
[nSize
- 1]->GetScaleMode() == SmScaleMode::Height
)
2142 && (aRelationArray
[nSize
- 1]->GetType() == SmNodeType::Math
)))
2145 aToken
.cMathChar
= u
"";
2148 int nLeft
= 0, nRight
= 0;
2149 if ((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2150 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2152 aToken
= aRelationArray
[0]->GetToken();
2156 aToken
.cMathChar
= u
"";
2158 aToken
.eType
= TLPARENT
;
2159 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
2161 if ((aRelationArray
[nSize
- 1]->GetScaleMode() == SmScaleMode::Height
)
2162 && (aRelationArray
[nSize
- 1]->GetType() == SmNodeType::Math
))
2164 aToken
= aRelationArray
[nSize
- 1]->GetToken();
2168 aToken
.cMathChar
= u
"";
2170 aToken
.eType
= TRPARENT
;
2171 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
2173 SmNodeArray aRelationArray2
;
2175 //!! nSize-nLeft-nRight may be < 0 !!
2176 int nRelArrSize
= nSize
- nLeft
- nRight
;
2177 if (nRelArrSize
> 0)
2179 aRelationArray2
.resize(nRelArrSize
);
2180 for (int i
= 0; i
< nRelArrSize
; i
++)
2182 aRelationArray2
[i
] = aRelationArray
[i
+ nLeft
];
2183 aRelationArray
[i
+ nLeft
] = nullptr;
2188 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
2189 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
2190 pBody
->SetSubNodes(std::move(aRelationArray2
));
2192 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
2193 pSNode
->SetScaleMode(SmScaleMode::Height
);
2194 rNodeStack
.push_front(std::move(pSNode
));
2196 for (auto a
: aRelationArray
)
2204 // The elements msqrt, mstyle, merror, menclose, mpadded, mphantom, mtd, and math
2205 // treat their content as a single inferred mrow in case their content is empty.
2206 // Here an empty group {} is used to catch those cases and transform them without error
2208 aRelationArray
.resize(2);
2210 aToken
.setChar(MS_LBRACE
);
2212 aToken
.eType
= TLGROUP
;
2213 aToken
.nGroup
= TG::NONE
;
2215 aRelationArray
[0] = new SmLineNode(aToken
);
2217 aToken
.setChar(MS_RBRACE
);
2219 aToken
.eType
= TRGROUP
;
2220 aToken
.nGroup
= TG::NONE
;
2222 aRelationArray
[1] = new SmLineNode(aToken
);
2226 std::unique_ptr
<SmStructureNode
> pSNode(new SmExpressionNode(aDummy
));
2227 pSNode
->SetSubNodes(std::move(aRelationArray
));
2228 rNodeStack
.push_front(std::move(pSNode
));
2231 uno::Reference
<xml::sax::XFastContextHandler
>
2232 SmXMLRowContext_Impl::StrictCreateChildContext(sal_Int32 nElement
)
2234 uno::Reference
<xml::sax::XFastContextHandler
> pContext
;
2238 /*Note that these should accept malignmark subelements, but do not*/
2239 case XML_ELEMENT(MATH
, XML_MN
):
2240 pContext
= new SmXMLNumberContext_Impl(GetSmImport());
2242 case XML_ELEMENT(MATH
, XML_MI
):
2243 pContext
= new SmXMLIdentifierContext_Impl(GetSmImport());
2245 case XML_ELEMENT(MATH
, XML_MO
):
2246 pContext
= new SmXMLOperatorContext_Impl(GetSmImport());
2248 case XML_ELEMENT(MATH
, XML_MTEXT
):
2249 pContext
= new SmXMLTextContext_Impl(GetSmImport());
2251 case XML_ELEMENT(MATH
, XML_MSPACE
):
2252 pContext
= new SmXMLSpaceContext_Impl(GetSmImport());
2254 case XML_ELEMENT(MATH
, XML_MS
):
2255 pContext
= new SmXMLStringContext_Impl(GetSmImport());
2258 /*Note: The maligngroup should only be seen when the row
2259 * (or descendants) are in a table*/
2260 case XML_ELEMENT(MATH
, XML_MALIGNGROUP
):
2261 pContext
= new SmXMLAlignGroupContext_Impl(GetSmImport());
2264 case XML_ELEMENT(MATH
, XML_ANNOTATION
):
2265 pContext
= new SmXMLAnnotationContext_Impl(GetSmImport());
2274 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLRowContext_Impl::createFastChildContext(
2275 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2277 uno::Reference
<xml::sax::XFastContextHandler
> xContext
= StrictCreateChildContext(nElement
);
2281 //Hmm, unrecognized for this level, check to see if it's
2282 //an element that can have an implicit schema around it
2283 xContext
= SmXMLDocContext_Impl::createFastChildContext(nElement
, xAttrList
);
2288 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLMultiScriptsContext_Impl::createFastChildContext(
2289 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2291 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
2295 case XML_ELEMENT(MATH
, XML_MPRESCRIPTS
):
2296 bHasPrescripts
= true;
2297 ProcessSubSupPairs(false);
2298 xContext
= new SmXMLPrescriptsContext_Impl(GetSmImport());
2300 case XML_ELEMENT(MATH
, XML_NONE
):
2301 xContext
= new SmXMLNoneContext_Impl(GetSmImport());
2304 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2310 void SmXMLMultiScriptsContext_Impl::ProcessSubSupPairs(bool bIsPrescript
)
2312 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2314 if (rNodeStack
.size() <= nElementCount
)
2317 auto nCount
= rNodeStack
.size() - nElementCount
- 1;
2321 if (nCount
% 2 == 0)
2324 aToken
.cMathChar
= u
"";
2325 aToken
.eType
= bIsPrescript
? TLSUB
: TRSUB
;
2327 SmNodeStack aReverseStack
;
2328 for (size_t i
= 0; i
< nCount
+ 1; i
++)
2330 auto pNode
= std::move(rNodeStack
.front());
2331 rNodeStack
.pop_front();
2332 aReverseStack
.push_front(std::move(pNode
));
2335 SmSubSup eSub
= bIsPrescript
? LSUB
: RSUB
;
2336 SmSubSup eSup
= bIsPrescript
? LSUP
: RSUP
;
2338 for (size_t i
= 0; i
< nCount
; i
+= 2)
2340 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
2342 // initialize subnodes array
2343 SmNodeArray
aSubNodes(1 + SUBSUP_NUM_ENTRIES
);
2345 /*On each loop the base and its sub sup pair becomes the
2346 base for the next loop to which the next sub sup pair is
2347 attached, i.e. wheels within wheels*/
2348 aSubNodes
[0] = popOrZero(aReverseStack
).release();
2350 std::unique_ptr
<SmNode
> pScriptNode
= popOrZero(aReverseStack
);
2353 && ((pScriptNode
->GetToken().eType
!= TIDENT
)
2354 || (!pScriptNode
->GetToken().aText
.isEmpty())))
2355 aSubNodes
[eSub
+ 1] = pScriptNode
.release();
2356 pScriptNode
= popOrZero(aReverseStack
);
2358 && ((pScriptNode
->GetToken().eType
!= TIDENT
)
2359 || (!pScriptNode
->GetToken().aText
.isEmpty())))
2360 aSubNodes
[eSup
+ 1] = pScriptNode
.release();
2362 pNode
->SetSubNodes(std::move(aSubNodes
));
2363 aReverseStack
.push_front(std::move(pNode
));
2365 assert(!aReverseStack
.empty());
2366 auto pNode
= std::move(aReverseStack
.front());
2367 aReverseStack
.pop_front();
2368 rNodeStack
.push_front(std::move(pNode
));
2372 // Ignore odd number of elements.
2373 for (size_t i
= 0; i
< nCount
; i
++)
2375 rNodeStack
.pop_front();
2380 void SmXMLTableContext_Impl::endFastElement(sal_Int32
)
2382 SmNodeArray aExpressionArray
;
2383 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2384 SmNodeStack aReverseStack
;
2385 aExpressionArray
.resize(rNodeStack
.size() - nElementCount
);
2387 size_t nRows
= rNodeStack
.size() - nElementCount
;
2390 for (size_t i
= nRows
; i
> 0; --i
)
2392 SmNode
* pArray
= rNodeStack
.front().release();
2393 rNodeStack
.pop_front();
2394 if (pArray
->GetNumSubNodes() == 0)
2396 //This is a little tricky, it is possible that there was
2397 //be elements that were not inside a <mtd> pair, in which
2398 //case they will not be in a row, i.e. they will not have
2399 //SubNodes, so we have to wait until here before we can
2400 //resolve the situation. Implicit surrounding tags are
2401 //surprisingly difficult to get right within this
2404 SmNodeArray aRelationArray
;
2405 aRelationArray
.resize(1);
2406 aRelationArray
[0] = pArray
;
2408 SmExpressionNode
* pExprNode
= new SmExpressionNode(aDummy
);
2409 pExprNode
->SetSubNodes(std::move(aRelationArray
));
2413 nCols
= std::max(nCols
, pArray
->GetNumSubNodes());
2414 aReverseStack
.push_front(std::unique_ptr
<SmNode
>(pArray
));
2416 if (nCols
> SAL_MAX_UINT16
)
2417 throw std::range_error("column limit");
2418 if (nRows
> SAL_MAX_UINT16
)
2419 throw std::range_error("row limit");
2420 aExpressionArray
.resize(nCols
* nRows
);
2422 for (auto& elem
: aReverseStack
)
2424 std::unique_ptr
<SmStructureNode
> xArray(static_cast<SmStructureNode
*>(elem
.release()));
2425 for (size_t i
= 0; i
< xArray
->GetNumSubNodes(); ++i
)
2426 aExpressionArray
[j
++] = xArray
->GetSubNode(i
);
2427 xArray
->ClearSubNodes();
2429 aReverseStack
.clear();
2432 aToken
.cMathChar
= u
"";
2433 aToken
.eType
= TMATRIX
;
2434 std::unique_ptr
<SmMatrixNode
> pSNode(new SmMatrixNode(aToken
));
2435 pSNode
->SetSubNodes(std::move(aExpressionArray
));
2436 pSNode
->SetRowCol(nRows
, nCols
);
2437 rNodeStack
.push_front(std::move(pSNode
));
2440 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLTableRowContext_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_MTD
):
2448 xContext
= new SmXMLTableCellContext_Impl(GetSmImport());
2451 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2457 uno::Reference
<xml::sax::XFastContextHandler
> SmXMLTableContext_Impl::createFastChildContext(
2458 sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2460 uno::Reference
<xml::sax::XFastContextHandler
> xContext
;
2464 case XML_ELEMENT(MATH
, XML_MTR
):
2465 xContext
= new SmXMLTableRowContext_Impl(GetSmImport());
2468 xContext
= SmXMLTableRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2474 void SmXMLMultiScriptsContext_Impl::endFastElement(sal_Int32
)
2476 ProcessSubSupPairs(bHasPrescripts
);
2479 void SmXMLActionContext_Impl::startFastElement(
2480 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2482 for (auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
))
2484 switch (aIter
.getToken())
2488 sal_Int32 n
= aIter
.toInt32();
2490 mnSelection
= static_cast<size_t>(n
);
2494 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
2500 void SmXMLActionContext_Impl::endFastElement(sal_Int32
)
2502 SmNodeStack
& rNodeStack
= GetSmImport().GetNodeStack();
2503 auto nSize
= rNodeStack
.size();
2504 if (nSize
<= nElementCount
)
2506 // not compliant to maction's specification, e.g., no subexpressions
2509 assert(mnSelection
> 0);
2510 if (nSize
< nElementCount
+ mnSelection
)
2512 // No selected subexpression exists, which is a MathML error;
2513 // fallback to selecting the first
2516 assert(nSize
>= nElementCount
+ mnSelection
);
2517 for (auto i
= nSize
- (nElementCount
+ mnSelection
); i
> 0; i
--)
2519 rNodeStack
.pop_front();
2521 auto pSelected
= std::move(rNodeStack
.front());
2522 rNodeStack
.pop_front();
2523 for (auto i
= rNodeStack
.size() - nElementCount
; i
> 0; i
--)
2525 rNodeStack
.pop_front();
2527 rNodeStack
.push_front(std::move(pSelected
));
2531 SmXMLImport::CreateFastContext(sal_Int32 nElement
,
2532 const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
2534 SvXMLImportContext
* pContext
= nullptr;
2538 case XML_ELEMENT(OFFICE
, XML_DOCUMENT
):
2539 case XML_ELEMENT(OFFICE
, XML_DOCUMENT_META
):
2541 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(GetModel(),
2542 uno::UNO_QUERY_THROW
);
2543 pContext
= ((nElement
& TOKEN_MASK
) == XML_DOCUMENT_META
)
2544 ? new SvXMLMetaDocumentContext(*this, xDPS
->getDocumentProperties())
2545 // flat OpenDocument file format -- this has not been tested...
2546 : new SmXMLFlatDocContext_Impl(*this, xDPS
->getDocumentProperties());
2550 if (IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE
))
2551 pContext
= new SmXMLOfficeContext_Impl(*this);
2553 pContext
= new SmXMLDocContext_Impl(*this);
2558 SmXMLImport::~SmXMLImport() noexcept
{ cleanup(); }
2560 void SmXMLImport::SetViewSettings(const Sequence
<PropertyValue
>& aViewProps
)
2562 uno::Reference
<frame::XModel
> xModel
= GetModel();
2566 SmModel
* pModel
= dynamic_cast<SmModel
*>(xModel
.get());
2571 SmDocShell
* pDocShell
= static_cast<SmDocShell
*>(pModel
->GetObjectShell());
2575 tools::Rectangle
aRect(pDocShell
->GetVisArea());
2577 tools::Long nTmp
= 0;
2579 for (const PropertyValue
& rValue
: aViewProps
)
2581 if (rValue
.Name
== "ViewAreaTop")
2583 rValue
.Value
>>= nTmp
;
2584 aRect
.SaturatingSetPosY(nTmp
);
2586 else if (rValue
.Name
== "ViewAreaLeft")
2588 rValue
.Value
>>= nTmp
;
2589 aRect
.SaturatingSetPosX(nTmp
);
2591 else if (rValue
.Name
== "ViewAreaWidth")
2593 rValue
.Value
>>= nTmp
;
2594 Size
aSize(aRect
.GetSize());
2595 aSize
.setWidth(nTmp
);
2596 aRect
.SaturatingSetSize(aSize
);
2598 else if (rValue
.Name
== "ViewAreaHeight")
2600 rValue
.Value
>>= nTmp
;
2601 Size
aSize(aRect
.GetSize());
2602 aSize
.setHeight(nTmp
);
2603 aRect
.SaturatingSetSize(aSize
);
2607 pDocShell
->SetVisArea(aRect
);
2610 void SmXMLImport::SetConfigurationSettings(const Sequence
<PropertyValue
>& aConfProps
)
2612 uno::Reference
<XPropertySet
> xProps(GetModel(), UNO_QUERY
);
2616 Reference
<XPropertySetInfo
> xInfo(xProps
->getPropertySetInfo());
2620 static const OUStringLiteral
sFormula(u
"Formula");
2621 static const OUStringLiteral
sBasicLibraries(u
"BasicLibraries");
2622 static const OUStringLiteral
sDialogLibraries(u
"DialogLibraries");
2623 for (const PropertyValue
& rValue
: aConfProps
)
2625 if (rValue
.Name
!= sFormula
&& rValue
.Name
!= sBasicLibraries
2626 && rValue
.Name
!= sDialogLibraries
)
2630 if (xInfo
->hasPropertyByName(rValue
.Name
))
2631 xProps
->setPropertyValue(rValue
.Name
, rValue
.Value
);
2633 catch (const beans::PropertyVetoException
&)
2635 // dealing with read-only properties here. Nothing to do...
2637 catch (const Exception
&)
2639 DBG_UNHANDLED_EXCEPTION("starmath");
2645 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportMML(SvStream
& rStream
)
2647 SmGlobals::ensure();
2649 SfxObjectShellLock
xDocSh(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT
));
2650 xDocSh
->DoInitNew();
2651 uno::Reference
<frame::XModel
> xModel(xDocSh
->GetModel());
2653 uno::Reference
<beans::XPropertySet
> xInfoSet
;
2654 uno::Reference
<uno::XComponentContext
> xContext(comphelper::getProcessComponentContext());
2655 uno::Reference
<io::XInputStream
> xStream(new utl::OSeekableInputStreamWrapper(rStream
));
2657 //SetLoading hack because the document properties will be re-initted
2658 //by the xml filter and during the init, while it's considered uninitialized,
2659 //setting a property will inform the document it's modified, which attempts
2660 //to update the properties, which throws cause the properties are uninitialized
2661 xDocSh
->SetLoading(SfxLoadedFlags::NONE
);
2663 ErrCode nRet
= ERRCODE_SFX_DOLOADFAILED
;
2667 nRet
= SmXMLImportWrapper::ReadThroughComponent(xStream
, xModel
, xContext
, xInfoSet
,
2668 "com.sun.star.comp.Math.XMLImporter", false,
2675 xDocSh
->SetLoading(SfxLoadedFlags::ALL
);
2679 return nRet
!= ERRCODE_NONE
;
2682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */