xref: /core/sw/source/filter/ww8/docxexport.cxx (revision 8b5e23ea)
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 "docxexport.hxx"
21 #include "docxexportfilter.hxx"
22 #include "docxattributeoutput.hxx"
23 #include "docxsdrexport.hxx"
24 #include "docxhelper.hxx"
25 
26 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
27 #include <com/sun/star/document/XDocumentProperties.hpp>
28 #include <com/sun/star/document/XStorageBasedDocument.hpp>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <com/sun/star/i18n/ScriptType.hpp>
31 #include <com/sun/star/frame/XModel.hpp>
32 #include <com/sun/star/xml/dom/XDocument.hpp>
33 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
34 #include <com/sun/star/xml/sax/Writer.hpp>
35 #include <com/sun/star/awt/XControlModel.hpp>
36 
37 #include <oox/token/namespaces.hxx>
38 #include <oox/token/tokens.hxx>
39 #include <oox/export/drawingml.hxx>
40 #include <oox/export/vmlexport.hxx>
41 #include <oox/export/chartexport.hxx>
42 #include <oox/export/shapes.hxx>
43 #include <oox/helper/propertyset.hxx>
44 #include <oox/token/relationship.hxx>
45 #include <oox/helper/binaryoutputstream.hxx>
46 #include <oox/ole/olestorage.hxx>
47 #include <oox/ole/olehelper.hxx>
48 
49 #include <map>
50 #include <algorithm>
51 
52 #include <IMark.hxx>
53 #include <IDocumentSettingAccess.hxx>
54 #include <IDocumentLayoutAccess.hxx>
55 #include <IDocumentStylePoolAccess.hxx>
56 #include <docsh.hxx>
57 #include <ndtxt.hxx>
58 #include "wrtww8.hxx"
59 #include <fltini.hxx>
60 #include <fmtline.hxx>
61 #include <fmtpdsc.hxx>
62 #include <frmfmt.hxx>
63 #include <section.hxx>
64 #include <ftninfo.hxx>
65 #include <pagedesc.hxx>
66 
67 #include <editeng/unoprnms.hxx>
68 #include <editeng/editobj.hxx>
69 #include <editeng/outlobj.hxx>
70 #include <editeng/brushitem.hxx>
71 #include <editeng/hyphenzoneitem.hxx>
72 
73 #include <docary.hxx>
74 #include <numrule.hxx>
75 #include <charfmt.hxx>
76 #include <viewsh.hxx>
77 #include <viewopt.hxx>
78 
79 #include "ww8par.hxx"
80 #include "ww8scan.hxx"
81 #include <oox/token/properties.hxx>
82 #include <comphelper/processfactory.hxx>
83 #include <comphelper/storagehelper.hxx>
84 #include <rtl/ustrbuf.hxx>
85 #include <sal/log.hxx>
86 #include <vcl/font.hxx>
87 #include <unotools/ucbstreamhelper.hxx>
88 #include <tools/diagnose_ex.h>
89 
90 using namespace sax_fastparser;
91 using namespace ::comphelper;
92 using namespace ::com::sun::star;
93 using namespace ::oox;
94 
95 using oox::vml::VMLExport;
96 
97 using sw::mark::IMark;
98 
99 AttributeOutputBase& DocxExport::AttrOutput() const
100 {
101     return *m_pAttrOutput;
102 }
103 
104 DocxAttributeOutput& DocxExport::DocxAttrOutput() const
105 {
106     return *m_pAttrOutput;
107 }
108 
109 MSWordSections& DocxExport::Sections() const
110 {
111     return *m_pSections;
112 }
113 
114 bool DocxExport::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
115 {
116     // TODO FIXME is this actually true for docx? - this is ~copied from WW8
117     if ( nScript == i18n::ScriptType::ASIAN )
118     {
119         // for asian in ww8, there is only one fontsize
120         // and one fontstyle (posture/weight)
121         switch ( nWhich )
122         {
123             case RES_CHRATR_FONTSIZE:
124             case RES_CHRATR_POSTURE:
125             case RES_CHRATR_WEIGHT:
126                 return false;
127             default:
128                 break;
129         }
130     }
131     else if ( nScript != i18n::ScriptType::COMPLEX )
132     {
133         // for western in ww8, there is only one fontsize
134         // and one fontstyle (posture/weight)
135         switch ( nWhich )
136         {
137             case RES_CHRATR_CJK_FONTSIZE:
138             case RES_CHRATR_CJK_POSTURE:
139             case RES_CHRATR_CJK_WEIGHT:
140                 return false;
141             default:
142                 break;
143         }
144     }
145     return true;
146 }
147 
148 void DocxExport::AppendBookmarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
149 {
150     std::vector< OUString > aStarts;
151     std::vector< OUString > aEnds;
152 
153     IMarkVector aMarks;
154     if ( GetBookmarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
155     {
156         for ( IMark* pMark : aMarks )
157         {
158             const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
159             const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
160 
161             if ( nStart == nCurrentPos )
162                 aStarts.push_back( pMark->GetName() );
163 
164             if ( nEnd == nCurrentPos )
165                 aEnds.push_back( pMark->GetName() );
166         }
167     }
168 
169     const OUString& aStr( rNode.GetText() );
170     const sal_Int32 nEnd = aStr.getLength();
171 
172     if ( nCurrentPos == nEnd )
173         m_pAttrOutput->WriteFinalBookmarks_Impl( aStarts, aEnds );
174     else
175         m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
176 }
177 
178 void DocxExport::AppendBookmark( const OUString& rName )
179 {
180     std::vector< OUString > aStarts;
181     std::vector< OUString > aEnds;
182 
183     aStarts.push_back( rName );
184     aEnds.push_back( rName );
185 
186     m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
187 }
188 
189 void DocxExport::AppendAnnotationMarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
190 {
191     std::vector< OUString > aStarts;
192     std::vector< OUString > aEnds;
193 
194     IMarkVector aMarks;
195     if ( GetAnnotationMarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
196     {
197         for ( IMark* pMark : aMarks )
198         {
199             const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
200             const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
201 
202             if ( nStart == nCurrentPos )
203                 aStarts.push_back( pMark->GetName() );
204 
205             if ( nEnd == nCurrentPos )
206                 aEnds.push_back( pMark->GetName() );
207         }
208     }
209 
210     m_pAttrOutput->WriteAnnotationMarks_Impl( aStarts, aEnds );
211 }
212 
213 void DocxExport::ExportGrfBullet(const SwTextNode&)
214 {
215     // Just collect the bullets for now, numbering.xml is not yet started.
216     CollectGrfsOfBullets();
217 }
218 
219 OString DocxExport::AddRelation( const OUString& rType, const OUString& rTarget )
220 {
221     OUString sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
222            rType, rTarget, true );
223 
224     return sId.toUtf8();
225 }
226 
227 bool DocxExport::DisallowInheritingOutlineNumbering( const SwFormat& rFormat )
228 {
229     bool bRet( false );
230 
231     if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
232     {
233         if (const SwFormat *pParent = rFormat.DerivedFrom())
234         {
235             if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
236             {
237                 ::sax_fastparser::FSHelperPtr pSerializer = m_pAttrOutput->GetSerializer( );
238                 // Level 9 disables the outline
239                 pSerializer->singleElementNS( XML_w, XML_outlineLvl,
240                         FSNS( XML_w, XML_val ), "9" ,
241                         FSEND );
242 
243                 bRet = true;
244             }
245         }
246     }
247 
248     return bRet;
249 }
250 
251 void DocxExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
252         const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat, sal_uInt8 nBreakCode )
253 {
254     m_nHeadersFootersInSection = 1;
255 
256     // document setting indicating the requirement of EVEN and ODD for both headers and footers
257     if ( nHeadFootFlags & ( nsHdFtFlags::WW8_FOOTER_EVEN | nsHdFtFlags::WW8_HEADER_EVEN ))
258         m_aSettings.evenAndOddHeaders = true;
259 
260     // Turn ON flag for 'Writing Headers \ Footers'
261     m_pAttrOutput->SetWritingHeaderFooter( true );
262 
263     // headers
264     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN )
265         WriteHeaderFooter( &rLeftFormat, true, "even" );
266     else if ( m_aSettings.evenAndOddHeaders )
267     {
268         if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
269             WriteHeaderFooter( &rFormat, true, "even" );
270         else if ( m_bHasHdr && nBreakCode == 2 )
271             WriteHeaderFooter( nullptr, true, "even" );
272     }
273 
274     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
275         WriteHeaderFooter( &rFormat, true, "default" );
276 
277     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST )
278         WriteHeaderFooter( &rFirstPageFormat, true, "first" );
279 
280     if( (nHeadFootFlags & (nsHdFtFlags::WW8_HEADER_EVEN
281                          | nsHdFtFlags::WW8_HEADER_ODD
282                          | nsHdFtFlags::WW8_HEADER_FIRST)) == 0
283             && m_bHasHdr && nBreakCode == 2 ) // 2: nexPage
284         WriteHeaderFooter( nullptr, true, "default" );
285 
286 
287     // footers
288     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN )
289         WriteHeaderFooter( &rLeftFormat, false, "even" );
290     else if ( m_aSettings.evenAndOddHeaders )
291     {
292         if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
293            WriteHeaderFooter( &rFormat, false, "even" );
294         else if ( m_bHasFtr && nBreakCode == 2 )
295             WriteHeaderFooter( nullptr, false, "even");
296     }
297 
298     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
299         WriteHeaderFooter( &rFormat, false, "default" );
300 
301     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST )
302         WriteHeaderFooter( &rFirstPageFormat, false, "first" );
303 
304     if( (nHeadFootFlags & (nsHdFtFlags::WW8_FOOTER_EVEN
305                          | nsHdFtFlags::WW8_FOOTER_ODD
306                          | nsHdFtFlags::WW8_FOOTER_FIRST)) == 0
307             && m_bHasFtr && nBreakCode == 2 ) // 2: nexPage
308         WriteHeaderFooter( nullptr, false, "default");
309 
310     // Turn OFF flag for 'Writing Headers \ Footers'
311     m_pAttrOutput->SetWritingHeaderFooter( false );
312 }
313 
314 void DocxExport::OutputField( const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd, FieldFlags nMode )
315 {
316     m_pAttrOutput->WriteField_Impl( pField, eFieldType, rFieldCmd, nMode );
317 }
318 
319 void DocxExport::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
320 {
321     m_pAttrOutput->WriteFormData_Impl( rFieldmark );
322 }
323 
324 void DocxExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ )
325 {
326 #if OSL_DEBUG_LEVEL > 1
327     fprintf( stderr, "TODO DocxExport::WriteHyperlinkData()\n" );
328 #endif
329 }
330 
331 void DocxExport::DoComboBox(const OUString& rName,
332                              const OUString& rHelp,
333                              const OUString& rToolTip,
334                              const OUString& rSelected,
335                              uno::Sequence<OUString>& rListItems)
336 {
337     m_pDocumentFS->startElementNS( XML_w, XML_ffData, FSEND );
338 
339     m_pDocumentFS->singleElementNS( XML_w, XML_name,
340             FSNS( XML_w, XML_val ), OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(),
341             FSEND );
342 
343     m_pDocumentFS->singleElementNS( XML_w, XML_enabled, FSEND );
344 
345     if ( !rHelp.isEmpty() )
346         m_pDocumentFS->singleElementNS( XML_w, XML_helpText,
347             FSNS( XML_w, XML_val ), OUStringToOString( rHelp, RTL_TEXTENCODING_UTF8 ).getStr(),
348             FSEND );
349 
350     if ( !rToolTip.isEmpty() )
351         m_pDocumentFS->singleElementNS( XML_w, XML_statusText,
352             FSNS( XML_w, XML_val ), OUStringToOString( rToolTip, RTL_TEXTENCODING_UTF8 ).getStr(),
353             FSEND );
354 
355     m_pDocumentFS->startElementNS( XML_w, XML_ddList, FSEND );
356 
357     // Output the 0-based index of the selected value
358     sal_uInt32 nListItems = rListItems.getLength();
359     sal_Int32 nId = 0;
360     sal_uInt32 nI = 0;
361     while ( ( nI < nListItems ) && ( nId == 0 ) )
362     {
363         if ( rListItems[nI] == rSelected )
364             nId = nI;
365         nI++;
366     }
367 
368     m_pDocumentFS->singleElementNS( XML_w, XML_result,
369             FSNS( XML_w, XML_val ), OString::number( nId ).getStr( ),
370             FSEND );
371 
372     // Loop over the entries
373 
374     for (sal_uInt32 i = 0; i < nListItems; i++)
375     {
376         m_pDocumentFS->singleElementNS( XML_w, XML_listEntry,
377                 FSNS( XML_w, XML_val ), OUStringToOString( rListItems[i], RTL_TEXTENCODING_UTF8 ).getStr(),
378                FSEND );
379     }
380 
381     m_pDocumentFS->endElementNS( XML_w, XML_ddList );
382 
383     m_pDocumentFS->endElementNS( XML_w, XML_ffData );
384 }
385 
386 void DocxExport::DoFormText(const SwInputField* /*pField*/)
387 {
388     SAL_INFO("sw.ww8", "TODO DocxExport::ForFormText()" );
389 }
390 
391 OString DocxExport::OutputChart( uno::Reference< frame::XModel > const & xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer )
392 {
393     OUString aFileName = "charts/chart" + OUString::number(nCount) + ".xml";
394     OUString sId = m_pFilter->addRelation( m_pSerializer->getOutputStream(),
395                     oox::getRelationship(Relationship::CHART),
396                     aFileName );
397     aFileName = "word/charts/chart" + OUString::number(nCount) + ".xml";
398     ::sax_fastparser::FSHelperPtr pChartFS =
399         m_pFilter->openFragmentStreamWithSerializer( aFileName,
400             "application/vnd.openxmlformats-officedocument.drawingml.chart+xml" );
401 
402     oox::drawingml::ChartExport aChartExport(XML_w, pChartFS, xModel, m_pFilter, oox::drawingml::DOCUMENT_DOCX);
403     aChartExport.ExportContent();
404     return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
405 }
406 
407 OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID)
408 {
409     uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
410     uno::Reference<uno::XComponentContext> const xContext(
411         GetFilter().getComponentContext());
412 
413     OUString sMediaType;
414     OUString sRelationType;
415     OUString sSuffix;
416     const char * pProgID(nullptr);
417 
418     uno::Reference<io::XInputStream> const xInStream =
419         oox::GetOLEObjectStream(xContext, xObj, io_rProgID,
420             sMediaType, sRelationType, sSuffix, pProgID);
421 
422     if (!xInStream.is())
423     {
424         return OString();
425     }
426 
427     assert(!sMediaType.isEmpty());
428     assert(!sRelationType.isEmpty());
429     assert(!sSuffix.isEmpty());
430     OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + "." + sSuffix;
431     uno::Reference<io::XOutputStream> const xOutStream =
432         GetFilter().openFragmentStream("word/" + sFileName, sMediaType);
433     assert(xOutStream.is()); // no reason why that could fail
434 
435     try
436     {
437         ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
438     }
439     catch (uno::Exception const& e)
440     {
441         SAL_WARN("sw.ww8", "DocxExport::WriteOLEObject: " << e);
442         return OString();
443     }
444 
445     OUString const sId = m_pFilter->addRelation( GetFS()->getOutputStream(),
446                 sRelationType, sFileName );
447     if (pProgID)
448     {
449         io_rProgID = OUString::createFromAscii(pProgID);
450     }
451 
452     return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
453 }
454 
455 std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<drawing::XShape>& rxShape,
456                                                            const uno::Reference<awt::XControlModel>& rxControlModel)
457 {
458     ++m_nActiveXControls;
459 
460     // Write out ActiveX binary
461     const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin";
462 
463     OString sGUID;
464     OString sName;
465     uno::Reference<io::XStream> xOutStorage(m_pFilter->openFragmentStream(sBinaryFileName, "application/vnd.ms-office.activeX"), uno::UNO_QUERY);
466     if(xOutStorage.is())
467     {
468         oox::ole::OleStorage aOleStorage(m_pFilter->getComponentContext(), xOutStorage, false);
469         uno::Reference<io::XOutputStream> xOutputStream(aOleStorage.openOutputStream("contents"), uno::UNO_SET_THROW);
470         uno::Reference< css::frame::XModel > xModel( m_pDoc->GetDocShell() ? m_pDoc->GetDocShell()->GetModel() : nullptr );
471         oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, rxControlModel);
472         if ( !exportHelper.isValid() )
473             return std::make_pair<OString, OString>(OString(), OString());
474         sGUID = OUStringToOString(exportHelper.getGUID(), RTL_TEXTENCODING_UTF8);
475         sName = OUStringToOString(exportHelper.getName(), RTL_TEXTENCODING_UTF8);
476         exportHelper.exportControl(xOutputStream, rxShape->getSize(), true);
477         aOleStorage.commit();
478     }
479 
480     // Write out ActiveX fragment
481     const OUString sXMLFileName = "word/activeX/activeX" + OUString::number( m_nActiveXControls ) + ".xml";
482     ::sax_fastparser::FSHelperPtr pActiveXFS = m_pFilter->openFragmentStreamWithSerializer(sXMLFileName, "application/vnd.ms-office.activeX+xml" );
483 
484     const OUString sBinaryId = m_pFilter->addRelation( pActiveXFS->getOutputStream(),
485                                                        oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY),
486                                                        sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) );
487 
488     pActiveXFS->singleElementNS(XML_ax, XML_ocx,
489                                 FSNS(XML_xmlns, XML_ax), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(ax)), RTL_TEXTENCODING_UTF8).getStr(),
490                                 FSNS(XML_xmlns, XML_r), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
491                                 FSNS(XML_ax, XML_classid), OString("{" + sGUID + "}").getStr(),
492                                 FSNS(XML_ax, XML_persistence), "persistStorage",
493                                 FSNS(XML_r, XML_id), OUStringToOString(sBinaryId, RTL_TEXTENCODING_UTF8).getStr(), FSEND);
494 
495     OString sXMLId = OUStringToOString(m_pFilter->addRelation(m_pDocumentFS->getOutputStream(),
496                                                               oox::getRelationship(Relationship::CONTROL),
497                                                               sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)),
498                                        RTL_TEXTENCODING_UTF8);
499 
500     return std::pair<OString, OString>(sXMLId, sName);
501 }
502 
503 void DocxExport::OutputDML(uno::Reference<drawing::XShape> const & xShape)
504 {
505     uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
506     sal_Int32 nNamespace = XML_wps;
507     if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
508         nNamespace = XML_wpg;
509     else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
510         nNamespace = XML_pic;
511     oox::drawingml::ShapeExport aExport(nNamespace, m_pAttrOutput->GetSerializer(), nullptr, m_pFilter, oox::drawingml::DOCUMENT_DOCX, m_pAttrOutput.get());
512     aExport.WriteShape(xShape);
513 }
514 
515 ErrCode DocxExport::ExportDocument_Impl()
516 {
517     // Set the 'Track Revisions' flag in the settings structure
518     m_aSettings.trackRevisions = bool( RedlineFlags::On & m_nOrigRedlineFlags );
519 
520     InitStyles();
521 
522     // init sections
523     m_pSections.reset(new MSWordSections( *this ));
524 
525     // Make sure images are counted from one, even when exporting multiple documents.
526     oox::drawingml::DrawingML::ResetCounters();
527 
528     WriteMainText();
529 
530     WriteFootnotesEndnotes();
531 
532     WritePostitFields();
533 
534     WriteNumbering();
535 
536     WriteFonts();
537 
538     WriteSettings();
539 
540     WriteTheme();
541 
542     WriteGlossary();
543 
544     WriteCustomXml();
545 
546     WriteEmbeddings();
547 
548     WriteVBA();
549 
550     m_aLinkedTextboxesHelper.clear();   //final cleanup
551     m_pStyles.reset();
552     m_pSections.reset();
553 
554     return ERRCODE_NONE;
555 }
556 
557 void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum )
558 {
559     AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
560     m_pSections->AppendSection( pPageDesc, pFormat, nLnNum, m_pAttrOutput->IsFirstParagraph() );
561 }
562 
563 void DocxExport::OutputEndNode( const SwEndNode& rEndNode )
564 {
565     MSWordExportBase::OutputEndNode( rEndNode );
566 
567     if ( TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsSectionNode() )
568     {
569         // this originally comes from WW8Export::WriteText(), and looks like it
570         // could have some code common with SectionNode()...
571 
572         const SwSection& rSect = rEndNode.StartOfSectionNode()->GetSectionNode()->GetSection();
573         if ( m_bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
574             m_bStartTOX = false;
575 
576         SwNodeIndex aIdx( rEndNode, 1 );
577         const SwNode& rNd = aIdx.GetNode();
578         if ( rNd.IsEndNode() && rNd.StartOfSectionNode()->IsSectionNode() )
579             return;
580 
581         bool isInTable = IsInTable();
582         if ( !rNd.IsSectionNode() && isInTable ) // No sections in table
583         {
584             const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
585             if( !pParentFormat )
586                 pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
587 
588             sal_uLong nRstLnNum;
589             if( rNd.IsContentNode() )
590                 nRstLnNum = rNd.GetContentNode()->GetSwAttrSet().GetLineNumber().GetStartValue();
591             else
592                 nRstLnNum = 0;
593 
594             AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
595         }
596         else
597         {
598             AttrOutput().SectionBreaks( rEndNode );
599         }
600     }
601     else if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode())
602         // End node of a table: see if a section break should be written after the table.
603         AttrOutput().SectionBreaks(rEndNode);
604 }
605 
606 void DocxExport::OutputGrfNode( const SwGrfNode& )
607 {
608     SAL_INFO("sw.ww8", "TODO DocxExport::OutputGrfNode( const SwGrfNode& )" );
609 }
610 
611 void DocxExport::OutputOLENode( const SwOLENode& )
612 {
613     SAL_INFO("sw.ww8", "TODO DocxExport::OutputOLENode( const SwOLENode& )" );
614 }
615 
616 void DocxExport::OutputLinkedOLE( const OUString& )
617 {
618     // Nothing to implement here: WW8 only
619 }
620 
621 sal_uLong DocxExport::ReplaceCr( sal_uInt8 )
622 {
623     // Completely unused for Docx export... only here for code sharing
624     // purpose with binary export
625     return 0;
626 }
627 
628 void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet,
629         const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat,
630         const SwPageDesc* pNewPgDesc )
631 {
632     // tell the attribute output that we are ready to write the section
633     // break [has to be output inside paragraph properties]
634     AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
635 
636     const SwSectionFormat* pFormat = GetSectionFormat( rNd );
637     const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
638 
639     OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
640 
641     if ( pNewPgDescFormat )
642     {
643         m_pSections->AppendSection( *pNewPgDescFormat, rNd, pFormat, nLnNm );
644     }
645     else if ( pNewPgDesc )
646     {
647         m_pSections->AppendSection( pNewPgDesc, rNd, pFormat, nLnNm );
648     }
649 
650 }
651 
652 void DocxExport::InitStyles()
653 {
654     m_pStyles.reset(new MSWordStyles( *this, /*bListStyles =*/ true ));
655 
656     // setup word/styles.xml and the relations + content type
657     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
658             oox::getRelationship(Relationship::STYLES),
659             "styles.xml" );
660 
661     ::sax_fastparser::FSHelperPtr pStylesFS =
662         m_pFilter->openFragmentStreamWithSerializer( "word/styles.xml",
663             "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" );
664 
665     // switch the serializer to redirect the output to word/styles.xml
666     m_pAttrOutput->SetSerializer( pStylesFS );
667 
668     // do the work
669     m_pStyles->OutputStylesTable();
670 
671     // switch the serializer back
672     m_pAttrOutput->SetSerializer( m_pDocumentFS );
673 }
674 
675 void DocxExport::WriteFootnotesEndnotes()
676 {
677     if ( m_pAttrOutput->HasFootnotes() )
678     {
679         // setup word/styles.xml and the relations + content type
680         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
681                 oox::getRelationship(Relationship::FOOTNOTES),
682                 "footnotes.xml" );
683 
684         ::sax_fastparser::FSHelperPtr pFootnotesFS =
685             m_pFilter->openFragmentStreamWithSerializer( "word/footnotes.xml",
686                     "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" );
687 
688         // switch the serializer to redirect the output to word/footnotes.xml
689         m_pAttrOutput->SetSerializer( pFootnotesFS );
690         // tdf#99227
691         m_pSdrExport->setSerializer( pFootnotesFS );
692         // tdf#107969
693         m_pVMLExport->SetFS(pFootnotesFS);
694 
695         // do the work
696         m_pAttrOutput->FootnotesEndnotes( true );
697 
698         // switch the serializer back
699         m_pVMLExport->SetFS(m_pDocumentFS);
700         m_pSdrExport->setSerializer( m_pDocumentFS );
701         m_pAttrOutput->SetSerializer( m_pDocumentFS );
702     }
703 
704     if ( m_pAttrOutput->HasEndnotes() )
705     {
706         // setup word/styles.xml and the relations + content type
707         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
708                 oox::getRelationship(Relationship::ENDNOTES),
709                 "endnotes.xml" );
710 
711         ::sax_fastparser::FSHelperPtr pEndnotesFS =
712             m_pFilter->openFragmentStreamWithSerializer( "word/endnotes.xml",
713                     "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" );
714 
715         // switch the serializer to redirect the output to word/endnotes.xml
716         m_pAttrOutput->SetSerializer( pEndnotesFS );
717         // tdf#99227
718         m_pSdrExport->setSerializer( pEndnotesFS );
719         // tdf#107969
720         m_pVMLExport->SetFS(pEndnotesFS);
721 
722         // do the work
723         m_pAttrOutput->FootnotesEndnotes( false );
724 
725         // switch the serializer back
726         m_pVMLExport->SetFS(m_pDocumentFS);
727         m_pSdrExport->setSerializer( m_pDocumentFS );
728         m_pAttrOutput->SetSerializer( m_pDocumentFS );
729     }
730 }
731 
732 void DocxExport::WritePostitFields()
733 {
734     if ( m_pAttrOutput->HasPostitFields() )
735     {
736         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
737                 oox::getRelationship(Relationship::COMMENTS),
738                 "comments.xml" );
739 
740         ::sax_fastparser::FSHelperPtr pPostitFS =
741             m_pFilter->openFragmentStreamWithSerializer( "word/comments.xml",
742                     "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" );
743 
744         pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces());
745         m_pAttrOutput->SetSerializer( pPostitFS );
746         m_pAttrOutput->WritePostitFields();
747         m_pAttrOutput->SetSerializer( m_pDocumentFS );
748         pPostitFS->endElementNS( XML_w, XML_comments );
749     }
750 }
751 
752 void DocxExport::WriteNumbering()
753 {
754     if ( !m_pUsedNumTable )
755         return; // no numbering is used
756 
757     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
758         oox::getRelationship(Relationship::NUMBERING),
759         "numbering.xml" );
760 
761     ::sax_fastparser::FSHelperPtr pNumberingFS = m_pFilter->openFragmentStreamWithSerializer( "word/numbering.xml",
762         "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" );
763 
764     // switch the serializer to redirect the output to word/numbering.xml
765     m_pAttrOutput->SetSerializer( pNumberingFS );
766     m_pDrawingML->SetFS( pNumberingFS );
767 
768     pNumberingFS->startElementNS( XML_w, XML_numbering,
769             FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
770             FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr(),
771             FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
772             FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr(),
773             FSEND );
774 
775     BulletDefinitions();
776 
777     AbstractNumberingDefinitions();
778 
779     NumberingDefinitions();
780 
781     pNumberingFS->endElementNS( XML_w, XML_numbering );
782 
783     // switch the serializer back
784     m_pDrawingML->SetFS( m_pDocumentFS );
785     m_pAttrOutput->SetSerializer( m_pDocumentFS );
786 }
787 
788 void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const char* pType )
789 {
790     // setup the xml stream
791     OUString aRelId;
792     ::sax_fastparser::FSHelperPtr pFS;
793     if ( bHeader )
794     {
795         OUString aName( "header" + OUString::number( ++m_nHeaders ) + ".xml" );
796 
797         aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
798                 oox::getRelationship(Relationship::HEADER),
799                 aName );
800 
801         pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
802                     "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" );
803 
804         pFS->startElementNS( XML_w, XML_hdr, MainXmlNamespaces());
805     }
806     else
807     {
808         OUString aName( "footer" + OUString::number( ++m_nFooters ) + ".xml" );
809 
810         aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
811                 oox::getRelationship(Relationship::FOOTER),
812                 aName );
813 
814         pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
815                     "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" );
816 
817         pFS->startElementNS( XML_w, XML_ftr, MainXmlNamespaces());
818     }
819 
820     // switch the serializer to redirect the output to word/styles.xml
821     m_pAttrOutput->SetSerializer( pFS );
822     m_pVMLExport->SetFS( pFS );
823     m_pSdrExport->setSerializer(pFS);
824     SetFS( pFS );
825     {
826         DocxTableExportContext aTableExportContext(*m_pAttrOutput);
827         //When the stream changes the cache which is maintained for the graphics in case of alternate content is not cleared.
828         //So clearing the alternate content graphic cache.
829         m_pAttrOutput->PushRelIdCache();
830         // do the work
831         if (pFormat == nullptr)
832             AttrOutput().EmptyParagraph();
833         else
834             WriteHeaderFooterText(*pFormat, bHeader);
835         m_pAttrOutput->PopRelIdCache();
836         m_pAttrOutput->EndParaSdtBlock();
837     }
838 
839     // switch the serializer back
840     m_pAttrOutput->SetSerializer( m_pDocumentFS );
841     m_pVMLExport->SetFS( m_pDocumentFS );
842     m_pSdrExport->setSerializer(m_pDocumentFS);
843     SetFS( m_pDocumentFS );
844 
845     // close the tag
846     sal_Int32 nReference;
847     if ( bHeader )
848     {
849         pFS->endElementNS( XML_w, XML_hdr );
850         nReference = XML_headerReference;
851     }
852     else
853     {
854         pFS->endElementNS( XML_w, XML_ftr );
855         nReference = XML_footerReference;
856     }
857 
858     // and write the reference
859     m_pDocumentFS->singleElementNS( XML_w, nReference,
860             FSNS( XML_w, XML_type ), pType,
861             FSNS( XML_r, XML_id ), aRelId.toUtf8().getStr(),
862             FSEND );
863 }
864 
865 void DocxExport::WriteFonts()
866 {
867     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
868             oox::getRelationship(Relationship::FONTTABLE),
869             "fontTable.xml" );
870 
871     ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
872             "word/fontTable.xml",
873             "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" );
874 
875     pFS->startElementNS( XML_w, XML_fonts,
876             FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
877             FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
878             FSEND );
879 
880     // switch the serializer to redirect the output to word/styles.xml
881     m_pAttrOutput->SetSerializer( pFS );
882 
883     // do the work
884     m_aFontHelper.WriteFontTable( *m_pAttrOutput );
885 
886     // switch the serializer back
887     m_pAttrOutput->SetSerializer( m_pDocumentFS );
888 
889     pFS->endElementNS( XML_w, XML_fonts );
890 }
891 
892 void DocxExport::WriteProperties( )
893 {
894     // Write the core properties
895     SwDocShell* pDocShell( m_pDoc->GetDocShell( ) );
896     uno::Reference<document::XDocumentProperties> xDocProps;
897     bool bSecurityOptOpenReadOnly = false;
898     if ( pDocShell )
899     {
900         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
901                pDocShell->GetModel( ), uno::UNO_QUERY );
902         xDocProps = xDPS->getDocumentProperties();
903         bSecurityOptOpenReadOnly = pDocShell->IsSecurityOptOpenReadOnly();
904     }
905 
906     m_pFilter->exportDocumentProperties( xDocProps, bSecurityOptOpenReadOnly );
907 }
908 
909 void DocxExport::WriteSettings()
910 {
911     SwViewShell *pViewShell(m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
912     if( !pViewShell && !m_aSettings.hasData() && !m_pAttrOutput->HasFootnotes() && !m_pAttrOutput->HasEndnotes())
913         return;
914 
915     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
916             oox::getRelationship(Relationship::SETTINGS),
917             "settings.xml" );
918 
919     ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
920             "word/settings.xml",
921             "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" );
922 
923     pFS->startElementNS( XML_w, XML_settings,
924             FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
925             FSEND );
926 
927     // View
928     if (pViewShell && pViewShell->GetViewOptions()->getBrowseMode())
929     {
930         pFS->singleElementNS(XML_w, XML_view, FSNS(XML_w, XML_val), "web", FSEND);
931     }
932 
933     // Zoom
934     if (pViewShell)
935     {
936         rtl::Reference<sax_fastparser::FastAttributeList> pAttributeList(
937             sax_fastparser::FastSerializerHelper::createAttrList());
938 
939         switch (pViewShell->GetViewOptions()->GetZoomType())
940         {
941             case SvxZoomType::WHOLEPAGE:
942                 pAttributeList->add(FSNS(XML_w, XML_val), "fullPage");
943                 break;
944             case SvxZoomType::PAGEWIDTH:
945                 pAttributeList->add(FSNS(XML_w, XML_val), "bestFit");
946                 break;
947             case SvxZoomType::OPTIMAL:
948                 pAttributeList->add(FSNS(XML_w, XML_val), "textFit");
949                 break;
950             default:
951                 break;
952         }
953 
954         OString aZoom(OString::number(pViewShell->GetViewOptions()->GetZoom()));
955         pAttributeList->add(FSNS(XML_w, XML_percent), aZoom);
956         sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList.get());
957         pFS->singleElementNS(XML_w, XML_zoom, xAttributeList);
958     }
959 
960     // Display Background Shape
961     if (boost::optional<SvxBrushItem> oBrush = getBackground())
962     {
963         // Turn on the 'displayBackgroundShape'
964         pFS->singleElementNS( XML_w, XML_displayBackgroundShape, FSEND );
965     }
966 
967     // Track Changes
968     if ( m_aSettings.trackRevisions )
969         pFS->singleElementNS( XML_w, XML_trackRevisions, FSEND );
970 
971     // Mirror Margins
972     if(isMirroredMargin())
973         pFS->singleElementNS( XML_w, XML_mirrorMargins, FSEND );
974 
975     // Embed Fonts
976     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
977         pFS->singleElementNS( XML_w, XML_embedTrueTypeFonts, FSEND );
978 
979     // Embed System Fonts
980     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_SYSTEM_FONTS ))
981         pFS->singleElementNS( XML_w, XML_embedSystemFonts, FSEND );
982 
983     // Default Tab Stop
984     if( m_aSettings.defaultTabStop != 0 )
985         pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
986             OString::number( m_aSettings.defaultTabStop).getStr(), FSEND );
987 
988     // Do not justify lines with manual break
989     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ))
990     {
991         pFS->startElementNS( XML_w, XML_compat, FSEND );
992         pFS->singleElementNS( XML_w, XML_doNotExpandShiftReturn, FSEND );
993         pFS->endElementNS( XML_w, XML_compat );
994     }
995 
996     // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
997     // Use the setting from the default style.
998     SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
999     const SfxPoolItem* pItem;
1000     if (pColl && SfxItemState::SET == pColl->GetItemState(RES_PARATR_HYPHENZONE, false, &pItem))
1001     {
1002         pFS->singleElementNS(XML_w, XML_autoHyphenation,
1003                              FSNS(XML_w, XML_val), OString::boolean(static_cast<const SvxHyphenZoneItem*>(pItem)->IsHyphen()),
1004                              FSEND);
1005     }
1006 
1007     // Even and Odd Headers
1008     if( m_aSettings.evenAndOddHeaders )
1009         pFS->singleElementNS( XML_w, XML_evenAndOddHeaders, FSEND );
1010 
1011     // Has Footnotes
1012     if( m_pAttrOutput->HasFootnotes())
1013         DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_footnotePr, m_pDoc->GetFootnoteInfo(), XML_footnote );
1014 
1015     // Has Endnotes
1016     if( m_pAttrOutput->HasEndnotes())
1017         DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_endnotePr, m_pDoc->GetEndNoteInfo(), XML_endnote );
1018 
1019     // Has themeFontLang information
1020     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1021 
1022     bool hasProtectionProperties = false;
1023     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1024     const OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1025     if ( xPropSetInfo->hasPropertyByName( aGrabBagName ) )
1026     {
1027         uno::Sequence< beans::PropertyValue > propList;
1028         xPropSet->getPropertyValue( aGrabBagName ) >>= propList;
1029 
1030         for( sal_Int32 i=0; i < propList.getLength(); ++i )
1031         {
1032             if ( propList[i].Name == "ThemeFontLangProps" )
1033             {
1034                 uno::Sequence< beans::PropertyValue > themeFontLangProps;
1035                 propList[i].Value >>= themeFontLangProps;
1036                 OUString aValues[3];
1037                 for( sal_Int32 j=0; j < themeFontLangProps.getLength(); ++j )
1038                 {
1039                     if( themeFontLangProps[j].Name == "val" )
1040                         themeFontLangProps[j].Value >>= aValues[0];
1041                     else if( themeFontLangProps[j].Name == "eastAsia" )
1042                         themeFontLangProps[j].Value >>= aValues[1];
1043                     else if( themeFontLangProps[j].Name == "bidi" )
1044                         themeFontLangProps[j].Value >>= aValues[2];
1045                 }
1046                 pFS->singleElementNS( XML_w, XML_themeFontLang,
1047                                       FSNS( XML_w, XML_val ), OUStringToOString( aValues[0], RTL_TEXTENCODING_UTF8 ).getStr(),
1048                                       FSNS( XML_w, XML_eastAsia ), OUStringToOString( aValues[1], RTL_TEXTENCODING_UTF8 ).getStr(),
1049                                       FSNS( XML_w, XML_bidi ), OUStringToOString( aValues[2], RTL_TEXTENCODING_UTF8 ).getStr(),
1050                                       FSEND );
1051             }
1052             else if ( propList[i].Name == "CompatSettings" )
1053             {
1054                 pFS->startElementNS( XML_w, XML_compat, FSEND );
1055 
1056                 uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
1057                 propList[i].Value >>= aCompatSettingsSequence;
1058 
1059                 for(sal_Int32 j=0; j < aCompatSettingsSequence.getLength(); ++j)
1060                 {
1061                     uno::Sequence< beans::PropertyValue > aCompatSetting;
1062                     aCompatSettingsSequence[j].Value >>= aCompatSetting;
1063                     OUString aName;
1064                     OUString aUri;
1065                     OUString aValue;
1066 
1067                     for(sal_Int32 k=0; k < aCompatSetting.getLength(); ++k)
1068                     {
1069                         if( aCompatSetting[k].Name == "name" )
1070                             aCompatSetting[k].Value >>= aName;
1071                         else if( aCompatSetting[k].Name == "uri" )
1072                             aCompatSetting[k].Value >>= aUri;
1073                         else if( aCompatSetting[k].Name == "val" )
1074                             aCompatSetting[k].Value >>= aValue;
1075                     }
1076                     pFS->singleElementNS( XML_w, XML_compatSetting,
1077                         FSNS( XML_w, XML_name ), OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr(),
1078                         FSNS( XML_w, XML_uri ),  OUStringToOString(aUri, RTL_TEXTENCODING_UTF8).getStr(),
1079                         FSNS( XML_w, XML_val ),  OUStringToOString(aValue, RTL_TEXTENCODING_UTF8).getStr(),
1080                         FSEND);
1081                 }
1082 
1083                 pFS->endElementNS( XML_w, XML_compat );
1084             }
1085             else if (propList[i].Name == "DocumentProtection")
1086             {
1087 
1088                 uno::Sequence< beans::PropertyValue > rAttributeList;
1089                 propList[i].Value >>= rAttributeList;
1090 
1091                 if (rAttributeList.getLength())
1092                 {
1093                     sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList();
1094                     for (sal_Int32 j = 0; j < rAttributeList.getLength(); ++j)
1095                     {
1096                         static DocxStringTokenMap const aTokens[] =
1097                         {
1098                             { "edit",                XML_edit },
1099                             { "enforcement",         XML_enforcement },
1100                             { "formatting",          XML_formatting },
1101                             { "cryptProviderType",   XML_cryptProviderType },
1102                             { "cryptAlgorithmClass", XML_cryptAlgorithmClass },
1103                             { "cryptAlgorithmType",  XML_cryptAlgorithmType },
1104                             { "cryptAlgorithmSid",   XML_cryptAlgorithmSid },
1105                             { "cryptSpinCount",      XML_cryptSpinCount },
1106                             { "hash",                XML_hash },
1107                             { "salt",                XML_salt },
1108                             { nullptr, 0 }
1109                         };
1110 
1111                         if (sal_Int32 nToken = DocxStringGetToken(aTokens, rAttributeList[j].Name))
1112                             pAttributeList->add(FSNS(XML_w, nToken), rAttributeList[j].Value.get<OUString>().toUtf8());
1113                     }
1114 
1115                     // we have document protection from input DOCX file
1116 
1117                     sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList);
1118                     pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList);
1119 
1120                     hasProtectionProperties = true;
1121                 }
1122             }
1123         }
1124     }
1125 
1126     // Protect form
1127     // Section-specific write protection
1128     if (! hasProtectionProperties)
1129     {
1130         if (m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM) ||
1131             m_pSections->DocumentIsProtected())
1132         {
1133             // we have form protection from Writer or from input ODT file
1134 
1135             pFS->singleElementNS(XML_w, XML_documentProtection,
1136                 FSNS(XML_w, XML_edit), "forms",
1137                 FSNS(XML_w, XML_enforcement), "true",
1138                 FSEND);
1139         }
1140     }
1141 
1142     // finish settings.xml
1143     pFS->endElementNS( XML_w, XML_settings );
1144 }
1145 
1146 void DocxExport::WriteTheme()
1147 {
1148     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1149 
1150     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1151     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1152     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1153         return;
1154 
1155     uno::Reference<xml::dom::XDocument> themeDom;
1156     uno::Sequence< beans::PropertyValue > propList;
1157     xPropSet->getPropertyValue( aName ) >>= propList;
1158     for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1159     {
1160         OUString propName = propList[nProp].Name;
1161         if ( propName == "OOXTheme" )
1162         {
1163              propList[nProp].Value >>= themeDom;
1164              break;
1165         }
1166     }
1167 
1168     // no theme dom to write
1169     if ( !themeDom.is() )
1170         return;
1171 
1172     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1173             oox::getRelationship(Relationship::THEME),
1174             "theme/theme1.xml" );
1175 
1176     uno::Reference< xml::sax::XSAXSerializable > serializer( themeDom, uno::UNO_QUERY );
1177     uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1178     writer->setOutputStream( GetFilter().openFragmentStream( "word/theme/theme1.xml",
1179         "application/vnd.openxmlformats-officedocument.theme+xml" ) );
1180     serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1181         uno::Sequence< beans::StringPair >() );
1182 }
1183 
1184 void DocxExport::WriteGlossary()
1185 {
1186     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1187 
1188     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1189     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1190     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1191         return;
1192 
1193     uno::Reference<xml::dom::XDocument> glossaryDocDom;
1194     uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
1195     uno::Sequence< beans::PropertyValue > propList;
1196     xPropSet->getPropertyValue( aName ) >>= propList;
1197     sal_Int32 collectedProperties = 0;
1198     for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1199     {
1200         OUString propName = propList[nProp].Name;
1201         if ( propName == "OOXGlossary" )
1202         {
1203              propList[nProp].Value >>= glossaryDocDom;
1204              collectedProperties++;
1205         }
1206         if (propName == "OOXGlossaryDom")
1207         {
1208             propList[nProp].Value >>= glossaryDomList;
1209             collectedProperties++;
1210         }
1211         if (collectedProperties == 2)
1212             break;
1213     }
1214 
1215     // no glossary dom to write
1216     if ( !glossaryDocDom.is() )
1217         return;
1218 
1219     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1220             oox::getRelationship(Relationship::GLOSSARYDOCUMENT),
1221             "glossary/document.xml" );
1222 
1223     uno::Reference< io::XOutputStream > xOutputStream = GetFilter().openFragmentStream( "word/glossary/document.xml",
1224             "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" );
1225 
1226     uno::Reference< xml::sax::XSAXSerializable > serializer( glossaryDocDom, uno::UNO_QUERY );
1227     uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1228     writer->setOutputStream( xOutputStream );
1229     serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1230         uno::Sequence< beans::StringPair >() );
1231 
1232     sal_Int32 length = glossaryDomList.getLength();
1233     for ( int i =0; i < length; i++)
1234     {
1235         uno::Sequence< uno::Any> glossaryElement = glossaryDomList[i];
1236         OUString gTarget, gType, gId, contentType;
1237         uno::Reference<xml::dom::XDocument> xDom;
1238         glossaryElement[0] >>= xDom;
1239         glossaryElement[1] >>= gId;
1240         glossaryElement[2] >>= gType;
1241         glossaryElement[3] >>= gTarget;
1242         glossaryElement[4] >>= contentType;
1243         gId = gId.copy(3); //"rId" only save the numeric value
1244 
1245         PropertySet aProps(xOutputStream);
1246         aProps.setAnyProperty( PROP_RelId, uno::makeAny( gId.toInt32() ));
1247         m_pFilter->addRelation( xOutputStream, gType, gTarget);
1248         uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
1249         writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
1250         gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1251                uno::Sequence< beans::StringPair >() );
1252     }
1253 }
1254 
1255 void DocxExport::WriteCustomXml()
1256 {
1257     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1258 
1259     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1260     static const OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1261     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1262         return;
1263 
1264     uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomlist;
1265     uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomPropslist;
1266     uno::Sequence< beans::PropertyValue > propList;
1267     xPropSet->getPropertyValue( aName ) >>= propList;
1268     for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1269     {
1270         const OUString propName = propList[nProp].Name;
1271         if ( propName == "OOXCustomXml" )
1272         {
1273              propList[nProp].Value >>= customXmlDomlist;
1274              break;
1275         }
1276     }
1277 
1278     for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1279     {
1280         OUString propName = propList[nProp].Name;
1281         if ( propName == "OOXCustomXmlProps" )
1282         {
1283              propList[nProp].Value >>= customXmlDomPropslist;
1284              break;
1285         }
1286     }
1287 
1288     for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
1289     {
1290         uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1291         uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1292         if (customXmlDom.is())
1293         {
1294             m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1295                     oox::getRelationship(Relationship::CUSTOMXML),
1296                     "../customXml/item"+OUString::number((j+1))+".xml" );
1297 
1298             uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
1299             uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1300             writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1301                 "application/xml" ) );
1302             serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1303                 uno::Sequence< beans::StringPair >() );
1304         }
1305 
1306         if (customXmlDomProps.is())
1307         {
1308             uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDomProps, uno::UNO_QUERY );
1309             uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1310             writer->setOutputStream( GetFilter().openFragmentStream( "customXml/itemProps"+OUString::number((j+1))+".xml",
1311                 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml" ) );
1312             serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1313                 uno::Sequence< beans::StringPair >() );
1314 
1315             // Adding itemprops's relationship entry to item.xml.rels file
1316             m_pFilter->addRelation( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1317                     "application/xml" ) ,
1318                     oox::getRelationship(Relationship::CUSTOMXMLPROPS),
1319                     "itemProps"+OUString::number((j+1))+".xml" );
1320         }
1321     }
1322 }
1323 
1324 void DocxExport::WriteVBA()
1325 {
1326     uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
1327     if (!xStorageBasedDocument.is())
1328         return;
1329 
1330     uno::Reference<embed::XStorage> xDocumentStorage(xStorageBasedDocument->getDocumentStorage(), uno::UNO_QUERY);
1331     OUString aMacrosName("_MS_VBA_Macros");
1332     if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
1333         return;
1334 
1335     const sal_Int32 nOpenMode = embed::ElementModes::READ;
1336     uno::Reference<io::XStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY);
1337     uno::Reference<io::XOutputStream> xProjectStream;
1338     if (xMacrosStream.is())
1339     {
1340         // First handle the project stream, this sets xProjectStream.
1341         std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xMacrosStream));
1342 
1343         xProjectStream = GetFilter().openFragmentStream("word/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1344         uno::Reference<io::XStream> xOutputStream(xProjectStream, uno::UNO_QUERY);
1345         if (!xOutputStream.is())
1346             return;
1347         std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1348 
1349         // Write the stream.
1350         pOut->WriteStream(*pIn);
1351 
1352         // Write the relationship.
1353         m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin");
1354     }
1355 
1356     OUString aDataName("_MS_VBA_Macros_XML");
1357     if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName))
1358         return;
1359 
1360     uno::Reference<io::XStream> xDataStream(xDocumentStorage->openStreamElement(aDataName, nOpenMode), uno::UNO_QUERY);
1361     if (xDataStream.is())
1362     {
1363         // Then the data stream, which wants to work with an already set
1364         // xProjectStream.
1365         std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream));
1366 
1367         uno::Reference<io::XStream> xOutputStream(GetFilter().openFragmentStream("word/vbaData.xml", "application/vnd.ms-word.vbaData+xml"), uno::UNO_QUERY);
1368         if (!xOutputStream.is())
1369             return;
1370         std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1371 
1372         // Write the stream.
1373         pOut->WriteStream(*pIn);
1374 
1375         // Write the relationship.
1376         if (!xProjectStream.is())
1377             return;
1378 
1379         m_pFilter->addRelation(xProjectStream, oox::getRelationship(Relationship::WORDVBADATA), "vbaData.xml");
1380     }
1381 }
1382 
1383 void DocxExport::WriteEmbeddings()
1384 {
1385     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1386 
1387     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1388     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1389     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1390         return;
1391 
1392     uno::Sequence< beans::PropertyValue > embeddingsList;
1393     uno::Sequence< beans::PropertyValue > propList;
1394     xPropSet->getPropertyValue( aName ) >>= propList;
1395     for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
1396     {
1397         OUString propName = propList[nProp].Name;
1398         if ( propName == "OOXEmbeddings" )
1399         {
1400              propList[nProp].Value >>= embeddingsList;
1401              break;
1402         }
1403     }
1404     for (sal_Int32 j = 0; j < embeddingsList.getLength(); j++)
1405     {
1406         OUString embeddingPath = embeddingsList[j].Name;
1407         uno::Reference<io::XInputStream> embeddingsStream;
1408         embeddingsList[j].Value >>= embeddingsStream;
1409 
1410         OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
1411         // FIXME: this .xlsm hack is silly - if anything the mime-type for an existing embedded object should be read from [Content_Types].xml
1412         if (embeddingPath.endsWith(".xlsm"))
1413             contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
1414         else if (embeddingPath.endsWith(".bin"))
1415             contentType = "application/vnd.openxmlformats-officedocument.oleObject";
1416 
1417         if ( embeddingsStream.is() )
1418         {
1419             uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream(embeddingPath,
1420                                     contentType);
1421             try
1422             {
1423                 sal_Int32 nBufferSize = 512;
1424                 uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
1425                 sal_Int32 nRead;
1426                 do
1427                 {
1428                     nRead = embeddingsStream->readBytes( aDataBuffer, nBufferSize );
1429                     if( nRead )
1430                     {
1431                         if( nRead < nBufferSize )
1432                         {
1433                             nBufferSize = nRead;
1434                             aDataBuffer.realloc(nRead);
1435                         }
1436                         xOutStream->writeBytes( aDataBuffer );
1437                     }
1438                 }
1439                 while( nRead );
1440                 xOutStream->flush();
1441             }
1442             catch(const uno::Exception&)
1443             {
1444                 css::uno::Any ex( cppu::getCaughtException() );
1445                 SAL_WARN("sw.ww8", "WriteEmbeddings() ::Failed to copy Inputstream to outputstream exception caught! " << exceptionToString(ex));
1446             }
1447             xOutStream->closeOutput();
1448         }
1449     }
1450 }
1451 
1452 bool DocxExport::isMirroredMargin()
1453 {
1454     bool bMirroredMargins = false;
1455     if ( UseOnPage::Mirror == (UseOnPage::Mirror & m_pDoc->GetPageDesc(0).ReadUseOn()) )
1456     {
1457         bMirroredMargins = true;
1458     }
1459     return bMirroredMargins;
1460 }
1461 
1462 void DocxExport::WriteMainText()
1463 {
1464     // setup the namespaces
1465     m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
1466 
1467     if ( getenv("SW_DEBUG_DOM") )
1468     {
1469         m_pDoc->dumpAsXml();
1470     }
1471 
1472     // reset the incrementing linked-textboxes chain ID before re-saving.
1473     m_nLinkedTextboxesChainId=0;
1474     m_aLinkedTextboxesHelper.clear();
1475 
1476     // Write background page color
1477     if (boost::optional<SvxBrushItem> oBrush = getBackground())
1478     {
1479         Color backgroundColor = oBrush->GetColor();
1480         OString aBackgroundColorStr = msfilter::util::ConvertColor(backgroundColor);
1481 
1482         m_pDocumentFS->singleElementNS( XML_w, XML_background, FSNS( XML_w, XML_color ), aBackgroundColorStr, FSEND );
1483     }
1484 
1485     // body
1486     m_pDocumentFS->startElementNS( XML_w, XML_body, FSEND );
1487 
1488     m_pCurPam->GetPoint()->nNode = m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
1489 
1490     // the text
1491     WriteText();
1492 
1493     // clear linked textboxes since old ones can't be linked to frames in a different section (correct?)
1494     m_aLinkedTextboxesHelper.clear();
1495 
1496     // the last section info
1497     m_pAttrOutput->EndParaSdtBlock();
1498     const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): nullptr;
1499     if ( pSectionInfo )
1500         SectionProperties( *pSectionInfo );
1501 
1502     // finish body and document
1503     m_pDocumentFS->endElementNS( XML_w, XML_body );
1504     m_pDocumentFS->endElementNS( XML_w, XML_document );
1505 }
1506 
1507 XFastAttributeListRef DocxExport::MainXmlNamespaces()
1508 {
1509     FastAttributeList* pAttr = FastSerializerHelper::createAttrList();
1510     pAttr->add( FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr() );
1511     pAttr->add( FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr() );
1512     pAttr->add( FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr() );
1513     pAttr->add( FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr() );
1514     pAttr->add( FSNS( XML_xmlns, XML_w10 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlWord)), RTL_TEXTENCODING_UTF8).getStr() );
1515     pAttr->add( FSNS( XML_xmlns, XML_wp ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(dmlWordDr)), RTL_TEXTENCODING_UTF8).getStr() );
1516     pAttr->add( FSNS( XML_xmlns, XML_wps ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wps)), RTL_TEXTENCODING_UTF8).getStr() );
1517     pAttr->add( FSNS( XML_xmlns, XML_wpg ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wpg)), RTL_TEXTENCODING_UTF8).getStr() );
1518     pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() );
1519     pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() );
1520     pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() );
1521     pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
1522     return XFastAttributeListRef( pAttr );
1523 }
1524 
1525 bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const
1526 {
1527     if( nWhich == RES_TEXTGRID )
1528         return true; // w:docGrid is written only to document.xml, not to styles.xml
1529     if (nWhich == RES_PARATR_HYPHENZONE)
1530         return true; // w:suppressAutoHyphens is only a formatting exception, not a default
1531     return MSWordExportBase::ignoreAttributeForStyleDefaults( nWhich );
1532 }
1533 
1534 void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp)
1535 {
1536     const EditTextObject& rEditObj = rParaObj.GetTextObject();
1537     MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp );
1538 
1539     sal_Int32 nPara = rEditObj.GetParagraphCount();
1540     for( sal_Int32 n = 0; n < nPara; ++n )
1541     {
1542         if( n )
1543             aAttrIter.NextPara( n );
1544 
1545         AttrOutput().StartParagraph( ww8::WW8TableNodeInfo::Pointer_t());
1546         rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
1547         OUString aStr( rEditObj.GetText( n ));
1548         sal_Int32 nCurrentPos = 0;
1549         const sal_Int32 nEnd = aStr.getLength();
1550         do {
1551             AttrOutput().StartRun( nullptr, 0 );
1552             const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
1553             rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
1554 
1555             bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
1556             if( !bTextAtr )
1557             {
1558                 if( nCurrentPos == 0 && nNextAttr - nCurrentPos == aStr.getLength())
1559                     AttrOutput().RunText( aStr, eChrSet );
1560                 else
1561                 {
1562                     OUString tmp( aStr.copy( nCurrentPos, nNextAttr - nCurrentPos ));
1563                     AttrOutput().RunText( tmp, eChrSet );
1564                 }
1565             }
1566             AttrOutput().StartRunProperties();
1567             aAttrIter.OutAttr( nCurrentPos );
1568             AttrOutput().EndRunProperties( nullptr );
1569 
1570             nCurrentPos = nNextAttr;
1571             eChrSet = eNextChrSet;
1572             aAttrIter.NextPos();
1573 
1574             AttrOutput().EndRun( nullptr, 0 );
1575 
1576         } while( nCurrentPos < nEnd );
1577 //        aAttrIter.OutParaAttr(false);
1578         AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
1579     }
1580 }
1581 
1582 void DocxExport::SetFS( ::sax_fastparser::FSHelperPtr const & pFS )
1583 {
1584     mpFS = pFS;
1585 }
1586 
1587 DocxExport::DocxExport(DocxExportFilter* pFilter, SwDoc* pDocument, SwPaM* pCurrentPam,
1588                        SwPaM* pOriginalPam, bool bDocm, bool bTemplate)
1589     : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
1590       m_pFilter( pFilter ),
1591       m_nHeaders( 0 ),
1592       m_nFooters( 0 ),
1593       m_nOLEObjects( 0 ),
1594       m_nActiveXControls( 0 ),
1595       m_nHeadersFootersInSection(0),
1596       m_bDocm(bDocm),
1597       m_bTemplate(bTemplate)
1598 {
1599     // Write the document properties
1600     WriteProperties( );
1601 
1602     // relations for the document
1603     m_pFilter->addRelation( oox::getRelationship(Relationship::OFFICEDOCUMENT),
1604             "word/document.xml" );
1605 
1606     // Set media type depending of document type
1607     OUString aMediaType;
1608     if (m_bDocm)
1609     {
1610         if (m_bTemplate)
1611         {
1612             aMediaType = "application/vnd.ms-word.template.macroEnabledTemplate.main+xml";
1613         }
1614         else
1615         {
1616             aMediaType = "application/vnd.ms-word.document.macroEnabled.main+xml";
1617         }
1618     }
1619     else
1620     {
1621         if (m_bTemplate)
1622         {
1623             aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml";
1624         }
1625         else
1626         {
1627             aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
1628         }
1629     }
1630 
1631 
1632     // the actual document
1633     m_pDocumentFS = m_pFilter->openFragmentStreamWithSerializer( "word/document.xml", aMediaType );
1634 
1635     SetFS(m_pDocumentFS);
1636 
1637     // the DrawingML access
1638     m_pDrawingML.reset(new oox::drawingml::DrawingML(m_pDocumentFS, m_pFilter, oox::drawingml::DOCUMENT_DOCX));
1639 
1640     // the attribute output for the document
1641     m_pAttrOutput.reset(new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML.get() ));
1642 
1643     // the related VMLExport
1644     m_pVMLExport.reset(new VMLExport( m_pDocumentFS, m_pAttrOutput.get() ));
1645 
1646     // the related drawing export
1647     m_pSdrExport.reset(new DocxSdrExport( *this, m_pDocumentFS, m_pDrawingML.get() ));
1648 }
1649 
1650 DocxExport::~DocxExport()
1651 {
1652 }
1653 
1654 DocxSettingsData::DocxSettingsData()
1655 : evenAndOddHeaders( false )
1656 , defaultTabStop( 0 )
1657 , trackRevisions( false )
1658 {
1659 }
1660 
1661 bool DocxSettingsData::hasData() const
1662 {
1663     if( evenAndOddHeaders )
1664         return true;
1665     if( defaultTabStop != 0 )
1666         return true;
1667     if ( trackRevisions )
1668         return true;
1669 
1670     return false;
1671 }
1672 
1673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1674