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