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 .
21 /*todo: Change characters and tcharacters to accumulate the characters together
22 into one string, xml parser hands them to us line by line rather than all in
25 #include <com/sun/star/xml/sax/InputSource.hpp>
26 #include <com/sun/star/xml/sax/FastParser.hpp>
27 #include <com/sun/star/xml/sax/Parser.hpp>
28 #include <com/sun/star/xml/sax/SAXParseException.hpp>
29 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
30 #include <com/sun/star/packages/WrongPasswordException.hpp>
31 #include <com/sun/star/packages/zip/ZipIOException.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/container/XNameAccess.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include <com/sun/star/uno/Any.h>
36 #include <com/sun/star/task/XStatusIndicator.hpp>
38 #include <comphelper/fileformat.h>
39 #include <comphelper/genericpropertyset.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/servicehelper.hxx>
42 #include <comphelper/propertysetinfo.hxx>
43 #include <rtl/character.hxx>
44 #include <sal/log.hxx>
45 #include <sfx2/frame.hxx>
46 #include <sfx2/docfile.hxx>
47 #include <sfx2/sfxsids.hrc>
48 #include <sfx2/sfxmodelfactory.hxx>
49 #include <osl/diagnose.h>
50 #include <sot/storage.hxx>
51 #include <svtools/sfxecode.hxx>
52 #include <svl/itemset.hxx>
53 #include <svl/stritem.hxx>
54 #include <unotools/streamwrap.hxx>
55 #include <sax/tools/converter.hxx>
56 #include <xmloff/DocumentSettingsContext.hxx>
57 #include <xmloff/xmlnamespace.hxx>
58 #include <xmloff/xmltoken.hxx>
59 #include <xmloff/namespacemap.hxx>
60 #include <xmloff/xmluconv.hxx>
61 #include <xmloff/xmlmetai.hxx>
62 #include <svx/dialmgr.hxx>
63 #include <svx/strings.hrc>
64 #include <tools/diagnose_ex.h>
68 #include "mathmlattr.hxx"
69 #include "mathmlimport.hxx"
70 #include <document.hxx>
72 #include <unomodel.hxx>
73 #include <utility.hxx>
74 #include <visitors.hxx>
75 #include <starmathdatabase.hxx>
77 using namespace ::com::sun::star::beans
;
78 using namespace ::com::sun::star::container
;
79 using namespace ::com::sun::star::document
;
80 using namespace ::com::sun::star::lang
;
81 using namespace ::com::sun::star::uno
;
82 using namespace ::com::sun::star
;
83 using namespace ::xmloff::token
;
87 std::unique_ptr
<SmNode
> popOrZero(SmNodeStack
& rStack
)
91 auto pTmp
= std::move(rStack
.front());
98 ErrCode
SmXMLImportWrapper::Import(SfxMedium
&rMedium
)
100 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
102 uno::Reference
<uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
104 //Make a model component from our SmModel
105 uno::Reference
< lang::XComponent
> xModelComp
= xModel
;
106 OSL_ENSURE( xModelComp
.is(), "XMLReader::Read: got no model" );
108 // try to get an XStatusIndicator from the Medium
109 uno::Reference
<task::XStatusIndicator
> xStatusIndicator
;
111 bool bEmbedded
= false;
112 SmModel
*pModel
= comphelper::getUnoTunnelImplementation
<SmModel
>(xModel
);
114 SmDocShell
*pDocShell
= pModel
?
115 static_cast<SmDocShell
*>(pModel
->GetObjectShell()) : nullptr;
118 OSL_ENSURE( pDocShell
->GetMedium() == &rMedium
,
119 "different SfxMedium found" );
121 SfxItemSet
* pSet
= rMedium
.GetItemSet();
124 const SfxUnoAnyItem
* pItem
= static_cast<const SfxUnoAnyItem
*>(
125 pSet
->GetItem(SID_PROGRESS_STATUSBAR_CONTROL
) );
127 pItem
->GetValue() >>= xStatusIndicator
;
130 if ( SfxObjectCreateMode::EMBEDDED
== pDocShell
->GetCreateMode() )
134 comphelper::PropertyMapEntry aInfoMap
[] =
136 { OUString("PrivateData"), 0,
137 cppu::UnoType
<XInterface
>::get(),
138 beans::PropertyAttribute::MAYBEVOID
, 0 },
139 { OUString("BaseURI"), 0,
140 ::cppu::UnoType
<OUString
>::get(),
141 beans::PropertyAttribute::MAYBEVOID
, 0 },
142 { OUString("StreamRelPath"), 0,
143 ::cppu::UnoType
<OUString
>::get(),
144 beans::PropertyAttribute::MAYBEVOID
, 0 },
145 { OUString("StreamName"), 0,
146 ::cppu::UnoType
<OUString
>::get(),
147 beans::PropertyAttribute::MAYBEVOID
, 0 },
148 { OUString(), 0, css::uno::Type(), 0, 0 }
150 uno::Reference
< beans::XPropertySet
> xInfoSet(
151 comphelper::GenericPropertySet_CreateInstance(
152 new comphelper::PropertySetInfo( aInfoMap
) ) );
155 OUString
const baseURI(rMedium
.GetBaseURL());
156 // needed for relative URLs; but it's OK to import e.g. MathML from the
157 // clipboard without one
158 SAL_INFO_IF(baseURI
.isEmpty(), "starmath", "SmXMLImportWrapper: no base URL");
159 xInfoSet
->setPropertyValue("BaseURI", makeAny(baseURI
));
162 if ( !(rMedium
.IsStorage()))
165 sal_Int32
nProgressRange(nSteps
);
166 if (xStatusIndicator
.is())
168 xStatusIndicator
->start(SvxResId(RID_SVXSTR_DOC_LOAD
), nProgressRange
);
172 if (xStatusIndicator
.is())
173 xStatusIndicator
->setValue(nSteps
++);
175 if ( rMedium
.IsStorage())
177 // TODO/LATER: handle the case of embedded links gracefully
178 if ( bEmbedded
) // && !rMedium.GetStorage()->IsRoot() )
180 OUString
aName( "dummyObjName" );
181 if ( rMedium
.GetItemSet() )
183 const SfxStringItem
* pDocHierarchItem
= static_cast<const SfxStringItem
*>(
184 rMedium
.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME
) );
185 if ( pDocHierarchItem
)
186 aName
= pDocHierarchItem
->GetValue();
189 if ( !aName
.isEmpty() )
191 xInfoSet
->setPropertyValue("StreamRelPath", makeAny(aName
));
195 bool bOASIS
= ( SotStorage::GetVersion( rMedium
.GetStorage() ) > SOFFICE_FILEFORMAT_60
);
196 if (xStatusIndicator
.is())
197 xStatusIndicator
->setValue(nSteps
++);
199 auto nWarn
= ReadThroughComponent(
200 rMedium
.GetStorage(), xModelComp
, "meta.xml",
202 (bOASIS
? "com.sun.star.comp.Math.XMLOasisMetaImporter"
203 : "com.sun.star.comp.Math.XMLMetaImporter") );
205 if ( nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
207 if (xStatusIndicator
.is())
208 xStatusIndicator
->setValue(nSteps
++);
210 nWarn
= ReadThroughComponent(
211 rMedium
.GetStorage(), xModelComp
, "settings.xml",
213 (bOASIS
? "com.sun.star.comp.Math.XMLOasisSettingsImporter"
214 : "com.sun.star.comp.Math.XMLSettingsImporter" ) );
216 if ( nWarn
!= ERRCODE_IO_BROKENPACKAGE
)
218 if (xStatusIndicator
.is())
219 xStatusIndicator
->setValue(nSteps
++);
221 nError
= ReadThroughComponent(
222 rMedium
.GetStorage(), xModelComp
, "content.xml",
223 xContext
, xInfoSet
, "com.sun.star.comp.Math.XMLImporter" );
226 nError
= ERRCODE_IO_BROKENPACKAGE
;
229 nError
= ERRCODE_IO_BROKENPACKAGE
;
233 Reference
<io::XInputStream
> xInputStream
=
234 new utl::OInputStreamWrapper(rMedium
.GetInStream());
236 if (xStatusIndicator
.is())
237 xStatusIndicator
->setValue(nSteps
++);
239 nError
= ReadThroughComponent( xInputStream
, xModelComp
,
240 xContext
, xInfoSet
, "com.sun.star.comp.Math.XMLImporter", false );
243 if (xStatusIndicator
.is())
244 xStatusIndicator
->end();
249 /// read a component (file + filter version)
250 ErrCode
SmXMLImportWrapper::ReadThroughComponent(
251 const Reference
<io::XInputStream
>& xInputStream
,
252 const Reference
<XComponent
>& xModelComponent
,
253 Reference
<uno::XComponentContext
> const & rxContext
,
254 Reference
<beans::XPropertySet
> const & rPropSet
,
255 const char* pFilterName
,
258 ErrCode nError
= ERRCODE_SFX_DOLOADFAILED
;
259 OSL_ENSURE(xInputStream
.is(), "input stream missing");
260 OSL_ENSURE(xModelComponent
.is(), "document missing");
261 OSL_ENSURE(rxContext
.is(), "factory missing");
262 OSL_ENSURE(nullptr != pFilterName
,"I need a service name for the component!");
264 // prepare ParserInputSource
265 xml::sax::InputSource aParserInput
;
266 aParserInput
.aInputStream
= xInputStream
;
268 Sequence
<Any
> aArgs( 1 );
269 aArgs
[0] <<= rPropSet
;
272 Reference
< XInterface
> xFilter
=
273 rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
274 OUString::createFromAscii(pFilterName
), aArgs
, rxContext
);
275 SAL_WARN_IF( !xFilter
, "starmath", "Can't instantiate filter component " << pFilterName
);
279 // connect model and filter
280 Reference
< XImporter
> xImporter( xFilter
, UNO_QUERY
);
281 xImporter
->setTargetDocument( xModelComponent
);
283 // finally, parser the stream
286 Reference
<css::xml::sax::XFastParser
> xFastParser(xFilter
, UNO_QUERY
);
287 Reference
<css::xml::sax::XFastDocumentHandler
> xFastDocHandler(xFilter
, UNO_QUERY
);
289 xFastParser
->parseStream( aParserInput
);
290 else if (xFastDocHandler
)
292 Reference
<css::xml::sax::XFastParser
> xParser
= css::xml::sax::FastParser::create(rxContext
);
293 xParser
->setFastDocumentHandler(xFastDocHandler
);
294 xParser
->parseStream( aParserInput
);
298 Reference
<css::xml::sax::XDocumentHandler
> xDocHandler(xFilter
, UNO_QUERY
);
300 Reference
<css::xml::sax::XParser
> xParser
= css::xml::sax::Parser::create(rxContext
);
301 xParser
->setDocumentHandler(xDocHandler
);
302 xParser
->parseStream( aParserInput
);
305 auto pFilter
= comphelper::getUnoTunnelImplementation
<SmXMLImport
>(xFilter
);
306 if ( pFilter
&& pFilter
->GetSuccess() )
307 nError
= ERRCODE_NONE
;
309 catch (const xml::sax::SAXParseException
& r
)
311 // sax parser sends wrapped exceptions,
312 // try to find the original one
313 xml::sax::SAXException aSaxEx
= *static_cast<const xml::sax::SAXException
*>(&r
);
314 bool bTryChild
= true;
318 xml::sax::SAXException aTmp
;
319 if ( aSaxEx
.WrappedException
>>= aTmp
)
325 packages::zip::ZipIOException aBrokenPackage
;
326 if ( aSaxEx
.WrappedException
>>= aBrokenPackage
)
327 return ERRCODE_IO_BROKENPACKAGE
;
330 nError
= ERRCODE_SFX_WRONGPASSWORD
;
332 catch (const xml::sax::SAXException
& r
)
334 packages::zip::ZipIOException aBrokenPackage
;
335 if ( r
.WrappedException
>>= aBrokenPackage
)
336 return ERRCODE_IO_BROKENPACKAGE
;
339 nError
= ERRCODE_SFX_WRONGPASSWORD
;
341 catch (const packages::zip::ZipIOException
&)
343 nError
= ERRCODE_IO_BROKENPACKAGE
;
345 catch (const io::IOException
&)
348 catch (const std::range_error
&)
356 ErrCode
SmXMLImportWrapper::ReadThroughComponent(
357 const uno::Reference
< embed::XStorage
>& xStorage
,
358 const Reference
<XComponent
>& xModelComponent
,
359 const char* pStreamName
,
360 Reference
<uno::XComponentContext
> const & rxContext
,
361 Reference
<beans::XPropertySet
> const & rPropSet
,
362 const char* pFilterName
)
364 OSL_ENSURE(xStorage
.is(), "Need storage!");
365 OSL_ENSURE(nullptr != pStreamName
, "Please, please, give me a name!");
367 // open stream (and set parser input)
368 OUString sStreamName
= OUString::createFromAscii(pStreamName
);
373 uno::Reference
< io::XStream
> xEventsStream
= xStorage
->openStreamElement( sStreamName
, embed::ElementModes::READ
);
375 // determine if stream is encrypted or not
376 uno::Reference
< beans::XPropertySet
> xProps( xEventsStream
, uno::UNO_QUERY
);
377 Any aAny
= xProps
->getPropertyValue( "Encrypted" );
378 bool bEncrypted
= false;
379 if ( aAny
.getValueType() == cppu::UnoType
<bool>::get() )
385 rPropSet
->setPropertyValue( "StreamName", makeAny( sStreamName
) );
389 Reference
< io::XInputStream
> xStream
= xEventsStream
->getInputStream();
390 return ReadThroughComponent( xStream
, xModelComponent
, rxContext
, rPropSet
, pFilterName
, bEncrypted
);
392 catch ( packages::WrongPasswordException
& )
394 return ERRCODE_SFX_WRONGPASSWORD
;
396 catch( packages::zip::ZipIOException
& )
398 return ERRCODE_IO_BROKENPACKAGE
;
400 catch ( uno::Exception
& )
404 return ERRCODE_SFX_DOLOADFAILED
;
408 SmXMLImport::SmXMLImport(
409 const css::uno::Reference
< css::uno::XComponentContext
>& rContext
,
410 OUString
const & implementationName
, SvXMLImportFlags nImportFlags
)
411 : SvXMLImport(rContext
, implementationName
, nImportFlags
),
419 class theSmXMLImportUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theSmXMLImportUnoTunnelId
> {};
422 const uno::Sequence
< sal_Int8
> & SmXMLImport::getUnoTunnelId() throw()
424 return theSmXMLImportUnoTunnelId::get().getSeq();
427 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
428 Math_XMLImporter_get_implementation(uno::XComponentContext
* pCtx
,
429 uno::Sequence
<uno::Any
> const& /*rSeq*/)
431 return cppu::acquire(
432 new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLImporter", SvXMLImportFlags::ALL
));
435 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
436 Math_XMLOasisMetaImporter_get_implementation(uno::XComponentContext
* pCtx
,
437 uno::Sequence
<uno::Any
> const& /*rSeq*/)
439 return cppu::acquire(new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLOasisMetaImporter",
440 SvXMLImportFlags::META
));
443 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
444 Math_XMLOasisSettingsImporter_get_implementation(uno::XComponentContext
* pCtx
,
445 uno::Sequence
<uno::Any
> const& /*rSeq*/)
447 return cppu::acquire(new SmXMLImport(pCtx
, "com.sun.star.comp.Math.XMLOasisSettingsImporter",
448 SvXMLImportFlags::SETTINGS
));
451 sal_Int64 SAL_CALL
SmXMLImport::getSomething(
452 const uno::Sequence
< sal_Int8
>&rId
)
454 if ( isUnoTunnelId
<SmXMLImport
>(rId
) )
455 return sal::static_int_cast
< sal_Int64
>(reinterpret_cast< sal_uIntPtr
>(this));
457 return SvXMLImport::getSomething( rId
);
460 void SmXMLImport::endDocument()
462 //Set the resulted tree into the SmDocShell where it belongs
463 std::unique_ptr
<SmNode
> pTree
= popOrZero(aNodeStack
);
464 if (pTree
&& pTree
->GetType() == SmNodeType::Table
)
466 uno::Reference
<frame::XModel
> xModel
= GetModel();
467 SmModel
*pModel
= comphelper::getUnoTunnelImplementation
<SmModel
>(xModel
);
471 SmDocShell
*pDocShell
= static_cast<SmDocShell
*>(pModel
->GetObjectShell());
472 auto pTreeTmp
= pTree
.get();
473 pDocShell
->SetFormulaTree(static_cast<SmTableNode
*>(pTree
.release()));
474 if (aText
.isEmpty()) //If we picked up no annotation text
476 // Get text from imported formula
477 SmNodeToTextVisitor
tmpvisitor( pTreeTmp
, aText
);
480 // Convert symbol names
481 SmParser
&rParser
= pDocShell
->GetParser();
482 bool bVal
= rParser
.IsImportSymbolNames();
483 rParser
.SetImportSymbolNames( true );
484 auto pTmpTree
= rParser
.Parse( aText
);
485 aText
= rParser
.GetText();
487 rParser
.SetImportSymbolNames( bVal
);
489 pDocShell
->SetText( aText
);
491 OSL_ENSURE(pModel
,"So there *was* a UNO problem after all");
496 SvXMLImport::endDocument();
501 class SmXMLImportContext
: public SvXMLImportContext
504 SmXMLImportContext( SmXMLImport
&rImport
)
505 : SvXMLImportContext(rImport
)
507 GetSmImport().IncParseDepth();
510 virtual ~SmXMLImportContext() override
512 GetSmImport().DecParseDepth();
515 SmXMLImport
& GetSmImport()
517 return static_cast<SmXMLImport
&>(GetImport());
520 virtual void TCharacters(const OUString
& /*rChars*/);
521 virtual void SAL_CALL
characters(const OUString
&rChars
) override
;
522 virtual void SAL_CALL
startFastElement(sal_Int32
/*nElement*/, const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& /*rAttrList*/) override
524 if (GetSmImport().TooDeep())
525 throw std::range_error("too deep");
531 void SmXMLImportContext::TCharacters(const OUString
& /*rChars*/)
535 void SmXMLImportContext::characters(const OUString
&rChars
)
538 Whitespace occurring within the content of token elements is "trimmed"
539 from the ends (i.e. all whitespace at the beginning and end of the
540 content is removed), and "collapsed" internally (i.e. each sequence of
541 1 or more whitespace characters is replaced with one blank character).
543 //collapsing not done yet!
544 const OUString
&rChars2
= rChars
.trim();
545 if (!rChars2
.isEmpty())
546 TCharacters(rChars2
/*.collapse()*/);
551 struct SmXMLContext_Helper
556 OUString sFontFamily
;
559 SmXMLImportContext
& rContext
;
561 explicit SmXMLContext_Helper(SmXMLImportContext
&rImport
)
565 , rContext( rImport
)
568 bool IsFontNodeNeeded() const;
569 void RetrieveAttrs(const uno::Reference
< xml::sax::XFastAttributeList
> &xAttrList
);
575 bool SmXMLContext_Helper::IsFontNodeNeeded() const
577 return nIsBold
!= -1 ||
580 !sFontFamily
.isEmpty() ||
584 void SmXMLContext_Helper::RetrieveAttrs(const uno::Reference
<
585 xml::sax::XFastAttributeList
> & xAttrList
)
587 bool bMvFound
= false;
588 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
590 OUString sValue
= aIter
.toString();
591 // sometimes they have namespace, sometimes not?
592 switch(aIter
.getToken() & TOKEN_MASK
)
595 nIsBold
= sal_Int8(sValue
== GetXMLToken(XML_BOLD
));
598 nIsItalic
= sal_Int8(sValue
== GetXMLToken(XML_ITALIC
));
602 ::sax::Converter::convertDouble(nFontSize
, sValue
);
603 rContext
.GetSmImport().GetMM100UnitConverter().
604 SetXMLMeasureUnit(util::MeasureUnit::POINT
);
605 if (-1 == sValue
.indexOf(GetXMLToken(XML_UNIT_PT
)))
607 if (-1 == sValue
.indexOf('%'))
611 rContext
.GetSmImport().GetMM100UnitConverter().
612 SetXMLMeasureUnit(util::MeasureUnit::PERCENT
);
617 sFontFamily
= sValue
;
625 case XML_MATHVARIANT
:
629 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
636 // Ignore deprecated attributes fontfamily, fontweight, and fontstyle
637 // in favor of mathvariant, as specified in
638 // <https://www.w3.org/TR/MathML3/chapter3.html#presm.deprecatt>.
645 void SmXMLContext_Helper::ApplyAttrs()
647 SmNodeStack
&rNodeStack
= rContext
.GetSmImport().GetNodeStack();
649 if (!IsFontNodeNeeded())
653 aToken
.cMathChar
= '\0';
659 aToken
.eType
= TBOLD
;
661 aToken
.eType
= TNBOLD
;
662 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
663 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
664 rNodeStack
.push_front(std::move(pFontNode
));
669 aToken
.eType
= TITALIC
;
671 aToken
.eType
= TNITALIC
;
672 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
673 pFontNode
->SetSubNodes(nullptr,popOrZero(rNodeStack
));
674 rNodeStack
.push_front(std::move(pFontNode
));
676 if (nFontSize
!= 0.0)
678 aToken
.eType
= TSIZE
;
679 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
681 if (util::MeasureUnit::PERCENT
== rContext
.GetSmImport()
682 .GetMM100UnitConverter().GetXMLMeasureUnit())
684 if (nFontSize
< 100.00)
685 pFontNode
->SetSizeParameter(Fraction(100.00/nFontSize
),
686 FontSizeType::DIVIDE
);
688 pFontNode
->SetSizeParameter(Fraction(nFontSize
/100.00),
689 FontSizeType::MULTIPLY
);
692 pFontNode
->SetSizeParameter(Fraction(nFontSize
),FontSizeType::ABSOLUT
);
694 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
695 rNodeStack
.push_front(std::move(pFontNode
));
697 if (!sColor
.isEmpty())
699 std::unique_ptr
<SmColorTokenTableEntry
> aSmColorTokenTableEntry
;
700 aSmColorTokenTableEntry
= starmathdatabase::Identify_ColorName_HTML( sColor
);
701 if( aSmColorTokenTableEntry
->eType
== TRGB
)
702 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( sal_uInt32(aSmColorTokenTableEntry
->cColor
) );
703 if( aSmColorTokenTableEntry
->eType
!= TERROR
)
705 aToken
= aSmColorTokenTableEntry
;
706 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
707 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
708 rNodeStack
.push_front(std::move(pFontNode
));
710 // If not known, not implemented yet. Giving up.
712 if (!sFontFamily
.isEmpty())
714 if (sFontFamily
.equalsIgnoreAsciiCase(GetXMLToken(XML_FIXED
)))
715 aToken
.eType
= TFIXED
;
716 else if (sFontFamily
.equalsIgnoreAsciiCase("sans"))
717 aToken
.eType
= TSANS
;
718 else if (sFontFamily
.equalsIgnoreAsciiCase("serif"))
719 aToken
.eType
= TSERIF
;
720 else //Just give up, we need to extend our font mechanism to be
724 aToken
.aText
= sFontFamily
;
725 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
726 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
727 rNodeStack
.push_front(std::move(pFontNode
));
733 class SmXMLTokenAttrHelper
735 SmXMLImportContext
& mrContext
;
736 MathMLMathvariantValue meMv
;
740 SmXMLTokenAttrHelper(SmXMLImportContext
& rContext
)
741 : mrContext(rContext
)
742 , meMv(MathMLMathvariantValue::Normal
)
746 void RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
);
747 void ApplyAttrs(MathMLMathvariantValue eDefaultMv
);
752 void SmXMLTokenAttrHelper::RetrieveAttrs(const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
754 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
756 OUString sValue
= aIter
.toString();
757 switch(aIter
.getToken())
759 case XML_MATHVARIANT
:
760 if (!GetMathMLMathvariantValue(sValue
, meMv
))
761 SAL_WARN("starmath", "failed to recognize mathvariant: " << sValue
);
765 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
771 void SmXMLTokenAttrHelper::ApplyAttrs(MathMLMathvariantValue eDefaultMv
)
773 assert( eDefaultMv
== MathMLMathvariantValue::Normal
||
774 eDefaultMv
== MathMLMathvariantValue::Italic
);
776 std::vector
<SmTokenType
> vVariant
;
777 MathMLMathvariantValue eMv
= mbMvFound
? meMv
: eDefaultMv
;
780 case MathMLMathvariantValue::Normal
:
781 vVariant
.push_back(TNITALIC
);
783 case MathMLMathvariantValue::Bold
:
784 vVariant
.push_back(TBOLD
);
786 case MathMLMathvariantValue::Italic
:
789 case MathMLMathvariantValue::BoldItalic
:
790 vVariant
.push_back(TITALIC
);
791 vVariant
.push_back(TBOLD
);
793 case MathMLMathvariantValue::DoubleStruck
:
796 case MathMLMathvariantValue::BoldFraktur
:
798 vVariant
.push_back(TBOLD
);
800 case MathMLMathvariantValue::Script
:
803 case MathMLMathvariantValue::BoldScript
:
805 vVariant
.push_back(TBOLD
);
807 case MathMLMathvariantValue::Fraktur
:
810 case MathMLMathvariantValue::SansSerif
:
811 vVariant
.push_back(TSANS
);
813 case MathMLMathvariantValue::BoldSansSerif
:
814 vVariant
.push_back(TSANS
);
815 vVariant
.push_back(TBOLD
);
817 case MathMLMathvariantValue::SansSerifItalic
:
818 vVariant
.push_back(TITALIC
);
819 vVariant
.push_back(TSANS
);
821 case MathMLMathvariantValue::SansSerifBoldItalic
:
822 vVariant
.push_back(TITALIC
);
823 vVariant
.push_back(TBOLD
);
824 vVariant
.push_back(TSANS
);
826 case MathMLMathvariantValue::Monospace
:
827 vVariant
.push_back(TFIXED
);
829 case MathMLMathvariantValue::Initial
:
830 case MathMLMathvariantValue::Tailed
:
831 case MathMLMathvariantValue::Looped
:
832 case MathMLMathvariantValue::Stretched
:
836 if (vVariant
.empty())
838 SmNodeStack
&rNodeStack
= mrContext
.GetSmImport().GetNodeStack();
839 for (auto eType
: vVariant
)
842 aToken
.eType
= eType
;
843 aToken
.cMathChar
= '\0';
845 std::unique_ptr
<SmFontNode
> pFontNode(new SmFontNode(aToken
));
846 pFontNode
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
847 rNodeStack
.push_front(std::move(pFontNode
));
853 class SmXMLDocContext_Impl
: public SmXMLImportContext
856 SmXMLDocContext_Impl( SmXMLImport
&rImport
)
857 : SmXMLImportContext(rImport
) {}
859 virtual uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
860 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
862 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
866 /*avert the gaze from the originator*/
867 class SmXMLRowContext_Impl
: public SmXMLDocContext_Impl
870 size_t nElementCount
;
873 SmXMLRowContext_Impl(SmXMLImport
&rImport
)
874 : SmXMLDocContext_Impl(rImport
)
875 , nElementCount(GetSmImport().GetNodeStack().size())
879 virtual uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
880 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
882 uno::Reference
< xml::sax::XFastContextHandler
> StrictCreateChildContext(sal_Int32 nElement
);
884 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
887 class SmXMLEncloseContext_Impl
: public SmXMLRowContext_Impl
890 // TODO/LATER: convert <menclose notation="horizontalstrike"> into
891 // "overstrike{}" and extend the Math syntax to support more notations
892 SmXMLEncloseContext_Impl(SmXMLImport
&rImport
)
893 : SmXMLRowContext_Impl(rImport
) {}
895 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
900 void SmXMLEncloseContext_Impl::endFastElement(sal_Int32 nElement
)
903 <menclose> accepts any number of arguments; if this number is not 1, its
904 contents are treated as a single "inferred <mrow>" containing its
907 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
908 SmXMLRowContext_Impl::endFastElement( nElement
);
913 class SmXMLFracContext_Impl
: public SmXMLRowContext_Impl
916 // TODO/LATER: convert <mfrac bevelled="true"> into "wideslash{}{}"
917 SmXMLFracContext_Impl(SmXMLImport
&rImport
)
918 : SmXMLRowContext_Impl(rImport
) {}
920 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
924 class SmXMLSqrtContext_Impl
: public SmXMLRowContext_Impl
927 SmXMLSqrtContext_Impl(SmXMLImport
&rImport
)
928 : SmXMLRowContext_Impl(rImport
) {}
930 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
934 class SmXMLRootContext_Impl
: public SmXMLRowContext_Impl
937 SmXMLRootContext_Impl(SmXMLImport
&rImport
)
938 : SmXMLRowContext_Impl(rImport
) {}
940 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
944 class SmXMLStyleContext_Impl
: public SmXMLRowContext_Impl
947 SmXMLContext_Helper aStyleHelper
;
950 /*Right now the style tag is completely ignored*/
951 SmXMLStyleContext_Impl(SmXMLImport
&rImport
) : SmXMLRowContext_Impl(rImport
),
952 aStyleHelper(*this) {}
954 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
955 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
> &xAttrList
) override
;
960 void SmXMLStyleContext_Impl::startFastElement( sal_Int32
/*nElement*/, const uno::Reference
<
961 xml::sax::XFastAttributeList
> & xAttrList
)
963 aStyleHelper
.RetrieveAttrs(xAttrList
);
967 void SmXMLStyleContext_Impl::endFastElement(sal_Int32 nElement
)
970 <mstyle> accepts any number of arguments; if this number is not 1, its
971 contents are treated as a single "inferred <mrow>" containing its
974 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
975 if (rNodeStack
.size() - nElementCount
!= 1)
976 SmXMLRowContext_Impl::endFastElement(nElement
);
977 aStyleHelper
.ApplyAttrs();
982 class SmXMLPaddedContext_Impl
: public SmXMLRowContext_Impl
985 /*Right now the style tag is completely ignored*/
986 SmXMLPaddedContext_Impl(SmXMLImport
&rImport
)
987 : SmXMLRowContext_Impl(rImport
) {}
989 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
994 void SmXMLPaddedContext_Impl::endFastElement(sal_Int32 nElement
)
997 <mpadded> accepts any number of arguments; if this number is not 1, its
998 contents are treated as a single "inferred <mrow>" containing its
1001 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
1002 SmXMLRowContext_Impl::endFastElement(nElement
);
1007 class SmXMLPhantomContext_Impl
: public SmXMLRowContext_Impl
1010 /*Right now the style tag is completely ignored*/
1011 SmXMLPhantomContext_Impl(SmXMLImport
&rImport
)
1012 : SmXMLRowContext_Impl(rImport
) {}
1014 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1019 void SmXMLPhantomContext_Impl::endFastElement(sal_Int32 nElement
)
1022 <mphantom> accepts any number of arguments; if this number is not 1, its
1023 contents are treated as a single "inferred <mrow>" containing its
1026 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
1027 SmXMLRowContext_Impl::endFastElement(nElement
);
1030 aToken
.cMathChar
= '\0';
1032 aToken
.eType
= TPHANTOM
;
1034 std::unique_ptr
<SmFontNode
> pPhantom(new SmFontNode(aToken
));
1035 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1036 pPhantom
->SetSubNodes(nullptr, popOrZero(rNodeStack
));
1037 rNodeStack
.push_front(std::move(pPhantom
));
1042 class SmXMLFencedContext_Impl
: public SmXMLRowContext_Impl
1050 SmXMLFencedContext_Impl(SmXMLImport
&rImport
)
1051 : SmXMLRowContext_Impl(rImport
)
1052 , cBegin('('), cEnd(')')
1053 , bIsStretchy(false) {}
1055 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
> & xAttrList
) override
;
1056 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1061 void SmXMLFencedContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<
1062 xml::sax::XFastAttributeList
> & xAttrList
)
1064 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
1066 OUString sValue
= aIter
.toString();
1067 switch(aIter
.getToken())
1069 //temp, starmath cannot handle multichar brackets (I think)
1077 bIsStretchy
= sValue
== GetXMLToken(XML_TRUE
);
1080 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1081 /*Go to superclass*/
1088 void SmXMLFencedContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1091 aToken
.cMathChar
= '\0';
1095 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
1096 if( bIsStretchy
) aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( cBegin
);
1097 else aToken
= starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl( cBegin
);
1098 if( aToken
.eType
== TERROR
) aToken
= SmToken( TLPARENT
, MS_LPARENT
, "(", TG::LBrace
, 5 );
1099 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
1100 if( bIsStretchy
) aToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( cEnd
);
1101 else aToken
= starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl( cEnd
);
1102 if( aToken
.eType
== TERROR
) aToken
= SmToken( TRPARENT
, MS_RPARENT
, ")", TG::LBrace
, 5 );
1103 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
1105 SmNodeArray aRelationArray
;
1106 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1107 aToken
.cMathChar
= '\0';
1108 aToken
.eType
= TIDENT
;
1110 auto i
= rNodeStack
.size() - nElementCount
;
1111 if (rNodeStack
.size() - nElementCount
> 1)
1112 i
+= rNodeStack
.size() - 1 - nElementCount
;
1113 aRelationArray
.resize(i
);
1114 while (rNodeStack
.size() > nElementCount
)
1116 auto pNode
= std::move(rNodeStack
.front());
1117 rNodeStack
.pop_front();
1118 aRelationArray
[--i
] = pNode
.release();
1119 if (i
> 1 && rNodeStack
.size() > 1)
1120 aRelationArray
[--i
] = new SmGlyphSpecialNode(aToken
);
1124 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
1125 pBody
->SetSubNodes(std::move(aRelationArray
));
1128 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
1129 // mfenced is always scalable. Stretchy keyword is not official, but in case of been in there
1130 // can be used as a hint.
1131 pSNode
->SetScaleMode(SmScaleMode::Height
);
1132 GetSmImport().GetNodeStack().push_front(std::move(pSNode
));
1137 class SmXMLErrorContext_Impl
: public SmXMLRowContext_Impl
1140 SmXMLErrorContext_Impl(SmXMLImport
&rImport
)
1141 : SmXMLRowContext_Impl(rImport
) {}
1143 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1148 void SmXMLErrorContext_Impl::endFastElement(sal_Int32
/*nElement*/)
1150 /*Right now the error tag is completely ignored, what
1151 can I do with it in starmath, ?, maybe we need a
1152 report window ourselves, do a test for validity of
1153 the xml input, use mirrors, and then generate
1154 the markup inside the merror with a big red colour
1155 of something. For now just throw them all away.
1157 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1158 while (rNodeStack
.size() > nElementCount
)
1160 rNodeStack
.pop_front();
1166 class SmXMLNumberContext_Impl
: public SmXMLImportContext
1172 SmXMLNumberContext_Impl(SmXMLImport
&rImport
)
1173 : SmXMLImportContext(rImport
)
1175 aToken
.cMathChar
= '\0';
1177 aToken
.eType
= TNUMBER
;
1180 virtual void TCharacters(const OUString
&rChars
) override
;
1182 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1187 void SmXMLNumberContext_Impl::TCharacters(const OUString
&rChars
)
1189 aToken
.aText
= rChars
;
1192 void SmXMLNumberContext_Impl::endFastElement(sal_Int32
)
1194 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
,FNT_NUMBER
));
1199 class SmXMLAnnotationContext_Impl
: public SmXMLImportContext
1204 SmXMLAnnotationContext_Impl(SmXMLImport
&rImport
)
1205 : SmXMLImportContext(rImport
), bIsStarMath(false) {}
1207 void SAL_CALL
characters(const OUString
&rChars
) override
;
1209 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
> & xAttrList
) override
;
1214 void SmXMLAnnotationContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<
1215 xml::sax::XFastAttributeList
> & xAttrList
)
1217 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
1219 OUString sValue
= aIter
.toString();
1220 // sometimes they have namespace, sometimes not?
1221 switch(aIter
.getToken() & TOKEN_MASK
)
1224 bIsStarMath
= sValue
== "StarMath 5.0";
1227 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1233 void SmXMLAnnotationContext_Impl::characters(const OUString
&rChars
)
1236 GetSmImport().SetText( GetSmImport().GetText() + rChars
);
1241 class SmXMLTextContext_Impl
: public SmXMLImportContext
1247 SmXMLTextContext_Impl(SmXMLImport
&rImport
)
1248 : SmXMLImportContext(rImport
)
1250 aToken
.cMathChar
= '\0';
1252 aToken
.eType
= TTEXT
;
1255 virtual void TCharacters(const OUString
&rChars
) override
;
1257 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1262 void SmXMLTextContext_Impl::TCharacters(const OUString
&rChars
)
1264 aToken
.aText
= rChars
;
1267 void SmXMLTextContext_Impl::endFastElement(sal_Int32
)
1269 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
,FNT_TEXT
));
1274 class SmXMLStringContext_Impl
: public SmXMLImportContext
1280 SmXMLStringContext_Impl(SmXMLImport
&rImport
)
1281 : SmXMLImportContext(rImport
)
1283 aToken
.cMathChar
= '\0';
1285 aToken
.eType
= TTEXT
;
1288 virtual void TCharacters(const OUString
&rChars
) override
;
1290 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1295 void SmXMLStringContext_Impl::TCharacters(const OUString
&rChars
)
1298 The content of <ms> elements should be rendered with visible "escaping" of
1299 certain characters in the content, including at least "double quote"
1300 itself, and preferably whitespace other than individual blanks. The intent
1301 is for the viewer to see that the expression is a string literal, and to
1302 see exactly which characters form its content. For example, <ms>double
1303 quote is "</ms> might be rendered as "double quote is \"".
1305 Obviously this isn't fully done here.
1307 aToken
.aText
= "\"" + rChars
+ "\"";
1310 void SmXMLStringContext_Impl::endFastElement(sal_Int32
)
1312 GetSmImport().GetNodeStack().push_front(std::make_unique
<SmTextNode
>(aToken
,FNT_FIXED
));
1317 class SmXMLIdentifierContext_Impl
: public SmXMLImportContext
1319 SmXMLTokenAttrHelper maTokenAttrHelper
;
1320 SmXMLContext_Helper aStyleHelper
;
1324 SmXMLIdentifierContext_Impl(SmXMLImport
&rImport
)
1325 : SmXMLImportContext(rImport
)
1326 , maTokenAttrHelper(*this)
1327 , aStyleHelper(*this)
1329 aToken
.cMathChar
= '\0';
1331 aToken
.eType
= TIDENT
;
1334 void TCharacters(const OUString
&rChars
) override
;
1335 void SAL_CALL
startFastElement(sal_Int32
/*nElement*/, const uno::Reference
< xml::sax::XFastAttributeList
> & xAttrList
) override
1337 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1338 aStyleHelper
.RetrieveAttrs(xAttrList
);
1340 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1345 void SmXMLIdentifierContext_Impl::endFastElement(sal_Int32
)
1347 std::unique_ptr
<SmTextNode
> pNode
;
1348 //we will handle identifier italic/normal here instead of with a standalone
1350 if (((aStyleHelper
.nIsItalic
== -1) && (aToken
.aText
.getLength() > 1))
1351 || ((aStyleHelper
.nIsItalic
== 0) && (aToken
.aText
.getLength() == 1)))
1353 pNode
.reset(new SmTextNode(aToken
,FNT_FUNCTION
));
1354 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1355 aStyleHelper
.nIsItalic
= -1;
1358 pNode
.reset(new SmTextNode(aToken
,FNT_VARIABLE
));
1359 if (aStyleHelper
.nIsItalic
!= -1)
1361 if (aStyleHelper
.nIsItalic
)
1362 pNode
->GetFont().SetItalic(ITALIC_NORMAL
);
1364 pNode
->GetFont().SetItalic(ITALIC_NONE
);
1365 aStyleHelper
.nIsItalic
= -1;
1367 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1368 aStyleHelper
.ApplyAttrs();
1370 maTokenAttrHelper
.ApplyAttrs( (aToken
.aText
.getLength() == 1)
1371 ? MathMLMathvariantValue::Italic
1372 : MathMLMathvariantValue::Normal
);
1375 void SmXMLIdentifierContext_Impl::TCharacters(const OUString
&rChars
)
1377 aToken
.aText
= rChars
;
1382 class SmXMLOperatorContext_Impl
: public SmXMLImportContext
1384 SmXMLTokenAttrHelper maTokenAttrHelper
;
1393 SmXMLOperatorContext_Impl(SmXMLImport
&rImport
)
1394 : SmXMLImportContext(rImport
)
1395 , maTokenAttrHelper(*this)
1396 , bIsStretchy(false)
1402 aToken
.eType
= TSPECIAL
;
1406 void TCharacters(const OUString
&rChars
) override
;
1407 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
> &xAttrList
) override
;
1408 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1413 void SmXMLOperatorContext_Impl::TCharacters(const OUString
&rChars
)
1415 aToken
.cMathChar
= rChars
[0];
1418 if( isPrefix
) bToken
= starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl( aToken
.cMathChar
);
1419 else if( isInfix
) bToken
= SmToken( TMLINE
, MS_VERTLINE
, "mline", TG::NONE
, 0 );
1420 else if( isPostfix
) bToken
= starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl( aToken
.cMathChar
);
1421 else bToken
= starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( aToken
.cMathChar
);
1423 else bToken
= starmathdatabase::Identify_SmXMLOperatorContext_Impl( aToken
.cMathChar
, bIsStretchy
);
1424 if( bToken
.eType
!= TERROR
) aToken
= bToken
;
1427 void SmXMLOperatorContext_Impl::endFastElement(sal_Int32
)
1429 std::unique_ptr
<SmMathSymbolNode
> pNode(new SmMathSymbolNode(aToken
));
1430 //For stretchy scaling the scaling must be retrieved from this node
1431 //and applied to the expression itself so as to get the expression
1432 //to scale the operator to the height of the expression itself
1434 pNode
->SetScaleMode(SmScaleMode::Height
);
1435 GetSmImport().GetNodeStack().push_front(std::move(pNode
));
1437 // TODO: apply to non-alphabetic characters too
1438 if (rtl::isAsciiAlpha(aToken
.cMathChar
))
1439 maTokenAttrHelper
.ApplyAttrs(MathMLMathvariantValue::Normal
);
1443 void SmXMLOperatorContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<
1444 xml::sax::XFastAttributeList
> & xAttrList
)
1446 maTokenAttrHelper
.RetrieveAttrs(xAttrList
);
1448 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
1450 OUString sValue
= aIter
.toString();
1451 switch(aIter
.getToken())
1454 bIsStretchy
= sValue
== GetXMLToken(XML_TRUE
);
1457 bIsFenced
= sValue
== GetXMLToken(XML_TRUE
);
1460 isPrefix
= sValue
== GetXMLToken(XML_PREFIX
); // <
1461 isInfix
= sValue
== GetXMLToken(XML_INFIX
); // |
1462 isPostfix
= sValue
== GetXMLToken(XML_POSTFIX
); // >
1465 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1473 class SmXMLSpaceContext_Impl
: public SmXMLImportContext
1476 SmXMLSpaceContext_Impl(SmXMLImport
&rImport
)
1477 : SmXMLImportContext(rImport
) {}
1479 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
1482 bool lcl_CountBlanks(const MathMLAttributeLengthValue
&rLV
,
1483 sal_Int32
*pWide
, sal_Int32
*pNarrow
)
1487 if (rLV
.aNumber
.GetNumerator() == 0)
1489 *pWide
= *pNarrow
= 0;
1492 // TODO: honor other units than em
1493 if (rLV
.eUnit
!= MathMLLengthUnit::Em
)
1495 if (rLV
.aNumber
.GetNumerator() < 0)
1497 const Fraction
aTwo(2, 1);
1498 auto aWide
= rLV
.aNumber
/ aTwo
;
1499 auto nWide
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aWide
));
1502 const Fraction
aPointFive(1, 2);
1503 auto aNarrow
= (rLV
.aNumber
- Fraction(nWide
, 1) * aTwo
) / aPointFive
;
1504 auto nNarrow
= static_cast<sal_Int32
>(static_cast<tools::Long
>(aNarrow
));
1514 void SmXMLSpaceContext_Impl::startFastElement(sal_Int32
/*nElement*/,
1515 const uno::Reference
<xml::sax::XFastAttributeList
> & xAttrList
)
1517 // There is no syntax in Math to specify blank nodes of arbitrary size yet.
1518 MathMLAttributeLengthValue aLV
;
1519 sal_Int32 nWide
= 0, nNarrow
= 0;
1521 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
1523 OUString sValue
= aIter
.toString();
1524 switch (aIter
.getToken())
1527 if ( ParseMathMLAttributeLengthValue(sValue
.trim(), aLV
) <= 0 ||
1528 !lcl_CountBlanks(aLV
, &nWide
, &nNarrow
) )
1529 SAL_WARN("starmath", "ignore mspace's width: " << sValue
);
1532 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
1537 aToken
.eType
= TBLANK
;
1538 aToken
.cMathChar
= '\0';
1539 aToken
.nGroup
= TG::Blank
;
1541 std::unique_ptr
<SmBlankNode
> pBlank(new SmBlankNode(aToken
));
1543 pBlank
->IncreaseBy(aToken
, nWide
);
1546 aToken
.eType
= TSBLANK
;
1547 pBlank
->IncreaseBy(aToken
, nNarrow
);
1549 GetSmImport().GetNodeStack().push_front(std::move(pBlank
));
1554 class SmXMLSubContext_Impl
: public SmXMLRowContext_Impl
1557 void GenericEndElement(SmTokenType eType
,SmSubSup aSubSup
);
1560 SmXMLSubContext_Impl(SmXMLImport
&rImport
)
1561 : SmXMLRowContext_Impl(rImport
) {}
1563 void SAL_CALL
endFastElement(sal_Int32
) override
1565 GenericEndElement(TRSUB
,RSUB
);
1571 void SmXMLSubContext_Impl::GenericEndElement(SmTokenType eType
, SmSubSup eSubSup
)
1573 /*The <msub> element requires exactly 2 arguments.*/
1574 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1575 OSL_ENSURE( bNodeCheck
, "Sub has not two arguments" );
1580 aToken
.cMathChar
= '\0';
1581 aToken
.eType
= eType
;
1582 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1583 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1585 // initialize subnodes array
1586 SmNodeArray aSubNodes
;
1587 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1588 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1589 aSubNodes
[i
] = nullptr;
1591 aSubNodes
[eSubSup
+1] = popOrZero(rNodeStack
).release();
1592 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1593 pNode
->SetSubNodes(std::move(aSubNodes
));
1594 rNodeStack
.push_front(std::move(pNode
));
1599 class SmXMLSupContext_Impl
: public SmXMLSubContext_Impl
1602 SmXMLSupContext_Impl(SmXMLImport
&rImport
)
1603 : SmXMLSubContext_Impl(rImport
) {}
1605 void SAL_CALL
endFastElement(sal_Int32
) override
1607 GenericEndElement(TRSUP
,RSUP
);
1612 class SmXMLSubSupContext_Impl
: public SmXMLRowContext_Impl
1615 void GenericEndElement(SmTokenType eType
, SmSubSup aSub
,SmSubSup aSup
);
1618 SmXMLSubSupContext_Impl(SmXMLImport
&rImport
)
1619 : SmXMLRowContext_Impl(rImport
) {}
1621 void SAL_CALL
endFastElement(sal_Int32
) override
1623 GenericEndElement(TRSUB
,RSUB
,RSUP
);
1629 void SmXMLSubSupContext_Impl::GenericEndElement(SmTokenType eType
,
1630 SmSubSup aSub
,SmSubSup aSup
)
1632 /*The <msub> element requires exactly 3 arguments.*/
1633 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 3;
1634 OSL_ENSURE( bNodeCheck
, "SubSup has not three arguments" );
1639 aToken
.cMathChar
= '\0';
1640 aToken
.eType
= eType
;
1641 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
1642 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1644 // initialize subnodes array
1645 SmNodeArray aSubNodes
;
1646 aSubNodes
.resize(1 + SUBSUP_NUM_ENTRIES
);
1647 for (size_t i
= 1; i
< aSubNodes
.size(); i
++)
1648 aSubNodes
[i
] = nullptr;
1650 aSubNodes
[aSup
+1] = popOrZero(rNodeStack
).release();
1651 aSubNodes
[aSub
+1] = popOrZero(rNodeStack
).release();
1652 aSubNodes
[0] = popOrZero(rNodeStack
).release();
1653 pNode
->SetSubNodes(std::move(aSubNodes
));
1654 rNodeStack
.push_front(std::move(pNode
));
1659 class SmXMLUnderContext_Impl
: public SmXMLSubContext_Impl
1662 sal_Int16 nAttrCount
;
1665 SmXMLUnderContext_Impl(SmXMLImport
&rImport
)
1666 : SmXMLSubContext_Impl(rImport
)
1670 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
> &xAttrList
) override
;
1671 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1672 void HandleAccent();
1677 void SmXMLUnderContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<
1678 xml::sax::XFastAttributeList
> & xAttrList
)
1680 sax_fastparser::FastAttributeList
& rAttribList
=
1681 sax_fastparser::castToFastAttributeList( xAttrList
);
1682 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1685 void SmXMLUnderContext_Impl::HandleAccent()
1687 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1688 OSL_ENSURE( bNodeCheck
, "Sub has not two arguments" );
1692 /*Just one special case for the underline thing*/
1693 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1694 std::unique_ptr
<SmNode
> pTest
= popOrZero(rNodeStack
);
1696 aToken
.cMathChar
= '\0';
1697 aToken
.eType
= TUNDERLINE
;
1699 std::unique_ptr
<SmNode
> pFirst
;
1700 std::unique_ptr
<SmStructureNode
> pNode(new SmAttributNode(aToken
));
1701 if ((pTest
->GetToken().cMathChar
& 0x0FFF) == 0x0332)
1703 pFirst
.reset(new SmRectangleNode(aToken
));
1706 pFirst
= std::move(pTest
);
1708 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1709 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1710 pNode
->SetScaleMode(SmScaleMode::Width
);
1711 rNodeStack
.push_front(std::move(pNode
));
1715 void SmXMLUnderContext_Impl::endFastElement(sal_Int32
)
1718 GenericEndElement(TCSUB
,CSUB
);
1725 class SmXMLOverContext_Impl
: public SmXMLSubContext_Impl
1728 sal_Int16 nAttrCount
;
1731 SmXMLOverContext_Impl(SmXMLImport
&rImport
)
1732 : SmXMLSubContext_Impl(rImport
), nAttrCount(0) {}
1734 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1735 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
> &xAttrList
) override
;
1736 void HandleAccent();
1741 void SmXMLOverContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<
1742 xml::sax::XFastAttributeList
> & xAttrList
)
1744 sax_fastparser::FastAttributeList
& rAttribList
=
1745 sax_fastparser::castToFastAttributeList( xAttrList
);
1746 nAttrCount
= rAttribList
.getFastAttributeTokens().size();
1750 void SmXMLOverContext_Impl::endFastElement(sal_Int32
)
1753 GenericEndElement(TCSUP
,CSUP
);
1759 void SmXMLOverContext_Impl::HandleAccent()
1761 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
1762 OSL_ENSURE (bNodeCheck
, "Sub has not two arguments");
1767 aToken
.cMathChar
= '\0';
1768 aToken
.eType
= TACUTE
;
1770 std::unique_ptr
<SmAttributNode
> pNode(new SmAttributNode(aToken
));
1771 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
1773 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
1774 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
1775 pNode
->SetSubNodes(std::move(pFirst
), std::move(pSecond
));
1776 pNode
->SetScaleMode(SmScaleMode::Width
);
1777 rNodeStack
.push_front(std::move(pNode
));
1783 class SmXMLUnderOverContext_Impl
: public SmXMLSubSupContext_Impl
1786 SmXMLUnderOverContext_Impl(SmXMLImport
&rImport
)
1787 : SmXMLSubSupContext_Impl(rImport
) {}
1789 void SAL_CALL
endFastElement(sal_Int32
) override
1791 GenericEndElement(TCSUB
,CSUB
,CSUP
);
1796 class SmXMLMultiScriptsContext_Impl
: public SmXMLSubSupContext_Impl
1798 bool bHasPrescripts
;
1800 void ProcessSubSupPairs(bool bIsPrescript
);
1803 SmXMLMultiScriptsContext_Impl(SmXMLImport
&rImport
) :
1804 SmXMLSubSupContext_Impl(rImport
),
1805 bHasPrescripts(false) {}
1807 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1808 virtual uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1809 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
1813 class SmXMLNoneContext_Impl
: public SmXMLImportContext
1816 SmXMLNoneContext_Impl(SmXMLImport
&rImport
)
1817 : SmXMLImportContext(rImport
) {}
1819 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1824 void SmXMLNoneContext_Impl::endFastElement(sal_Int32
)
1827 aToken
.cMathChar
= '\0';
1828 aToken
.aText
.clear();
1830 aToken
.eType
= TIDENT
;
1831 GetSmImport().GetNodeStack().push_front(
1832 std::make_unique
<SmTextNode
>(aToken
,FNT_VARIABLE
));
1837 class SmXMLPrescriptsContext_Impl
: public SmXMLImportContext
1840 SmXMLPrescriptsContext_Impl(SmXMLImport
&rImport
)
1841 : SmXMLImportContext(rImport
) {}
1845 class SmXMLTableRowContext_Impl
: public SmXMLRowContext_Impl
1848 SmXMLTableRowContext_Impl(SmXMLImport
&rImport
) :
1849 SmXMLRowContext_Impl(rImport
)
1852 virtual uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1853 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
1857 class SmXMLTableContext_Impl
: public SmXMLTableRowContext_Impl
1860 SmXMLTableContext_Impl(SmXMLImport
&rImport
) :
1861 SmXMLTableRowContext_Impl(rImport
)
1864 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1865 virtual uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1866 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
) override
;
1870 class SmXMLTableCellContext_Impl
: public SmXMLRowContext_Impl
1873 SmXMLTableCellContext_Impl(SmXMLImport
&rImport
) :
1874 SmXMLRowContext_Impl(rImport
)
1879 class SmXMLAlignGroupContext_Impl
: public SmXMLRowContext_Impl
1882 SmXMLAlignGroupContext_Impl(SmXMLImport
&rImport
) :
1883 SmXMLRowContext_Impl(rImport
)
1886 /*Don't do anything with alignment for now*/
1890 class SmXMLActionContext_Impl
: public SmXMLRowContext_Impl
1892 size_t mnSelection
; // 1-based
1895 SmXMLActionContext_Impl(SmXMLImport
&rImport
) :
1896 SmXMLRowContext_Impl(rImport
)
1900 void SAL_CALL
startFastElement(sal_Int32 nElement
, const uno::Reference
<xml::sax::XFastAttributeList
> &xAttrList
) override
;
1901 void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
1905 // NB: virtually inherit so we can multiply inherit properly
1906 // in SmXMLFlatDocContext_Impl
1907 class SmXMLOfficeContext_Impl
: public virtual SvXMLImportContext
1910 SmXMLOfficeContext_Impl( SmXMLImport
&rImport
)
1911 : SvXMLImportContext(rImport
) {}
1913 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1914 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1919 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLOfficeContext_Impl::createFastChildContext(sal_Int32 nElement
,
1920 const uno::Reference
< xml::sax::XFastAttributeList
> &/*xAttrList*/)
1922 if ( nElement
== XML_ELEMENT(OFFICE
, XML_META
) )
1924 SAL_WARN("starmath", "XML_TOK_DOC_META: should not have come here, maybe document is invalid?");
1926 else if ( nElement
== XML_ELEMENT(OFFICE
, XML_SETTINGS
) )
1928 return new XMLDocumentSettingsContext( GetImport() );
1935 // context for flat file xml format
1936 class SmXMLFlatDocContext_Impl
1937 : public SmXMLOfficeContext_Impl
, public SvXMLMetaDocumentContext
1940 SmXMLFlatDocContext_Impl( SmXMLImport
& i_rImport
,
1941 const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
);
1943 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
1944 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
1949 SmXMLFlatDocContext_Impl::SmXMLFlatDocContext_Impl( SmXMLImport
& i_rImport
,
1950 const uno::Reference
<document::XDocumentProperties
>& i_xDocProps
) :
1951 SvXMLImportContext(i_rImport
),
1952 SmXMLOfficeContext_Impl(i_rImport
),
1953 SvXMLMetaDocumentContext(i_rImport
, i_xDocProps
)
1957 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
SmXMLFlatDocContext_Impl::createFastChildContext(
1958 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
1960 // behave like meta base class iff we encounter office:meta
1961 if ( nElement
== XML_ELEMENT(OFFICE
, XML_META
) )
1963 return SvXMLMetaDocumentContext::createFastChildContext(
1964 nElement
, xAttrList
);
1968 return SmXMLOfficeContext_Impl::createFastChildContext(
1969 nElement
, xAttrList
);
1973 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLDocContext_Impl::createFastChildContext(
1975 const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/)
1977 uno::Reference
< xml::sax::XFastContextHandler
> xContext
;
1981 //Consider semantics a dummy except for any starmath annotations
1982 case XML_ELEMENT(MATH
, XML_SEMANTICS
):
1983 xContext
= new SmXMLRowContext_Impl(GetSmImport());
1985 /*General Layout Schemata*/
1986 case XML_ELEMENT(MATH
, XML_MROW
):
1987 xContext
= new SmXMLRowContext_Impl(GetSmImport());
1989 case XML_ELEMENT(MATH
, XML_MENCLOSE
):
1990 xContext
= new SmXMLEncloseContext_Impl(GetSmImport());
1992 case XML_ELEMENT(MATH
, XML_MFRAC
):
1993 xContext
= new SmXMLFracContext_Impl(GetSmImport());
1995 case XML_ELEMENT(MATH
, XML_MSQRT
):
1996 xContext
= new SmXMLSqrtContext_Impl(GetSmImport());
1998 case XML_ELEMENT(MATH
, XML_MROOT
):
1999 xContext
= new SmXMLRootContext_Impl(GetSmImport());
2001 case XML_ELEMENT(MATH
, XML_MSTYLE
):
2002 xContext
= new SmXMLStyleContext_Impl(GetSmImport());
2004 case XML_ELEMENT(MATH
, XML_MERROR
):
2005 xContext
= new SmXMLErrorContext_Impl(GetSmImport());
2007 case XML_ELEMENT(MATH
, XML_MPADDED
):
2008 xContext
= new SmXMLPaddedContext_Impl(GetSmImport());
2010 case XML_ELEMENT(MATH
, XML_MPHANTOM
):
2011 xContext
= new SmXMLPhantomContext_Impl(GetSmImport());
2013 case XML_ELEMENT(MATH
, XML_MFENCED
):
2014 xContext
= new SmXMLFencedContext_Impl(GetSmImport());
2016 /*Script and Limit Schemata*/
2017 case XML_ELEMENT(MATH
, XML_MSUB
):
2018 xContext
= new SmXMLSubContext_Impl(GetSmImport());
2020 case XML_ELEMENT(MATH
, XML_MSUP
):
2021 xContext
= new SmXMLSupContext_Impl(GetSmImport());
2023 case XML_ELEMENT(MATH
, XML_MSUBSUP
):
2024 xContext
= new SmXMLSubSupContext_Impl(GetSmImport());
2026 case XML_ELEMENT(MATH
, XML_MUNDER
):
2027 xContext
= new SmXMLUnderContext_Impl(GetSmImport());
2029 case XML_ELEMENT(MATH
, XML_MOVER
):
2030 xContext
= new SmXMLOverContext_Impl(GetSmImport());
2032 case XML_ELEMENT(MATH
, XML_MUNDEROVER
):
2033 xContext
= new SmXMLUnderOverContext_Impl(GetSmImport());
2035 case XML_ELEMENT(MATH
, XML_MMULTISCRIPTS
):
2036 xContext
= new SmXMLMultiScriptsContext_Impl(GetSmImport());
2038 case XML_ELEMENT(MATH
, XML_MTABLE
):
2039 xContext
= new SmXMLTableContext_Impl(GetSmImport());
2041 case XML_ELEMENT(MATH
, XML_MACTION
):
2042 xContext
= new SmXMLActionContext_Impl(GetSmImport());
2045 /*Basically there's an implicit mrow around certain bare
2046 *elements, use a RowContext to see if this is one of
2048 rtl::Reference
<SmXMLRowContext_Impl
> aTempContext(new SmXMLRowContext_Impl(GetSmImport()));
2050 xContext
= aTempContext
->StrictCreateChildContext(nElement
);
2056 void SmXMLDocContext_Impl::endFastElement(sal_Int32
)
2058 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2060 std::unique_ptr
<SmNode
> pContextNode
= popOrZero(rNodeStack
);
2063 std::unique_ptr
<SmStructureNode
> pSNode(new SmLineNode(aDummy
));
2064 pSNode
->SetSubNodes(std::move(pContextNode
), nullptr);
2065 rNodeStack
.push_front(std::move(pSNode
));
2067 SmNodeArray LineArray
;
2068 auto n
= rNodeStack
.size();
2069 LineArray
.resize(n
);
2070 for (size_t j
= 0; j
< n
; j
++)
2072 auto pNode
= std::move(rNodeStack
.front());
2073 rNodeStack
.pop_front();
2074 LineArray
[n
- (j
+ 1)] = pNode
.release();
2076 std::unique_ptr
<SmStructureNode
> pSNode2(new SmTableNode(aDummy
));
2077 pSNode2
->SetSubNodes(std::move(LineArray
));
2078 rNodeStack
.push_front(std::move(pSNode2
));
2081 void SmXMLFracContext_Impl::endFastElement(sal_Int32
)
2083 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2084 const bool bNodeCheck
= rNodeStack
.size() - nElementCount
== 2;
2085 OSL_ENSURE( bNodeCheck
, "Fraction (mfrac) tag is missing component" );
2090 aToken
.cMathChar
= '\0';
2091 aToken
.eType
= TFRAC
;
2092 std::unique_ptr
<SmStructureNode
> pSNode(new SmBinVerNode(aToken
));
2093 std::unique_ptr
<SmNode
> pOper(new SmRectangleNode(aToken
));
2094 std::unique_ptr
<SmNode
> pSecond
= popOrZero(rNodeStack
);
2095 std::unique_ptr
<SmNode
> pFirst
= popOrZero(rNodeStack
);
2096 pSNode
->SetSubNodes(std::move(pFirst
), std::move(pOper
), std::move(pSecond
));
2097 rNodeStack
.push_front(std::move(pSNode
));
2100 void SmXMLRootContext_Impl::endFastElement(sal_Int32
)
2102 /*The <mroot> element requires exactly 2 arguments.*/
2103 const bool bNodeCheck
= GetSmImport().GetNodeStack().size() - nElementCount
== 2;
2104 OSL_ENSURE( bNodeCheck
, "Root tag is missing component");
2109 aToken
.cMathChar
= MS_SQRT
; //Temporary: alert, based on StarSymbol font
2110 aToken
.eType
= TNROOT
;
2111 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2112 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2113 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2114 std::unique_ptr
<SmNode
> pIndex
= popOrZero(rNodeStack
);
2115 std::unique_ptr
<SmNode
> pBase
= popOrZero(rNodeStack
);
2116 pSNode
->SetSubNodes(std::move(pIndex
), std::move(pOper
), std::move(pBase
));
2117 rNodeStack
.push_front(std::move(pSNode
));
2120 void SmXMLSqrtContext_Impl::endFastElement(sal_Int32 nElement
)
2123 <msqrt> accepts any number of arguments; if this number is not 1, its
2124 contents are treated as a single "inferred <mrow>" containing its
2127 if (GetSmImport().GetNodeStack().size() - nElementCount
!= 1)
2128 SmXMLRowContext_Impl::endFastElement(nElement
);
2131 aToken
.cMathChar
= MS_SQRT
; //Temporary: alert, based on StarSymbol font
2132 aToken
.eType
= TSQRT
;
2133 std::unique_ptr
<SmStructureNode
> pSNode(new SmRootNode(aToken
));
2134 std::unique_ptr
<SmNode
> pOper(new SmRootSymbolNode(aToken
));
2135 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2136 pSNode
->SetSubNodes(nullptr, std::move(pOper
), popOrZero(rNodeStack
));
2137 rNodeStack
.push_front(std::move(pSNode
));
2140 void SmXMLRowContext_Impl::endFastElement(sal_Int32
)
2142 SmNodeArray aRelationArray
;
2143 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2145 if (rNodeStack
.size() > nElementCount
)
2147 auto nSize
= rNodeStack
.size() - nElementCount
;
2149 aRelationArray
.resize(nSize
);
2150 for (auto j
=nSize
;j
> 0;j
--)
2152 auto pNode
= std::move(rNodeStack
.front());
2153 rNodeStack
.pop_front();
2154 aRelationArray
[j
-1] = pNode
.release();
2157 //If the first or last element is an operator with stretchyness
2158 //set then we must create a brace node here from those elements,
2159 //removing the stretchness from the operators and applying it to
2160 //ourselves, and creating the appropriate dummy StarMath none bracket
2161 //to balance the arrangement
2162 if (((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2163 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2164 || ((aRelationArray
[nSize
-1]->GetScaleMode() == SmScaleMode::Height
)
2165 && (aRelationArray
[nSize
-1]->GetType() == SmNodeType::Math
)))
2168 aToken
.cMathChar
= '\0';
2171 int nLeft
=0,nRight
=0;
2172 if ((aRelationArray
[0]->GetScaleMode() == SmScaleMode::Height
)
2173 && (aRelationArray
[0]->GetType() == SmNodeType::Math
))
2175 aToken
= aRelationArray
[0]->GetToken();
2179 aToken
.cMathChar
= '\0';
2181 aToken
.eType
= TLPARENT
;
2182 std::unique_ptr
<SmNode
> pLeft(new SmMathSymbolNode(aToken
));
2184 if ((aRelationArray
[nSize
-1]->GetScaleMode() == SmScaleMode::Height
)
2185 && (aRelationArray
[nSize
-1]->GetType() == SmNodeType::Math
))
2187 aToken
= aRelationArray
[nSize
-1]->GetToken();
2191 aToken
.cMathChar
= '\0';
2193 aToken
.eType
= TRPARENT
;
2194 std::unique_ptr
<SmNode
> pRight(new SmMathSymbolNode(aToken
));
2196 SmNodeArray aRelationArray2
;
2198 //!! nSize-nLeft-nRight may be < 0 !!
2199 int nRelArrSize
= nSize
-nLeft
-nRight
;
2200 if (nRelArrSize
> 0)
2202 aRelationArray2
.resize(nRelArrSize
);
2203 for (int i
=0;i
< nRelArrSize
;i
++)
2205 aRelationArray2
[i
] = aRelationArray
[i
+nLeft
];
2206 aRelationArray
[i
+nLeft
] = nullptr;
2211 std::unique_ptr
<SmStructureNode
> pSNode(new SmBraceNode(aToken
));
2212 std::unique_ptr
<SmStructureNode
> pBody(new SmExpressionNode(aDummy
));
2213 pBody
->SetSubNodes(std::move(aRelationArray2
));
2215 pSNode
->SetSubNodes(std::move(pLeft
), std::move(pBody
), std::move(pRight
));
2216 pSNode
->SetScaleMode(SmScaleMode::Height
);
2217 rNodeStack
.push_front(std::move(pSNode
));
2219 for (auto a
: aRelationArray
)
2227 // The elements msqrt, mstyle, merror, menclose, mpadded, mphantom, mtd, and math
2228 // treat their content as a single inferred mrow in case their content is empty.
2229 // Here an empty group {} is used to catch those cases and transform them without error
2231 aRelationArray
.resize(2);
2233 aToken
.cMathChar
= MS_LBRACE
;
2235 aToken
.eType
= TLGROUP
;
2236 aToken
.nGroup
= TG::NONE
;
2238 aRelationArray
[0] = new SmLineNode(aToken
);
2240 aToken
.cMathChar
= MS_RBRACE
;
2242 aToken
.eType
= TRGROUP
;
2243 aToken
.nGroup
= TG::NONE
;
2245 aRelationArray
[1] = new SmLineNode(aToken
);
2249 std::unique_ptr
<SmStructureNode
> pSNode(new SmExpressionNode(aDummy
));
2250 pSNode
->SetSubNodes(std::move(aRelationArray
));
2251 rNodeStack
.push_front(std::move(pSNode
));
2254 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLRowContext_Impl::StrictCreateChildContext(
2257 uno::Reference
< xml::sax::XFastContextHandler
> pContext
;
2261 /*Note that these should accept malignmark subelements, but do not*/
2262 case XML_ELEMENT(MATH
, XML_MN
):
2263 pContext
= new SmXMLNumberContext_Impl(GetSmImport());
2265 case XML_ELEMENT(MATH
, XML_MI
):
2266 pContext
= new SmXMLIdentifierContext_Impl(GetSmImport());
2268 case XML_ELEMENT(MATH
, XML_MO
):
2269 pContext
= new SmXMLOperatorContext_Impl(GetSmImport());
2271 case XML_ELEMENT(MATH
, XML_MTEXT
):
2272 pContext
= new SmXMLTextContext_Impl(GetSmImport());
2274 case XML_ELEMENT(MATH
, XML_MSPACE
):
2275 pContext
= new SmXMLSpaceContext_Impl(GetSmImport());
2277 case XML_ELEMENT(MATH
, XML_MS
):
2278 pContext
= new SmXMLStringContext_Impl(GetSmImport());
2281 /*Note: The maligngroup should only be seen when the row
2282 * (or descendants) are in a table*/
2283 case XML_ELEMENT(MATH
, XML_MALIGNGROUP
):
2284 pContext
= new SmXMLAlignGroupContext_Impl(GetSmImport());
2287 case XML_ELEMENT(MATH
, XML_ANNOTATION
):
2288 pContext
= new SmXMLAnnotationContext_Impl(GetSmImport());
2298 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLRowContext_Impl::createFastChildContext(
2300 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2302 uno::Reference
< xml::sax::XFastContextHandler
> xContext
= StrictCreateChildContext(nElement
);
2306 //Hmm, unrecognized for this level, check to see if its
2307 //an element that can have an implicit schema around it
2308 xContext
= SmXMLDocContext_Impl::createFastChildContext(nElement
, xAttrList
);
2313 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLMultiScriptsContext_Impl::createFastChildContext(
2315 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2317 uno::Reference
< xml::sax::XFastContextHandler
> xContext
;
2321 case XML_ELEMENT(MATH
, XML_MPRESCRIPTS
):
2322 bHasPrescripts
= true;
2323 ProcessSubSupPairs(false);
2324 xContext
= new SmXMLPrescriptsContext_Impl(GetSmImport());
2326 case XML_ELEMENT(MATH
, XML_NONE
):
2327 xContext
= new SmXMLNoneContext_Impl(GetSmImport());
2330 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
,xAttrList
);
2336 void SmXMLMultiScriptsContext_Impl::ProcessSubSupPairs(bool bIsPrescript
)
2338 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2340 if (rNodeStack
.size() <= nElementCount
)
2343 auto nCount
= rNodeStack
.size() - nElementCount
- 1;
2347 if (nCount
% 2 == 0)
2350 aToken
.cMathChar
= '\0';
2351 aToken
.eType
= bIsPrescript
? TLSUB
: TRSUB
;
2353 SmNodeStack aReverseStack
;
2354 for (size_t i
= 0; i
< nCount
+ 1; i
++)
2356 auto pNode
= std::move(rNodeStack
.front());
2357 rNodeStack
.pop_front();
2358 aReverseStack
.push_front(std::move(pNode
));
2361 SmSubSup eSub
= bIsPrescript
? LSUB
: RSUB
;
2362 SmSubSup eSup
= bIsPrescript
? LSUP
: RSUP
;
2364 for (size_t i
= 0; i
< nCount
; i
+= 2)
2366 std::unique_ptr
<SmSubSupNode
> pNode(new SmSubSupNode(aToken
));
2368 // initialize subnodes array
2369 SmNodeArray
aSubNodes(1 + SUBSUP_NUM_ENTRIES
);
2371 /*On each loop the base and its sub sup pair becomes the
2372 base for the next loop to which the next sub sup pair is
2373 attached, i.e. wheels within wheels*/
2374 aSubNodes
[0] = popOrZero(aReverseStack
).release();
2376 std::unique_ptr
<SmNode
> pScriptNode
= popOrZero(aReverseStack
);
2378 if (pScriptNode
&& ((pScriptNode
->GetToken().eType
!= TIDENT
) ||
2379 (!pScriptNode
->GetToken().aText
.isEmpty())))
2380 aSubNodes
[eSub
+1] = pScriptNode
.release();
2381 pScriptNode
= popOrZero(aReverseStack
);
2382 if (pScriptNode
&& ((pScriptNode
->GetToken().eType
!= TIDENT
) ||
2383 (!pScriptNode
->GetToken().aText
.isEmpty())))
2384 aSubNodes
[eSup
+1] = pScriptNode
.release();
2386 pNode
->SetSubNodes(std::move(aSubNodes
));
2387 aReverseStack
.push_front(std::move(pNode
));
2389 assert(!aReverseStack
.empty());
2390 auto pNode
= std::move(aReverseStack
.front());
2391 aReverseStack
.pop_front();
2392 rNodeStack
.push_front(std::move(pNode
));
2396 // Ignore odd number of elements.
2397 for (size_t i
= 0; i
< nCount
; i
++)
2399 rNodeStack
.pop_front();
2405 void SmXMLTableContext_Impl::endFastElement(sal_Int32
)
2407 SmNodeArray aExpressionArray
;
2408 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2409 SmNodeStack aReverseStack
;
2410 aExpressionArray
.resize(rNodeStack
.size()-nElementCount
);
2412 size_t nRows
= rNodeStack
.size()-nElementCount
;
2415 for (size_t i
= nRows
; i
> 0; --i
)
2417 SmNode
* pArray
= rNodeStack
.front().release();
2418 rNodeStack
.pop_front();
2419 if (pArray
->GetNumSubNodes() == 0)
2421 //This is a little tricky, it is possible that there was
2422 //be elements that were not inside a <mtd> pair, in which
2423 //case they will not be in a row, i.e. they will not have
2424 //SubNodes, so we have to wait until here before we can
2425 //resolve the situation. Implicit surrounding tags are
2426 //surprisingly difficult to get right within this
2429 SmNodeArray aRelationArray
;
2430 aRelationArray
.resize(1);
2431 aRelationArray
[0] = pArray
;
2433 SmExpressionNode
* pExprNode
= new SmExpressionNode(aDummy
);
2434 pExprNode
->SetSubNodes(std::move(aRelationArray
));
2438 nCols
= std::max(nCols
, pArray
->GetNumSubNodes());
2439 aReverseStack
.push_front(std::unique_ptr
<SmNode
>(pArray
));
2441 if (nCols
> SAL_MAX_UINT16
)
2442 throw std::range_error("column limit");
2443 if (nRows
> SAL_MAX_UINT16
)
2444 throw std::range_error("row limit");
2445 aExpressionArray
.resize(nCols
*nRows
);
2447 for (auto & elem
: aReverseStack
)
2449 std::unique_ptr
<SmStructureNode
> xArray(static_cast<SmStructureNode
*>(elem
.release()));
2450 for (size_t i
= 0; i
< xArray
->GetNumSubNodes(); ++i
)
2451 aExpressionArray
[j
++] = xArray
->GetSubNode(i
);
2452 xArray
->ClearSubNodes();
2454 aReverseStack
.clear();
2457 aToken
.cMathChar
= '\0';
2458 aToken
.eType
= TMATRIX
;
2459 std::unique_ptr
<SmMatrixNode
> pSNode(new SmMatrixNode(aToken
));
2460 pSNode
->SetSubNodes(std::move(aExpressionArray
));
2461 pSNode
->SetRowCol(nRows
, nCols
);
2462 rNodeStack
.push_front(std::move(pSNode
));
2465 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLTableRowContext_Impl::createFastChildContext(
2467 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2469 uno::Reference
< xml::sax::XFastContextHandler
> xContext
;
2473 case XML_ELEMENT(MATH
, XML_MTD
):
2474 xContext
= new SmXMLTableCellContext_Impl(GetSmImport());
2477 xContext
= SmXMLRowContext_Impl::createFastChildContext(nElement
,xAttrList
);
2483 uno::Reference
< xml::sax::XFastContextHandler
> SmXMLTableContext_Impl::createFastChildContext(
2485 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
)
2487 uno::Reference
< xml::sax::XFastContextHandler
> xContext
;
2491 case XML_ELEMENT(MATH
, XML_MTR
):
2492 xContext
= new SmXMLTableRowContext_Impl(GetSmImport());
2495 xContext
= SmXMLTableRowContext_Impl::createFastChildContext(nElement
, xAttrList
);
2501 void SmXMLMultiScriptsContext_Impl::endFastElement(sal_Int32
)
2503 ProcessSubSupPairs(bHasPrescripts
);
2506 void SmXMLActionContext_Impl::startFastElement(sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
> & xAttrList
)
2508 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
2510 OUString sValue
= aIter
.toString();
2511 switch(aIter
.getToken())
2515 sal_uInt32 n
= sValue
.toUInt32();
2516 if (n
> 0) mnSelection
= static_cast<size_t>(n
);
2520 XMLOFF_WARN_UNKNOWN("starmath", aIter
);
2526 void SmXMLActionContext_Impl::endFastElement(sal_Int32
)
2528 SmNodeStack
&rNodeStack
= GetSmImport().GetNodeStack();
2529 auto nSize
= rNodeStack
.size();
2530 if (nSize
<= nElementCount
) {
2531 // not compliant to maction's specification, e.g., no subexpressions
2534 assert(mnSelection
> 0);
2535 if (nSize
< nElementCount
+ mnSelection
) {
2536 // No selected subexpression exists, which is a MathML error;
2537 // fallback to selecting the first
2540 assert(nSize
>= nElementCount
+ mnSelection
);
2541 for (auto i
=nSize
-(nElementCount
+mnSelection
); i
> 0; i
--)
2543 rNodeStack
.pop_front();
2545 auto pSelected
= std::move(rNodeStack
.front());
2546 rNodeStack
.pop_front();
2547 for (auto i
=rNodeStack
.size()-nElementCount
; i
> 0; i
--)
2549 rNodeStack
.pop_front();
2551 rNodeStack
.push_front(std::move(pSelected
));
2554 SvXMLImportContext
*SmXMLImport::CreateFastContext(sal_Int32 nElement
,
2555 const uno::Reference
<xml::sax::XFastAttributeList
> & /*xAttrList*/)
2557 SvXMLImportContext
*pContext
= nullptr;
2561 case XML_ELEMENT( OFFICE
, XML_DOCUMENT
):
2562 case XML_ELEMENT( OFFICE
, XML_DOCUMENT_META
):
2564 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
2565 GetModel(), uno::UNO_QUERY_THROW
);
2566 pContext
= ( (nElement
& TOKEN_MASK
) == XML_DOCUMENT_META
)
2567 ? new SvXMLMetaDocumentContext( *this,
2568 xDPS
->getDocumentProperties() )
2569 // flat OpenDocument file format -- this has not been tested...
2570 : new SmXMLFlatDocContext_Impl( *this,
2571 xDPS
->getDocumentProperties() );
2575 if (IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE
))
2576 pContext
= new SmXMLOfficeContext_Impl(*this);
2578 pContext
= new SmXMLDocContext_Impl(*this);
2583 SmXMLImport::~SmXMLImport() throw ()
2588 void SmXMLImport::SetViewSettings(const Sequence
<PropertyValue
>& aViewProps
)
2590 uno::Reference
<frame::XModel
> xModel
= GetModel();
2594 SmModel
*pModel
= comphelper::getUnoTunnelImplementation
<SmModel
>(xModel
);
2599 SmDocShell
*pDocShell
=
2600 static_cast<SmDocShell
*>(pModel
->GetObjectShell());
2604 tools::Rectangle
aRect( pDocShell
->GetVisArea() );
2606 tools::Long nTmp
= 0;
2608 for (const PropertyValue
& rValue
: aViewProps
)
2610 if (rValue
.Name
== "ViewAreaTop" )
2612 rValue
.Value
>>= nTmp
;
2613 aRect
.SaturatingSetY(nTmp
);
2615 else if (rValue
.Name
== "ViewAreaLeft" )
2617 rValue
.Value
>>= nTmp
;
2618 aRect
.SaturatingSetX(nTmp
);
2620 else if (rValue
.Name
== "ViewAreaWidth" )
2622 rValue
.Value
>>= nTmp
;
2623 Size
aSize( aRect
.GetSize() );
2624 aSize
.setWidth( nTmp
);
2625 aRect
.SaturatingSetSize(aSize
);
2627 else if (rValue
.Name
== "ViewAreaHeight" )
2629 rValue
.Value
>>= nTmp
;
2630 Size
aSize( aRect
.GetSize() );
2631 aSize
.setHeight( nTmp
);
2632 aRect
.SaturatingSetSize(aSize
);
2636 pDocShell
->SetVisArea ( aRect
);
2639 void SmXMLImport::SetConfigurationSettings(const Sequence
<PropertyValue
>& aConfProps
)
2641 uno::Reference
< XPropertySet
> xProps ( GetModel(), UNO_QUERY
);
2645 Reference
< XPropertySetInfo
> xInfo ( xProps
->getPropertySetInfo() );
2649 const OUString
sFormula ( "Formula" );
2650 const OUString
sBasicLibraries ( "BasicLibraries" );
2651 const OUString
sDialogLibraries ( "DialogLibraries" );
2652 for ( const PropertyValue
& rValue
: aConfProps
)
2654 if (rValue
.Name
!= sFormula
&&
2655 rValue
.Name
!= sBasicLibraries
&&
2656 rValue
.Name
!= sDialogLibraries
)
2660 if ( xInfo
->hasPropertyByName( rValue
.Name
) )
2661 xProps
->setPropertyValue( rValue
.Name
, rValue
.Value
);
2663 catch (const beans::PropertyVetoException
&)
2665 // dealing with read-only properties here. Nothing to do...
2667 catch (const Exception
&)
2669 DBG_UNHANDLED_EXCEPTION("starmath");
2675 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportMML(SvStream
&rStream
)
2677 SmGlobals::ensure();
2679 SfxObjectShellLock
xDocSh(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT
));
2680 xDocSh
->DoInitNew();
2681 uno::Reference
<frame::XModel
> xModel(xDocSh
->GetModel());
2683 uno::Reference
<beans::XPropertySet
> xInfoSet
;
2684 uno::Reference
<uno::XComponentContext
> xContext(comphelper::getProcessComponentContext());
2685 uno::Reference
<io::XInputStream
> xStream(new utl::OSeekableInputStreamWrapper(rStream
));
2687 //SetLoading hack because the document properties will be re-initted
2688 //by the xml filter and during the init, while it's considered uninitialized,
2689 //setting a property will inform the document it's modified, which attempts
2690 //to update the properties, which throws cause the properties are uninitialized
2691 xDocSh
->SetLoading(SfxLoadedFlags::NONE
);
2693 ErrCode nRet
= ERRCODE_SFX_DOLOADFAILED
;
2697 nRet
= SmXMLImportWrapper::ReadThroughComponent(xStream
, xModel
, xContext
, xInfoSet
, "com.sun.star.comp.Math.XMLImporter", false);
2703 xDocSh
->SetLoading(SfxLoadedFlags::ALL
);
2707 return nRet
!= ERRCODE_NONE
;
2710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */