Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / starmath / source / mathml / mathmlimport.cxx
blobfc27ecedabb1b3f00dbc359e924f5682d238f451
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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
22 one go*/
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>
68 #include <smdll.hxx>
69 #include <unomodel.hxx>
70 #include <utility.hxx>
71 #include <visitors.hxx>
72 #include <starmathdatabase.hxx>
73 #include <smmod.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;
83 namespace
85 std::unique_ptr<SmNode> popOrZero(SmNodeStack& rStack)
87 if (rStack.empty())
88 return nullptr;
89 auto pTmp = std::move(rStack.front());
90 rStack.pop_front();
91 return pTmp;
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;
111 if (pDocShell)
113 OSL_ENSURE(pDocShell->GetMedium() == &rMedium, "different SfxMedium found");
115 const SfxUnoAnyItem* pItem = rMedium.GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
116 if (pItem)
117 pItem->GetValue() >>= xStatusIndicator;
119 if (SfxObjectCreateMode::EMBEDDED == pDocShell->GetCreateMode())
120 bEmbedded = true;
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)));
135 // Set base URI
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()))
144 nSteps = 1;
146 sal_Int32 nProgressRange(nSteps);
147 if (xStatusIndicator.is())
149 xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
152 nSteps = 0;
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++);
177 auto nWarn
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,
189 xInfoSet,
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);
203 else
204 nError = ERRCODE_IO_BROKENPACKAGE;
206 else
207 nError = ERRCODE_IO_BROKENPACKAGE;
209 else
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();
224 return nError;
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) };
247 // get filter
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);
252 if (!xFilter.is())
253 return nError;
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);
264 if (xFastParser)
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);
279 else
281 Reference<css::xml::sax::XDocumentHandler> xDocHandler(xFilter, UNO_QUERY);
282 assert(xDocHandler);
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;
299 while (bTryChild)
301 xml::sax::SAXException aTmp;
302 if (aSaxEx.WrappedException >>= aTmp)
303 aSaxEx = std::move(aTmp);
304 else
305 bTryChild = false;
308 packages::zip::ZipIOException aBrokenPackage;
309 if (aSaxEx.WrappedException >>= aBrokenPackage)
310 return ERRCODE_IO_BROKENPACKAGE;
312 if (bEncrypted)
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;
321 if (bEncrypted)
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&)
335 return nError;
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);
351 // get input stream
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())
362 aAny >>= bEncrypted;
364 // set Base URL
365 if (rPropSet.is())
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)
392 , bSuccess(false)
393 , nParseDepth(0)
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());
431 if (pModel)
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();
448 pTmpTree.reset();
449 rParser->SetImportSymbolNames(bVal);
451 pDocShell->SetText(aText);
452 pDocShell->SetSmSyntaxVersion(mnSmSyntaxVersion);
454 OSL_ENSURE(pModel, "So there *was* a UNO problem after all");
456 bSuccess = true;
459 SvXMLImport::endDocument();
462 namespace
464 class SmXMLImportContext : public SvXMLImportContext
466 public:
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()*/);
505 namespace
507 struct SmXMLContext_Helper
509 sal_Int8 nIsBold;
510 sal_Int8 nIsItalic;
511 double nFontSize;
512 OUString sFontFamily;
513 OUString sColor;
515 SmXMLImportContext& rContext;
517 explicit SmXMLContext_Helper(SmXMLImportContext& rImport)
518 : nIsBold(-1)
519 , nIsItalic(-1)
520 , nFontSize(0.0)
521 , rContext(rImport)
525 bool IsFontNodeNeeded() const;
526 void RetrieveAttrs(const uno::Reference<xml::sax::XFastAttributeList>& xAttrList);
527 void ApplyAttrs();
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)
546 case XML_FONTWEIGHT:
547 nIsBold = sal_Int8(IsXMLToken(aIter, XML_BOLD));
548 break;
549 case XML_FONTSTYLE:
550 nIsItalic = sal_Int8(IsXMLToken(aIter, XML_ITALIC));
551 break;
552 case XML_FONTSIZE:
553 case XML_MATHSIZE:
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('%'))
562 nFontSize = 0.0;
563 else
565 rContext.GetSmImport().GetMM100UnitConverter().SetXMLMeasureUnit(
566 util::MeasureUnit::PERCENT);
569 break;
571 case XML_FONTFAMILY:
572 sFontFamily = aIter.toString();
573 break;
574 case XML_COLOR:
575 case XML_MATHCOLOR:
576 sColor = aIter.toString();
577 break;
578 case XML_MATHVARIANT:
579 bMvFound = true;
580 break;
581 default:
582 XMLOFF_WARN_UNKNOWN("starmath", aIter);
583 break;
587 if (bMvFound)
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>.
592 sFontFamily.clear();
593 nIsBold = -1;
594 nIsItalic = -1;
598 void SmXMLContext_Helper::ApplyAttrs()
600 SmNodeStack& rNodeStack = rContext.GetSmImport().GetNodeStack();
602 if (!IsFontNodeNeeded())
603 return;
605 SmToken aToken;
606 aToken.cMathChar = u""_ustr;
607 aToken.nLevel = 5;
609 if (nIsBold != -1)
611 if (nIsBold)
612 aToken.eType = TBOLD;
613 else
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));
619 if (nIsItalic != -1)
621 if (nIsItalic)
622 aToken.eType = TITALIC;
623 else
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);
639 else
640 pFontNode->SetSizeParameter(Fraction(nFontSize / 100.00), FontSizeType::MULTIPLY);
642 else
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())
665 return;
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
674 //more general
675 return;
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));
683 namespace
685 class SmXMLTokenAttrHelper
687 SmXMLImportContext& mrContext;
688 MathMLMathvariantValue meMv;
689 bool mbMvFound;
691 public:
692 SmXMLTokenAttrHelper(SmXMLImportContext& rContext)
693 : mrContext(rContext)
694 , meMv(MathMLMathvariantValue::Normal)
695 , mbMvFound(false)
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);
715 mbMvFound = true;
716 break;
717 default:
718 XMLOFF_WARN_UNKNOWN("starmath", aIter);
719 break;
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;
731 switch (eMv)
733 case MathMLMathvariantValue::Normal:
734 vVariant.push_back(TNITALIC);
735 break;
736 case MathMLMathvariantValue::Bold:
737 case MathMLMathvariantValue::BoldFraktur:
738 // TODO: Fraktur
739 case MathMLMathvariantValue::BoldScript:
740 // TODO: Script
741 vVariant.push_back(TBOLD);
742 break;
743 case MathMLMathvariantValue::Italic:
744 // nothing to do
745 break;
746 case MathMLMathvariantValue::BoldItalic:
747 vVariant.push_back(TITALIC);
748 vVariant.push_back(TBOLD);
749 break;
750 case MathMLMathvariantValue::DoubleStruck:
751 // TODO
752 break;
753 case MathMLMathvariantValue::Script:
754 // TODO
755 break;
756 case MathMLMathvariantValue::Fraktur:
757 // TODO
758 break;
759 case MathMLMathvariantValue::SansSerif:
760 vVariant.push_back(TSANS);
761 break;
762 case MathMLMathvariantValue::BoldSansSerif:
763 vVariant.push_back(TSANS);
764 vVariant.push_back(TBOLD);
765 break;
766 case MathMLMathvariantValue::SansSerifItalic:
767 vVariant.push_back(TITALIC);
768 vVariant.push_back(TSANS);
769 break;
770 case MathMLMathvariantValue::SansSerifBoldItalic:
771 vVariant.push_back(TITALIC);
772 vVariant.push_back(TBOLD);
773 vVariant.push_back(TSANS);
774 break;
775 case MathMLMathvariantValue::Monospace:
776 vVariant.push_back(TFIXED);
777 break;
778 case MathMLMathvariantValue::Initial:
779 case MathMLMathvariantValue::Tailed:
780 case MathMLMathvariantValue::Looped:
781 case MathMLMathvariantValue::Stretched:
782 // TODO
783 break;
785 if (vVariant.empty())
786 return;
787 SmNodeStack& rNodeStack = mrContext.GetSmImport().GetNodeStack();
788 for (auto eType : vVariant)
790 SmToken aToken;
791 aToken.eType = eType;
792 aToken.cMathChar = u""_ustr;
793 aToken.nLevel = 5;
794 std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(aToken));
795 pFontNode->SetSubNodes(nullptr, popOrZero(rNodeStack));
796 rNodeStack.push_front(std::move(pFontNode));
800 namespace
802 class SmXMLDocContext_Impl : public SmXMLImportContext
804 public:
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
819 protected:
820 size_t nElementCount;
822 public:
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
839 public:
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
856 arguments
858 if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
859 SmXMLRowContext_Impl::endFastElement(nElement);
862 namespace
864 class SmXMLFracContext_Impl : public SmXMLRowContext_Impl
866 public:
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
878 public:
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
889 public:
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
900 protected:
901 SmXMLContext_Helper aStyleHelper;
903 public:
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
928 arguments
930 SmNodeStack& rNodeStack = GetSmImport().GetNodeStack();
931 if (rNodeStack.size() - nElementCount != 1)
932 SmXMLRowContext_Impl::endFastElement(nElement);
933 aStyleHelper.ApplyAttrs();
936 namespace
938 class SmXMLPaddedContext_Impl : public SmXMLRowContext_Impl
940 public:
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
956 arguments
958 if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
959 SmXMLRowContext_Impl::endFastElement(nElement);
962 namespace
964 class SmXMLPhantomContext_Impl : public SmXMLRowContext_Impl
966 public:
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
982 arguments
984 if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
985 SmXMLRowContext_Impl::endFastElement(nElement);
987 SmToken aToken;
988 aToken.cMathChar = u""_ustr;
989 aToken.nLevel = 5;
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));
998 namespace
1000 class SmXMLFencedContext_Impl : public SmXMLRowContext_Impl
1002 protected:
1003 OUString cBegin;
1004 OUString cEnd;
1005 bool bIsStretchy;
1007 public:
1008 SmXMLFencedContext_Impl(SmXMLImport& rImport)
1009 : SmXMLRowContext_Impl(rImport)
1010 , cBegin('(')
1011 , cEnd(')')
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)
1030 case XML_OPEN:
1031 cBegin = aIter.toString();
1032 break;
1033 case XML_CLOSE:
1034 cEnd = aIter.toString();
1035 break;
1036 case XML_STRETCHY:
1037 bIsStretchy = IsXMLToken(aIter, XML_TRUE);
1038 break;
1039 default:
1040 XMLOFF_WARN_UNKNOWN("starmath", aIter);
1041 /*Go to superclass*/
1042 break;
1047 void SmXMLFencedContext_Impl::endFastElement(sal_Int32 /*nElement*/)
1049 SmToken aToken;
1050 aToken.cMathChar = u""_ustr;
1051 aToken.aText = ",";
1052 aToken.nLevel = 5;
1054 std::unique_ptr<SmStructureNode> pSNode(new SmBraceNode(aToken));
1055 if (bIsStretchy)
1056 aToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cBegin);
1057 else
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));
1062 if (bIsStretchy)
1063 aToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(cEnd);
1064 else
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);
1088 SmToken aDummy;
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));
1099 namespace
1101 class SmXMLErrorContext_Impl : public SmXMLRowContext_Impl
1103 public:
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();
1129 namespace
1131 class SmXMLNumberContext_Impl : public SmXMLImportContext
1133 protected:
1134 SmToken aToken;
1136 public:
1137 SmXMLNumberContext_Impl(SmXMLImport& rImport)
1138 : SmXMLImportContext(rImport)
1140 aToken.cMathChar = u""_ustr;
1141 aToken.nLevel = 5;
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));
1158 namespace
1160 class SmXMLAnnotationContext_Impl : public SmXMLImportContext
1162 sal_uInt8 mnStarMathVersion;
1164 public:
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)
1186 case XML_ENCODING:
1187 mnStarMathVersion
1188 = aIter.toView() == "StarMath 5.0" ? 5 : aIter.toView() == "StarMath 6" ? 6 : 0;
1189 break;
1190 default:
1191 XMLOFF_WARN_UNKNOWN("starmath", aIter);
1192 break;
1197 void SmXMLAnnotationContext_Impl::characters(const OUString& rChars)
1199 if (mnStarMathVersion)
1201 GetSmImport().SetText(GetSmImport().GetText() + rChars);
1202 GetSmImport().SetSmSyntaxVersion(mnStarMathVersion);
1206 namespace
1208 class SmXMLTextContext_Impl : public SmXMLImportContext
1210 protected:
1211 SmToken aToken;
1213 public:
1214 SmXMLTextContext_Impl(SmXMLImport& rImport)
1215 : SmXMLImportContext(rImport)
1217 aToken.cMathChar = u""_ustr;
1218 aToken.nLevel = 5;
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));
1235 namespace
1237 class SmXMLStringContext_Impl : public SmXMLImportContext
1239 protected:
1240 SmToken aToken;
1242 public:
1243 SmXMLStringContext_Impl(SmXMLImport& rImport)
1244 : SmXMLImportContext(rImport)
1246 aToken.cMathChar = u""_ustr;
1247 aToken.nLevel = 5;
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));
1277 namespace
1279 class SmXMLIdentifierContext_Impl : public SmXMLImportContext
1281 SmXMLTokenAttrHelper maTokenAttrHelper;
1282 SmXMLContext_Helper aStyleHelper;
1283 SmToken aToken;
1285 public:
1286 SmXMLIdentifierContext_Impl(SmXMLImport& rImport)
1287 : SmXMLImportContext(rImport)
1288 , maTokenAttrHelper(*this)
1289 , aStyleHelper(*this)
1291 aToken.cMathChar = u""_ustr;
1292 aToken.nLevel = 5;
1293 aToken.eType = TIDENT;
1296 void TCharacters(const OUString& rChars) override;
1297 void SAL_CALL
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
1312 //font node
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;
1320 else
1321 pNode.reset(new SmTextNode(aToken, FNT_VARIABLE));
1322 if (aStyleHelper.nIsItalic != -1)
1324 if (aStyleHelper.nIsItalic)
1325 pNode->GetFont().SetItalic(ITALIC_NORMAL);
1326 else
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; }
1339 namespace
1341 class SmXMLOperatorContext_Impl : public SmXMLImportContext
1343 SmXMLTokenAttrHelper maTokenAttrHelper;
1344 bool bIsStretchy;
1345 bool bIsFenced;
1346 bool isPrefix;
1347 bool isInfix;
1348 bool isPostfix;
1349 SmToken aToken;
1351 public:
1352 SmXMLOperatorContext_Impl(SmXMLImport& rImport)
1353 : SmXMLImportContext(rImport)
1354 , maTokenAttrHelper(*this)
1355 , bIsStretchy(false)
1356 , bIsFenced(false)
1357 , isPrefix(false)
1358 , isInfix(false)
1359 , isPostfix(false)
1361 aToken.eType = TSPECIAL;
1362 aToken.nLevel = 5;
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);
1375 SmToken bToken;
1376 if (bIsFenced)
1378 if (isPrefix)
1379 bToken = starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(aToken.cMathChar);
1380 else if (isInfix)
1381 bToken = SmToken(TMLINE, MS_VERTLINE, u"mline"_ustr, TG::NONE, 0);
1382 else if (isPostfix)
1383 bToken = starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(aToken.cMathChar);
1384 else
1385 bToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(
1386 aToken.cMathChar);
1388 else
1389 bToken
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
1401 if (bIsStretchy)
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())
1419 case XML_STRETCHY:
1420 bIsStretchy = IsXMLToken(aIter, XML_TRUE);
1421 break;
1422 case XML_FENCE:
1423 bIsFenced = IsXMLToken(aIter, XML_TRUE);
1424 break;
1425 case XML_FORM:
1426 isPrefix = IsXMLToken(aIter, XML_PREFIX); // <
1427 isInfix = IsXMLToken(aIter, XML_INFIX); // |
1428 isPostfix = IsXMLToken(aIter, XML_POSTFIX); // >
1429 break;
1430 default:
1431 XMLOFF_WARN_UNKNOWN("starmath", aIter);
1432 break;
1437 namespace
1439 class SmXMLSpaceContext_Impl : public SmXMLImportContext
1441 public:
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)
1453 assert(pWide);
1454 assert(pNarrow);
1455 if (rLV.aNumber.GetNumerator() == 0)
1457 *pWide = *pNarrow = 0;
1458 return true;
1460 // TODO: honor other units than em
1461 if (rLV.eUnit != MathMLLengthUnit::Em)
1462 return false;
1463 if (rLV.aNumber.GetNumerator() < 0)
1464 return false;
1465 const Fraction aTwo(2, 1);
1466 auto aWide = rLV.aNumber / aTwo;
1467 auto nWide = static_cast<sal_Int32>(static_cast<tools::Long>(aWide));
1468 if (nWide < 0)
1469 return false;
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));
1473 if (nNarrow < 0)
1474 return false;
1475 *pWide = nWide;
1476 *pNarrow = nNarrow;
1477 return true;
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())
1493 case XML_WIDTH:
1494 if (!ParseMathMLAttributeLengthValue(o3tl::trim(sValue), aLV)
1495 || !lcl_CountBlanks(aLV, &nWide, &nNarrow))
1496 SAL_WARN("starmath", "ignore mspace's width: " << sValue);
1497 break;
1498 default:
1499 XMLOFF_WARN_UNKNOWN("starmath", aIter);
1500 break;
1503 SmToken aToken;
1504 aToken.eType = TBLANK;
1505 aToken.cMathChar = u""_ustr;
1506 aToken.nGroup = TG::Blank;
1507 aToken.nLevel = 5;
1508 std::unique_ptr<SmBlankNode> pBlank(new SmBlankNode(aToken));
1509 if (nWide > 0)
1510 pBlank->IncreaseBy(aToken, nWide);
1511 if (nNarrow > 0)
1513 aToken.eType = TSBLANK;
1514 pBlank->IncreaseBy(aToken, nNarrow);
1516 GetSmImport().GetNodeStack().push_front(std::move(pBlank));
1519 namespace
1521 class SmXMLSubContext_Impl : public SmXMLRowContext_Impl
1523 protected:
1524 void GenericEndElement(SmTokenType eType, SmSubSup aSubSup);
1526 public:
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");
1541 if (!bNodeCheck)
1542 return;
1544 SmToken aToken;
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));
1562 namespace
1564 class SmXMLSupContext_Impl : public SmXMLSubContext_Impl
1566 public:
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
1577 protected:
1578 void GenericEndElement(SmTokenType eType, SmSubSup aSub, SmSubSup aSup);
1580 public:
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");
1595 if (!bNodeCheck)
1596 return;
1598 SmToken aToken;
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));
1617 namespace
1619 class SmXMLUnderContext_Impl : public SmXMLSubContext_Impl
1621 protected:
1622 sal_Int16 nAttrCount;
1624 public:
1625 SmXMLUnderContext_Impl(SmXMLImport& rImport)
1626 : SmXMLSubContext_Impl(rImport)
1627 , nAttrCount(0)
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");
1650 if (!bNodeCheck)
1651 return;
1653 /*Just one special case for the underline thing*/
1654 SmNodeStack& rNodeStack = GetSmImport().GetNodeStack();
1655 std::unique_ptr<SmNode> pTest = popOrZero(rNodeStack);
1656 SmToken aToken;
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));
1666 else
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)
1677 if (!nAttrCount)
1678 GenericEndElement(TCSUB, CSUB);
1679 else
1680 HandleAccent();
1683 namespace
1685 class SmXMLOverContext_Impl : public SmXMLSubContext_Impl
1687 protected:
1688 sal_Int16 nAttrCount;
1690 public:
1691 SmXMLOverContext_Impl(SmXMLImport& rImport)
1692 : SmXMLSubContext_Impl(rImport)
1693 , nAttrCount(0)
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)
1714 if (!nAttrCount)
1715 GenericEndElement(TCSUP, CSUP);
1716 else
1717 HandleAccent();
1720 void SmXMLOverContext_Impl::HandleAccent()
1722 const bool bNodeCheck = GetSmImport().GetNodeStack().size() - nElementCount == 2;
1723 OSL_ENSURE(bNodeCheck, "Sub has not two arguments");
1724 if (!bNodeCheck)
1725 return;
1727 SmToken aToken;
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));
1741 namespace
1743 class SmXMLUnderOverContext_Impl : public SmXMLSubSupContext_Impl
1745 public:
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);
1760 public:
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
1774 public:
1775 SmXMLNoneContext_Impl(SmXMLImport& rImport)
1776 : SmXMLImportContext(rImport)
1780 void SAL_CALL endFastElement(sal_Int32 nElement) override;
1784 void SmXMLNoneContext_Impl::endFastElement(sal_Int32)
1786 SmToken aToken;
1787 aToken.cMathChar = u""_ustr;
1788 aToken.aText.clear();
1789 aToken.nLevel = 5;
1790 aToken.eType = TIDENT;
1791 GetSmImport().GetNodeStack().push_front(std::make_unique<SmTextNode>(aToken, FNT_VARIABLE));
1794 namespace
1796 class SmXMLPrescriptsContext_Impl : public SmXMLImportContext
1798 public:
1799 SmXMLPrescriptsContext_Impl(SmXMLImport& rImport)
1800 : SmXMLImportContext(rImport)
1805 class SmXMLTableRowContext_Impl : public SmXMLRowContext_Impl
1807 public:
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
1819 public:
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
1832 public:
1833 SmXMLTableCellContext_Impl(SmXMLImport& rImport)
1834 : SmXMLRowContext_Impl(rImport)
1839 class SmXMLAlignGroupContext_Impl : public SmXMLRowContext_Impl
1841 public:
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
1854 public:
1855 SmXMLActionContext_Impl(SmXMLImport& rImport)
1856 : SmXMLRowContext_Impl(rImport)
1857 , mnSelection(1)
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
1870 public:
1871 SmXMLOfficeContext_Impl(SmXMLImport& rImport)
1872 : SvXMLImportContext(rImport)
1876 virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
1877 sal_Int32 nElement,
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());
1894 return nullptr;
1897 namespace
1899 // context for flat file xml format
1900 class SmXMLFlatDocContext_Impl : public SmXMLOfficeContext_Impl, public SvXMLMetaDocumentContext
1902 public:
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(
1907 sal_Int32 nElement,
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);
1929 else
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;
1940 switch (nElement)
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());
1947 break;
1948 case XML_ELEMENT(MATH, XML_MENCLOSE):
1949 xContext = new SmXMLEncloseContext_Impl(GetSmImport());
1950 break;
1951 case XML_ELEMENT(MATH, XML_MFRAC):
1952 xContext = new SmXMLFracContext_Impl(GetSmImport());
1953 break;
1954 case XML_ELEMENT(MATH, XML_MSQRT):
1955 xContext = new SmXMLSqrtContext_Impl(GetSmImport());
1956 break;
1957 case XML_ELEMENT(MATH, XML_MROOT):
1958 xContext = new SmXMLRootContext_Impl(GetSmImport());
1959 break;
1960 case XML_ELEMENT(MATH, XML_MSTYLE):
1961 xContext = new SmXMLStyleContext_Impl(GetSmImport());
1962 break;
1963 case XML_ELEMENT(MATH, XML_MERROR):
1964 xContext = new SmXMLErrorContext_Impl(GetSmImport());
1965 break;
1966 case XML_ELEMENT(MATH, XML_MPADDED):
1967 xContext = new SmXMLPaddedContext_Impl(GetSmImport());
1968 break;
1969 case XML_ELEMENT(MATH, XML_MPHANTOM):
1970 xContext = new SmXMLPhantomContext_Impl(GetSmImport());
1971 break;
1972 case XML_ELEMENT(MATH, XML_MFENCED):
1973 xContext = new SmXMLFencedContext_Impl(GetSmImport());
1974 break;
1975 /*Script and Limit Schemata*/
1976 case XML_ELEMENT(MATH, XML_MSUB):
1977 xContext = new SmXMLSubContext_Impl(GetSmImport());
1978 break;
1979 case XML_ELEMENT(MATH, XML_MSUP):
1980 xContext = new SmXMLSupContext_Impl(GetSmImport());
1981 break;
1982 case XML_ELEMENT(MATH, XML_MSUBSUP):
1983 xContext = new SmXMLSubSupContext_Impl(GetSmImport());
1984 break;
1985 case XML_ELEMENT(MATH, XML_MUNDER):
1986 xContext = new SmXMLUnderContext_Impl(GetSmImport());
1987 break;
1988 case XML_ELEMENT(MATH, XML_MOVER):
1989 xContext = new SmXMLOverContext_Impl(GetSmImport());
1990 break;
1991 case XML_ELEMENT(MATH, XML_MUNDEROVER):
1992 xContext = new SmXMLUnderOverContext_Impl(GetSmImport());
1993 break;
1994 case XML_ELEMENT(MATH, XML_MMULTISCRIPTS):
1995 xContext = new SmXMLMultiScriptsContext_Impl(GetSmImport());
1996 break;
1997 case XML_ELEMENT(MATH, XML_MTABLE):
1998 xContext = new SmXMLTableContext_Impl(GetSmImport());
1999 break;
2000 case XML_ELEMENT(MATH, XML_MACTION):
2001 xContext = new SmXMLActionContext_Impl(GetSmImport());
2002 break;
2003 default:
2004 /*Basically there's an implicit mrow around certain bare
2005 *elements, use a RowContext to see if this is one of
2006 *those ones*/
2007 rtl::Reference<SmXMLRowContext_Impl> aTempContext(
2008 new SmXMLRowContext_Impl(GetSmImport()));
2010 xContext = aTempContext->StrictCreateChildContext(nElement);
2011 break;
2013 return xContext;
2016 void SmXMLDocContext_Impl::endFastElement(sal_Int32)
2018 SmNodeStack& rNodeStack = GetSmImport().GetNodeStack();
2020 std::unique_ptr<SmNode> pContextNode = popOrZero(rNodeStack);
2022 SmToken aDummy;
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");
2046 if (!bNodeCheck)
2047 return;
2049 SmToken aToken;
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");
2065 if (!bNodeCheck)
2066 return;
2068 SmToken aToken;
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
2085 arguments
2087 if (GetSmImport().GetNodeStack().size() - nElementCount != 1)
2088 SmXMLRowContext_Impl::endFastElement(nElement);
2090 SmToken aToken;
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)))
2127 SmToken aToken;
2128 aToken.cMathChar = u""_ustr;
2129 aToken.nLevel = 5;
2131 int nLeft = 0, nRight = 0;
2132 if ((aRelationArray[0]->GetScaleMode() == SmScaleMode::Height)
2133 && (aRelationArray[0]->GetType() == SmNodeType::Math))
2135 aToken = aRelationArray[0]->GetToken();
2136 nLeft = 1;
2138 else
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();
2148 nRight = 1;
2150 else
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;
2170 SmToken aDummy;
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)
2180 delete a;
2182 return;
2185 else
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
2190 // to StarMath.
2191 aRelationArray.resize(2);
2192 SmToken aToken;
2193 aToken.setChar(MS_LBRACE);
2194 aToken.nLevel = 5;
2195 aToken.eType = TLGROUP;
2196 aToken.nGroup = TG::NONE;
2197 aToken.aText = "{";
2198 aRelationArray[0] = new SmLineNode(aToken);
2200 aToken.setChar(MS_RBRACE);
2201 aToken.nLevel = 0;
2202 aToken.eType = TRGROUP;
2203 aToken.nGroup = TG::NONE;
2204 aToken.aText = "}";
2205 aRelationArray[1] = new SmLineNode(aToken);
2208 SmToken aDummy;
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;
2219 switch (nElement)
2221 /*Note that these should accept malignmark subelements, but do not*/
2222 case XML_ELEMENT(MATH, XML_MN):
2223 pContext = new SmXMLNumberContext_Impl(GetSmImport());
2224 break;
2225 case XML_ELEMENT(MATH, XML_MI):
2226 pContext = new SmXMLIdentifierContext_Impl(GetSmImport());
2227 break;
2228 case XML_ELEMENT(MATH, XML_MO):
2229 pContext = new SmXMLOperatorContext_Impl(GetSmImport());
2230 break;
2231 case XML_ELEMENT(MATH, XML_MTEXT):
2232 pContext = new SmXMLTextContext_Impl(GetSmImport());
2233 break;
2234 case XML_ELEMENT(MATH, XML_MSPACE):
2235 pContext = new SmXMLSpaceContext_Impl(GetSmImport());
2236 break;
2237 case XML_ELEMENT(MATH, XML_MS):
2238 pContext = new SmXMLStringContext_Impl(GetSmImport());
2239 break;
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());
2245 break;
2247 case XML_ELEMENT(MATH, XML_ANNOTATION):
2248 pContext = new SmXMLAnnotationContext_Impl(GetSmImport());
2249 break;
2251 default:
2252 break;
2254 return pContext;
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);
2262 if (!xContext)
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);
2268 return xContext;
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;
2276 switch (nElement)
2278 case XML_ELEMENT(MATH, XML_MPRESCRIPTS):
2279 bHasPrescripts = true;
2280 ProcessSubSupPairs(false);
2281 xContext = new SmXMLPrescriptsContext_Impl(GetSmImport());
2282 break;
2283 case XML_ELEMENT(MATH, XML_NONE):
2284 xContext = new SmXMLNoneContext_Impl(GetSmImport());
2285 break;
2286 default:
2287 xContext = SmXMLRowContext_Impl::createFastChildContext(nElement, xAttrList);
2288 break;
2290 return xContext;
2293 void SmXMLMultiScriptsContext_Impl::ProcessSubSupPairs(bool bIsPrescript)
2295 SmNodeStack& rNodeStack = GetSmImport().GetNodeStack();
2297 if (rNodeStack.size() <= nElementCount)
2298 return;
2300 auto nCount = rNodeStack.size() - nElementCount - 1;
2301 if (nCount == 0)
2302 return;
2304 if (nCount % 2 == 0)
2306 SmToken aToken;
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);
2335 if (pScriptNode
2336 && ((pScriptNode->GetToken().eType != TIDENT)
2337 || (!pScriptNode->GetToken().aText.isEmpty())))
2338 aSubNodes[eSub + 1] = pScriptNode.release();
2339 pScriptNode = popOrZero(aReverseStack);
2340 if (pScriptNode
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));
2353 else
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;
2371 size_t nCols = 0;
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
2385 //architecture
2387 SmNodeArray aRelationArray;
2388 aRelationArray.resize(1);
2389 aRelationArray[0] = pArray;
2390 SmToken aDummy;
2391 SmExpressionNode* pExprNode = new SmExpressionNode(aDummy);
2392 pExprNode->SetSubNodes(std::move(aRelationArray));
2393 pArray = pExprNode;
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);
2404 size_t j = 0;
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();
2414 SmToken aToken;
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;
2428 switch (nElement)
2430 case XML_ELEMENT(MATH, XML_MTD):
2431 xContext = new SmXMLTableCellContext_Impl(GetSmImport());
2432 break;
2433 default:
2434 xContext = SmXMLRowContext_Impl::createFastChildContext(nElement, xAttrList);
2435 break;
2437 return xContext;
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;
2445 switch (nElement)
2447 case XML_ELEMENT(MATH, XML_MTR):
2448 xContext = new SmXMLTableRowContext_Impl(GetSmImport());
2449 break;
2450 default:
2451 xContext = SmXMLTableRowContext_Impl::createFastChildContext(nElement, xAttrList);
2452 break;
2454 return xContext;
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())
2469 case XML_SELECTION:
2471 sal_Int32 n = aIter.toInt32();
2472 if (n > 0)
2473 mnSelection = static_cast<size_t>(n);
2475 break;
2476 default:
2477 XMLOFF_WARN_UNKNOWN("starmath", aIter);
2478 break;
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
2490 return;
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
2497 mnSelection = 1;
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));
2513 SvXMLImportContext*
2514 SmXMLImport::CreateFastContext(sal_Int32 nElement,
2515 const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/)
2517 SvXMLImportContext* pContext = nullptr;
2519 switch (nElement)
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());
2531 break;
2532 default:
2533 if (IsTokenInNamespace(nElement, XML_NAMESPACE_OFFICE))
2534 pContext = new SmXMLOfficeContext_Impl(*this);
2535 else
2536 pContext = new SmXMLDocContext_Impl(*this);
2538 return pContext;
2541 SmXMLImport::~SmXMLImport() noexcept { cleanup(); }
2543 void SmXMLImport::SetViewSettings(const Sequence<PropertyValue>& aViewProps)
2545 uno::Reference<frame::XModel> xModel = GetModel();
2546 if (!xModel.is())
2547 return;
2549 SmModel* pModel = dynamic_cast<SmModel*>(xModel.get());
2551 if (!pModel)
2552 return;
2554 SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell());
2555 if (!pDocShell)
2556 return;
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);
2596 if (!xProps.is())
2597 return;
2599 Reference<XPropertySetInfo> xInfo(xProps->getPropertySetInfo());
2600 if (!xInfo.is())
2601 return;
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,
2653 false);
2655 catch (...)
2659 xDocSh->SetLoading(SfxLoadedFlags::ALL);
2661 xDocSh->DoClose();
2663 return nRet != ERRCODE_NONE;
2666 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */