xref: /core/xmloff/source/text/txtparae.cxx (revision f87fab63)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <o3tl/any.hxx>
23 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
24 #include <tools/debug.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <sal/types.h>
27 #include <sal/log.hxx>
28 #include <osl/diagnose.h>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/container/XEnumerationAccess.hpp>
31 #include <com/sun/star/container/XEnumeration.hpp>
32 #include <com/sun/star/container/XIndexReplace.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertyState.hpp>
36 #include <com/sun/star/graphic/XGraphic.hpp>
37 #include <com/sun/star/graphic/GraphicProvider.hpp>
38 #include <com/sun/star/text/XTextDocument.hpp>
39 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
40 #include <com/sun/star/text/XTextTablesSupplier.hpp>
41 #include <com/sun/star/text/XNumberingRulesSupplier.hpp>
42 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
43 #include <com/sun/star/text/XTextTable.hpp>
44 #include <com/sun/star/text/XText.hpp>
45 #include <com/sun/star/text/XTextContent.hpp>
46 #include <com/sun/star/text/XTextRange.hpp>
47 #include <com/sun/star/text/XTextField.hpp>
48 #include <com/sun/star/text/XFootnote.hpp>
49 #include <com/sun/star/container/XNamed.hpp>
50 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
51 #include <com/sun/star/text/XTextFrame.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/text/SizeType.hpp>
54 #include <com/sun/star/text/HoriOrientation.hpp>
55 #include <com/sun/star/text/VertOrientation.hpp>
56 #include <com/sun/star/text/TextContentAnchorType.hpp>
57 #include <com/sun/star/text/XTextFramesSupplier.hpp>
58 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
59 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
60 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
61 #include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
62 #include <com/sun/star/document/XEventsSupplier.hpp>
63 #include <com/sun/star/document/XRedlinesSupplier.hpp>
64 #include <com/sun/star/text/XBookmarksSupplier.hpp>
65 #include <com/sun/star/text/XFormField.hpp>
66 #include <com/sun/star/text/XTextSection.hpp>
67 #include <com/sun/star/text/SectionFileLink.hpp>
68 #include <com/sun/star/drawing/XShape.hpp>
69 #include <com/sun/star/text/XTextShapesSupplier.hpp>
70 #include <com/sun/star/style/XAutoStylesSupplier.hpp>
71 #include <com/sun/star/style/XAutoStyleFamily.hpp>
72 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
73 #include <com/sun/star/text/XFootnotesSupplier.hpp>
74 #include <com/sun/star/text/XEndnotesSupplier.hpp>
75 #include <com/sun/star/drawing/XControlShape.hpp>
76 #include <com/sun/star/util/DateTime.hpp>
77 
78 #include <sax/tools/converter.hxx>
79 
80 #include <xmloff/xmlnmspe.hxx>
81 #include <xmloff/xmlaustp.hxx>
82 #include <xmloff/families.hxx>
83 #include "txtexppr.hxx"
84 #include <xmloff/xmlnumfe.hxx>
85 #include <xmloff/xmlnume.hxx>
86 #include <xmloff/xmluconv.hxx>
87 #include "XMLAnchorTypePropHdl.hxx"
88 #include <xexptran.hxx>
89 #include <xmloff/ProgressBarHelper.hxx>
90 #include <xmloff/nmspmap.hxx>
91 #include <xmloff/xmlexp.hxx>
92 #include <txtflde.hxx>
93 #include <xmloff/txtprmap.hxx>
94 #include <XMLImageMapExport.hxx>
95 #include "XMLTextNumRuleInfo.hxx"
96 #include <xmloff/XMLTextListAutoStylePool.hxx>
97 #include <xmloff/txtparae.hxx>
98 #include "XMLSectionExport.hxx"
99 #include "XMLIndexMarkExport.hxx"
100 #include <xmloff/XMLEventExport.hxx>
101 #include "XMLRedlineExport.hxx"
102 #include <MultiPropertySetHelper.hxx>
103 #include <xmloff/formlayerexport.hxx>
104 #include "XMLTextCharStyleNamesElementExport.hxx"
105 #include <xmloff/odffields.hxx>
106 #include <xmloff/maptype.hxx>
107 #include <basegfx/polygon/b2dpolypolygon.hxx>
108 #include <basegfx/polygon/b2dpolypolygontools.hxx>
109 #include <basegfx/polygon/b2dpolygontools.hxx>
110 #include <com/sun/star/embed/ElementModes.hpp>
111 #include <com/sun/star/embed/XTransactedObject.hpp>
112 #include <com/sun/star/document/XStorageBasedDocument.hpp>
113 #include <txtlists.hxx>
114 #include <com/sun/star/rdf/XMetadatable.hpp>
115 #include <list>
116 #include <unordered_map>
117 #include <memory>
118 #include <vector>
119 #include <algorithm>
120 #include <iterator>
121 #include <officecfg/Office/Common.hxx>
122 
123 using namespace ::std;
124 using namespace ::com::sun::star;
125 using namespace ::com::sun::star::uno;
126 using namespace ::com::sun::star::lang;
127 using namespace ::com::sun::star::beans;
128 using namespace ::com::sun::star::container;
129 using namespace ::com::sun::star::text;
130 using namespace ::com::sun::star::style;
131 using namespace ::com::sun::star::util;
132 using namespace ::com::sun::star::drawing;
133 using namespace ::com::sun::star::document;
134 using namespace ::com::sun::star::graphic;
135 using namespace ::xmloff;
136 using namespace ::xmloff::token;
137 
138 // Implement Title/Description Elements UI (#i73249#)
139 static const OUStringLiteral gsTitle("Title");
140 static const OUStringLiteral gsDescription("Description");
141 const OUStringLiteral XMLTextParagraphExport::gsAnchorCharStyleName("AnchorCharStyleName");
142 static const OUStringLiteral gsAnchorPageNo("AnchorPageNo");
143 static const OUStringLiteral gsAnchorType("AnchorType");
144 const OUStringLiteral XMLTextParagraphExport::gsBeginNotice("BeginNotice");
145 static const OUStringLiteral gsBookmark("Bookmark");
146 const OUStringLiteral XMLTextParagraphExport::gsCategory("Category");
147 static const OUStringLiteral gsChainNextName("ChainNextName");
148 const OUStringLiteral XMLTextParagraphExport::gsCharStyleName("CharStyleName");
149 const OUStringLiteral XMLTextParagraphExport::gsCharStyleNames("CharStyleNames");
150 static const OUStringLiteral gsContourPolyPolygon("ContourPolyPolygon");
151 static const OUStringLiteral gsDocumentIndexMark("DocumentIndexMark");
152 const OUStringLiteral XMLTextParagraphExport::gsEndNotice("EndNotice");
153 const OUStringLiteral XMLTextParagraphExport::gsFootnote("Footnote");
154 const OUStringLiteral XMLTextParagraphExport::gsFootnoteCounting("FootnoteCounting");
155 static const OUStringLiteral gsFrame("Frame");
156 static const OUStringLiteral gsGraphicFilter("GraphicFilter");
157 static const OUStringLiteral gsGraphicRotation("GraphicRotation");
158 static const OUStringLiteral gsHeight("Height");
159 static const OUStringLiteral gsHoriOrient("HoriOrient");
160 static const OUStringLiteral gsHoriOrientPosition("HoriOrientPosition");
161 static const OUStringLiteral gsHyperLinkName("HyperLinkName");
162 static const OUStringLiteral gsHyperLinkTarget("HyperLinkTarget");
163 static const OUStringLiteral gsHyperLinkURL("HyperLinkURL");
164 static const OUStringLiteral gsIsAutomaticContour("IsAutomaticContour");
165 static const OUStringLiteral gsIsCollapsed("IsCollapsed");
166 static const OUStringLiteral gsIsPixelContour("IsPixelContour");
167 static const OUStringLiteral gsIsStart("IsStart");
168 static const OUStringLiteral gsIsSyncHeightToWidth("IsSyncHeightToWidth");
169 static const OUStringLiteral gsIsSyncWidthToHeight("IsSyncWidthToHeight");
170 static const OUStringLiteral gsNumberingRules("NumberingRules");
171 const OUStringLiteral XMLTextParagraphExport::gsNumberingType("NumberingType");
172 const OUStringLiteral XMLTextParagraphExport::gsPageDescName("PageDescName");
173 const OUStringLiteral XMLTextParagraphExport::gsPageStyleName("PageStyleName");
174 static const OUStringLiteral gsParaConditionalStyleName("ParaConditionalStyleName");
175 static const OUStringLiteral gsParagraphService("com.sun.star.text.Paragraph");
176 const OUStringLiteral XMLTextParagraphExport::gsParaStyleName("ParaStyleName");
177 const OUStringLiteral XMLTextParagraphExport::gsPositionEndOfDoc("PositionEndOfDoc");
178 const OUStringLiteral XMLTextParagraphExport::gsPrefix("Prefix");
179 static const OUStringLiteral gsRedline("Redline");
180 const OUStringLiteral XMLTextParagraphExport::gsReferenceId("ReferenceId");
181 static const OUStringLiteral gsReferenceMark("ReferenceMark");
182 static const OUStringLiteral gsRelativeHeight("RelativeHeight");
183 static const OUStringLiteral gsRelativeWidth("RelativeWidth");
184 static const OUStringLiteral gsRuby("Ruby");
185 static const OUStringLiteral gsRubyCharStyleName("RubyCharStyleName");
186 static const OUStringLiteral gsRubyText("RubyText");
187 static const OUStringLiteral gsServerMap("ServerMap");
188 static const OUStringLiteral gsShapeService("com.sun.star.drawing.Shape");
189 static const OUStringLiteral gsSizeType("SizeType");
190 static const OUStringLiteral gsSoftPageBreak( "SoftPageBreak"  );
191 const OUStringLiteral XMLTextParagraphExport::gsStartAt("StartAt");
192 const OUStringLiteral XMLTextParagraphExport::gsSuffix("Suffix");
193 static const OUStringLiteral gsTableService("com.sun.star.text.TextTable");
194 static const OUStringLiteral gsText("Text");
195 static const OUStringLiteral gsTextContentService("com.sun.star.text.TextContent");
196 static const OUStringLiteral gsTextEmbeddedService("com.sun.star.text.TextEmbeddedObject");
197 const OUStringLiteral XMLTextParagraphExport::gsTextEndnoteService("com.sun.star.text.Endnote");
198 static const OUStringLiteral gsTextField("TextField");
199 static const OUStringLiteral gsTextFieldService("com.sun.star.text.TextField");
200 static const OUStringLiteral gsTextFrameService("com.sun.star.text.TextFrame");
201 static const OUStringLiteral gsTextGraphicService("com.sun.star.text.TextGraphicObject");
202 static const OUStringLiteral gsTextPortionType("TextPortionType");
203 const OUStringLiteral XMLTextParagraphExport::gsTextSection("TextSection");
204 static const OUStringLiteral gsUnvisitedCharStyleName("UnvisitedCharStyleName");
205 static const OUStringLiteral gsVertOrient("VertOrient");
206 static const OUStringLiteral gsVertOrientPosition("VertOrientPosition");
207 static const OUStringLiteral gsVisitedCharStyleName("VisitedCharStyleName");
208 static const OUStringLiteral gsWidth("Width");
209 static const OUStringLiteral gsWidthType( "WidthType"  );
210 static const OUStringLiteral gsTextFieldStart( "TextFieldStart"  );
211 static const OUStringLiteral gsTextFieldEnd( "TextFieldEnd"  );
212 static const OUStringLiteral gsTextFieldStartEnd( "TextFieldStartEnd"  );
213 
214 const OUStringLiteral XMLTextParagraphExport::gsFrameStyleName("FrameStyleName");
215 
216 namespace
217 {
218     class TextContentSet
219     {
220         public:
221             typedef list<Reference<XTextContent>> contents_t;
222             typedef back_insert_iterator<contents_t> inserter_t;
223             typedef contents_t::const_iterator const_iterator_t;
224 
225             inserter_t getInserter()
226                 { return back_insert_iterator<contents_t>(m_vTextContents); };
227             const_iterator_t getBegin() const
228                 { return m_vTextContents.begin(); };
229             const_iterator_t getEnd() const
230                 { return m_vTextContents.end(); };
231 
232         private:
233             contents_t m_vTextContents;
234     };
235 
236     struct FrameRefHash
237     {
238         size_t operator()(const Reference<XTextFrame>& rFrame) const
239             { return sal::static_int_cast<size_t>(reinterpret_cast<sal_uIntPtr>(rFrame.get())); }
240     };
241 
242     bool lcl_TextContentsUnfiltered(const Reference<XTextContent>&)
243         { return true; };
244 
245     bool lcl_ShapeFilter(const Reference<XTextContent>& xTxtContent)
246     {
247         Reference<XShape> xShape(xTxtContent, UNO_QUERY);
248         if(!xShape.is())
249             return false;
250         Reference<XServiceInfo> xServiceInfo(xTxtContent, UNO_QUERY);
251         return !xServiceInfo->supportsService("com.sun.star.text.TextFrame") &&
252                !xServiceInfo->supportsService("com.sun.star.text.TextGraphicObject") &&
253                !xServiceInfo->supportsService("com.sun.star.text.TextEmbeddedObject");
254     };
255 
256     class BoundFrames
257     {
258         public:
259             typedef bool (*filter_t)(const Reference<XTextContent>&);
260             BoundFrames(
261                 const Reference<XEnumerationAccess>& rEnumAccess,
262                 const filter_t& rFilter)
263                 : m_xEnumAccess(rEnumAccess)
264             {
265                 Fill(rFilter);
266             };
267             BoundFrames()
268                 {};
269             const TextContentSet& GetPageBoundContents() const
270                 { return m_vPageBounds; };
271             const TextContentSet* GetFrameBoundContents(const Reference<XTextFrame>& rParentFrame) const
272             {
273                 framebound_map_t::const_iterator it = m_vFrameBoundsOf.find(rParentFrame);
274                 if(it == m_vFrameBoundsOf.end())
275                     return nullptr;
276                 return &(it->second);
277             };
278             Reference<XEnumeration> createEnumeration() const
279             {
280                 if(!m_xEnumAccess.is())
281                     return Reference<XEnumeration>();
282                 return m_xEnumAccess->createEnumeration();
283             };
284 
285         private:
286             typedef std::unordered_map<
287                 Reference<XTextFrame>,
288                 TextContentSet,
289                 FrameRefHash> framebound_map_t;
290             TextContentSet m_vPageBounds;
291             framebound_map_t m_vFrameBoundsOf;
292             const Reference<XEnumerationAccess> m_xEnumAccess;
293             void Fill(const filter_t& rFilter);
294     };
295 
296     class FieldParamExporter
297     {
298         public:
299             FieldParamExporter(SvXMLExport* const pExport, Reference<XNameContainer> const & xFieldParams)
300                 : m_pExport(pExport)
301                 , m_xFieldParams(xFieldParams)
302                 { };
303             void Export();
304 
305         private:
306             SvXMLExport* const m_pExport;
307             const Reference<XNameContainer> m_xFieldParams;
308 
309             void ExportParameter(const OUString& sKey, const OUString& sValue);
310     };
311 }
312 
313 namespace xmloff
314 {
315     class BoundFrameSets
316     {
317         public:
318             explicit BoundFrameSets(const Reference<XInterface>& rModel);
319             const BoundFrames* GetTexts() const
320                 { return m_pTexts.get(); };
321             const BoundFrames* GetGraphics() const
322                 { return m_pGraphics.get(); };
323             const BoundFrames* GetEmbeddeds() const
324                 { return m_pEmbeddeds.get(); };
325             const BoundFrames* GetShapes() const
326                 { return m_pShapes.get(); };
327         private:
328             unique_ptr<BoundFrames> m_pTexts;
329             unique_ptr<BoundFrames> m_pGraphics;
330             unique_ptr<BoundFrames> m_pEmbeddeds;
331             unique_ptr<BoundFrames> m_pShapes;
332     };
333 }
334 
335 #ifdef DBG_UTIL
336 static bool txtparae_bContainsIllegalCharacters = false;
337 #endif
338 
339 // The following map shows which property values are required:
340 
341 // property                     auto style pass     export
342 
343 // ParaStyleName                if style exists     always
344 // ParaConditionalStyleName     if style exists     always
345 // NumberingRules               if style exists     always
346 // TextSection                  always              always
347 // ParaChapterNumberingLevel    never               always
348 // NumberingIsNumber            never               always
349 
350 // The conclusion is that for auto styles the first three properties
351 // should be queried using a multi property set if, and only if, an
352 // auto style needs to be exported. TextSection should be queried by
353 // an individual call to getPropertyvalue, because this seems to be
354 // less expensive than querying the first three properties if they aren't
355 // required.
356 
357 // For the export pass all properties can be queried using a multi property
358 // set.
359 
360 static const sal_Char* aParagraphPropertyNamesAuto[] =
361 {
362     "NumberingRules",
363     "ParaConditionalStyleName",
364     "ParaStyleName",
365     nullptr
366 };
367 
368 enum eParagraphPropertyNamesEnumAuto
369 {
370     NUMBERING_RULES_AUTO = 0,
371     PARA_CONDITIONAL_STYLE_NAME_AUTO = 1,
372     PARA_STYLE_NAME_AUTO = 2
373 };
374 
375 static const sal_Char* aParagraphPropertyNames[] =
376 {
377     "NumberingIsNumber",
378     "NumberingStyleName",
379     "OutlineLevel",
380     "ParaConditionalStyleName",
381     "ParaStyleName",
382     "TextSection",
383     nullptr
384 };
385 
386 enum eParagraphPropertyNamesEnum
387 {
388     NUMBERING_IS_NUMBER = 0,
389     PARA_NUMBERING_STYLENAME = 1,
390     PARA_OUTLINE_LEVEL=2,
391     PARA_CONDITIONAL_STYLE_NAME = 3,
392     PARA_STYLE_NAME = 4,
393     TEXT_SECTION = 5
394 };
395 
396 void BoundFrames::Fill(const filter_t& rFilter)
397 {
398     if(!m_xEnumAccess.is())
399         return;
400     const Reference< XEnumeration > xEnum = m_xEnumAccess->createEnumeration();
401     if(!xEnum.is())
402         return;
403     const OUString our_sAnchorType("AnchorType");
404     const OUString our_sAnchorFrame("AnchorFrame");
405     while(xEnum->hasMoreElements())
406     {
407         Reference<XPropertySet> xPropSet(xEnum->nextElement(), UNO_QUERY);
408         Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY);
409         if(!xPropSet.is() || !xTextContent.is())
410             continue;
411         TextContentAnchorType eAnchor;
412         xPropSet->getPropertyValue(our_sAnchorType) >>= eAnchor;
413         if(TextContentAnchorType_AT_PAGE != eAnchor && TextContentAnchorType_AT_FRAME != eAnchor)
414             continue;
415         if(!rFilter(xTextContent))
416             continue;
417 
418         TextContentSet::inserter_t pInserter = m_vPageBounds.getInserter();
419         if(TextContentAnchorType_AT_FRAME == eAnchor)
420         {
421             Reference<XTextFrame> xAnchorTxtFrame(
422                 xPropSet->getPropertyValue(our_sAnchorFrame),
423                 uno::UNO_QUERY);
424             pInserter = m_vFrameBoundsOf[xAnchorTxtFrame].getInserter();
425         }
426         *pInserter++ = xTextContent;
427     }
428 }
429 
430 BoundFrameSets::BoundFrameSets(const Reference<XInterface>& rModel)
431     : m_pTexts(new BoundFrames())
432     , m_pGraphics(new BoundFrames())
433     , m_pEmbeddeds(new BoundFrames())
434     , m_pShapes(new BoundFrames())
435 {
436     const Reference<XTextFramesSupplier> xTFS(rModel, UNO_QUERY);
437     const Reference<XTextGraphicObjectsSupplier> xGOS(rModel, UNO_QUERY);
438     const Reference<XTextEmbeddedObjectsSupplier> xEOS(rModel, UNO_QUERY);
439     const Reference<XDrawPageSupplier> xDPS(rModel, UNO_QUERY);
440     if(xTFS.is())
441         m_pTexts.reset(new BoundFrames(
442             Reference<XEnumerationAccess>(xTFS->getTextFrames(), UNO_QUERY),
443             &lcl_TextContentsUnfiltered));
444     if(xGOS.is())
445         m_pGraphics.reset(new BoundFrames(
446             Reference<XEnumerationAccess>(xGOS->getGraphicObjects(), UNO_QUERY),
447             &lcl_TextContentsUnfiltered));
448     if(xEOS.is())
449         m_pEmbeddeds.reset(new BoundFrames(
450             Reference<XEnumerationAccess>(xEOS->getEmbeddedObjects(), UNO_QUERY),
451             &lcl_TextContentsUnfiltered));
452     if(xDPS.is())
453         m_pShapes.reset(new BoundFrames(
454             Reference<XEnumerationAccess>(xDPS->getDrawPage(), UNO_QUERY),
455             &lcl_ShapeFilter));
456 };
457 
458 void FieldParamExporter::Export()
459 {
460     const Type aStringType = ::cppu::UnoType<OUString>::get();
461     const Type aBoolType = cppu::UnoType<sal_Bool>::get();
462     const Type aSeqType = cppu::UnoType<Sequence<OUString>>::get();
463     const Type aIntType = ::cppu::UnoType<sal_Int32>::get();
464     Sequence<OUString> vParameters(m_xFieldParams->getElementNames());
465     for(const auto & rParameter : vParameters)
466     {
467         const Any aValue = m_xFieldParams->getByName(rParameter);
468         const Type& aValueType = aValue.getValueType();
469         if(aValueType == aStringType)
470         {
471             OUString sValue;
472             aValue >>= sValue;
473             ExportParameter(rParameter,sValue);
474 
475             if ( rParameter == ODF_OLE_PARAM )
476             {
477                 // Save the OLE object
478                 Reference< embed::XStorage > xTargetStg = m_pExport->GetTargetStorage();
479                 Reference< embed::XStorage > xDstStg = xTargetStg->openStorageElement(
480                         "OLELinks", embed::ElementModes::WRITE );
481 
482                 if ( !xDstStg->hasByName( sValue ) ) {
483                     Reference< XStorageBasedDocument > xStgDoc (
484                             m_pExport->GetModel( ), UNO_QUERY );
485                     Reference< embed::XStorage > xDocStg = xStgDoc->getDocumentStorage();
486                     Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement(
487                             "OLELinks", embed::ElementModes::READ );
488 
489                     xOleStg->copyElementTo( sValue, xDstStg, sValue );
490                     Reference< embed::XTransactedObject > xTransact( xDstStg, UNO_QUERY );
491                     if ( xTransact.is( ) )
492                         xTransact->commit( );
493                 }
494             }
495         }
496         else if(aValueType == aBoolType)
497         {
498             bool bValue = false;
499             aValue >>= bValue;
500             ExportParameter(rParameter, OUString::boolean(bValue) );
501         }
502         else if(aValueType == aSeqType)
503         {
504             Sequence<OUString> vValue;
505             aValue >>= vValue;
506             for(const OUString & i : vValue)
507             {
508                 ExportParameter(rParameter, i);
509             }
510         }
511         else if(aValueType == aIntType)
512         {
513             sal_Int32 nValue = 0;
514             aValue >>= nValue;
515             ExportParameter(rParameter, OUString::number(nValue));
516         }
517     }
518 }
519 
520 void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& sValue)
521 {
522     m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_NAME, sKey);
523     m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_VALUE, sValue);
524     m_pExport->StartElement(XML_NAMESPACE_FIELD, XML_PARAM, false);
525     m_pExport->EndElement(XML_NAMESPACE_FIELD, XML_PARAM, false);
526 }
527 
528 void XMLTextParagraphExport::Add( sal_uInt16 nFamily,
529                                   const Reference < XPropertySet > & rPropSet,
530                                   const XMLPropertyState** ppAddStates, bool bDontSeek )
531 {
532     rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
533     switch( nFamily )
534     {
535     case XML_STYLE_FAMILY_TEXT_PARAGRAPH:
536         xPropMapper = GetParaPropMapper();
537         break;
538     case XML_STYLE_FAMILY_TEXT_TEXT:
539         xPropMapper = GetTextPropMapper();
540         break;
541     case XML_STYLE_FAMILY_TEXT_FRAME:
542         xPropMapper = GetAutoFramePropMapper();
543         break;
544     case XML_STYLE_FAMILY_TEXT_SECTION:
545         xPropMapper = GetSectionPropMapper();
546         break;
547     case XML_STYLE_FAMILY_TEXT_RUBY:
548         xPropMapper = GetRubyPropMapper();
549         break;
550     }
551     SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
552 
553     vector< XMLPropertyState > aPropStates =
554             xPropMapper->Filter( rPropSet );
555 
556     if( ppAddStates )
557     {
558         while( *ppAddStates )
559         {
560             aPropStates.push_back( **ppAddStates );
561             ppAddStates++;
562         }
563     }
564 
565     if( !aPropStates.empty() )
566     {
567         Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo());
568         OUString sParent, sCondParent;
569         sal_uInt16 nIgnoreProps = 0;
570         switch( nFamily )
571         {
572         case XML_STYLE_FAMILY_TEXT_PARAGRAPH:
573             if( xPropSetInfo->hasPropertyByName( gsParaStyleName ) )
574             {
575                 rPropSet->getPropertyValue( gsParaStyleName ) >>= sParent;
576             }
577             if( xPropSetInfo->hasPropertyByName( gsParaConditionalStyleName ) )
578             {
579                 rPropSet->getPropertyValue( gsParaConditionalStyleName ) >>= sCondParent;
580             }
581             if( xPropSetInfo->hasPropertyByName( gsNumberingRules ) )
582             {
583                 Reference < XIndexReplace > xNumRule(rPropSet->getPropertyValue( gsNumberingRules ), uno::UNO_QUERY);
584                 if( xNumRule.is() && xNumRule->getCount() )
585                 {
586                     Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
587                     OUString sName;
588                     if( xNamed.is() )
589                         sName = xNamed->getName();
590                     bool bAdd = sName.isEmpty();
591                     if( !bAdd )
592                     {
593                         Reference < XPropertySet > xNumPropSet( xNumRule,
594                                                                 UNO_QUERY );
595                         if( xNumPropSet.is() &&
596                             xNumPropSet->getPropertySetInfo()
597                                        ->hasPropertyByName( "IsAutomatic" ) )
598                         {
599                             bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" ));
600                             // Check on outline style (#i73361#)
601                             if ( bAdd &&
602                                  xNumPropSet->getPropertySetInfo()
603                                            ->hasPropertyByName( "NumberingIsOutline" ) )
604                             {
605                                 bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" )));
606                             }
607                         }
608                         else
609                         {
610                             bAdd = true;
611                         }
612                     }
613                     if( bAdd )
614                         maListAutoPool.Add( xNumRule );
615                 }
616             }
617             break;
618         case XML_STYLE_FAMILY_TEXT_TEXT:
619             {
620                 // Get parent and remove hyperlinks (they aren't of interest)
621                 rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
622                 for( ::std::vector< XMLPropertyState >::iterator i(aPropStates.begin());
623                       nIgnoreProps < 2 && i != aPropStates.end(); )
624                 {
625                     if( i->mnIndex == -1 )
626                     {
627                         ++i;
628                         continue;
629                     }
630 
631                     switch( xPM->GetEntryContextId(i->mnIndex) )
632                     {
633                     case CTF_CHAR_STYLE_NAME:
634                     case CTF_HYPERLINK_URL:
635                         i->mnIndex = -1;
636                         nIgnoreProps++;
637                         i = aPropStates.erase( i );
638                         break;
639                     default:
640                         ++i;
641                         break;
642                     }
643                 }
644             }
645             break;
646         case XML_STYLE_FAMILY_TEXT_FRAME:
647             if( xPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
648             {
649                 rPropSet->getPropertyValue( gsFrameStyleName ) >>= sParent;
650             }
651             break;
652         case XML_STYLE_FAMILY_TEXT_SECTION:
653         case XML_STYLE_FAMILY_TEXT_RUBY:
654             ; // section styles have no parents
655             break;
656         }
657         if (aPropStates.size() - nIgnoreProps)
658         {
659             GetAutoStylePool().Add( nFamily, sParent, aPropStates, bDontSeek );
660             if( !sCondParent.isEmpty() && sParent != sCondParent )
661                 GetAutoStylePool().Add( nFamily, sCondParent, aPropStates );
662         }
663     }
664 }
665 
666 static bool lcl_validPropState( const XMLPropertyState& rState )
667 {
668     return rState.mnIndex != -1;
669 }
670 
671 void XMLTextParagraphExport::Add( sal_uInt16 nFamily,
672                                   MultiPropertySetHelper& rPropSetHelper,
673                                   const Reference < XPropertySet > & rPropSet)
674 {
675     rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
676     switch( nFamily )
677     {
678     case XML_STYLE_FAMILY_TEXT_PARAGRAPH:
679         xPropMapper = GetParaPropMapper();
680         break;
681     }
682     SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
683 
684     vector< XMLPropertyState > aPropStates(xPropMapper->Filter( rPropSet ));
685 
686     if( rPropSetHelper.hasProperty( NUMBERING_RULES_AUTO ) )
687     {
688         Reference < XIndexReplace > xNumRule(rPropSetHelper.getValue( NUMBERING_RULES_AUTO,
689             rPropSet, true ), uno::UNO_QUERY);
690         if( xNumRule.is() && xNumRule->getCount() )
691         {
692             Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
693             OUString sName;
694             if( xNamed.is() )
695                 sName = xNamed->getName();
696             bool bAdd = sName.isEmpty();
697             if( !bAdd )
698             {
699                 Reference < XPropertySet > xNumPropSet( xNumRule,
700                                                         UNO_QUERY );
701                 if( xNumPropSet.is() &&
702                     xNumPropSet->getPropertySetInfo()
703                                ->hasPropertyByName( "IsAutomatic" ) )
704                 {
705                     bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" ));
706                     // Check on outline style (#i73361#)
707                     if ( bAdd &&
708                          xNumPropSet->getPropertySetInfo()
709                                    ->hasPropertyByName( "NumberingIsOutline" ) )
710                     {
711                         bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" )));
712                     }
713                 }
714                 else
715                 {
716                     bAdd = true;
717                 }
718             }
719             if( bAdd )
720                 maListAutoPool.Add( xNumRule );
721         }
722     }
723 
724     if( !aPropStates.empty() )
725     {
726         OUString sParent, sCondParent;
727         switch( nFamily )
728         {
729         case XML_STYLE_FAMILY_TEXT_PARAGRAPH:
730             if( rPropSetHelper.hasProperty( PARA_STYLE_NAME_AUTO ) )
731             {
732                 rPropSetHelper.getValue( PARA_STYLE_NAME_AUTO, rPropSet,
733                                                 true ) >>= sParent;
734             }
735             if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME_AUTO ) )
736             {
737                 rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME_AUTO,
738                                                  rPropSet, true ) >>= sCondParent;
739             }
740 
741             break;
742         }
743 
744         if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
745         {
746             GetAutoStylePool().Add( nFamily, sParent, aPropStates );
747             if( !sCondParent.isEmpty() && sParent != sCondParent )
748                 GetAutoStylePool().Add( nFamily, sCondParent, aPropStates );
749         }
750     }
751 }
752 
753 OUString XMLTextParagraphExport::Find(
754         sal_uInt16 nFamily,
755            const Reference < XPropertySet > & rPropSet,
756         const OUString& rParent,
757         const XMLPropertyState** ppAddStates) const
758 {
759     OUString sName( rParent );
760     rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
761     switch( nFamily )
762     {
763     case XML_STYLE_FAMILY_TEXT_PARAGRAPH:
764         xPropMapper = GetParaPropMapper();
765         break;
766     case XML_STYLE_FAMILY_TEXT_FRAME:
767         xPropMapper = GetAutoFramePropMapper();
768         break;
769     case XML_STYLE_FAMILY_TEXT_SECTION:
770         xPropMapper = GetSectionPropMapper();
771         break;
772     case XML_STYLE_FAMILY_TEXT_RUBY:
773         xPropMapper = GetRubyPropMapper();
774         break;
775     }
776     SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
777     if( !xPropMapper.is() )
778         return sName;
779     vector< XMLPropertyState > aPropStates(xPropMapper->Filter( rPropSet ));
780     if( ppAddStates )
781     {
782         while( *ppAddStates )
783         {
784             aPropStates.push_back( **ppAddStates );
785             ++ppAddStates;
786         }
787     }
788     if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
789         sName = GetAutoStylePool().Find( nFamily, sName, aPropStates );
790 
791     return sName;
792 }
793 
794 OUString XMLTextParagraphExport::FindTextStyleAndHyperlink(
795            const Reference < XPropertySet > & rPropSet,
796         bool& rbHyperlink,
797         bool& rbHasCharStyle,
798         bool& rbHasAutoStyle,
799         const XMLPropertyState** ppAddStates ) const
800 {
801     rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper());
802     vector< XMLPropertyState > aPropStates(xPropMapper->Filter( rPropSet ));
803 
804     // Get parent and remove hyperlinks (they aren't of interest)
805     OUString sName;
806     rbHyperlink = rbHasCharStyle = rbHasAutoStyle = false;
807     sal_uInt16 nIgnoreProps = 0;
808     rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
809     ::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end();
810     ::std::vector< XMLPropertyState >::iterator aSecondDel = aPropStates.end();
811 
812     for( ::std::vector< XMLPropertyState >::iterator
813             i = aPropStates.begin();
814          nIgnoreProps < 2 && i != aPropStates.end();
815          ++i )
816     {
817         if( i->mnIndex == -1 )
818             continue;
819 
820         switch( xPM->GetEntryContextId(i->mnIndex) )
821         {
822         case CTF_CHAR_STYLE_NAME:
823             i->maValue >>= sName;
824             i->mnIndex = -1;
825             rbHasCharStyle = !sName.isEmpty();
826             if( nIgnoreProps )
827                 aSecondDel = i;
828             else
829                 aFirstDel = i;
830             nIgnoreProps++;
831             break;
832         case CTF_HYPERLINK_URL:
833             rbHyperlink = true;
834             i->mnIndex = -1;
835             if( nIgnoreProps )
836                 aSecondDel = i;
837             else
838                 aFirstDel = i;
839             nIgnoreProps++;
840             break;
841         }
842     }
843     if( ppAddStates )
844     {
845         while( *ppAddStates )
846         {
847             aPropStates.push_back( **ppAddStates );
848             ppAddStates++;
849         }
850     }
851     if (aPropStates.size() - nIgnoreProps)
852     {
853         // erase the character style, otherwise the autostyle cannot be found!
854         // erase the hyperlink, otherwise the autostyle cannot be found!
855         if ( nIgnoreProps )
856         {
857             // If two elements of a vector have to be deleted,
858             // we should delete the second one first.
859             if( --nIgnoreProps )
860                 aPropStates.erase( aSecondDel );
861             aPropStates.erase( aFirstDel );
862         }
863         sName = GetAutoStylePool().Find(
864             XML_STYLE_FAMILY_TEXT_TEXT,
865             OUString(), // AutoStyles should not have parents!
866             aPropStates );
867         rbHasAutoStyle = true;
868     }
869 
870     return sName;
871 }
872 
873 // adjustments to support lists independent from list style
874 void XMLTextParagraphExport::exportListChange(
875         const XMLTextNumRuleInfo& rPrevInfo,
876         const XMLTextNumRuleInfo& rNextInfo )
877 {
878     // end a list
879     if ( rPrevInfo.GetLevel() > 0 )
880     {
881         sal_Int16 nListLevelsToBeClosed = 0;
882         if ( !rNextInfo.BelongsToSameList( rPrevInfo ) ||
883              rNextInfo.GetLevel() <= 0 )
884         {
885             // close complete previous list
886             nListLevelsToBeClosed = rPrevInfo.GetLevel();
887         }
888         else if ( rPrevInfo.GetLevel() > rNextInfo.GetLevel() )
889         {
890             // close corresponding sub lists
891             SAL_WARN_IF( rNextInfo.GetLevel() <= 0, "xmloff",
892                         "<rPrevInfo.GetLevel() > 0> not hold. Serious defect." );
893             nListLevelsToBeClosed = rPrevInfo.GetLevel() - rNextInfo.GetLevel();
894         }
895 
896         if ( nListLevelsToBeClosed > 0 &&
897              pListElements &&
898              pListElements->size() >= sal::static_int_cast< sal_uInt32 >( 2 * nListLevelsToBeClosed ) )
899         {
900             do {
901                 for(size_t j = 0; j < 2; ++j)
902                 {
903                     OUString aElem(pListElements->back());
904                     pListElements->pop_back();
905                     GetExport().EndElement(aElem, true);
906                 }
907 
908                 // remove closed list from list stack
909                 mpTextListsHelper->PopListFromStack();
910 
911                 --nListLevelsToBeClosed;
912             } while ( nListLevelsToBeClosed > 0 );
913         }
914     }
915 
916     const bool bExportODF =
917                 bool( GetExport().getExportFlags() & SvXMLExportFlags::OASIS );
918     const SvtSaveOptions::ODFDefaultVersion eODFDefaultVersion =
919                                     GetExport().getDefaultVersion();
920 
921     // start a new list
922     if ( rNextInfo.GetLevel() > 0 )
923     {
924         bool bRootListToBeStarted = false;
925         sal_Int16 nListLevelsToBeOpened = 0;
926         if ( !rPrevInfo.BelongsToSameList( rNextInfo ) ||
927              rPrevInfo.GetLevel() <= 0 )
928         {
929             // new root list
930             bRootListToBeStarted = true;
931             nListLevelsToBeOpened = rNextInfo.GetLevel();
932         }
933         else if ( rNextInfo.GetLevel() > rPrevInfo.GetLevel() )
934         {
935             // open corresponding sub lists
936             SAL_WARN_IF( rPrevInfo.GetLevel() <= 0, "xmloff",
937                         "<rPrevInfo.GetLevel() > 0> not hold. Serious defect." );
938             nListLevelsToBeOpened = rNextInfo.GetLevel() - rPrevInfo.GetLevel();
939         }
940 
941         if ( nListLevelsToBeOpened > 0 )
942         {
943             const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
944             // Currently only the text documents support <ListId>.
945             // Thus, for other document types <sListId> is empty.
946             const OUString& sListId( rNextInfo.GetListId() );
947             bool bExportListStyle( true );
948             bool bRestartNumberingAtContinuedList( false );
949             sal_Int32 nRestartValueForContinuedList( -1 );
950             bool bContinueingPreviousSubList = !bRootListToBeStarted &&
951                                                rNextInfo.IsContinueingPreviousSubTree();
952             do {
953                 GetExport().CheckAttrList();
954 
955                 if ( bRootListToBeStarted )
956                 {
957                     if ( !mpTextListsHelper->IsListProcessed( sListId ) )
958                     {
959                         if ( bExportODF &&
960                              eODFDefaultVersion >= SvtSaveOptions::ODFVER_012 &&
961                              !sListId.isEmpty() )
962                         {
963                             /* Property text:id at element <text:list> has to be
964                                replaced by property xml:id (#i92221#)
965                             */
966                             GetExport().AddAttribute( XML_NAMESPACE_XML,
967                                                       XML_ID,
968                                                       sListId );
969                         }
970                         mpTextListsHelper->KeepListAsProcessed( sListId,
971                                                                 sListStyleName,
972                                                                 OUString() );
973                     }
974                     else
975                     {
976                         const OUString sNewListId(
977                                         mpTextListsHelper->GenerateNewListId() );
978                         if ( bExportODF &&
979                              eODFDefaultVersion >= SvtSaveOptions::ODFVER_012 &&
980                              !sListId.isEmpty() )
981                         {
982                             /* Property text:id at element <text:list> has to be
983                                replaced by property xml:id (#i92221#)
984                             */
985                             GetExport().AddAttribute( XML_NAMESPACE_XML,
986                                                       XML_ID,
987                                                       sNewListId );
988                         }
989 
990                         const OUString sContinueListId =
991                             mpTextListsHelper->GetLastContinuingListId( sListId );
992                         // store that list with list id <sNewListId> is last list,
993                         // which has continued list with list id <sListId>
994                         mpTextListsHelper->StoreLastContinuingList( sListId,
995                                                                     sNewListId );
996                         if ( sListStyleName ==
997                                 mpTextListsHelper->GetListStyleOfLastProcessedList() &&
998                              // Inconsistent behavior regarding lists (#i92811#)
999                              sContinueListId ==
1000                                 mpTextListsHelper->GetLastProcessedListId() &&
1001                              !rNextInfo.IsRestart() )
1002                         {
1003                             GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1004                                                       XML_CONTINUE_NUMBERING,
1005                                                       XML_TRUE );
1006                         }
1007                         else
1008                         {
1009                             if ( bExportODF &&
1010                                  eODFDefaultVersion >= SvtSaveOptions::ODFVER_012 &&
1011                                  !sListId.isEmpty() )
1012                             {
1013                                 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1014                                                           XML_CONTINUE_LIST,
1015                                                           sContinueListId );
1016                             }
1017 
1018                             if ( rNextInfo.IsRestart() &&
1019                                  ( nListLevelsToBeOpened != 1 ||
1020                                    !rNextInfo.HasStartValue() ) )
1021                             {
1022                                 bRestartNumberingAtContinuedList = true;
1023                                 nRestartValueForContinuedList =
1024                                             rNextInfo.GetListLevelStartValue();
1025                             }
1026                         }
1027 
1028                         mpTextListsHelper->KeepListAsProcessed( sNewListId,
1029                                                                 sListStyleName,
1030                                                                 sContinueListId );
1031                     }
1032 
1033                     GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
1034                             GetExport().EncodeStyleName( sListStyleName ) );
1035                     bExportListStyle = false;
1036 
1037                     bRootListToBeStarted = false;
1038                 }
1039                 else if ( bExportListStyle &&
1040                           !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
1041                 {
1042                     GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
1043                             GetExport().EncodeStyleName( sListStyleName ) );
1044                     bExportListStyle = false;
1045 
1046                 }
1047                 else
1048                 {
1049                     // rhbz#746174: also export list restart for non root list
1050                     if (rNextInfo.IsRestart() && !rNextInfo.HasStartValue())
1051                     {
1052                         bRestartNumberingAtContinuedList = true;
1053                         nRestartValueForContinuedList =
1054                                         rNextInfo.GetListLevelStartValue();
1055                     }
1056                 }
1057 
1058                 if ( bContinueingPreviousSubList )
1059                 {
1060                     GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1061                                               XML_CONTINUE_NUMBERING, XML_TRUE );
1062                     bContinueingPreviousSubList = false;
1063                 }
1064 
1065                 enum XMLTokenEnum eLName = XML_LIST;
1066 
1067                 OUString aElem(GetExport().GetNamespaceMap().GetQNameByKey(
1068                                             XML_NAMESPACE_TEXT,
1069                                             GetXMLToken(eLName) ) );
1070                 GetExport().IgnorableWhitespace();
1071                 GetExport().StartElement(aElem, false);
1072 
1073                 if(!pListElements)
1074                     pListElements.reset( new std::vector<OUString> );
1075                 pListElements->push_back(aElem);
1076 
1077                 mpTextListsHelper->PushListOnStack( sListId,
1078                                                     sListStyleName );
1079 
1080                 // <text:list-header> or <text:list-item>
1081                 GetExport().CheckAttrList();
1082 
1083                 /* Export start value at correct list item (#i97309#) */
1084                 if ( nListLevelsToBeOpened == 1 )
1085                 {
1086                     if ( rNextInfo.HasStartValue() )
1087                     {
1088                         OUStringBuffer aBuffer;
1089                         aBuffer.append( static_cast<sal_Int32>(rNextInfo.GetStartValue()) );
1090                         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE,
1091                                       aBuffer.makeStringAndClear() );
1092                     }
1093                     else if (bRestartNumberingAtContinuedList)
1094                     {
1095                         OUStringBuffer aBuffer;
1096                         aBuffer.append( nRestartValueForContinuedList );
1097                         GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1098                                                   XML_START_VALUE,
1099                                                   aBuffer.makeStringAndClear() );
1100                         bRestartNumberingAtContinuedList = false;
1101                     }
1102                 }
1103 
1104                 eLName = ( rNextInfo.IsNumbered() || nListLevelsToBeOpened > 1 )
1105                          ? XML_LIST_ITEM
1106                          : XML_LIST_HEADER;
1107                 aElem = GetExport().GetNamespaceMap().GetQNameByKey(
1108                                             XML_NAMESPACE_TEXT,
1109                                             GetXMLToken(eLName) );
1110                 GetExport().IgnorableWhitespace();
1111                 GetExport().StartElement(aElem, false);
1112                 pListElements->push_back(aElem);
1113 
1114                 // export of <text:number> element for last opened <text:list-item>, if requested
1115                 if ( GetExport().exportTextNumberElement() &&
1116                      eLName == XML_LIST_ITEM && nListLevelsToBeOpened == 1 && // last iteration --> last opened <text:list-item>
1117                      !rNextInfo.ListLabelString().isEmpty() )
1118                 {
1119                     const OUString aTextNumberElem =
1120                             GetExport().GetNamespaceMap().GetQNameByKey(
1121                                       XML_NAMESPACE_TEXT,
1122                                       GetXMLToken(XML_NUMBER) );
1123                     GetExport().IgnorableWhitespace();
1124                     GetExport().StartElement( aTextNumberElem, false );
1125                     GetExport().Characters( rNextInfo.ListLabelString() );
1126                     GetExport().EndElement( aTextNumberElem, true );
1127                 }
1128                 --nListLevelsToBeOpened;
1129             } while ( nListLevelsToBeOpened > 0 );
1130         }
1131     }
1132 
1133     bool bEndElement = false;
1134 
1135     if ( rNextInfo.GetLevel() > 0 &&
1136          rNextInfo.IsNumbered() &&
1137          rPrevInfo.BelongsToSameList( rNextInfo ) &&
1138          rPrevInfo.GetLevel() >= rNextInfo.GetLevel() )
1139     {
1140         assert(pListElements && pListElements->size() >= 2 && "list elements missing");
1141         bEndElement = pListElements && pListElements->size() >= 2;
1142     }
1143 
1144     if (!bEndElement)
1145         return;
1146 
1147     // close previous list-item
1148     GetExport().EndElement(pListElements->back(), true );
1149     pListElements->pop_back();
1150 
1151     // Only for sub lists (#i103745#)
1152     if ( rNextInfo.IsRestart() && !rNextInfo.HasStartValue() &&
1153          rNextInfo.GetLevel() != 1 )
1154     {
1155         // start new sub list respectively list on same list level
1156         GetExport().EndElement(pListElements->back(), true );
1157         GetExport().IgnorableWhitespace();
1158         GetExport().StartElement(pListElements->back(), false);
1159     }
1160 
1161     // open new list-item
1162     GetExport().CheckAttrList();
1163     if( rNextInfo.HasStartValue() )
1164     {
1165         OUStringBuffer aBuffer;
1166         aBuffer.append( static_cast<sal_Int32>(rNextInfo.GetStartValue()) );
1167         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE,
1168                                   aBuffer.makeStringAndClear() );
1169     }
1170     // Handle restart without start value on list level 1 (#i103745#)
1171     else if ( rNextInfo.IsRestart() && /*!rNextInfo.HasStartValue() &&*/
1172               rNextInfo.GetLevel() == 1 )
1173     {
1174         OUStringBuffer aBuffer;
1175         aBuffer.append( static_cast<sal_Int32>(rNextInfo.GetListLevelStartValue()) );
1176         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE,
1177                                   aBuffer.makeStringAndClear() );
1178     }
1179     if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1180          GetExport().getDefaultVersion() >= SvtSaveOptions::ODFVER_012 )
1181     {
1182         const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
1183         if ( !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
1184         {
1185             GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1186                                       XML_STYLE_OVERRIDE,
1187                                       GetExport().EncodeStyleName( sListStyleName ) );
1188         }
1189     }
1190     OUString aElem( GetExport().GetNamespaceMap().GetQNameByKey(
1191                             XML_NAMESPACE_TEXT,
1192                             GetXMLToken(XML_LIST_ITEM) ) );
1193     GetExport().IgnorableWhitespace();
1194     GetExport().StartElement(aElem, false );
1195     pListElements->push_back(aElem);
1196 
1197     // export of <text:number> element for <text:list-item>, if requested
1198     if ( GetExport().exportTextNumberElement() &&
1199          !rNextInfo.ListLabelString().isEmpty() )
1200     {
1201         const OUString aTextNumberElem =
1202                 GetExport().GetNamespaceMap().GetQNameByKey(
1203                           XML_NAMESPACE_TEXT,
1204                           GetXMLToken(XML_NUMBER) );
1205         GetExport().IgnorableWhitespace();
1206         GetExport().StartElement( aTextNumberElem, false );
1207         GetExport().Characters( rNextInfo.ListLabelString() );
1208         GetExport().EndElement( aTextNumberElem, true );
1209     }
1210 
1211 }
1212 
1213 struct XMLTextParagraphExport::Impl
1214 {
1215     typedef ::std::map<Reference<XFormField>, sal_Int32> FieldMarkMap_t;
1216     FieldMarkMap_t m_FieldMarkMap;
1217 
1218     explicit Impl() {}
1219     sal_Int32 AddFieldMarkStart(Reference<XFormField> const& i_xFieldMark)
1220     {
1221         assert(m_FieldMarkMap.find(i_xFieldMark) == m_FieldMarkMap.end());
1222         sal_Int32 const ret(m_FieldMarkMap.size());
1223         m_FieldMarkMap.insert(::std::make_pair(i_xFieldMark, ret));
1224         return ret;
1225     }
1226     sal_Int32 GetFieldMarkIndex(Reference<XFormField> const& i_xFieldMark)
1227     {
1228         FieldMarkMap_t::const_iterator const it(
1229                 m_FieldMarkMap.find(i_xFieldMark));
1230         // rely on SwXFieldmark::CreateXFieldmark returning the same instance
1231         // because the Reference in m_FieldMarkMap will keep it alive
1232         assert(it != m_FieldMarkMap.end());
1233         return it->second;
1234     }
1235 };
1236 
1237 XMLTextParagraphExport::XMLTextParagraphExport(
1238         SvXMLExport& rExp,
1239         SvXMLAutoStylePoolP & rASP
1240         ) :
1241     XMLStyleExport( rExp, &rASP ),
1242     m_xImpl(new Impl),
1243     rAutoStylePool( rASP ),
1244     pBoundFrameSets(new BoundFrameSets(GetExport().GetModel())),
1245     maListAutoPool( GetExport() ),
1246     bProgress( false ),
1247     bBlock( false ),
1248     bOpenRuby( false ),
1249     mpTextListsHelper( nullptr ),
1250     maTextListsHelperStack(),
1251     mbCollected(false),
1252     aCharStyleNamesPropInfoCache( gsCharStyleNames )
1253 {
1254     rtl::Reference < XMLPropertySetMapper > xPropMapper(new XMLTextPropertySetMapper( TextPropMap::PARA, true ));
1255     xParaPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1256                                                              GetExport() );
1257 
1258     OUString sFamily( GetXMLToken(XML_PARAGRAPH) );
1259     OUString aPrefix(u'P');
1260     rAutoStylePool.AddFamily( XML_STYLE_FAMILY_TEXT_PARAGRAPH, sFamily,
1261                               xParaPropMapper, aPrefix );
1262 
1263     xPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
1264     xTextPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1265                                                              GetExport() );
1266     sFamily = GetXMLToken(XML_TEXT);
1267     aPrefix = "T";
1268     rAutoStylePool.AddFamily( XML_STYLE_FAMILY_TEXT_TEXT, sFamily,
1269                               xTextPropMapper, aPrefix );
1270 
1271     xPropMapper = new XMLTextPropertySetMapper( TextPropMap::AUTO_FRAME, true );
1272     xAutoFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1273                                                                   GetExport() );
1274     sFamily = XML_STYLE_FAMILY_SD_GRAPHICS_NAME;
1275     aPrefix = "fr";
1276     rAutoStylePool.AddFamily( XML_STYLE_FAMILY_TEXT_FRAME, sFamily,
1277                               xAutoFramePropMapper, aPrefix );
1278 
1279     xPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, true );
1280     xSectionPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1281                                                              GetExport() );
1282     sFamily = GetXMLToken( XML_SECTION );
1283     aPrefix = "Sect" ;
1284     rAutoStylePool.AddFamily( XML_STYLE_FAMILY_TEXT_SECTION, sFamily,
1285                               xSectionPropMapper, aPrefix );
1286 
1287     xPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, true );
1288     xRubyPropMapper = new SvXMLExportPropertyMapper( xPropMapper );
1289     sFamily = GetXMLToken( XML_RUBY );
1290     aPrefix = "Ru";
1291     rAutoStylePool.AddFamily( XML_STYLE_FAMILY_TEXT_RUBY, sFamily,
1292                               xRubyPropMapper, aPrefix );
1293 
1294     xPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, true );
1295     xFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1296                                                               GetExport() );
1297 
1298     pSectionExport.reset( new XMLSectionExport( rExp, *this ) );
1299     pIndexMarkExport.reset( new XMLIndexMarkExport( rExp ) );
1300 
1301     if( ! IsBlockMode() &&
1302         Reference<XRedlinesSupplier>( GetExport().GetModel(), UNO_QUERY ).is())
1303         pRedlineExport.reset( new XMLRedlineExport( rExp ) );
1304 
1305     // The text field helper needs a pre-constructed XMLPropertyState
1306     // to export the combined characters field. We construct that
1307     // here, because we need the text property mapper to do it.
1308 
1309     // construct Any value, then find index
1310     sal_Int32 nIndex = xTextPropMapper->getPropertySetMapper()->FindEntryIndex(
1311                                 "", XML_NAMESPACE_STYLE,
1312                                 GetXMLToken(XML_TEXT_COMBINE));
1313     pFieldExport.reset( new XMLTextFieldExport( rExp, std::make_unique<XMLPropertyState>( nIndex, uno::makeAny(true) ) ) );
1314     PushNewTextListsHelper();
1315 }
1316 
1317 XMLTextParagraphExport::~XMLTextParagraphExport()
1318 {
1319     pRedlineExport.reset();
1320     pIndexMarkExport.reset();
1321     pSectionExport.reset();
1322     pFieldExport.reset();
1323     pListElements.reset();
1324 #ifdef DBG_UTIL
1325     txtparae_bContainsIllegalCharacters = false;
1326 #endif
1327     PopTextListsHelper();
1328     SAL_WARN_IF( !maTextListsHelperStack.empty(), "xmloff",
1329                 "misusage of text lists helper stack - it is not empty. Serious defect" );
1330 }
1331 
1332 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateShapeExtPropMapper(
1333         SvXMLExport& rExport )
1334 {
1335     rtl::Reference < XMLPropertySetMapper > xPropMapper =
1336         new XMLTextPropertySetMapper( TextPropMap::SHAPE, true );
1337     return new XMLTextExportPropertySetMapper( xPropMapper, rExport );
1338 }
1339 
1340 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateCharExtPropMapper(
1341         SvXMLExport& rExport)
1342 {
1343     XMLPropertySetMapper *pPropMapper =
1344         new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
1345     return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1346 }
1347 
1348 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaExtPropMapper(
1349         SvXMLExport& rExport)
1350 {
1351     XMLPropertySetMapper *pPropMapper =
1352         new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, true );
1353     return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1354 }
1355 
1356 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaDefaultExtPropMapper(
1357         SvXMLExport& rExport)
1358 {
1359     XMLPropertySetMapper *pPropMapper =
1360         new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, true );
1361     return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1362 }
1363 
1364 void XMLTextParagraphExport::exportPageFrames( bool bIsProgress )
1365 {
1366     const TextContentSet& rTexts = pBoundFrameSets->GetTexts()->GetPageBoundContents();
1367     const TextContentSet& rGraphics = pBoundFrameSets->GetGraphics()->GetPageBoundContents();
1368     const TextContentSet& rEmbeddeds = pBoundFrameSets->GetEmbeddeds()->GetPageBoundContents();
1369     const TextContentSet& rShapes = pBoundFrameSets->GetShapes()->GetPageBoundContents();
1370     for(TextContentSet::const_iterator_t it = rTexts.getBegin();
1371         it != rTexts.getEnd();
1372         ++it)
1373         exportTextFrame(*it, false/*bAutoStyles*/, bIsProgress, true);
1374     for(TextContentSet::const_iterator_t it = rGraphics.getBegin();
1375         it != rGraphics.getEnd();
1376         ++it)
1377         exportTextGraphic(*it, false/*bAutoStyles*/);
1378     for(TextContentSet::const_iterator_t it = rEmbeddeds.getBegin();
1379         it != rEmbeddeds.getEnd();
1380         ++it)
1381         exportTextEmbedded(*it, false/*bAutoStyles*/);
1382     for(TextContentSet::const_iterator_t it = rShapes.getBegin();
1383         it != rShapes.getEnd();
1384         ++it)
1385         exportShape(*it, false/*bAutoStyles*/);
1386 }
1387 
1388 void XMLTextParagraphExport::exportFrameFrames(
1389         bool bAutoStyles,
1390         bool bIsProgress,
1391         const Reference < XTextFrame > *pParentTxtFrame )
1392 {
1393     const TextContentSet* const pTexts = pBoundFrameSets->GetTexts()->GetFrameBoundContents(*pParentTxtFrame);
1394     if(pTexts)
1395         for(TextContentSet::const_iterator_t it = pTexts->getBegin();
1396             it != pTexts->getEnd();
1397             ++it)
1398             exportTextFrame(*it, bAutoStyles, bIsProgress, true);
1399     const TextContentSet* const pGraphics = pBoundFrameSets->GetGraphics()->GetFrameBoundContents(*pParentTxtFrame);
1400     if(pGraphics)
1401         for(TextContentSet::const_iterator_t it = pGraphics->getBegin();
1402             it != pGraphics->getEnd();
1403             ++it)
1404             exportTextGraphic(*it, bAutoStyles);
1405     const TextContentSet* const pEmbeddeds = pBoundFrameSets->GetEmbeddeds()->GetFrameBoundContents(*pParentTxtFrame);
1406     if(pEmbeddeds)
1407         for(TextContentSet::const_iterator_t it = pEmbeddeds->getBegin();
1408             it != pEmbeddeds->getEnd();
1409             ++it)
1410             exportTextEmbedded(*it, bAutoStyles);
1411     const TextContentSet* const pShapes = pBoundFrameSets->GetShapes()->GetFrameBoundContents(*pParentTxtFrame);
1412     if(pShapes)
1413         for(TextContentSet::const_iterator_t it = pShapes->getBegin();
1414             it != pShapes->getEnd();
1415             ++it)
1416             exportShape(*it, bAutoStyles);
1417 }
1418 
1419 // bookmarks, reference marks (and TOC marks) are the same except for the
1420 // element names. We use the same method for export and it an array with
1421 // the proper element names
1422 static const enum XMLTokenEnum lcl_XmlReferenceElements[] = {
1423     XML_REFERENCE_MARK, XML_REFERENCE_MARK_START, XML_REFERENCE_MARK_END };
1424 static const enum XMLTokenEnum lcl_XmlBookmarkElements[] = {
1425     XML_BOOKMARK, XML_BOOKMARK_START, XML_BOOKMARK_END };
1426 
1427 // This function replaces the text portion iteration during auto style
1428 // collection.
1429 void XMLTextParagraphExport::collectTextAutoStylesOptimized( bool bIsProgress )
1430 {
1431     GetExport().GetShapeExport(); // make sure the graphics styles family is added
1432 
1433     if (mbCollected)
1434         return;
1435 
1436     const bool bAutoStyles = true;
1437     const bool bExportContent = false;
1438 
1439     // Export AutoStyles:
1440     Reference< XAutoStylesSupplier > xAutoStylesSupp( GetExport().GetModel(), UNO_QUERY );
1441     if ( xAutoStylesSupp.is() )
1442     {
1443         Reference< XAutoStyles > xAutoStyleFamilies = xAutoStylesSupp->getAutoStyles();
1444         OUString sName;
1445         sal_uInt16 nFamily;
1446 
1447         for ( int i = 0; i < 3; ++i )
1448         {
1449             if ( 0 == i )
1450             {
1451                 sName = "CharacterStyles" ;
1452                 nFamily = XML_STYLE_FAMILY_TEXT_TEXT;
1453             }
1454             else if ( 1 == i )
1455             {
1456                 sName = "RubyStyles" ;
1457                 nFamily = XML_STYLE_FAMILY_TEXT_RUBY;
1458             }
1459             else
1460             {
1461                 sName = "ParagraphStyles" ;
1462                 nFamily = XML_STYLE_FAMILY_TEXT_PARAGRAPH;
1463             }
1464 
1465             Any aAny = xAutoStyleFamilies->getByName( sName );
1466             Reference< XAutoStyleFamily > xAutoStyles = *o3tl::doAccess<Reference<XAutoStyleFamily>>(aAny);
1467             Reference < XEnumeration > xAutoStylesEnum( xAutoStyles->createEnumeration() );
1468 
1469             while ( xAutoStylesEnum->hasMoreElements() )
1470             {
1471                 aAny = xAutoStylesEnum->nextElement();
1472                 Reference< XAutoStyle > xAutoStyle = *o3tl::doAccess<Reference<XAutoStyle>>(aAny);
1473                 Reference < XPropertySet > xPSet( xAutoStyle, uno::UNO_QUERY );
1474                 Add( nFamily, xPSet, nullptr, true );
1475             }
1476         }
1477     }
1478 
1479     // Export Field AutoStyles:
1480     Reference< XTextFieldsSupplier > xTextFieldsSupp( GetExport().GetModel(), UNO_QUERY );
1481     if ( xTextFieldsSupp.is() )
1482     {
1483         Reference< XEnumerationAccess > xTextFields = xTextFieldsSupp->getTextFields();
1484         Reference < XEnumeration > xTextFieldsEnum( xTextFields->createEnumeration() );
1485 
1486         while ( xTextFieldsEnum->hasMoreElements() )
1487         {
1488             Any aAny = xTextFieldsEnum->nextElement();
1489             Reference< XTextField > xTextField = *o3tl::doAccess<Reference<XTextField>>(aAny);
1490             exportTextField( xTextField, bAutoStyles, bIsProgress,
1491                 !xAutoStylesSupp.is(), nullptr );
1492             try
1493             {
1494                 Reference < XPropertySet > xSet( xTextField, UNO_QUERY );
1495                 Reference < XText > xText;
1496                 Any a = xSet->getPropertyValue("TextRange");
1497                 a >>= xText;
1498                 if ( xText.is() )
1499                 {
1500                     exportText( xText, true, bIsProgress, bExportContent );
1501                     GetExport().GetTextParagraphExport()
1502                         ->collectTextAutoStyles( xText );
1503                 }
1504             }
1505             catch (Exception&)
1506             {
1507             }
1508         }
1509     }
1510 
1511     // Export text frames:
1512     Reference<XEnumeration> xTextFramesEnum = pBoundFrameSets->GetTexts()->createEnumeration();
1513     if(xTextFramesEnum.is())
1514         while(xTextFramesEnum->hasMoreElements())
1515         {
1516             Reference<XTextContent> xTxtCntnt(xTextFramesEnum->nextElement(), UNO_QUERY);
1517             if(xTxtCntnt.is())
1518                 exportTextFrame(xTxtCntnt, bAutoStyles, bIsProgress, bExportContent);
1519         }
1520 
1521     // Export graphic objects:
1522     Reference<XEnumeration> xGraphicsEnum = pBoundFrameSets->GetGraphics()->createEnumeration();
1523     if(xGraphicsEnum.is())
1524         while(xGraphicsEnum->hasMoreElements())
1525         {
1526             Reference<XTextContent> xTxtCntnt(xGraphicsEnum->nextElement(), UNO_QUERY);
1527             if(xTxtCntnt.is())
1528                 exportTextGraphic(xTxtCntnt, true);
1529         }
1530 
1531     // Export embedded objects:
1532     Reference<XEnumeration> xEmbeddedsEnum = pBoundFrameSets->GetEmbeddeds()->createEnumeration();
1533     if(xEmbeddedsEnum.is())
1534         while(xEmbeddedsEnum->hasMoreElements())
1535         {
1536             Reference<XTextContent> xTxtCntnt(xEmbeddedsEnum->nextElement(), UNO_QUERY);
1537             if(xTxtCntnt.is())
1538                 exportTextEmbedded(xTxtCntnt, true);
1539         }
1540 
1541     // Export shapes:
1542     Reference<XEnumeration> xShapesEnum = pBoundFrameSets->GetShapes()->createEnumeration();
1543     if(xShapesEnum.is())
1544         while(xShapesEnum->hasMoreElements())
1545         {
1546             Reference<XTextContent> xTxtCntnt(xShapesEnum->nextElement(), UNO_QUERY);
1547             if(xTxtCntnt.is())
1548             {
1549                 Reference<XServiceInfo> xServiceInfo(xTxtCntnt, UNO_QUERY);
1550                 if( xServiceInfo->supportsService(gsShapeService))
1551                     exportShape(xTxtCntnt, true);
1552             }
1553         }
1554 
1555     sal_Int32 nCount;
1556     // AutoStyles for sections
1557     Reference< XTextSectionsSupplier > xSectionsSupp( GetExport().GetModel(), UNO_QUERY );
1558     if ( xSectionsSupp.is() )
1559     {
1560         Reference< XIndexAccess > xSections( xSectionsSupp->getTextSections(), UNO_QUERY );
1561         if ( xSections.is() )
1562         {
1563             nCount = xSections->getCount();
1564             for( sal_Int32 i = 0; i < nCount; ++i )
1565             {
1566                 Any aAny = xSections->getByIndex( i );
1567                 Reference< XTextSection > xSection = *o3tl::doAccess<Reference<XTextSection>>(aAny);
1568                 Reference < XPropertySet > xPSet( xSection, uno::UNO_QUERY );
1569                 Add( XML_STYLE_FAMILY_TEXT_SECTION, xPSet );
1570             }
1571         }
1572     }
1573 
1574     // AutoStyles for tables (Note: suppress autostyle collection for paragraphs in exportTable)
1575     Reference< XTextTablesSupplier > xTablesSupp( GetExport().GetModel(), UNO_QUERY );
1576     if ( xTablesSupp.is() )
1577     {
1578         Reference< XIndexAccess > xTables( xTablesSupp->getTextTables(), UNO_QUERY );
1579         if ( xTables.is() )
1580         {
1581             nCount = xTables->getCount();
1582             for( sal_Int32 i = 0; i < nCount; ++i )
1583             {
1584                 Any aAny = xTables->getByIndex( i );
1585                 Reference< XTextTable > xTable = *o3tl::doAccess<Reference<XTextTable>>(aAny);
1586                 exportTable( xTable, true, true );
1587             }
1588         }
1589     }
1590 
1591     Reference< XNumberingRulesSupplier > xNumberingRulesSupp( GetExport().GetModel(), UNO_QUERY );
1592     if ( xNumberingRulesSupp.is() )
1593     {
1594         Reference< XIndexAccess > xNumberingRules = xNumberingRulesSupp->getNumberingRules();
1595         nCount = xNumberingRules->getCount();
1596         // Custom outline assignment lost after re-importing sxw (#i73361#)
1597         for( sal_Int32 i = 0; i < nCount; ++i )
1598         {
1599             Reference< XIndexReplace > xNumRule( xNumberingRules->getByIndex( i ), UNO_QUERY );
1600             if( xNumRule.is() && xNumRule->getCount() )
1601             {
1602                 Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
1603                 OUString sName;
1604                 if( xNamed.is() )
1605                     sName = xNamed->getName();
1606                 bool bAdd = sName.isEmpty();
1607                 if( !bAdd )
1608                 {
1609                     Reference < XPropertySet > xNumPropSet( xNumRule,
1610                                                             UNO_QUERY );
1611                     if( xNumPropSet.is() &&
1612                         xNumPropSet->getPropertySetInfo()
1613                                    ->hasPropertyByName( "IsAutomatic" ) )
1614                     {
1615                         bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "IsAutomatic" ));
1616                         // Check on outline style (#i73361#)
1617                         if ( bAdd &&
1618                              xNumPropSet->getPropertySetInfo()
1619                                        ->hasPropertyByName( "NumberingIsOutline" ) )
1620                         {
1621                             bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( "NumberingIsOutline" )));
1622                         }
1623                     }
1624                     else
1625                     {
1626                         bAdd = true;
1627                     }
1628                 }
1629                 if( bAdd )
1630                     maListAutoPool.Add( xNumRule );
1631             }
1632         }
1633     }
1634     mbCollected = true;
1635 }
1636 
1637 void XMLTextParagraphExport::exportText(
1638         const Reference < XText > & rText,
1639         bool bAutoStyles,
1640         bool bIsProgress,
1641         bool bExportParagraph,
1642         TextPNS eExtensionNS)
1643 {
1644     if( bAutoStyles )
1645         GetExport().GetShapeExport(); // make sure the graphics styles family
1646                                       // is added
1647     Reference < XEnumerationAccess > xEA( rText, UNO_QUERY );
1648     if( ! xEA.is() )
1649         return;
1650 
1651     Reference < XEnumeration > xParaEnum(xEA->createEnumeration());
1652     Reference < XPropertySet > xPropertySet( rText, UNO_QUERY );
1653     Reference < XTextSection > xBaseSection;
1654 
1655     // #97718# footnotes don't supply paragraph enumerations in some cases
1656     // This is always a bug, but at least we don't want to crash.
1657     SAL_WARN_IF( !xParaEnum.is(), "xmloff", "We need a paragraph enumeration" );
1658     if( ! xParaEnum.is() )
1659         return;
1660 
1661     if (xPropertySet.is())
1662     {
1663         Reference < XPropertySetInfo > xInfo ( xPropertySet->getPropertySetInfo() );
1664 
1665         if( xInfo.is() )
1666         {
1667             if (xInfo->hasPropertyByName( gsTextSection ))
1668             {
1669                 xPropertySet->getPropertyValue(gsTextSection) >>= xBaseSection ;
1670             }
1671         }
1672     }
1673 
1674     // #96530# Export redlines at start & end of XText before & after
1675     // exporting the text content enumeration
1676     if( !bAutoStyles && (pRedlineExport != nullptr) )
1677         pRedlineExport->ExportStartOrEndRedline( xPropertySet, true );
1678     exportTextContentEnumeration( xParaEnum, bAutoStyles, xBaseSection,
1679                                   bIsProgress, bExportParagraph, nullptr, eExtensionNS );
1680     if( !bAutoStyles && (pRedlineExport != nullptr) )
1681         pRedlineExport->ExportStartOrEndRedline( xPropertySet, false );
1682 }
1683 
1684 void XMLTextParagraphExport::exportText(
1685         const Reference < XText > & rText,
1686         const Reference < XTextSection > & rBaseSection,
1687         bool bAutoStyles,
1688         bool bIsProgress,
1689         bool bExportParagraph)
1690 {
1691     if( bAutoStyles )
1692         GetExport().GetShapeExport(); // make sure the graphics styles family
1693                                       // is added
1694     Reference < XEnumerationAccess > xEA( rText, UNO_QUERY );
1695     Reference < XEnumeration > xParaEnum(xEA->createEnumeration());
1696 
1697     // #98165# don't continue without a paragraph enumeration
1698     if( ! xParaEnum.is() )
1699         return;
1700 
1701     // #96530# Export redlines at start & end of XText before & after
1702     // exporting the text content enumeration
1703     Reference<XPropertySet> xPropertySet;
1704     if( !bAutoStyles && (pRedlineExport != nullptr) )
1705     {
1706         xPropertySet.set(rText, uno::UNO_QUERY );
1707         pRedlineExport->ExportStartOrEndRedline( xPropertySet, true );
1708     }
1709     exportTextContentEnumeration( xParaEnum, bAutoStyles, rBaseSection,
1710                                   bIsProgress, bExportParagraph );
1711     if( !bAutoStyles && (pRedlineExport != nullptr) )
1712         pRedlineExport->ExportStartOrEndRedline( xPropertySet, false );
1713 }
1714 
1715 void XMLTextParagraphExport::exportTextContentEnumeration(
1716         const Reference < XEnumeration > & rContEnum,
1717         bool bAutoStyles,
1718         const Reference < XTextSection > & rBaseSection,
1719         bool bIsProgress,
1720         bool bExportParagraph,
1721         const Reference < XPropertySet > *pRangePropSet,
1722         TextPNS eExtensionNS )
1723 {
1724     SAL_WARN_IF( !rContEnum.is(), "xmloff", "No enumeration to export!" );
1725     bool bHasMoreElements = rContEnum->hasMoreElements();
1726     if( !bHasMoreElements )
1727         return;
1728 
1729     XMLTextNumRuleInfo aPrevNumInfo;
1730     XMLTextNumRuleInfo aNextNumInfo;
1731 
1732     bool bHasContent = false;
1733     Reference<XTextSection> xCurrentTextSection(rBaseSection);
1734 
1735     MultiPropertySetHelper aPropSetHelper(
1736                                bAutoStyles ? aParagraphPropertyNamesAuto :
1737                                           aParagraphPropertyNames );
1738 
1739     bool bHoldElement = false;
1740     Reference < XTextContent > xTxtCntnt;
1741     while( bHoldElement || bHasMoreElements )
1742     {
1743         if (bHoldElement)
1744         {
1745             bHoldElement = false;
1746         }
1747         else
1748         {
1749             xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY);
1750 
1751             aPropSetHelper.resetValues();
1752 
1753         }
1754 
1755         Reference<XServiceInfo> xServiceInfo( xTxtCntnt, UNO_QUERY );
1756         if( xServiceInfo->supportsService( gsParagraphService ) )
1757         {
1758             if( bAutoStyles )
1759             {
1760                 exportListAndSectionChange( xCurrentTextSection, xTxtCntnt,
1761                                             aPrevNumInfo, aNextNumInfo,
1762                                             bAutoStyles );
1763             }
1764             else
1765             {
1766                 /* Pass list auto style pool to <XMLTextNumRuleInfo> instance
1767                    Pass info about request to export <text:number> element
1768                    to <XMLTextNumRuleInfo> instance (#i69627#)
1769                 */
1770                 aNextNumInfo.Set( xTxtCntnt,
1771                                   GetExport().writeOutlineStyleAsNormalListStyle(),
1772                                   GetListAutoStylePool(),
1773                                   GetExport().exportTextNumberElement() );
1774 
1775                 exportListAndSectionChange( xCurrentTextSection, aPropSetHelper,
1776                                             TEXT_SECTION, xTxtCntnt,
1777                                             aPrevNumInfo, aNextNumInfo,
1778                                             bAutoStyles );
1779             }
1780 
1781             // if we found a mute section: skip all section content
1782             if (pSectionExport->IsMuteSection(xCurrentTextSection))
1783             {
1784                 // Make sure headings are exported anyway.
1785                 if( !bAutoStyles )
1786                     pSectionExport->ExportMasterDocHeadingDummies();
1787 
1788                 while (rContEnum->hasMoreElements() &&
1789                        XMLSectionExport::IsInSection( xCurrentTextSection,
1790                                                     xTxtCntnt, true ))
1791                 {
1792                     xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY);
1793                     aPropSetHelper.resetValues();
1794                     aNextNumInfo.Reset();
1795                 }
1796                 // the first non-mute element still needs to be processed
1797                 bHoldElement =
1798                     ! XMLSectionExport::IsInSection( xCurrentTextSection,
1799                                                    xTxtCntnt, false );
1800             }
1801             else
1802                 exportParagraph( xTxtCntnt, bAutoStyles, bIsProgress,
1803                                  bExportParagraph, aPropSetHelper, eExtensionNS );
1804             bHasContent = true;
1805         }
1806         else if( xServiceInfo->supportsService( gsTableService ) )
1807         {
1808             if( !bAutoStyles )
1809             {
1810                 aNextNumInfo.Reset();
1811             }
1812 
1813             exportListAndSectionChange( xCurrentTextSection, xTxtCntnt,
1814                                         aPrevNumInfo, aNextNumInfo,
1815                                         bAutoStyles );
1816 
1817             if (! pSectionExport->IsMuteSection(xCurrentTextSection))
1818             {
1819                 // export start + end redlines (for wholly redlined tables)
1820                 if ((! bAutoStyles) && (nullptr != pRedlineExport))
1821                     pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, true);
1822 
1823                 exportTable( xTxtCntnt, bAutoStyles, bIsProgress  );
1824 
1825                 if ((! bAutoStyles) && (nullptr != pRedlineExport))
1826                     pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, false);
1827             }
1828             else if( !bAutoStyles )
1829             {
1830                 // Make sure headings are exported anyway.
1831                 pSectionExport->ExportMasterDocHeadingDummies();
1832             }
1833 
1834             bHasContent = true;
1835         }
1836         else if( xServiceInfo->supportsService( gsTextFrameService ) )
1837         {
1838             exportTextFrame( xTxtCntnt, bAutoStyles, bIsProgress, true, pRangePropSet );
1839         }
1840         else if( xServiceInfo->supportsService( gsTextGraphicService ) )
1841         {
1842             exportTextGraphic( xTxtCntnt, bAutoStyles, pRangePropSet );
1843         }
1844         else if( xServiceInfo->supportsService( gsTextEmbeddedService ) )
1845         {
1846             exportTextEmbedded( xTxtCntnt, bAutoStyles, pRangePropSet );
1847         }
1848         else if( xServiceInfo->supportsService( gsShapeService ) )
1849         {
1850             exportShape( xTxtCntnt, bAutoStyles, pRangePropSet );
1851         }
1852         else
1853         {
1854             SAL_WARN_IF( xTxtCntnt.is(), "xmloff", "unknown text content" );
1855         }
1856 
1857         if( !bAutoStyles )
1858         {
1859             aPrevNumInfo = aNextNumInfo;
1860         }
1861 
1862         bHasMoreElements = rContEnum->hasMoreElements();
1863     }
1864 
1865     if( bHasContent && !bAutoStyles )
1866     {
1867         aNextNumInfo.Reset();
1868 
1869         // close open lists and sections; no new styles
1870         exportListAndSectionChange( xCurrentTextSection, rBaseSection,
1871                                     aPrevNumInfo, aNextNumInfo,
1872                                     bAutoStyles );
1873     }
1874 }
1875 
1876 void XMLTextParagraphExport::exportParagraph(
1877         const Reference < XTextContent > & rTextContent,
1878         bool bAutoStyles, bool bIsProgress, bool bExportParagraph,
1879         MultiPropertySetHelper& rPropSetHelper, TextPNS eExtensionNS)
1880 {
1881     sal_Int16 nOutlineLevel = -1;
1882 
1883     if( bIsProgress )
1884     {
1885         ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper();
1886         pProgress->SetValue( pProgress->GetValue()+1 );
1887     }
1888 
1889     // get property set or multi property set and initialize helper
1890     Reference<XMultiPropertySet> xMultiPropSet( rTextContent, UNO_QUERY );
1891     Reference<XPropertySet> xPropSet( rTextContent, UNO_QUERY );
1892 
1893     // check for supported properties
1894     if( !rPropSetHelper.checkedProperties() )
1895         rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() );
1896 
1897 //  if( xMultiPropSet.is() )
1898 //      rPropSetHelper.getValues( xMultiPropSet );
1899 //  else
1900 //      rPropSetHelper.getValues( xPropSet );
1901 
1902     if( bExportParagraph )
1903     {
1904         if( bAutoStyles )
1905         {
1906             Add( XML_STYLE_FAMILY_TEXT_PARAGRAPH, rPropSetHelper, xPropSet );
1907         }
1908         else
1909         {
1910             // xml:id for RDF metadata
1911             GetExport().AddAttributeXmlId(rTextContent);
1912             GetExport().AddAttributesRDFa(rTextContent);
1913 
1914             OUString sStyle;
1915             if( rPropSetHelper.hasProperty( PARA_STYLE_NAME ) )
1916             {
1917                 if( xMultiPropSet.is() )
1918                     rPropSetHelper.getValue( PARA_STYLE_NAME,
1919                                                     xMultiPropSet ) >>= sStyle;
1920                 else
1921                     rPropSetHelper.getValue( PARA_STYLE_NAME,
1922                                                     xPropSet ) >>= sStyle;
1923             }
1924 
1925             if( rTextContent.is() )
1926             {
1927                 const OUString& rIdentifier = GetExport().getInterfaceToIdentifierMapper().getIdentifier( rTextContent );
1928                 if( !rIdentifier.isEmpty() )
1929                 {
1930                     // FIXME: this is just temporary until EditEngine
1931                     // paragraphs implement XMetadatable.
1932                     // then that must be used and not the mapper, because
1933                     // when both can be used we get two xml:id!
1934                     uno::Reference<rdf::XMetadatable> const xMeta(rTextContent,
1935                         uno::UNO_QUERY);
1936                     OSL_ENSURE(!xMeta.is(), "paragraph that implements "
1937                         "XMetadatable used in interfaceToIdentifierMapper?");
1938                     GetExport().AddAttributeIdLegacy(XML_NAMESPACE_TEXT,
1939                         rIdentifier);
1940                 }
1941             }
1942 
1943             OUString sAutoStyle = Find( XML_STYLE_FAMILY_TEXT_PARAGRAPH, xPropSet, sStyle );
1944             if ( sAutoStyle.isEmpty() )
1945                 sAutoStyle = sStyle;
1946             if( !sAutoStyle.isEmpty() )
1947                 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
1948                               GetExport().EncodeStyleName( sAutoStyle ) );
1949 
1950             if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME ) )
1951             {
1952                 OUString sCondStyle;
1953                 if( xMultiPropSet.is() )
1954                     rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME,
1955                                                      xMultiPropSet ) >>= sCondStyle;
1956                 else
1957                     rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME,
1958                                                      xPropSet ) >>= sCondStyle;
1959                 if( sCondStyle != sStyle )
1960                 {
1961                     sCondStyle = Find( XML_STYLE_FAMILY_TEXT_PARAGRAPH, xPropSet,
1962                                           sCondStyle );
1963                     if( !sCondStyle.isEmpty() )
1964                         GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1965                                                   XML_COND_STYLE_NAME,
1966                               GetExport().EncodeStyleName( sCondStyle ) );
1967                 }
1968             }
1969 
1970             if( rPropSetHelper.hasProperty( PARA_OUTLINE_LEVEL ) )
1971             {
1972                 if( xMultiPropSet.is() )
1973                     rPropSetHelper.getValue( PARA_OUTLINE_LEVEL,
1974                                                      xMultiPropSet ) >>= nOutlineLevel;
1975                 else
1976                     rPropSetHelper.getValue( PARA_OUTLINE_LEVEL,
1977                                                      xPropSet ) >>= nOutlineLevel;
1978 
1979                 if( 0 < nOutlineLevel )
1980                 {
1981                     OUStringBuffer sTmp;
1982                     sTmp.append( sal_Int32( nOutlineLevel) );
1983                     GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1984                                               XML_OUTLINE_LEVEL,
1985                                   sTmp.makeStringAndClear() );
1986 
1987                     if( rPropSetHelper.hasProperty( NUMBERING_IS_NUMBER ) )
1988                     {
1989                         bool bIsNumber = false;
1990                         if( xMultiPropSet.is() )
1991                             rPropSetHelper.getValue(
1992                                        NUMBERING_IS_NUMBER, xMultiPropSet ) >>= bIsNumber;
1993                         else
1994                             rPropSetHelper.getValue(
1995                                        NUMBERING_IS_NUMBER, xPropSet ) >>= bIsNumber;
1996 
1997                         OUString sListStyleName;
1998                         if( xMultiPropSet.is() )
1999                             rPropSetHelper.getValue(
2000                                        PARA_NUMBERING_STYLENAME, xMultiPropSet ) >>= sListStyleName;
2001                         else
2002                             rPropSetHelper.getValue(
2003                                        PARA_NUMBERING_STYLENAME, xPropSet ) >>= sListStyleName;
2004 
2005                         bool bAssignedtoOutlineStyle = false;
2006                         {
2007                             Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), UNO_QUERY );
2008 
2009                             OUString sOutlineName;
2010                             if (xCNSupplier.is())
2011                             {
2012                                 Reference< XIndexReplace > xNumRule ( xCNSupplier->getChapterNumberingRules() );
2013                                 SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" );
2014 
2015                                 if (xNumRule.is())
2016                                 {
2017                                     Reference< XPropertySet > xNumRulePropSet( xNumRule, UNO_QUERY );
2018                                     xNumRulePropSet->getPropertyValue(
2019                                         "Name" ) >>= sOutlineName;
2020                                     bAssignedtoOutlineStyle = ( sListStyleName == sOutlineName );
2021                                 }
2022                             }
2023                         }
2024 
2025                         if( ! bIsNumber && bAssignedtoOutlineStyle )
2026                             GetExport().AddAttribute( XML_NAMESPACE_TEXT,
2027                                                       XML_IS_LIST_HEADER,
2028                                                       XML_TRUE );
2029                     }
2030 
2031                     {
2032                         bool bIsRestartNumbering = false;
2033 
2034                         Reference< XPropertySetInfo >
2035                         xPropSetInfo(xMultiPropSet.is() ?
2036                                      xMultiPropSet->getPropertySetInfo():
2037                                      xPropSet->getPropertySetInfo());
2038 
2039                         if (xPropSetInfo->
2040                             hasPropertyByName("ParaIsNumberingRestart"))
2041                         {
2042                             xPropSet->getPropertyValue("ParaIsNumberingRestart")
2043                                 >>= bIsRestartNumbering;
2044                         }
2045 
2046                         if (bIsRestartNumbering)
2047                         {
2048                             GetExport().AddAttribute(XML_NAMESPACE_TEXT,
2049                                                      XML_RESTART_NUMBERING,
2050                                                      XML_TRUE);
2051 
2052                             if (xPropSetInfo->
2053                                 hasPropertyByName("NumberingStartValue"))
2054                             {
2055                                 sal_Int32 nStartValue = 0;
2056 
2057                                 xPropSet->getPropertyValue("NumberingStartValue")
2058                                     >>= nStartValue;
2059 
2060                                 OUStringBuffer sTmpStartValue;
2061 
2062                                 sTmpStartValue.append(nStartValue);
2063 
2064                                 GetExport().
2065                                     AddAttribute(XML_NAMESPACE_TEXT,
2066                                                  XML_START_VALUE,
2067                                                  sTmpStartValue.
2068                                                  makeStringAndClear());
2069                             }
2070                         }
2071                     }
2072                 }
2073             }
2074         }
2075     }
2076 
2077     Reference < XEnumerationAccess > xEA( rTextContent, UNO_QUERY );
2078     Reference < XEnumeration > xTextEnum = xEA->createEnumeration();
2079     const bool bHasPortions = xTextEnum.is();
2080 
2081     Reference < XEnumeration> xContentEnum;
2082     Reference < XContentEnumerationAccess > xCEA( rTextContent, UNO_QUERY );
2083     if( xCEA.is() )
2084         xContentEnum.set(xCEA->createContentEnumeration( gsTextContentService ));
2085     const bool bHasContentEnum = xContentEnum.is() &&
2086                                         xContentEnum->hasMoreElements();
2087 
2088     Reference < XTextSection > xSection;
2089     if( bHasContentEnum )
2090     {
2091         // For the auto styles, the multi property set helper is only used
2092         // if hard attributes are existing. Therefore, it seems to be a better
2093         // strategy to have the TextSection property separate, because otherwise
2094         // we always retrieve the style names even if they are not required.
2095         if( bAutoStyles )
2096         {
2097             if( xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextSection ) )
2098             {
2099                 xSection.set(xPropSet->getPropertyValue( gsTextSection ), uno::UNO_QUERY);
2100             }
2101         }
2102         else
2103         {
2104             if( rPropSetHelper.hasProperty( TEXT_SECTION ) )
2105             {
2106                 xSection.set(rPropSetHelper.getValue( TEXT_SECTION ), uno::UNO_QUERY);
2107             }
2108         }
2109     }
2110 
2111     bool bPrevCharIsSpace(true); // true because whitespace at start is ignored
2112 
2113     if( bAutoStyles )
2114     {
2115         if( bHasContentEnum )
2116             exportTextContentEnumeration(
2117                                     xContentEnum, bAutoStyles, xSection,
2118                                     bIsProgress );
2119         if ( bHasPortions )
2120         {
2121             exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace);
2122         }
2123     }
2124     else
2125     {
2126         enum XMLTokenEnum eElem =
2127             0 < nOutlineLevel ? XML_H : XML_P;
2128         SvXMLElementExport aElem( GetExport(), eExtensionNS == TextPNS::EXTENSION ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_TEXT, eElem,
2129                                   true, false );
2130         if( bHasContentEnum )
2131         {
2132             exportTextContentEnumeration(
2133                                     xContentEnum, bAutoStyles, xSection,
2134                                     bIsProgress );
2135         }
2136         exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace);
2137     }
2138 }
2139 
2140 void XMLTextParagraphExport::exportTextRangeEnumeration(
2141         const Reference < XEnumeration > & rTextEnum,
2142         bool bAutoStyles, bool bIsProgress,
2143         bool & rPrevCharIsSpace)
2144 {
2145     static const char sFieldMarkName[] = "__FieldMark_";
2146 
2147     /* This is  used for exporting to strict OpenDocument 1.2, in which case traditional
2148      * bookmarks are used instead of fieldmarks. */
2149     FieldmarkType openFieldMark = NONE;
2150 
2151     while( rTextEnum->hasMoreElements() )
2152     {
2153         Reference<XPropertySet> xPropSet(rTextEnum->nextElement(), UNO_QUERY);
2154         Reference < XTextRange > xTxtRange(xPropSet, uno::UNO_QUERY);
2155         Reference<XPropertySetInfo> xPropInfo(xPropSet->getPropertySetInfo());
2156 
2157         if (xPropInfo->hasPropertyByName(gsTextPortionType))
2158         {
2159             OUString sType;
2160             xPropSet->getPropertyValue(gsTextPortionType) >>= sType;
2161 
2162             if( sType == gsText)
2163             {
2164                 exportTextRange( xTxtRange, bAutoStyles,
2165                                  rPrevCharIsSpace, openFieldMark);
2166             }
2167             else if( sType == gsTextField)
2168             {
2169                 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2170             }
2171             else if ( sType == "Annotation" )
2172             {
2173                 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2174             }
2175             else if ( sType == "AnnotationEnd" )
2176             {
2177                 if (!bAutoStyles)
2178                 {
2179                     Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2180                     const OUString& rName = xBookmark->getName();
2181                     if (!rName.isEmpty())
2182                     {
2183                         GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, rName);
2184                     }
2185                     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE, XML_ANNOTATION_END, false, false );
2186                 }
2187             }
2188             else if( sType == gsFrame )
2189             {
2190                 Reference < XEnumeration> xContentEnum;
2191                 Reference < XContentEnumerationAccess > xCEA( xTxtRange,
2192                                                               UNO_QUERY );
2193                 if( xCEA.is() )
2194                     xContentEnum.set(xCEA->createContentEnumeration(
2195                                                     gsTextContentService ));
2196                 // frames are never in sections
2197                 Reference<XTextSection> xSection;
2198                 if( xContentEnum.is() )
2199                     exportTextContentEnumeration( xContentEnum,
2200                                                     bAutoStyles,
2201                                                     xSection, bIsProgress, true,
2202                                                      &xPropSet  );
2203 
2204             }
2205             else if (sType == gsFootnote)
2206             {
2207                 exportTextFootnote(xPropSet,
2208                                    xTxtRange->getString(),
2209                                    bAutoStyles, bIsProgress );
2210             }
2211             else if (sType == gsBookmark)
2212             {
2213                 exportTextMark(xPropSet,
2214                                gsBookmark,
2215                                lcl_XmlBookmarkElements,
2216                                bAutoStyles);
2217             }
2218             else if (sType == gsReferenceMark)
2219             {
2220                 exportTextMark(xPropSet,
2221                                gsReferenceMark,
2222                                lcl_XmlReferenceElements,
2223                                bAutoStyles);
2224             }
2225             else if (sType == gsDocumentIndexMark)
2226             {
2227                 pIndexMarkExport->ExportIndexMark(xPropSet, bAutoStyles);
2228             }
2229             else if (sType == gsRedline)
2230             {
2231                 if (nullptr != pRedlineExport)
2232                     pRedlineExport->ExportChange(xPropSet, bAutoStyles);
2233             }
2234             else if (sType == gsRuby)
2235             {
2236                 exportRuby(xPropSet, bAutoStyles);
2237             }
2238             else if (sType == "InContentMetadata")
2239             {
2240                 exportMeta(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace);
2241             }
2242             else if (sType == gsTextFieldStart)
2243             {
2244                 Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2245 
2246                 /* As of now, textmarks are a proposed extension to the OpenDocument standard. */
2247                 if (!bAutoStyles)
2248                 {
2249                     if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
2250                     {
2251                         Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2252                         if (xBookmark.is())
2253                         {
2254                             GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2255                         }
2256 
2257                         if (xFormField.is())
2258                         {
2259                             GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType());
2260                         }
2261 
2262                         GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false);
2263                         if (xFormField.is())
2264                         {
2265                             FieldParamExporter(&GetExport(), xFormField->getParameters()).Export();
2266                         }
2267                         GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false);
2268                     }
2269                     /* The OpenDocument standard does not include support for TextMarks for now, so use bookmarks instead. */
2270                     else
2271                     {
2272                         if (xFormField.is())
2273                         {
2274                             OUString sName;
2275                             Reference< css::container::XNameAccess > xParameters(xFormField->getParameters(), UNO_QUERY);
2276                             if (xParameters.is() && xParameters->hasByName("Name"))
2277                             {
2278                                 const Any aValue = xParameters->getByName("Name");
2279                                 aValue >>= sName;
2280                             }
2281                             if (sName.isEmpty())
2282                             {   // name attribute is mandatory, so have to pull a
2283                                 // rabbit out of the hat here
2284                                 sName = sFieldMarkName + OUString::number(
2285                                         m_xImpl->AddFieldMarkStart(xFormField));
2286                             }
2287                             GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2288                                     sName);
2289                             SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2290                                 XML_NAMESPACE_TEXT, XML_BOOKMARK_START,
2291                                 false, false );
2292                             const OUString sFieldType = xFormField->getFieldType();
2293                             if (sFieldType ==  ODF_FORMTEXT)
2294                             {
2295                                 openFieldMark = TEXT;
2296                             }
2297                             else if (sFieldType == ODF_FORMCHECKBOX)
2298                             {
2299                                 openFieldMark = CHECK;
2300                             }
2301                             else
2302                             {
2303                                 openFieldMark = NONE;
2304                             }
2305                         }
2306                     }
2307                 }
2308             }
2309             else if (sType == gsTextFieldEnd)
2310             {
2311                 if (!bAutoStyles)
2312                 {
2313                     Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2314 
2315                     if ( GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012 )
2316                     {
2317                         SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2318                             XML_NAMESPACE_FIELD, XML_FIELDMARK_END,
2319                             false, false );
2320                     }
2321                     else
2322                     {
2323                         if (xFormField.is())
2324                         {
2325                             OUString sName;
2326                             Reference< css::container::XNameAccess > xParameters(xFormField->getParameters(), UNO_QUERY);
2327                             if (xParameters.is() && xParameters->hasByName("Name"))
2328                             {
2329                                 const Any aValue = xParameters->getByName("Name");
2330                                 aValue >>= sName;
2331                             }
2332                             if (sName.isEmpty())
2333                             {   // name attribute is mandatory, so have to pull a
2334                                 // rabbit out of the hat here
2335                                 sName = sFieldMarkName + OUString::number(
2336                                     m_xImpl->GetFieldMarkIndex(xFormField));
2337                             }
2338                             GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2339                                     sName);
2340                             SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2341                                 XML_NAMESPACE_TEXT, XML_BOOKMARK_END,
2342                                 false, false );
2343                         }
2344                     }
2345                 }
2346             }
2347             else if (sType == gsTextFieldStartEnd)
2348             {
2349                 if (!bAutoStyles)
2350                 {
2351                     if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
2352                     {
2353                         Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2354                         if (xBookmark.is())
2355                         {
2356                             GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2357                         }
2358                         Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2359                         if (xFormField.is())
2360                         {
2361                             GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType());
2362                         }
2363                         GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false);
2364                         if (xFormField.is())
2365                         {
2366                             FieldParamExporter(&GetExport(), xFormField->getParameters()).Export();
2367                         }
2368                         GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false);
2369                     }
2370                     else
2371                     {
2372                         Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2373                         if (xBookmark.is())
2374                         {
2375                             GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2376                             SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2377                                 XML_NAMESPACE_TEXT, XML_BOOKMARK,
2378                                 false, false );
2379                         }
2380                     }
2381                 }
2382             }
2383             else if (sType == gsSoftPageBreak)
2384             {
2385                 exportSoftPageBreak();
2386             }
2387             else {
2388                 OSL_FAIL("unknown text portion type");
2389             }
2390         }
2391         else
2392         {
2393             Reference<XServiceInfo> xServiceInfo( xTxtRange, UNO_QUERY );
2394             if( xServiceInfo->supportsService( gsTextFieldService ) )
2395             {
2396                 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2397             }
2398             else
2399             {
2400                 // no TextPortionType property -> non-Writer app -> text
2401                 exportTextRange(xTxtRange, bAutoStyles, rPrevCharIsSpace, openFieldMark);
2402             }
2403         }
2404     }
2405 
2406 // now that there are nested enumerations for meta(-field), this may be valid!
2407 //  SAL_WARN_IF( bOpenRuby, "xmloff", "Red Alert: Ruby still open!" );
2408 }
2409 
2410 void XMLTextParagraphExport::exportTable(
2411         const Reference < XTextContent > &,
2412         bool /*bAutoStyles*/, bool /*bIsProgress*/ )
2413 {
2414 }
2415 
2416 void XMLTextParagraphExport::exportTextField(
2417         const Reference < XTextRange > & rTextRange,
2418         bool bAutoStyles, bool bIsProgress, bool *const pPrevCharIsSpace)
2419 {
2420     Reference < XPropertySet > xPropSet( rTextRange, UNO_QUERY );
2421     // non-Writer apps need not support Property TextField, so test first
2422     if (xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextField ))
2423     {
2424         Reference < XTextField > xTxtFld(xPropSet->getPropertyValue( gsTextField ), uno::UNO_QUERY);
2425         SAL_WARN_IF( !xTxtFld.is(), "xmloff", "text field missing" );
2426         if( xTxtFld.is() )
2427         {
2428             exportTextField(xTxtFld, bAutoStyles, bIsProgress, true, pPrevCharIsSpace);
2429         }
2430         else
2431         {
2432             // write only characters
2433             GetExport().Characters(rTextRange->getString());
2434         }
2435     }
2436 }
2437 
2438 void XMLTextParagraphExport::exportTextField(
2439         const Reference < XTextField > & xTextField,
2440         const bool bAutoStyles, const bool bIsProgress,
2441         const bool bRecursive, bool *const pPrevCharIsSpace)
2442 {
2443     if ( bAutoStyles )
2444     {
2445         pFieldExport->ExportFieldAutoStyle( xTextField, bIsProgress,
2446                 bRecursive );
2447     }
2448     else
2449     {
2450         assert(pPrevCharIsSpace);
2451         pFieldExport->ExportField(xTextField, bIsProgress, *pPrevCharIsSpace);
2452     }
2453 }
2454 
2455 void XMLTextParagraphExport::exportSoftPageBreak()
2456 {
2457     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
2458                               XML_SOFT_PAGE_BREAK, false,
2459                               false );
2460 }
2461 
2462 void XMLTextParagraphExport::exportTextMark(
2463     const Reference<XPropertySet> & rPropSet,
2464     const OUString& rProperty,
2465     const ::xmloff::token::XMLTokenEnum pElements[],
2466     bool bAutoStyles)
2467 {
2468     // mib said: "Hau wech!"
2469 
2470     // (Originally, I'd export a span element in case the (book|reference)mark
2471     //  was formatted. This actually makes a difference in case some pervert
2472     //  sets a point reference mark in the document and, say, formats it bold.
2473     //  This basically meaningless formatting will now been thrown away
2474     //  (aka cleaned up), since mib said: ...                   dvo
2475 
2476      if (!bAutoStyles)
2477     {
2478         // name element
2479         Reference<XNamed> xName(rPropSet->getPropertyValue(rProperty), UNO_QUERY);
2480         GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2481                                  xName->getName());
2482 
2483         // start, end, or point-reference?
2484         sal_Int8 nElement;
2485         if( *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed)) )
2486         {
2487             nElement = 0;
2488         }
2489         else
2490         {
2491             nElement = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart)) ? 1 : 2;
2492         }
2493 
2494         // bookmark, bookmark-start: xml:id and RDFa for RDF metadata
2495         if( nElement < 2 ) {
2496             GetExport().AddAttributeXmlId(xName);
2497             const uno::Reference<text::XTextContent> xTextContent(
2498                     xName, uno::UNO_QUERY_THROW);
2499             GetExport().AddAttributesRDFa(xTextContent);
2500         }
2501 
2502         // bookmark-start: add attributes hidden and condition
2503         if (nElement == 1)
2504         {
2505             Reference<XPropertySet> bkmkProps(rPropSet->getPropertyValue(rProperty), UNO_QUERY);
2506             Reference<XPropertySetInfo> bkmkPropInfo(bkmkProps->getPropertySetInfo(), UNO_QUERY);
2507             OUString sHidden("BookmarkHidden");
2508             if (bkmkPropInfo->hasPropertyByName(sHidden))
2509             {
2510                 bool bHidden = false;
2511                 bkmkProps->getPropertyValue(sHidden) >>= bHidden;
2512                 if (bHidden)
2513                 {
2514                     GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "hidden", "true");
2515                     OUString sCondition("BookmarkCondition");
2516                     if (bkmkPropInfo->hasPropertyByName(sCondition))
2517                     {
2518                         OUString sBookmarkCondition;
2519                         bkmkProps->getPropertyValue(sCondition) >>= sBookmarkCondition;
2520                         GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "condition", sBookmarkCondition);
2521                     }
2522                 }
2523             }
2524         }
2525 
2526         // export element
2527         assert(pElements != nullptr);
2528         assert(0 <= nElement && nElement <= 2);
2529         SvXMLElementExport aElem(GetExport(),
2530                                  XML_NAMESPACE_TEXT, pElements[nElement],
2531                                  false, false);
2532     }
2533     // else: no styles. (see above)
2534 }
2535 
2536 static bool lcl_txtpara_isBoundAsChar(
2537         const Reference < XPropertySet > & rPropSet,
2538         const Reference < XPropertySetInfo > & rPropSetInfo )
2539 {
2540     bool bIsBoundAsChar = false;
2541     OUString sAnchorType( "AnchorType"  );
2542     if( rPropSetInfo->hasPropertyByName( sAnchorType ) )
2543     {
2544         TextContentAnchorType eAnchor;
2545         rPropSet->getPropertyValue( sAnchorType ) >>= eAnchor;
2546         bIsBoundAsChar = TextContentAnchorType_AS_CHARACTER == eAnchor;
2547     }
2548 
2549     return bIsBoundAsChar;
2550 }
2551 
2552 XMLShapeExportFlags XMLTextParagraphExport::addTextFrameAttributes(
2553     const Reference < XPropertySet >& rPropSet,
2554     bool bShape,
2555     basegfx::B2DPoint* pCenter,
2556     OUString* pMinHeightValue,
2557     OUString* pMinWidthValue)
2558 {
2559     XMLShapeExportFlags nShapeFeatures = SEF_DEFAULT;
2560 
2561     // draw:name (#97662#: not for shapes, since those names will be
2562     // treated in the shape export)
2563     if( !bShape )
2564     {
2565         Reference < XNamed > xNamed( rPropSet, UNO_QUERY );
2566         if( xNamed.is() )
2567         {
2568             OUString sName( xNamed->getName() );
2569             if( !sName.isEmpty() )
2570                 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_NAME,
2571                                           xNamed->getName() );
2572         }
2573     }
2574 
2575     OUStringBuffer sValue;
2576 
2577     // text:anchor-type
2578     TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH;
2579     rPropSet->getPropertyValue( gsAnchorType ) >>= eAnchor;
2580     {
2581         XMLAnchorTypePropHdl aAnchorTypeHdl;
2582         OUString sTmp;
2583         aAnchorTypeHdl.exportXML( sTmp, uno::makeAny(eAnchor),
2584                                   GetExport().GetMM100UnitConverter() );
2585         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, sTmp );
2586     }
2587 
2588     // text:anchor-page-number
2589     if( TextContentAnchorType_AT_PAGE == eAnchor )
2590     {
2591         sal_Int16 nPage = 0;
2592         rPropSet->getPropertyValue( gsAnchorPageNo ) >>= nPage;
2593         SAL_WARN_IF(nPage <= 0, "xmloff",
2594                 "ERROR: writing invalid anchor-page-number 0");
2595         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_PAGE_NUMBER,
2596                                   OUString::number( nPage ) );
2597     }
2598     else
2599     {
2600         nShapeFeatures |= XMLShapeExportFlags::NO_WS;
2601     }
2602 
2603     // OD 2004-06-01 #i27691# - correction: no export of svg:x, if object
2604     // is anchored as-character.
2605     if ( !bShape &&
2606          eAnchor != TextContentAnchorType_AS_CHARACTER )
2607     {
2608         // svg:x
2609         sal_Int16 nHoriOrient =  HoriOrientation::NONE;
2610         rPropSet->getPropertyValue( gsHoriOrient ) >>= nHoriOrient;
2611         if( HoriOrientation::NONE == nHoriOrient )
2612         {
2613             sal_Int32 nPos = 0;
2614             rPropSet->getPropertyValue( gsHoriOrientPosition ) >>= nPos;
2615             GetExport().GetMM100UnitConverter().convertMeasureToXML(
2616                     sValue, nPos );
2617             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_X,
2618                                       sValue.makeStringAndClear() );
2619             if(nullptr != pCenter)
2620             {
2621                 // add left edge to Center
2622                 pCenter->setX(pCenter->getX() + nPos);
2623             }
2624         }
2625     }
2626     else if( TextContentAnchorType_AS_CHARACTER == eAnchor )
2627         nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::X);
2628 
2629     if( !bShape || TextContentAnchorType_AS_CHARACTER == eAnchor  )
2630     {
2631         // svg:y
2632         sal_Int16 nVertOrient =  VertOrientation::NONE;
2633         rPropSet->getPropertyValue( gsVertOrient ) >>= nVertOrient;
2634         if( VertOrientation::NONE == nVertOrient )
2635         {
2636             sal_Int32 nPos = 0;
2637             rPropSet->getPropertyValue( gsVertOrientPosition ) >>= nPos;
2638             GetExport().GetMM100UnitConverter().convertMeasureToXML(
2639                     sValue, nPos );
2640             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_Y,
2641                                       sValue.makeStringAndClear() );
2642             if(nullptr != pCenter)
2643             {
2644                 // add top edge to Center
2645                 pCenter->setY(pCenter->getY() + nPos);
2646             }
2647         }
2648         if( bShape )
2649             nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::Y);
2650     }
2651 
2652     Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo());
2653 
2654     // svg:width
2655     sal_Int16 nWidthType = SizeType::FIX;
2656     if( xPropSetInfo->hasPropertyByName( gsWidthType ) )
2657     {
2658         rPropSet->getPropertyValue( gsWidthType ) >>= nWidthType;
2659     }
2660     if( xPropSetInfo->hasPropertyByName( gsWidth ) )
2661     {
2662         sal_Int32 nWidth =  0;
2663         // VAR size will be written as zero min-size
2664         if( SizeType::VARIABLE != nWidthType )
2665         {
2666             rPropSet->getPropertyValue( gsWidth ) >>= nWidth;
2667         }
2668         GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, nWidth);
2669         if( SizeType::FIX != nWidthType )
2670         {
2671             assert(pMinWidthValue);
2672             if (pMinWidthValue)
2673             {
2674                 *pMinWidthValue = sValue.makeStringAndClear();
2675             }
2676         }
2677         else
2678         {
2679             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH,
2680                                       sValue.makeStringAndClear() );
2681             if(nullptr != pCenter)
2682             {
2683                 // add half width to Center
2684                 pCenter->setX(pCenter->getX() + (0.5 * nWidth));
2685             }
2686         }
2687     }
2688     bool bSyncWidth = false;
2689     if( xPropSetInfo->hasPropertyByName( gsIsSyncWidthToHeight ) )
2690     {
2691         bSyncWidth = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsIsSyncWidthToHeight ));
2692         if( bSyncWidth )
2693             GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH,
2694                                       XML_SCALE );
2695     }
2696     if( !bSyncWidth && xPropSetInfo->hasPropertyByName( gsRelativeWidth ) )
2697     {
2698         sal_Int16 nRelWidth =  0;
2699         rPropSet->getPropertyValue( gsRelativeWidth ) >>= nRelWidth;
2700         SAL_WARN_IF( nRelWidth < 0 || nRelWidth > 254, "xmloff",
2701                     "Got illegal relative width from API" );
2702         if( nRelWidth > 0 )
2703         {
2704             ::sax::Converter::convertPercent( sValue, nRelWidth );
2705             GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH,
2706                                       sValue.makeStringAndClear() );
2707         }
2708     }
2709 
2710     // svg:height, fo:min-height or style:rel-height
2711     sal_Int16 nSizeType = SizeType::FIX;
2712     if( xPropSetInfo->hasPropertyByName( gsSizeType ) )
2713     {
2714         rPropSet->getPropertyValue( gsSizeType ) >>= nSizeType;
2715     }
2716     bool bSyncHeight = false;
2717     if( xPropSetInfo->hasPropertyByName( gsIsSyncHeightToWidth ) )
2718     {
2719         bSyncHeight = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsIsSyncHeightToWidth ));
2720     }
2721     sal_Int16 nRelHeight =  0;
2722     if( !bSyncHeight && xPropSetInfo->hasPropertyByName( gsRelativeHeight ) )
2723     {
2724         rPropSet->getPropertyValue( gsRelativeHeight ) >>= nRelHeight;
2725     }
2726     if( xPropSetInfo->hasPropertyByName( gsHeight ) )
2727     {
2728         sal_Int32 nHeight =  0;
2729         if( SizeType::VARIABLE != nSizeType )
2730         {
2731             rPropSet->getPropertyValue( gsHeight ) >>= nHeight;
2732         }
2733         GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue,
2734                                                             nHeight );
2735         if( SizeType::FIX != nSizeType && 0==nRelHeight && !bSyncHeight &&
2736              pMinHeightValue )
2737         {
2738             *pMinHeightValue = sValue.makeStringAndClear();
2739         }
2740         else
2741         {
2742             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT,
2743                                       sValue.makeStringAndClear() );
2744             if(nullptr != pCenter)
2745             {
2746                 // add half height to Center
2747                 pCenter->setY(pCenter->getY() + (0.5 * nHeight));
2748             }
2749         }
2750     }
2751     if( bSyncHeight )
2752     {
2753         GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT,
2754                 SizeType::MIN == nSizeType ? XML_SCALE_MIN : XML_SCALE );
2755 
2756     }
2757     else if( nRelHeight > 0 )
2758     {
2759         ::sax::Converter::convertPercent( sValue, nRelHeight );
2760         if( SizeType::MIN == nSizeType )
2761         {
2762             assert(pMinHeightValue);
2763             if (pMinHeightValue)
2764             {
2765                 *pMinHeightValue = sValue.makeStringAndClear();
2766             }
2767         }
2768         else
2769             GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT,
2770                                       sValue.makeStringAndClear() );
2771     }
2772 
2773     OUString sZOrder( "ZOrder"  );
2774     if( xPropSetInfo->hasPropertyByName( sZOrder ) )
2775     {
2776         sal_Int32 nZIndex = 0;
2777         rPropSet->getPropertyValue( sZOrder ) >>= nZIndex;
2778         if( -1 != nZIndex )
2779         {
2780             GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_ZINDEX,
2781                                       OUString::number( nZIndex ) );
2782         }
2783     }
2784 
2785     return nShapeFeatures;
2786 }
2787 
2788 void XMLTextParagraphExport::exportAnyTextFrame(
2789         const Reference < XTextContent > & rTxtCntnt,
2790         FrameType eType,
2791         bool bAutoStyles,
2792         bool bIsProgress,
2793         bool bExportContent,
2794         const Reference < XPropertySet > *pRangePropSet)
2795 {
2796     Reference < XPropertySet > xPropSet( rTxtCntnt, UNO_QUERY );
2797 
2798     if( bAutoStyles )
2799     {
2800         if( FrameType::Embedded == eType )
2801             _collectTextEmbeddedAutoStyles( xPropSet );
2802         // No text frame style for shapes (#i28745#)
2803         else if ( FrameType::Shape != eType )
2804             Add( XML_STYLE_FAMILY_TEXT_FRAME, xPropSet );
2805 
2806         if( pRangePropSet && lcl_txtpara_isBoundAsChar( xPropSet,
2807                                             xPropSet->getPropertySetInfo() ) )
2808             Add( XML_STYLE_FAMILY_TEXT_TEXT, *pRangePropSet );
2809 
2810         switch( eType )
2811         {
2812         case FrameType::Text:
2813             {
2814                 // frame bound frames
2815                 if ( bExportContent )
2816                 {
2817                     Reference < XTextFrame > xTxtFrame( rTxtCntnt, UNO_QUERY );
2818                     Reference < XText > xTxt(xTxtFrame->getText());
2819                     exportFrameFrames( true, bIsProgress, &xTxtFrame );
2820                     exportText( xTxt, bAutoStyles, bIsProgress, true );
2821                 }
2822             }
2823             break;
2824         case FrameType::Shape:
2825             {
2826                 Reference < XShape > xShape( rTxtCntnt, UNO_QUERY );
2827                 GetExport().GetShapeExport()->collectShapeAutoStyles( xShape );
2828             }
2829             break;
2830         default:
2831             break;
2832         }
2833     }
2834     else
2835     {
2836         Reference< XPropertySetInfo > xPropSetInfo(xPropSet->getPropertySetInfo());
2837         Reference< XPropertyState > xPropState( xPropSet, UNO_QUERY );
2838         {
2839             bool bAddCharStyles = pRangePropSet &&
2840                 lcl_txtpara_isBoundAsChar( xPropSet, xPropSetInfo );
2841 
2842             bool bIsUICharStyle;
2843             bool bHasAutoStyle = false;
2844 
2845             OUString sStyle;
2846 
2847             if( bAddCharStyles )
2848             {
2849                 bool bDummy;
2850                 sStyle = FindTextStyleAndHyperlink( *pRangePropSet, bDummy, bIsUICharStyle, bHasAutoStyle );
2851             }
2852             else
2853                 bIsUICharStyle = false;
2854 
2855             bool bDoSomething = bIsUICharStyle
2856                 && aCharStyleNamesPropInfoCache.hasProperty( *pRangePropSet );
2857             XMLTextCharStyleNamesElementExport aCharStylesExport(
2858                 GetExport(), bDoSomething, bHasAutoStyle,
2859                 bDoSomething ? *pRangePropSet : Reference<XPropertySet>(),
2860                 gsCharStyleNames );
2861 
2862             if( !sStyle.isEmpty() )
2863                 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
2864                                   GetExport().EncodeStyleName( sStyle ) );
2865             {
2866                 SvXMLElementExport aElem( GetExport(), !sStyle.isEmpty(),
2867                     XML_NAMESPACE_TEXT, XML_SPAN, false, false );
2868                 {
2869                     SvXMLElementExport aElement( GetExport(),
2870                         FrameType::Shape != eType &&
2871                         addHyperlinkAttributes( xPropSet,
2872                                                 xPropState,xPropSetInfo ),
2873                         XML_NAMESPACE_DRAW, XML_A, false, false );
2874                     switch( eType )
2875                     {
2876                     case FrameType::Text:
2877                         _exportTextFrame( xPropSet, xPropSetInfo, bIsProgress );
2878                         break;
2879                     case FrameType::Graphic:
2880                         _exportTextGraphic( xPropSet, xPropSetInfo );
2881                         break;
2882                     case FrameType::Embedded:
2883                         _exportTextEmbedded( xPropSet, xPropSetInfo );
2884                         break;
2885                     case FrameType::Shape:
2886                         {
2887                             Reference < XShape > xShape( rTxtCntnt, UNO_QUERY );
2888                             XMLShapeExportFlags nFeatures =
2889                                 addTextFrameAttributes( xPropSet, true );
2890                             GetExport().GetShapeExport()
2891                                 ->exportShape( xShape, nFeatures );
2892                         }
2893                         break;
2894                     }
2895                 }
2896             }
2897         }
2898     }
2899 }
2900 
2901 void XMLTextParagraphExport::_exportTextFrame(
2902         const Reference < XPropertySet > & rPropSet,
2903         const Reference < XPropertySetInfo > & rPropSetInfo,
2904         bool bIsProgress )
2905 {
2906     Reference < XTextFrame > xTxtFrame( rPropSet, UNO_QUERY );
2907     Reference < XText > xTxt(xTxtFrame->getText());
2908 
2909     OUString sStyle;
2910     if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
2911     {
2912         rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle;
2913     }
2914 
2915     OUString aMinHeightValue;
2916     OUString sMinWidthValue;
2917     OUString sAutoStyle = Find( XML_STYLE_FAMILY_TEXT_FRAME, rPropSet, sStyle );
2918     if ( sAutoStyle.isEmpty() )
2919         sAutoStyle = sStyle;
2920     if( !sAutoStyle.isEmpty() )
2921         GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
2922                               GetExport().EncodeStyleName( sAutoStyle ) );
2923     addTextFrameAttributes(rPropSet, false, nullptr, &aMinHeightValue, &sMinWidthValue);
2924 
2925     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
2926                               XML_FRAME, false, true );
2927 
2928     if( !aMinHeightValue.isEmpty() )
2929         GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_HEIGHT,
2930                                   aMinHeightValue );
2931 
2932     if (!sMinWidthValue.isEmpty())
2933     {
2934         GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_WIDTH,
2935                                   sMinWidthValue );
2936     }
2937 
2938     // draw:chain-next-name
2939     if( rPropSetInfo->hasPropertyByName( gsChainNextName ) )
2940     {
2941         OUString sNext;
2942         if( (rPropSet->getPropertyValue( gsChainNextName ) >>= sNext) && !sNext.isEmpty() )
2943             GetExport().AddAttribute( XML_NAMESPACE_DRAW,
2944                                       XML_CHAIN_NEXT_NAME,
2945                                       sNext );
2946     }
2947 
2948     {
2949         SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_DRAW,
2950                                   XML_TEXT_BOX, true, true );
2951 
2952         // frames bound to frame
2953         exportFrameFrames( false, bIsProgress, &xTxtFrame );
2954 
2955         exportText( xTxt, false, bIsProgress, true );
2956     }
2957 
2958     // script:events
2959     Reference<XEventsSupplier> xEventsSupp( xTxtFrame, UNO_QUERY );
2960     GetExport().GetEventExport().Export(xEventsSupp);
2961 
2962     // image map
2963     GetExport().GetImageMapExport().Export( rPropSet );
2964 
2965     // svg:title and svg:desc (#i73249#)
2966     exportTitleAndDescription( rPropSet, rPropSetInfo );
2967 }
2968 
2969 void XMLTextParagraphExport::exportContour(
2970     const Reference < XPropertySet > & rPropSet,
2971     const Reference < XPropertySetInfo > & rPropSetInfo )
2972 {
2973     if( !rPropSetInfo->hasPropertyByName( gsContourPolyPolygon ) )
2974     {
2975         return;
2976     }
2977 
2978     PointSequenceSequence aSourcePolyPolygon;
2979     rPropSet->getPropertyValue( gsContourPolyPolygon ) >>= aSourcePolyPolygon;
2980     const basegfx::B2DPolyPolygon aPolyPolygon(
2981         basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
2982             aSourcePolyPolygon));
2983     const sal_uInt32 nPolygonCount(aPolyPolygon.count());
2984 
2985     if(!nPolygonCount)
2986     {
2987         return;
2988     }
2989 
2990     const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
2991     bool bPixel(false);
2992 
2993     if( rPropSetInfo->hasPropertyByName( gsIsPixelContour ) )
2994     {
2995         bPixel = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsIsPixelContour ));
2996     }
2997 
2998     // svg: width
2999     OUStringBuffer aStringBuffer( 10 );
3000 
3001     if(bPixel)
3002     {
3003         ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth()));
3004     }
3005     else
3006     {
3007         GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth()));
3008     }
3009 
3010     GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStringBuffer.makeStringAndClear());
3011 
3012     // svg: height
3013     if(bPixel)
3014     {
3015         ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight()));
3016     }
3017     else
3018     {
3019         GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight()));
3020     }
3021 
3022     GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStringBuffer.makeStringAndClear());
3023 
3024     // svg:viewbox
3025     SdXMLImExViewBox aViewBox(0.0, 0.0, aPolyPolygonRange.getWidth(), aPolyPolygonRange.getHeight());
3026     GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3027     enum XMLTokenEnum eElem = XML_TOKEN_INVALID;
3028 
3029     if(1 == nPolygonCount )
3030     {
3031         // simple polygon shape, can be written as svg:points sequence
3032         const OUString aPointString(
3033             basegfx::utils::exportToSvgPoints(
3034                 aPolyPolygon.getB2DPolygon(0)));
3035 
3036         // write point array
3037         GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
3038         eElem = XML_CONTOUR_POLYGON;
3039     }
3040     else
3041     {
3042         // polypolygon, needs to be written as a svg:path sequence
3043         const OUString aPolygonString(
3044             basegfx::utils::exportToSvgD(
3045                 aPolyPolygon,
3046                 true,           // bUseRelativeCoordinates
3047                 false,          // bDetectQuadraticBeziers: not used in old, but maybe activated now
3048                 true));         // bHandleRelativeNextPointCompatible
3049 
3050         // write point array
3051         GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, aPolygonString);
3052         eElem = XML_CONTOUR_PATH;
3053     }
3054 
3055     if( rPropSetInfo->hasPropertyByName( gsIsAutomaticContour ) )
3056     {
3057         bool bTmp = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(
3058                                             gsIsAutomaticContour ));
3059         GetExport().AddAttribute( XML_NAMESPACE_DRAW,
3060                       XML_RECREATE_ON_EDIT, bTmp ? XML_TRUE : XML_FALSE );
3061     }
3062 
3063     // write object now
3064     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, eElem,
3065                               true, true );
3066 }
3067 
3068 void XMLTextParagraphExport::_exportTextGraphic(
3069         const Reference < XPropertySet > & rPropSet,
3070         const Reference < XPropertySetInfo > & rPropSetInfo )
3071 {
3072     OUString sStyle;
3073     if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
3074     {
3075         rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle;
3076     }
3077 
3078     OUString sAutoStyle = Find( XML_STYLE_FAMILY_TEXT_FRAME, rPropSet, sStyle );
3079     if ( sAutoStyle.isEmpty() )
3080         sAutoStyle = sStyle;
3081     if( !sAutoStyle.isEmpty() )
3082         GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
3083                                   GetExport().EncodeStyleName( sAutoStyle ) );
3084 
3085     // check if we need to use svg:transform
3086     sal_Int16 nRotation(0);
3087     rPropSet->getPropertyValue( gsGraphicRotation ) >>= nRotation;
3088     const bool bUseRotation(0 != nRotation);
3089     basegfx::B2DPoint aCenter(0.0, 0.0);
3090 
3091     // add TextFrame attributes like svg:x/y/width/height, also get back
3092     // object's center point if rotation is used and has to be exported
3093     addTextFrameAttributes(rPropSet, false, bUseRotation ? &aCenter : nullptr);
3094 
3095     // svg:transform
3096     if(bUseRotation)
3097     {
3098         // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling.
3099         // Currently only rotation is used, but combinations with 'draw:transform'
3100         // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height
3101         // may be extended/replaced with 'draw:transform' (see draw objects)
3102         SdXMLImExTransform2D aSdXMLImExTransform2D;
3103 
3104         // Convert from 10th degree integer to deg.
3105         // CAUTION: internal rotation is classically mathematically 'wrong' defined by ignoring that
3106         // we have a right-handed coordinate system, so need to correct this by mirroring
3107         // the rotation to get the correct transformation. See also case XML_TOK_TEXT_FRAME_TRANSFORM
3108         // in XMLTextFrameContext_Impl::XMLTextFrameContext_Impl and #i78696#
3109         // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed write it with the wrong
3110         // orientation as in all other cases - ARGH! We will need to correct this in future ODF ASAP!
3111         const double fRotate(static_cast< double >(nRotation) * (F_PI/1800.0));
3112 
3113         // transform to rotation center which is the object's center
3114         aSdXMLImExTransform2D.AddTranslate(-aCenter);
3115 
3116         // add rotation itself
3117         // tdf#115529 but correct value modulo 2PI to have it positive and in the range of [0.0 .. 2PI[
3118         aSdXMLImExTransform2D.AddRotate(basegfx::normalizeToRange(fRotate, F_2PI));
3119 
3120         // back-transform after rotation
3121         aSdXMLImExTransform2D.AddTranslate(aCenter);
3122 
3123         // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed,
3124         // but is not generally available (as it should be, a 'current' UnitConverter should
3125         // be available at GetExport() - and maybe was once). May have to be addressed as soon
3126         // as translate transformations are used here.
3127         GetExport().AddAttribute(
3128             XML_NAMESPACE_DRAW,
3129             XML_TRANSFORM,
3130             aSdXMLImExTransform2D.GetExportString(GetExport().GetMM100UnitConverter()));
3131     }
3132 
3133     // original content
3134     SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_DRAW, XML_FRAME, false, true);
3135 
3136     {
3137         // xlink:href
3138         uno::Reference<graphic::XGraphic> xGraphic;
3139         rPropSet->getPropertyValue("Graphic") >>= xGraphic;
3140 
3141         OUString sInternalURL;
3142         OUString sOutMimeType;
3143 
3144         if (xGraphic.is())
3145         {
3146             sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sOutMimeType);
3147         }
3148 
3149         // If there still is no url, then graphic is empty
3150         if (!sInternalURL.isEmpty())
3151         {
3152             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
3153             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3154             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3155             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3156         }
3157 
3158         // draw:filter-name
3159         OUString sGrfFilter;
3160         rPropSet->getPropertyValue( gsGraphicFilter ) >>= sGrfFilter;
3161         if( !sGrfFilter.isEmpty() )
3162             GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_FILTER_NAME,
3163                                       sGrfFilter );
3164 
3165         if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
3166         {
3167             if (sOutMimeType.isEmpty())
3168             {
3169                 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
3170             }
3171             if (!sOutMimeType.isEmpty())
3172             {
3173                 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "mime-type", sOutMimeType);
3174             }
3175         }
3176 
3177 
3178         // optional office:binary-data
3179         if (xGraphic.is())
3180         {
3181             SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3182             GetExport().AddEmbeddedXGraphicAsBase64(xGraphic);
3183         }
3184     }
3185 
3186     const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
3187     if (bAddReplacementImages)
3188     {
3189         // replacement graphic for backwards compatibility, but
3190         // only for SVG and metafiles currently
3191         uno::Reference<graphic::XGraphic> xReplacementGraphic;
3192         rPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic;
3193 
3194         OUString sInternalURL;
3195         OUString sOutMimeType;
3196 
3197         //Resolves: fdo#62461 put preferred image first above, followed by
3198         //fallback here
3199         if (xReplacementGraphic.is())
3200         {
3201             sInternalURL = GetExport().AddEmbeddedXGraphic(xReplacementGraphic, sOutMimeType);
3202         }
3203 
3204         // If there is no url, then graphic is empty
3205         if (!sInternalURL.isEmpty())
3206         {
3207             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
3208             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3209             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3210             GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3211         }
3212 
3213         if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
3214         {
3215             if (sOutMimeType.isEmpty())
3216             {
3217                 GetExport().GetGraphicMimeTypeFromStream(xReplacementGraphic, sOutMimeType);
3218             }
3219             if (!sOutMimeType.isEmpty())
3220             {
3221                 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "mime-type", sOutMimeType);
3222             }
3223         }
3224 
3225 
3226         // optional office:binary-data
3227         if (xReplacementGraphic.is())
3228         {
3229             SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
3230             GetExport().AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
3231         }
3232     }
3233 
3234     // script:events
3235     Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY );
3236     GetExport().GetEventExport().Export(xEventsSupp);
3237 
3238     // image map
3239     GetExport().GetImageMapExport().Export( rPropSet );
3240 
3241     // svg:title and svg:desc (#i73249#)
3242     exportTitleAndDescription( rPropSet, rPropSetInfo );
3243 
3244     // draw:contour
3245     exportContour( rPropSet, rPropSetInfo );
3246 }
3247 
3248 void XMLTextParagraphExport::_collectTextEmbeddedAutoStyles(const Reference < XPropertySet > & )
3249 {
3250     SAL_WARN( "xmloff", "no API implementation available" );
3251 }
3252 
3253 void XMLTextParagraphExport::_exportTextEmbedded(
3254         const Reference < XPropertySet > &,
3255         const Reference < XPropertySetInfo > & )
3256 {
3257     SAL_WARN( "xmloff", "no API implementation available" );
3258 }
3259 
3260 void XMLTextParagraphExport::exportEvents( const Reference < XPropertySet > & rPropSet )
3261 {
3262     // script:events
3263     Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY );
3264     GetExport().GetEventExport().Export(xEventsSupp);
3265 
3266     // image map
3267     if (rPropSet->getPropertySetInfo()->hasPropertyByName("ImageMap"))
3268         GetExport().GetImageMapExport().Export( rPropSet );
3269 }
3270 
3271 // Implement Title/Description Elements UI (#i73249#)
3272 void XMLTextParagraphExport::exportTitleAndDescription(
3273         const Reference < XPropertySet > & rPropSet,
3274         const Reference < XPropertySetInfo > & rPropSetInfo )
3275 {
3276     // svg:title
3277     if( rPropSetInfo->hasPropertyByName( gsTitle ) )
3278     {
3279         OUString sObjTitle;
3280         rPropSet->getPropertyValue( gsTitle ) >>= sObjTitle;
3281         if( !sObjTitle.isEmpty() )
3282         {
3283             SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG,
3284                                       XML_TITLE, true, false );
3285             GetExport().Characters( sObjTitle );
3286         }
3287     }
3288 
3289     // svg:description
3290     if( rPropSetInfo->hasPropertyByName( gsDescription ) )
3291     {
3292         OUString sObjDesc;
3293         rPropSet->getPropertyValue( gsDescription ) >>= sObjDesc;
3294         if( !sObjDesc.isEmpty() )
3295         {
3296             SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG,
3297                                       XML_DESC, true, false );
3298             GetExport().Characters( sObjDesc );
3299         }
3300     }
3301 }
3302 
3303 bool XMLTextParagraphExport::addHyperlinkAttributes(
3304     const Reference< XPropertySet > & rPropSet,
3305     const Reference< XPropertyState > & rPropState,
3306     const Reference< XPropertySetInfo > & rPropSetInfo )
3307 {
3308     bool bExport = false;
3309     OUString sHRef, sName, sTargetFrame, sUStyleName, sVStyleName;
3310     bool bServerMap = false;
3311 
3312     if( rPropSetInfo->hasPropertyByName( gsHyperLinkURL ) &&
3313         ( !rPropState.is() || PropertyState_DIRECT_VALUE ==
3314                     rPropState->getPropertyState( gsHyperLinkURL ) ) )
3315     {
3316         rPropSet->getPropertyValue( gsHyperLinkURL ) >>= sHRef;
3317 
3318         if( !sHRef.isEmpty() )
3319             bExport = true;
3320     }
3321 
3322     if ( sHRef.isEmpty() )
3323     {
3324         // hyperlink without an URL does not make sense
3325         OSL_ENSURE( false, "hyperlink without an URL --> no export to ODF" );
3326         return false;
3327     }
3328 
3329     if ( rPropSetInfo->hasPropertyByName( gsHyperLinkName )
3330          && ( !rPropState.is()
3331               || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsHyperLinkName ) ) )
3332     {
3333         rPropSet->getPropertyValue( gsHyperLinkName ) >>= sName;
3334         if( !sName.isEmpty() )
3335             bExport = true;
3336     }
3337 
3338     if ( rPropSetInfo->hasPropertyByName( gsHyperLinkTarget )
3339          && ( !rPropState.is()
3340               || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsHyperLinkTarget ) ) )
3341     {
3342         rPropSet->getPropertyValue( gsHyperLinkTarget ) >>= sTargetFrame;
3343         if( !sTargetFrame.isEmpty() )
3344             bExport = true;
3345     }
3346 
3347     if ( rPropSetInfo->hasPropertyByName( gsServerMap )
3348          && ( !rPropState.is()
3349               || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsServerMap ) ) )
3350     {
3351         bServerMap = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsServerMap ));
3352         if ( bServerMap )
3353             bExport = true;
3354     }
3355 
3356     if ( rPropSetInfo->hasPropertyByName( gsUnvisitedCharStyleName )
3357          && ( !rPropState.is()
3358               || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsUnvisitedCharStyleName ) ) )
3359     {
3360         rPropSet->getPropertyValue( gsUnvisitedCharStyleName ) >>= sUStyleName;
3361         if( !sUStyleName.isEmpty() )
3362             bExport = true;
3363     }
3364 
3365     if ( rPropSetInfo->hasPropertyByName( gsVisitedCharStyleName )
3366          && ( !rPropState.is()
3367               || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsVisitedCharStyleName ) ) )
3368     {
3369         rPropSet->getPropertyValue( gsVisitedCharStyleName ) >>= sVStyleName;
3370         if( !sVStyleName.isEmpty() )
3371             bExport = true;
3372     }
3373 
3374     if ( bExport )
3375     {
3376         GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3377         GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference( sHRef ) );
3378 
3379         if( !sName.isEmpty() )
3380             GetExport().AddAttribute( XML_NAMESPACE_OFFICE, XML_NAME, sName );
3381 
3382         if( !sTargetFrame.isEmpty() )
3383         {
3384             GetExport().AddAttribute( XML_NAMESPACE_OFFICE,
3385                                       XML_TARGET_FRAME_NAME, sTargetFrame );
3386             enum XMLTokenEnum eTok = sTargetFrame == "_blank" ? XML_NEW : XML_REPLACE;
3387             GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, eTok );
3388         }
3389 
3390         if( bServerMap  )
3391             GetExport().AddAttribute( XML_NAMESPACE_OFFICE,
3392                                       XML_SERVER_MAP, XML_TRUE );
3393 
3394         if( !sUStyleName.isEmpty() )
3395             GetExport().AddAttribute( XML_NAMESPACE_TEXT,
3396               XML_STYLE_NAME, GetExport().EncodeStyleName( sUStyleName ) );
3397 
3398         if( !sVStyleName.isEmpty() )
3399             GetExport().AddAttribute( XML_NAMESPACE_TEXT,
3400               XML_VISITED_STYLE_NAME, GetExport().EncodeStyleName( sVStyleName ) );
3401     }
3402 
3403     return bExport;
3404 }
3405 
3406 void XMLTextParagraphExport::exportTextRangeSpan(
3407     const css::uno::Reference< css::text::XTextRange > & rTextRange,
3408     Reference< XPropertySet > const & xPropSet,
3409     Reference < XPropertySetInfo > & xPropSetInfo,
3410     const bool bIsUICharStyle,
3411     const bool bHasAutoStyle,
3412     const OUString& sStyle,
3413     bool& rPrevCharIsSpace,
3414     FieldmarkType& openFieldMark )
3415 {
3416     XMLTextCharStyleNamesElementExport aCharStylesExport(
3417             GetExport(),
3418             bIsUICharStyle && aCharStyleNamesPropInfoCache.hasProperty( xPropSet, xPropSetInfo ),
3419             bHasAutoStyle,
3420             xPropSet,
3421             gsCharStyleNames );
3422 
3423     if ( !sStyle.isEmpty() )
3424     {
3425         GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, GetExport().EncodeStyleName( sStyle ) );
3426     }
3427     {
3428         SvXMLElementExport aElement( GetExport(), !sStyle.isEmpty(), XML_NAMESPACE_TEXT, XML_SPAN, false, false );
3429         const OUString aText( rTextRange->getString() );
3430         SvXMLElementExport aElem2( GetExport(), TEXT == openFieldMark,
3431             XML_NAMESPACE_TEXT, XML_TEXT_INPUT,
3432             false, false );
3433         exportCharacterData(aText, rPrevCharIsSpace);
3434         openFieldMark = NONE;
3435     }
3436 }
3437 
3438 void XMLTextParagraphExport::exportTextRange(
3439         const Reference< XTextRange > & rTextRange,
3440         bool bAutoStyles,
3441         bool& rPrevCharIsSpace,
3442         FieldmarkType& openFieldMark )
3443 {
3444     Reference< XPropertySet > xPropSet( rTextRange, UNO_QUERY );
3445     if ( bAutoStyles )
3446     {
3447         Add( XML_STYLE_FAMILY_TEXT_TEXT, xPropSet );
3448     }
3449     else
3450     {
3451         bool bHyperlink = false;
3452         bool bIsUICharStyle = false;
3453         bool bHasAutoStyle = false;
3454         const OUString sStyle(
3455             FindTextStyleAndHyperlink( xPropSet, bHyperlink, bIsUICharStyle, bHasAutoStyle ) );
3456 
3457         Reference < XPropertySetInfo > xPropSetInfo;
3458         bool bHyperlinkAttrsAdded = false;
3459         if ( bHyperlink )
3460         {
3461             Reference< XPropertyState > xPropState( xPropSet, UNO_QUERY );
3462             xPropSetInfo.set( xPropSet->getPropertySetInfo() );
3463             bHyperlinkAttrsAdded = addHyperlinkAttributes( xPropSet, xPropState, xPropSetInfo );
3464         }
3465 
3466         if ( bHyperlink && bHyperlinkAttrsAdded )
3467         {
3468             SvXMLElementExport aElem( GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false );
3469 
3470             // export events (if supported)
3471             OUString sHyperLinkEvents(
3472                 "HyperLinkEvents");
3473             if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
3474             {
3475                 Reference< XNameReplace > xName( xPropSet->getPropertyValue( sHyperLinkEvents ), uno::UNO_QUERY );
3476                 GetExport().GetEventExport().Export( xName, false );
3477             }
3478 
3479             exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
3480         }
3481         else
3482         {
3483             exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
3484         }
3485     }
3486 }
3487 
3488 void XMLTextParagraphExport::exportCharacterData(const OUString& rText,
3489                                            bool& rPrevCharIsSpace )
3490 {
3491     sal_Int32 nExpStartPos = 0;
3492     sal_Int32 nEndPos = rText.getLength();
3493     sal_Int32 nSpaceChars = 0;
3494     for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ )
3495     {
3496         sal_Unicode cChar = rText[nPos];
3497         bool bExpCharAsText = true;
3498         bool bExpCharAsElement = false;
3499         bool bCurrCharIsSpace = false;
3500         switch( cChar )
3501         {
3502         case 0x0009:    // Tab
3503         case 0x000A:    // LF
3504             // These characters are exported as text.
3505             bExpCharAsElement = true;
3506             bExpCharAsText = false;
3507             break;
3508         case 0x000D:
3509             break;  // legal character
3510         case 0x0020:    // Blank
3511             if( rPrevCharIsSpace )
3512             {
3513                 // If the previous character is a space character,
3514                 // too, export a special space element.
3515                 bExpCharAsText = false;
3516             }
3517             bCurrCharIsSpace = true;
3518             break;
3519         default:
3520             if( cChar < 0x0020 )
3521             {
3522 #ifdef DBG_UTIL
3523                 OSL_ENSURE( txtparae_bContainsIllegalCharacters ||
3524                             cChar >= 0x0020,
3525                             "illegal character in text content" );
3526                 txtparae_bContainsIllegalCharacters = true;
3527 #endif
3528                 bExpCharAsText = false;
3529             }
3530             break;
3531         }
3532 
3533         // If the current character is not exported as text
3534            // the text that has not been exported by now has to be exported now.
3535         if( nPos > nExpStartPos && !bExpCharAsText )
3536         {
3537             SAL_WARN_IF( 0 != nSpaceChars, "xmloff", "pending spaces" );
3538             OUString sExp( rText.copy( nExpStartPos, nPos - nExpStartPos ) );
3539             GetExport().Characters( sExp );
3540             nExpStartPos = nPos;
3541         }
3542 
3543         // If there are spaces left that have not been exported and the
3544         // current character is not a space , the pending spaces have to be
3545         // exported now.
3546         if( nSpaceChars > 0 && !bCurrCharIsSpace )
3547         {
3548             SAL_WARN_IF( nExpStartPos != nPos, "xmloff", " pending characters" );
3549 
3550             if( nSpaceChars > 1 )
3551             {
3552                 OUStringBuffer sTmp;
3553                 sTmp.append( nSpaceChars );
3554                 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C,
3555                               sTmp.makeStringAndClear() );
3556             }
3557 
3558             SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3559                                       XML_S, false, false );
3560 
3561             nSpaceChars = 0;
3562         }
3563 
3564         // If the current character has to be exported as a special
3565         // element, the element will be exported now.
3566         if( bExpCharAsElement )
3567         {
3568             switch( cChar )
3569             {
3570             case 0x0009:    // Tab
3571                 {
3572                     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3573                                               XML_TAB, false,
3574                                               false );
3575                 }
3576                 break;
3577             case 0x000A:    // LF
3578                 {
3579                     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3580                                               XML_LINE_BREAK, false,
3581                                               false );
3582                 }
3583                 break;
3584             }
3585         }
3586 
3587         // If the current character is a space, and the previous one
3588         // is a space, too, the number of pending spaces is incremented
3589         // only.
3590         if( bCurrCharIsSpace && rPrevCharIsSpace )
3591             nSpaceChars++;
3592         rPrevCharIsSpace = bCurrCharIsSpace;
3593 
3594         // If the current character is not exported as text, the start
3595         // position for text is the position behind the current position.
3596         if( !bExpCharAsText )
3597         {
3598             SAL_WARN_IF( nExpStartPos != nPos, "xmloff", "wrong export start pos" );
3599             nExpStartPos = nPos+1;
3600         }
3601     }
3602 
3603     if( nExpStartPos < nEndPos )
3604     {
3605         SAL_WARN_IF( 0 != nSpaceChars, "xmloff", " pending spaces " );
3606         OUString sExp( rText.copy( nExpStartPos, nEndPos - nExpStartPos ) );
3607         GetExport().Characters( sExp );
3608     }
3609 
3610     // If there are some spaces left, they have to be exported now.
3611     if( nSpaceChars > 0 )
3612     {
3613         if( nSpaceChars > 1 )
3614         {
3615             OUStringBuffer sTmp;
3616             sTmp.append( nSpaceChars );
3617             GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C,
3618                           sTmp.makeStringAndClear() );
3619         }
3620 
3621         SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_S,
3622                                   false, false );
3623     }
3624 }
3625 
3626 void XMLTextParagraphExport::exportTextDeclarations()
3627 {
3628     pFieldExport->ExportFieldDeclarations();
3629 
3630     // get XPropertySet from the document and ask for AutoMarkFileURL.
3631     // If it exists, export the auto-mark-file element.
3632     Reference<XPropertySet> xPropertySet( GetExport().GetModel(), UNO_QUERY );
3633     if (xPropertySet.is())
3634     {
3635         OUString sUrl;
3636         OUString sIndexAutoMarkFileURL(
3637             "IndexAutoMarkFileURL");
3638         if (xPropertySet->getPropertySetInfo()->hasPropertyByName(
3639             sIndexAutoMarkFileURL))
3640         {
3641             xPropertySet->getPropertyValue(sIndexAutoMarkFileURL) >>= sUrl;
3642             if (!sUrl.isEmpty())
3643             {
3644                 GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF,
3645                                           GetExport().GetRelativeReference(sUrl) );
3646                 SvXMLElementExport aAutoMarkElement(
3647                     GetExport(), XML_NAMESPACE_TEXT,
3648                     XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE,
3649                     true, true );
3650             }
3651         }
3652     }
3653 }
3654 
3655 void XMLTextParagraphExport::exportTextDeclarations(
3656     const Reference<XText> & rText )
3657 {
3658     pFieldExport->ExportFieldDeclarations(rText);
3659 }
3660 
3661 void XMLTextParagraphExport::exportUsedDeclarations()
3662 {
3663     pFieldExport->SetExportOnlyUsedFieldDeclarations( false/*bOnlyUsed*/ );
3664 }
3665 
3666 void XMLTextParagraphExport::exportTrackedChanges(bool bAutoStyles)
3667 {
3668     if (nullptr != pRedlineExport)
3669         pRedlineExport->ExportChangesList( bAutoStyles );
3670 }
3671 
3672 void XMLTextParagraphExport::exportTrackedChanges(
3673     const Reference<XText> & rText,
3674     bool bAutoStyle)
3675 {
3676     if (nullptr != pRedlineExport)
3677         pRedlineExport->ExportChangesList(rText, bAutoStyle);
3678 }
3679 
3680 void XMLTextParagraphExport::recordTrackedChangesForXText(
3681     const Reference<XText> & rText )
3682 {
3683     if (nullptr != pRedlineExport)
3684         pRedlineExport->SetCurrentXText(rText);
3685 }
3686 
3687 void XMLTextParagraphExport::recordTrackedChangesNoXText()
3688 {
3689     if (nullptr != pRedlineExport)
3690         pRedlineExport->SetCurrentXText();
3691 }
3692 
3693 void XMLTextParagraphExport::exportTextAutoStyles()
3694 {
3695     GetAutoStylePool().exportXML( XML_STYLE_FAMILY_TEXT_PARAGRAPH );
3696 
3697     GetAutoStylePool().exportXML( XML_STYLE_FAMILY_TEXT_TEXT );
3698 
3699     GetAutoStylePool().exportXML( XML_STYLE_FAMILY_TEXT_FRAME );
3700 
3701     GetAutoStylePool().exportXML( XML_STYLE_FAMILY_TEXT_SECTION );
3702 
3703     GetAutoStylePool().exportXML( XML_STYLE_FAMILY_TEXT_RUBY );
3704 
3705     maListAutoPool.exportXML();
3706 }
3707 
3708 void XMLTextParagraphExport::exportRuby(
3709     const Reference<XPropertySet> & rPropSet,
3710     bool bAutoStyles )
3711 {
3712     // early out: a collapsed ruby makes no sense
3713     if (*o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed)))
3714         return;
3715 
3716     // start value ?
3717     bool bStart = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart));
3718 
3719     if (bAutoStyles)
3720     {
3721         // ruby auto styles
3722         if (bStart)
3723             Add( XML_STYLE_FAMILY_TEXT_RUBY, rPropSet );
3724     }
3725     else
3726     {
3727         if (bStart)
3728         {
3729             // ruby start
3730 
3731             // we can only start a ruby if none is open
3732             assert(!bOpenRuby && "Can't open a ruby inside of ruby!");
3733             if( bOpenRuby )
3734                 return;
3735 
3736             // save ruby text + ruby char style
3737             rPropSet->getPropertyValue(gsRubyText) >>= sOpenRubyText;
3738             rPropSet->getPropertyValue(gsRubyCharStyleName) >>= sOpenRubyCharStyle;
3739 
3740             // ruby style
3741             GetExport().CheckAttrList();
3742             OUString sStyleName(Find(XML_STYLE_FAMILY_TEXT_RUBY, rPropSet, ""));
3743             SAL_WARN_IF(sStyleName.isEmpty(), "xmloff", "Can't find ruby style!");
3744             GetExport().AddAttribute(XML_NAMESPACE_TEXT,
3745                                      XML_STYLE_NAME, sStyleName);
3746 
3747             // export <text:ruby> and <text:ruby-base> start elements
3748             GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY, false);
3749             GetExport().ClearAttrList();
3750             GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE,
3751                                       false );
3752             bOpenRuby = true;
3753         }
3754         else
3755         {
3756             // ruby end
3757 
3758             // check for an open ruby
3759             assert(bOpenRuby && "Can't close a ruby if none is open!");
3760             if( !bOpenRuby )
3761                 return;
3762 
3763             // close <text:ruby-base>
3764             GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY_BASE,
3765                                    false);
3766 
3767             // write the ruby text (with char style)
3768             {
3769                 if (!sOpenRubyCharStyle.isEmpty())
3770                     GetExport().AddAttribute(
3771                         XML_NAMESPACE_TEXT, XML_STYLE_NAME,
3772                         GetExport().EncodeStyleName( sOpenRubyCharStyle) );
3773 
3774                 SvXMLElementExport aRubyElement(
3775                     GetExport(), XML_NAMESPACE_TEXT, XML_RUBY_TEXT,
3776                     false, false);
3777 
3778                 GetExport().Characters(sOpenRubyText);
3779             }
3780 
3781             // and finally, close the ruby
3782             GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY, false);
3783             bOpenRuby = false;
3784         }
3785     }
3786 }
3787 
3788 void XMLTextParagraphExport::exportMeta(
3789     const Reference<XPropertySet> & i_xPortion,
3790     bool i_bAutoStyles, bool i_isProgress, bool & rPrevCharIsSpace)
3791 {
3792     bool doExport(!i_bAutoStyles); // do not export element if autostyles
3793     // check version >= 1.2
3794     switch (GetExport().getDefaultVersion()) {
3795         case SvtSaveOptions::ODFVER_011: // fall through
3796         case SvtSaveOptions::ODFVER_010: doExport = false; break;
3797         default: break;
3798     }
3799 
3800     const Reference< XTextContent > xTextContent(
3801             i_xPortion->getPropertyValue("InContentMetadata"), UNO_QUERY_THROW);
3802     const Reference< XEnumerationAccess > xEA( xTextContent, UNO_QUERY_THROW );
3803     const Reference< XEnumeration > xTextEnum( xEA->createEnumeration() );
3804 
3805     if (doExport)
3806     {
3807         const Reference<rdf::XMetadatable> xMeta(xTextContent, UNO_QUERY_THROW);
3808 
3809         // text:meta with neither xml:id nor RDFa is invalid
3810         xMeta->ensureMetadataReference();
3811 
3812         // xml:id and RDFa for RDF metadata
3813         GetExport().AddAttributeXmlId(xMeta);
3814         GetExport().AddAttributesRDFa(xTextContent);
3815     }
3816 
3817     SvXMLElementExport aElem( GetExport(), doExport,
3818         XML_NAMESPACE_TEXT, XML_META, false, false );
3819 
3820     // recurse to export content
3821     exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_isProgress, rPrevCharIsSpace);
3822 }
3823 
3824 void XMLTextParagraphExport::PreventExportOfControlsInMuteSections(
3825     const Reference<XIndexAccess> & rShapes,
3826     const rtl::Reference<xmloff::OFormLayerXMLExport>& xFormExport   )
3827 {
3828     // check parameters ad pre-conditions
3829     if( ( ! rShapes.is() ) || ( ! xFormExport.is() ) )
3830     {
3831         // if we don't have shapes or a form export, there's nothing to do
3832         return;
3833     }
3834     SAL_WARN_IF( pSectionExport == nullptr, "xmloff", "We need the section export." );
3835 
3836     Reference<XEnumeration> xShapesEnum = pBoundFrameSets->GetShapes()->createEnumeration();
3837     if(!xShapesEnum.is())
3838         return;
3839     while( xShapesEnum->hasMoreElements() )
3840     {
3841         // now we need to check
3842         // 1) if this is a control shape, and
3843         // 2) if it's in a mute section
3844         // if both answers are 'yes', notify the form layer export
3845 
3846         // we join accessing the shape and testing for control
3847         Reference<XControlShape> xControlShape(xShapesEnum->nextElement(), UNO_QUERY);
3848         if( xControlShape.is() )
3849         {
3850             //            Reference<XPropertySet> xPropSet( xControlShape, UNO_QUERY );
3851             //            Reference<XTextContent> xTextContent;
3852             //            xPropSet->getPropertyValue("TextRange") >>= xTextContent;
3853 
3854             Reference<XTextContent> xTextContent( xControlShape, UNO_QUERY );
3855             if( xTextContent.is() )
3856             {
3857                 if( pSectionExport->IsMuteSection( xTextContent, false ) )
3858                 {
3859                     // Ah, we've found a shape that
3860                     // 1) is a control shape
3861                     // 2) is anchored in a mute section
3862                     // so: don't export it!
3863                     xFormExport->excludeFromExport(
3864                         xControlShape->getControl() );
3865                 }
3866                 // else: not in mute section -> should be exported -> nothing
3867                 // to do
3868             }
3869             // else: no anchor -> ignore
3870         }
3871         // else: no control shape -> nothing to do
3872     }
3873 }
3874 
3875 void XMLTextParagraphExport::PushNewTextListsHelper()
3876 {
3877     maTextListsHelperStack.emplace_back( new XMLTextListsHelper() );
3878     mpTextListsHelper = maTextListsHelperStack.back().get();
3879 }
3880 
3881 void XMLTextParagraphExport::PopTextListsHelper()
3882 {
3883     mpTextListsHelper = nullptr;
3884     maTextListsHelperStack.pop_back();
3885     if ( !maTextListsHelperStack.empty() )
3886     {
3887         mpTextListsHelper = maTextListsHelperStack.back().get();
3888     }
3889 }
3890 
3891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3892